From f4cd3a72fa2a3630ccab2c0224777c3eff05380e Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 20 Aug 2011 14:55:41 -0700 Subject: added rainy day test for ipv6 tests. fixed ipv6.to_global to trap correct exception. --- nova/ipv6/rfc2462.py | 2 +- nova/tests/test_ipv6.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/nova/ipv6/rfc2462.py b/nova/ipv6/rfc2462.py index 0074efe98..351df742e 100644 --- a/nova/ipv6/rfc2462.py +++ b/nova/ipv6/rfc2462.py @@ -30,7 +30,7 @@ def to_global(prefix, mac, project_id): maskIP = netaddr.IPNetwork(prefix).ip return (mac64_addr ^ netaddr.IPAddress('::0200:0:0:0') | maskIP).\ format() - except TypeError: + except netaddr.AddrFormatError: raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index d123df6f1..12d64f776 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -23,6 +23,7 @@ from nova import test LOG = logging.getLogger('nova.tests.test_ipv6') import sys +import netaddr class IPv6RFC2462TestCase(test.TestCase): @@ -40,6 +41,11 @@ class IPv6RFC2462TestCase(test.TestCase): mac = ipv6.to_mac('2001:db8::216:3eff:fe33:4455') self.assertEquals(mac, '00:16:3e:33:44:55') + def test_to_global_with_bad_mac(self): + bad_mac = '02:16:3e:33:44:5Z' + self.assertRaises(TypeError, ipv6.to_global, + '2001:db8::', bad_mac, 'test') + class IPv6AccountIdentiferTestCase(test.TestCase): """Unit tests for IPv6 account_identifier backend operations.""" -- cgit From bad921b5efa7b11a91d1df32b3d17fdb95852589 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 20 Aug 2011 15:07:37 -0700 Subject: removed leftover netaddr import --- nova/tests/test_ipv6.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 12d64f776..891d52358 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -23,7 +23,6 @@ from nova import test LOG = logging.getLogger('nova.tests.test_ipv6') import sys -import netaddr class IPv6RFC2462TestCase(test.TestCase): -- cgit From 43e2ca531f0fdea5173b7f237627fc3543caf13b Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 20 Aug 2011 15:30:59 -0700 Subject: lp:828610 --- nova/ipv6/account_identifier.py | 2 +- nova/tests/test_ipv6.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nova/ipv6/account_identifier.py b/nova/ipv6/account_identifier.py index 258678f0a..02b653925 100644 --- a/nova/ipv6/account_identifier.py +++ b/nova/ipv6/account_identifier.py @@ -34,7 +34,7 @@ def to_global(prefix, mac, project_id): mac_addr = netaddr.IPAddress(int_addr) maskIP = netaddr.IPNetwork(prefix).ip return (project_hash ^ static_num ^ mac_addr | maskIP).format() - except TypeError: + except netaddr.AddrFormatError: raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index d123df6f1..6afc7e3f9 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -55,3 +55,8 @@ class IPv6AccountIdentiferTestCase(test.TestCase): def test_to_mac(self): mac = ipv6.to_mac('2001:db8::a94a:8fe5:ff33:4455') self.assertEquals(mac, '02:16:3e:33:44:55') + + def test_to_global_with_bad_mac(self): + bad_mac = '02:16:3e:33:44:5X' + self.assertRaises(TypeError, ipv6.to_global, + '2001:db8::', bad_mac, 'test') -- cgit From 3bbecbbb8c857079f75bea6fc6610bce9942de34 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 20 Aug 2011 18:20:55 -0700 Subject: added unit tests for versions.py --- nova/tests/test_versions.py | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 nova/tests/test_versions.py diff --git a/nova/tests/test_versions.py b/nova/tests/test_versions.py new file mode 100644 index 000000000..9578eda6d --- /dev/null +++ b/nova/tests/test_versions.py @@ -0,0 +1,58 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Ken Pepple +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +from nova import exception +from nova import test +from nova import utils +from nova import version + + +class VersionTestCase(test.TestCase): + def setUp(self): + """setup test with unchanging values""" + super(VersionTestCase, self).setUp() + self.version = version + self.version.FINAL = False + self.version.NOVA_VERSION = ['2012', '10'] + self.version.YEAR, self.version.COUNT = self.version.NOVA_VERSION + self.version.version_info = {'branch_nick': u'LOCALBRANCH', + 'revision_id': 'LOCALREVISION', + 'revno': 0} + + def test_version_string_is_good(self): + """Ensure version string works""" + self.assertEqual("2012.10-dev", self.version.version_string()) + + def test_canonical_version_string_is_good(self): + """Ensure canonical version works""" + self.assertEqual("2012.10", self.version.canonical_version_string()) + + def test_final_version_strings_are_identical(self): + """Ensure final version strings match""" + self.version.FINAL = True + self.assertEqual(self.version.canonical_version_string(), + self.version.version_string()) + + def test_vcs_version_string_is_good(self): + """""" + self.assertEqual("LOCALBRANCH:LOCALREVISION", + self.version.vcs_version_string()) + + def test_version_string_with_vcs_is_good(self): + """""" + self.assertEqual("2012.10-LOCALBRANCH:LOCALREVISION", + self.version.version_string_with_vcs()) -- cgit From f2981d8463779fa1fca52c840d91b47845719340 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 20 Aug 2011 18:28:30 -0700 Subject: comment strings --- nova/tests/test_versions.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nova/tests/test_versions.py b/nova/tests/test_versions.py index 9578eda6d..4621b042b 100644 --- a/nova/tests/test_versions.py +++ b/nova/tests/test_versions.py @@ -22,6 +22,7 @@ from nova import version class VersionTestCase(test.TestCase): + """Test cases for Versions code""" def setUp(self): """setup test with unchanging values""" super(VersionTestCase, self).setUp() @@ -42,17 +43,19 @@ class VersionTestCase(test.TestCase): self.assertEqual("2012.10", self.version.canonical_version_string()) def test_final_version_strings_are_identical(self): - """Ensure final version strings match""" + """Ensure final version strings match only at release""" + self.assertNotEqual(self.version.canonical_version_string(), + self.version.version_string()) self.version.FINAL = True self.assertEqual(self.version.canonical_version_string(), self.version.version_string()) def test_vcs_version_string_is_good(self): - """""" + """Ensure uninstalled code generates local """ self.assertEqual("LOCALBRANCH:LOCALREVISION", self.version.vcs_version_string()) def test_version_string_with_vcs_is_good(self): - """""" + """Ensure uninstalled code get version string""" self.assertEqual("2012.10-LOCALBRANCH:LOCALREVISION", self.version.version_string_with_vcs()) -- cgit From 0fdbea56baaef08575b98e8a553ceac9876e4962 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sun, 21 Aug 2011 17:52:14 -0700 Subject: added exception catch and test for bad prefix --- nova/ipv6/rfc2462.py | 2 ++ nova/tests/test_ipv6.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/nova/ipv6/rfc2462.py b/nova/ipv6/rfc2462.py index 351df742e..acf42d201 100644 --- a/nova/ipv6/rfc2462.py +++ b/nova/ipv6/rfc2462.py @@ -32,6 +32,8 @@ def to_global(prefix, mac, project_id): format() except netaddr.AddrFormatError: raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) + except TypeError: + raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix) def to_mac(ipv6_address): diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 891d52358..6e72b7330 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -45,6 +45,13 @@ class IPv6RFC2462TestCase(test.TestCase): self.assertRaises(TypeError, ipv6.to_global, '2001:db8::', bad_mac, 'test') + def test_to_global_with_bad_prefix(self): + bad_prefix = '82' + self.assertRaises(TypeError, ipv6.to_global, + bad_prefix, + '2001:db8::216:3eff:fe33:4455', + 'test') + class IPv6AccountIdentiferTestCase(test.TestCase): """Unit tests for IPv6 account_identifier backend operations.""" -- cgit From 326cfda8cc50f5db083e9df381d3109e0302605d Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sun, 21 Aug 2011 17:55:54 -0700 Subject: added exception catch for bad prefix and matching test --- nova/ipv6/account_identifier.py | 2 ++ nova/tests/test_ipv6.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/nova/ipv6/account_identifier.py b/nova/ipv6/account_identifier.py index 02b653925..4ca7b5983 100644 --- a/nova/ipv6/account_identifier.py +++ b/nova/ipv6/account_identifier.py @@ -36,6 +36,8 @@ def to_global(prefix, mac, project_id): return (project_hash ^ static_num ^ mac_addr | maskIP).format() except netaddr.AddrFormatError: raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) + except TypeError: + raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix) def to_mac(ipv6_address): diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 6afc7e3f9..f9c2517a7 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -60,3 +60,10 @@ class IPv6AccountIdentiferTestCase(test.TestCase): bad_mac = '02:16:3e:33:44:5X' self.assertRaises(TypeError, ipv6.to_global, '2001:db8::', bad_mac, 'test') + + def test_to_global_with_bad_prefix(self): + bad_prefix = '78' + self.assertRaises(TypeError, ipv6.to_global, + bad_prefix, + '2001:db8::a94a:8fe5:ff33:4455', + 'test') -- cgit From b5bf5fbb77e95b44f3254a111374ddba73016c4d Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sun, 21 Aug 2011 18:01:34 -0700 Subject: added exception catch and test for bad project_id --- nova/ipv6/account_identifier.py | 2 ++ nova/tests/test_ipv6.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/nova/ipv6/account_identifier.py b/nova/ipv6/account_identifier.py index 4ca7b5983..27bb01988 100644 --- a/nova/ipv6/account_identifier.py +++ b/nova/ipv6/account_identifier.py @@ -38,6 +38,8 @@ def to_global(prefix, mac, project_id): raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) except TypeError: raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix) + except NameError: + raise TypeError(_('Bad project_id for to_global_ipv6: %s') % project_id) def to_mac(ipv6_address): diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index f9c2517a7..5c333b17e 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -67,3 +67,10 @@ class IPv6AccountIdentiferTestCase(test.TestCase): bad_prefix, '2001:db8::a94a:8fe5:ff33:4455', 'test') + + def test_to_global_with_bad_project(self): + bad_project = 'non-existent-project-name' + self.assertRaises(TypeError, ipv6.to_global, + '2001:db8::', + '2001:db8::a94a:8fe5:ff33:4455', + bad_project) -- cgit From d4b09b85ad20bd0b83bc48d7bd1e0c6754b2649b Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sun, 21 Aug 2011 18:07:07 -0700 Subject: added test for bad project_id ... although it may not be used --- nova/tests/test_ipv6.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py index 6e72b7330..f151b9840 100644 --- a/nova/tests/test_ipv6.py +++ b/nova/tests/test_ipv6.py @@ -52,6 +52,13 @@ class IPv6RFC2462TestCase(test.TestCase): '2001:db8::216:3eff:fe33:4455', 'test') + def test_to_global_with_bad_project(self): + bad_project = 'non-existent-project-name' + self.assertRaises(TypeError, ipv6.to_global, + '2001:db8::', + '2001:db8::a94a:8fe5:ff33:4455', + bad_project) + class IPv6AccountIdentiferTestCase(test.TestCase): """Unit tests for IPv6 account_identifier backend operations.""" -- cgit From 360dbeebadb76b3628b2cfbd8b3c41e77581b24c Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 23 Aug 2011 17:31:19 -0400 Subject: rebuilds are functional again --- nova/api/openstack/servers.py | 14 ++++++++++---- nova/compute/api.py | 6 ++++-- nova/compute/manager.py | 6 ++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 553357404..fa499b192 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -604,8 +604,10 @@ class ControllerV10(Controller): LOG.debug(msg) raise exc.HTTPBadRequest(explanation=msg) + password = utils.generate_password(16) + try: - self.compute_api.rebuild(context, instance_id, image_id) + self.compute_api.rebuild(context, instance_id, image_id, password) except exception.BuildInProgress: msg = _("Instance %s is currently being rebuilt.") % instance_id LOG.debug(msg) @@ -741,15 +743,19 @@ class ControllerV11(Controller): self._validate_metadata(metadata) self._decode_personalities(personalities) + password = info["rebuild"].get("adminPass", + utils.generate_password(16)) + try: - self.compute_api.rebuild(context, instance_id, image_href, name, - metadata, personalities) + self.compute_api.rebuild(context, instance_id, image_href, + password, name=name, metadata=metadata, + files_to_inject=personalities) except exception.BuildInProgress: msg = _("Instance %s is currently being rebuilt.") % instance_id LOG.debug(msg) raise exc.HTTPConflict(explanation=msg) - return webob.Response(status_int=202) + return webob.Response(status_int=202, headers={'x-nova-password':password}) @common.check_snapshots_enabled def _action_create_image(self, input_dict, req, instance_id): diff --git a/nova/compute/api.py b/nova/compute/api.py index 69f76bf40..0ac38a428 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1023,8 +1023,8 @@ class API(base.Base): self._cast_compute_message('reboot_instance', context, instance_id) @scheduler_api.reroute_compute("rebuild") - def rebuild(self, context, instance_id, image_href, name=None, - metadata=None, files_to_inject=None): + def rebuild(self, context, instance_id, image_href, admin_password, + name=None, metadata=None, files_to_inject=None): """Rebuild the given instance with the provided metadata.""" instance = db.api.instance_get(context, instance_id) @@ -1044,6 +1044,7 @@ class API(base.Base): self.db.instance_update(context, instance_id, values) rebuild_params = { + "new_pass": admin_password, "image_ref": image_href, "injected_files": files_to_inject, } @@ -1052,6 +1053,7 @@ class API(base.Base): context, instance_id, params=rebuild_params) + return rebuild_params @scheduler_api.reroute_compute("revert_resize") def revert_resize(self, context, instance_id): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c207eccbb..40cd09044 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -527,6 +527,7 @@ class ComputeManager(manager.SchedulerDependentManager): :param context: `nova.RequestContext` object :param instance_id: Instance identifier (integer) :param image_ref: Image identifier (href or integer) + :param new_pass: password to set on rebuilt instance """ context = context.elevated() @@ -544,6 +545,11 @@ class ComputeManager(manager.SchedulerDependentManager): network_info = self.network_api.get_instance_nw_info(context, instance_ref) bd_mapping = self._setup_block_device_mapping(context, instance_id) + + # pull in new password here since the original password isn't in the db + new_pass = kwargs.get('new_pass') + instance_ref.admin_pass = new_pass + self.driver.spawn(context, instance_ref, network_info, bd_mapping) self._update_image_ref(context, instance_id, image_ref) -- cgit From 309a264db6c952081f2e85db21efc719596240a6 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 23 Aug 2011 20:59:24 -0400 Subject: updating tests --- nova/api/openstack/servers.py | 9 +- nova/tests/api/openstack/test_server_actions.py | 122 +++++++++++++++++------- 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fa499b192..fc74b8288 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -755,7 +755,11 @@ class ControllerV11(Controller): LOG.debug(msg) raise exc.HTTPConflict(explanation=msg) - return webob.Response(status_int=202, headers={'x-nova-password':password}) + instance = self.compute_api.routing_get(context, instance_id) + view = self._build_view(request, instance, is_detail=True) + view['server']['adminPass'] = password + + return view @common.check_snapshots_enabled def _action_create_image(self, input_dict, req, instance_id): @@ -822,6 +826,9 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer): def delete(self, response, data): response.status_int = 204 + def action(self, response, data): + response.status_int = 202 + class ServerXMLSerializer(wsgi.XMLDictSerializer): diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index bdd6824e7..769de4b34 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -1,4 +1,5 @@ import base64 +import datetime import json import stubout @@ -8,8 +9,11 @@ from nova import context from nova import utils from nova import flags from nova.api.openstack import create_instance_helper +from nova.compute import instance_types from nova.compute import power_state import nova.db.api +from nova.db.sqlalchemy.models import Instance +from nova.db.sqlalchemy.models import InstanceMetadata from nova import test from nova.tests.api.openstack import common from nova.tests.api.openstack import fakes @@ -19,61 +23,58 @@ FLAGS = flags.FLAGS def return_server_by_id(context, id): - return _get_instance() + return stub_instance(id) def instance_update(context, instance_id, kwargs): - return _get_instance() + return stub_instance(instance_id) -def return_server_with_power_state(power_state): +def return_server_with_attributes(**kwargs): def _return_server(context, id): - instance = _get_instance() - instance['state'] = power_state - return instance + return stub_instance(id, **kwargs) return _return_server +def return_server_with_power_state(power_state): + return return_server_with_attributes(power_state=power_state) + + def return_server_with_uuid_and_power_state(power_state): - def _return_server(context, id): - return return_server_with_power_state(power_state) - return _return_server + return return_server_with_power_state(power_state) -class MockSetAdminPassword(object): - def __init__(self): - self.instance_id = None - self.password = None +def stub_instance(id, power_state=0, metadata=None, + image_ref="10", flavor_id="1", name=None): - def __call__(self, context, instance_id, password): - self.instance_id = instance_id - self.password = password + if metadata is not None: + metadata_items = [{'key': k, 'value': v} for k, v in metadata.items()] + else: + metadata_items = [{'key': 'seq', 'value':id}] + inst_type = instance_types.get_instance_type_by_flavor_id(int(flavor_id)) -def _get_instance(): instance = { - "id": 1, - "created_at": "2010-10-10 12:00:00", - "updated_at": "2010-11-11 11:00:00", + "id": int(id), + "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), + "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), "admin_pass": "", - "user_id": "", - "project_id": "", - "image_ref": "5", + "user_id": "fake", + "project_id": "fake", + "image_ref": image_ref, "kernel_id": "", "ramdisk_id": "", "launch_index": 0, "key_name": "", "key_data": "", - "state": 0, + "state": power_state, "state_description": "", "memory_mb": 0, "vcpus": 0, "local_gb": 0, "hostname": "", "host": "", - "instance_type": { - "flavorid": 1, - }, + "instance_type": dict(inst_type), "user_data": "", "reservation_id": "", "mac_address": "", @@ -81,17 +82,32 @@ def _get_instance(): "launched_at": utils.utcnow(), "terminated_at": utils.utcnow(), "availability_zone": "", - "display_name": "test_server", + "display_name": name or "server%s" % id, "display_description": "", "locked": False, - "metadata": [], - #"address": , - #"floating_ips": [{"address":ip} for ip in public_addresses]} - "uuid": "deadbeef-feed-edee-beef-d0ea7beefedd"} + "metadata": metadata_items, + "access_ip_v4": "", + "access_ip_v6": "", + "uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + "virtual_interfaces": []} + + instance["fixed_ips"] = { + "address": '192.168.0.1', + "floating_ips": []} return instance +class MockSetAdminPassword(object): + def __init__(self): + self.instance_id = None + self.password = None + + def __call__(self, context, instance_id, password): + self.instance_id = instance_id + self.password = password + + class ServerActionsTest(test.TestCase): def setUp(self): @@ -598,6 +614,9 @@ class ServerActionsTestV11(test.TestCase): self.assertEqual(res.status_int, 400) def test_server_rebuild_accepted_minimum(self): + new_return_server = return_server_with_attributes(image_ref='2') + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + body = { "rebuild": { "imageRef": "http://localhost/images/2", @@ -611,6 +630,9 @@ class ServerActionsTestV11(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 202) + body = json.loads(res.body) + self.assertEqual(body['server']['image']['id'], '2') + self.assertEqual(len(body['server']['adminPass']), 16) def test_server_rebuild_rejected_when_building(self): body = { @@ -634,12 +656,15 @@ class ServerActionsTestV11(test.TestCase): self.assertEqual(res.status_int, 409) def test_server_rebuild_accepted_with_metadata(self): + metadata = {'new': 'metadata'} + + new_return_server = return_server_with_attributes(metadata=metadata) + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + body = { "rebuild": { "imageRef": "http://localhost/images/2", - "metadata": { - "new": "metadata", - }, + "metadata": metadata, }, } @@ -649,7 +674,10 @@ class ServerActionsTestV11(test.TestCase): req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) + print res.body self.assertEqual(res.status_int, 202) + body = json.loads(res.body) + self.assertEqual(body['server']['metadata'], metadata) def test_server_rebuild_accepted_with_bad_metadata(self): body = { @@ -719,6 +747,30 @@ class ServerActionsTestV11(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 202) + body = json.loads(res.body) + self.assertTrue('personality' not in body['server']) + + def test_server_rebuild_admin_pass(self): + new_return_server = return_server_with_attributes(image_ref='2') + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + body = { + "rebuild": { + "imageRef": "http://localhost/images/2", + "adminPass": "asdf", + }, + } + + req = webob.Request.blank('/v1.1/fake/servers/1/action') + req.method = 'POST' + req.content_type = 'application/json' + req.body = json.dumps(body) + + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 202) + body = json.loads(res.body) + self.assertEqual(body['server']['image']['id'], '2') + self.assertEqual(body['server']['adminPass'], 'asdf') def test_resize_server(self): -- cgit From 410edd037486a2e09bfc8276adc2a25459e2e2c8 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 23 Aug 2011 22:00:42 -0400 Subject: cleanup --- nova/compute/api.py | 1 - nova/compute/manager.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 0ac38a428..06f09f9a6 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1053,7 +1053,6 @@ class API(base.Base): context, instance_id, params=rebuild_params) - return rebuild_params @scheduler_api.reroute_compute("revert_resize") def revert_resize(self, context, instance_id): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 40cd09044..d3a4c6f88 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -547,8 +547,8 @@ class ComputeManager(manager.SchedulerDependentManager): bd_mapping = self._setup_block_device_mapping(context, instance_id) # pull in new password here since the original password isn't in the db - new_pass = kwargs.get('new_pass') - instance_ref.admin_pass = new_pass + instance_ref.admin_pass = kwargs.get('new_pass', + utils.generate_password(FLAGS.password_length)) self.driver.spawn(context, instance_ref, network_info, bd_mapping) -- cgit From 8b6f6145a4a99f8b60e77cb8758ffcc2c0591ebd Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 23 Aug 2011 23:27:36 -0400 Subject: removing print statement --- nova/tests/api/openstack/test_server_actions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 769de4b34..aeb132e87 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -674,7 +674,6 @@ class ServerActionsTestV11(test.TestCase): req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) - print res.body self.assertEqual(res.status_int, 202) body = json.loads(res.body) self.assertEqual(body['server']['metadata'], metadata) -- cgit From 8191cd38b2030a9d8816bcc21bd0cbc0119a7d91 Mon Sep 17 00:00:00 2001 From: Thierry Carrez Date: Wed, 24 Aug 2011 14:42:30 +0200 Subject: Thou shalt not use underscores in hostnames --- nova/compute/api.py | 6 +++--- nova/tests/test_compute.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 69f76bf40..88ba81018 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -55,15 +55,15 @@ def generate_default_hostname(instance): """Default function to generate a hostname given an instance reference.""" display_name = instance['display_name'] if display_name is None: - return 'server_%d' % (instance['id'],) + return 'server-%d' % (instance['id'],) table = '' deletions = '' for i in xrange(256): c = chr(i) if ('a' <= c <= 'z') or ('0' <= c <= '9') or (c == '-'): table += c - elif c == ' ': - table += '_' + elif (c == ' ') or (c == '_'): + table += '-' elif ('A' <= c <= 'Z'): table += c.lower() else: diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 0523d73b6..6659b81eb 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -175,8 +175,9 @@ class ComputeTestCase(test.TestCase): db.instance_destroy(self.context, instance_id) def test_default_hostname_generator(self): - cases = [(None, 'server_1'), ('Hello, Server!', 'hello_server'), - ('<}\x1fh\x10e\x08l\x02l\x05o\x12!{>', 'hello')] + cases = [(None, 'server-1'), ('Hello, Server!', 'hello-server'), + ('<}\x1fh\x10e\x08l\x02l\x05o\x12!{>', 'hello'), + ('hello_server', 'hello-server')] for display_name, hostname in cases: ref = self.compute_api.create(self.context, instance_types.get_default_instance_type(), None, -- cgit From bc235682305c3eb70eb80f1dddc15d86359a9ca3 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 24 Aug 2011 09:38:43 -0400 Subject: pep8 --- nova/tests/api/openstack/test_server_actions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index aeb132e87..926420407 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -48,9 +48,9 @@ def stub_instance(id, power_state=0, metadata=None, image_ref="10", flavor_id="1", name=None): if metadata is not None: - metadata_items = [{'key': k, 'value': v} for k, v in metadata.items()] + metadata_items = [{'key':k, 'value':v} for k, v in metadata.items()] else: - metadata_items = [{'key': 'seq', 'value':id}] + metadata_items = [{'key':'seq', 'value':id}] inst_type = instance_types.get_instance_type_by_flavor_id(int(flavor_id)) -- cgit From e5e95e1bfb6b1569b7e30a7066a0cd9c6ebff2c7 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 24 Aug 2011 10:06:20 -0400 Subject: removing extraneous imports --- nova/tests/api/openstack/test_server_actions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 926420407..057277887 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -12,8 +12,6 @@ from nova.api.openstack import create_instance_helper from nova.compute import instance_types from nova.compute import power_state import nova.db.api -from nova.db.sqlalchemy.models import Instance -from nova.db.sqlalchemy.models import InstanceMetadata from nova import test from nova.tests.api.openstack import common from nova.tests.api.openstack import fakes -- cgit From 3d4d3d7f422c7327346b5731ad3c620f279411f2 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 24 Aug 2011 10:37:59 -0400 Subject: adding xml serialization and handling instance not found --- nova/api/openstack/servers.py | 8 ++ nova/tests/api/openstack/test_server_actions.py | 20 ++++ nova/tests/api/openstack/test_servers.py | 135 ++++++++++++++++++++++++ 3 files changed, 163 insertions(+) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fc74b8288..27c67e79e 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -754,6 +754,9 @@ class ControllerV11(Controller): msg = _("Instance %s is currently being rebuilt.") % instance_id LOG.debug(msg) raise exc.HTTPConflict(explanation=msg) + except exception.InstanceNotFound: + msg = _("Instance %s could not be found") % instance_id + raise exc.HTTPNotFound(explanation=msg) instance = self.compute_api.routing_get(context, instance_id) view = self._build_view(request, instance, is_detail=True) @@ -950,6 +953,11 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): node.setAttribute('adminPass', server_dict['server']['adminPass']) return self.to_xml_string(node, True) + def action(self, server_dict): + #NOTE(bcwaldon): We need a way to serialize actions individually. This + # assumes all actions return a server entity + return self.create(server_dict) + def update(self, server_dict): xml_doc = minidom.Document() node = self._server_to_xml_detailed(xml_doc, diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 057277887..9a664f44d 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -7,6 +7,7 @@ import webob from nova import context from nova import utils +from nova import exception from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types @@ -769,6 +770,25 @@ class ServerActionsTestV11(test.TestCase): self.assertEqual(body['server']['image']['id'], '2') self.assertEqual(body['server']['adminPass'], 'asdf') + def test_server_rebuild_server_not_found(self): + def server_not_found(self, instance_id): + raise exception.InstanceNotFound(instance_id=instance_id) + self.stubs.Set(nova.db.api, 'instance_get', server_not_found) + + body = { + "rebuild": { + "imageRef": "http://localhost/images/2", + }, + } + + req = webob.Request.blank('/v1.1/fake/servers/1/action') + req.method = 'POST' + req.content_type = 'application/json' + req.body = json.dumps(body) + + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 404) + def test_resize_server(self): req = webob.Request.blank('/v1.1/fake/servers/1/action') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index aec2ad947..e533fb190 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -4541,3 +4541,138 @@ class ServerXMLSerializationTest(test.TestCase): str(ip['version'])) self.assertEqual(str(ip_elem.get('addr')), str(ip['addr'])) + + def test_action(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "accessIPv4": "1.2.3.4", + "accessIPv6": "fead::1234", + "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0", + "adminPass": "test_password", + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'action') + root = etree.XML(output) + xmlutil.validate_schema(root, 'server') + + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + server_dict = fixture['server'] + + for key in ['name', 'id', 'uuid', 'created', 'accessIPv4', + 'updated', 'progress', 'status', 'hostId', + 'accessIPv6', 'adminPass']: + self.assertEqual(root.get(key), str(server_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(server_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = root.find('{0}metadata'.format(NS)) + metadata_elems = metadata_root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 2) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = server_dict['metadata'].items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) + + image_root = root.find('{0}image'.format(NS)) + self.assertEqual(image_root.get('id'), server_dict['image']['id']) + link_nodes = image_root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 1) + for i, link in enumerate(server_dict['image']['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + flavor_root = root.find('{0}flavor'.format(NS)) + self.assertEqual(flavor_root.get('id'), server_dict['flavor']['id']) + link_nodes = flavor_root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 1) + for i, link in enumerate(server_dict['flavor']['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + addresses_root = root.find('{0}addresses'.format(NS)) + addresses_dict = server_dict['addresses'] + network_elems = addresses_root.findall('{0}network'.format(NS)) + self.assertEqual(len(network_elems), 2) + for i, network_elem in enumerate(network_elems): + network = addresses_dict.items()[i] + self.assertEqual(str(network_elem.get('id')), str(network[0])) + ip_elems = network_elem.findall('{0}ip'.format(NS)) + for z, ip_elem in enumerate(ip_elems): + ip = network[1][z] + self.assertEqual(str(ip_elem.get('version')), + str(ip['version'])) + self.assertEqual(str(ip_elem.get('addr')), + str(ip['addr'])) -- cgit From 6e3d657c5733154bbf818bb5318fa5da2deb0122 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 24 Aug 2011 10:45:53 -0400 Subject: fixed indentation --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index d3a4c6f88..ade15e310 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -548,7 +548,7 @@ class ComputeManager(manager.SchedulerDependentManager): # pull in new password here since the original password isn't in the db instance_ref.admin_pass = kwargs.get('new_pass', - utils.generate_password(FLAGS.password_length)) + utils.generate_password(FLAGS.password_length)) self.driver.spawn(context, instance_ref, network_info, bd_mapping) -- cgit From 998f40594841094291c7472dd608b6a2ba689e4d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 24 Aug 2011 11:11:20 -0400 Subject: dict formatting --- nova/tests/api/openstack/test_server_actions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index 9a664f44d..3dfdeb79c 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -88,11 +88,13 @@ def stub_instance(id, power_state=0, metadata=None, "access_ip_v4": "", "access_ip_v6": "", "uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", - "virtual_interfaces": []} + "virtual_interfaces": [], + } instance["fixed_ips"] = { "address": '192.168.0.1', - "floating_ips": []} + "floating_ips": [], + } return instance -- cgit From 326268b9bf5d958263b70c64ca2ed21deac1a14e Mon Sep 17 00:00:00 2001 From: Thierry Carrez Date: Wed, 24 Aug 2011 18:01:29 +0200 Subject: Let's be more elegant --- nova/compute/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 88ba81018..be1dbdd51 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -62,7 +62,7 @@ def generate_default_hostname(instance): c = chr(i) if ('a' <= c <= 'z') or ('0' <= c <= '9') or (c == '-'): table += c - elif (c == ' ') or (c == '_'): + elif c in " _": table += '-' elif ('A' <= c <= 'Z'): table += c.lower() -- cgit