diff options
Diffstat (limited to 'nova/tests')
99 files changed, 3069 insertions, 273 deletions
diff --git a/nova/tests/README.rst b/nova/tests/README.rst new file mode 100644 index 000000000..76b92258a --- /dev/null +++ b/nova/tests/README.rst @@ -0,0 +1,78 @@ +===================================== +OpenStack Nova Testing Infrastructure +===================================== + +This README file attempts to provide current and prospective contributors with +everything they need to know in order to start creating unit tests for nova. + +Note: the content for the rest of this file will be added as the work items in +the following blueprint are completed: + https://blueprints.launchpad.net/nova/+spec/consolidate-testing-infrastructure + + +Test Types: Unit vs. Functional vs. Integration +----------------------------------------------- + +TBD + +Writing Unit Tests +------------------ + +TBD + +Using Fakes +~~~~~~~~~~~ + +TBD + +test.TestCase +------------- +The TestCase class from nova.test (generally imported as test) will +automatically manage self.stubs using the stubout module and self.mox +using the mox module during the setUp step. They will automatically +verify and clean up during the tearDown step. + +If using test.TestCase, calling the super class setUp is required and +calling the super class tearDown is required to be last if tearDown +is overriden. + +Writing Functional Tests +------------------------ + +TBD + +Writing Integration Tests +------------------------- + +TBD + +Tests and Exceptions +-------------------- +A properly written test asserts that particular behavior occurs. This can +be a success condition or a failure condition, including an exception. +When asserting that a particular exception is raised, the most specific +exception possible should be used. + +In particular, testing for Exception being raised is almost always a +mistake since it will match (almost) every exception, even those +unrelated to the exception intended to be tested. + +This applies to catching exceptions manually with a try/except block, +or using assertRaises(). + +Example:: + + self.assertRaises(exception.InstanceNotFound, db.instance_get_by_uuid, + elevated, instance_uuid) + +If a stubbed function/method needs a generic exception for testing +purposes, test.TestingException is available. + +Example:: + + def stubbed_method(self): + raise test.TestingException() + self.stubs.Set(cls, 'inner_method', stubbed_method) + + obj = cls() + self.assertRaises(test.TestingException, obj.outer_method) diff --git a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py index dfb687cf4..76351e489 100644 --- a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py +++ b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py @@ -64,13 +64,6 @@ def fake_compute_api_get(self, context, instance_id): 'task_state': None} -def fake_scheduler_api_live_migration(self, context, dest, - block_migration=False, - disk_over_commit=False, instance=None, - instance_id=None, topic=None): - return None - - class AdminActionsTest(test.TestCase): _actions = ('pause', 'unpause', 'suspend', 'resume', 'migrate', @@ -93,9 +86,6 @@ class AdminActionsTest(test.TestCase): self.UUID = uuid.uuid4() for _method in self._methods: self.stubs.Set(compute_api.API, _method, fake_compute_api) - self.stubs.Set(scheduler_rpcapi.SchedulerAPI, - 'live_migration', - fake_scheduler_api_live_migration) self.flags( osapi_compute_extension=[ 'nova.api.openstack.compute.contrib.select_extensions'], @@ -150,7 +140,16 @@ class AdminActionsTest(test.TestCase): task_state, expected_task_state): return None + def fake_scheduler_api_live_migration(self, context, dest, + block_migration=False, + disk_over_commit=False, instance=None, + instance_id=None, topic=None): + return None + self.stubs.Set(compute_api.API, 'update', fake_update) + self.stubs.Set(scheduler_rpcapi.SchedulerAPI, + 'live_migration', + fake_scheduler_api_live_migration) res = req.get_response(app) self.assertEqual(res.status_int, 202) @@ -174,6 +173,44 @@ class AdminActionsTest(test.TestCase): res = req.get_response(app) self.assertEqual(res.status_int, 400) + def test_migrate_live_compute_service_unavailable(self): + ctxt = context.get_admin_context() + ctxt.user_id = 'fake' + ctxt.project_id = 'fake' + ctxt.is_admin = True + app = fakes.wsgi_app(fake_auth_context=ctxt, init_only=('servers',)) + req = webob.Request.blank('/v2/fake/servers/%s/action' % self.UUID) + req.method = 'POST' + req.body = jsonutils.dumps({ + 'os-migrateLive': { + 'host': 'hostname', + 'block_migration': False, + 'disk_over_commit': False, + } + }) + req.content_type = 'application/json' + + def fake_update(inst, context, instance, + task_state, expected_task_state): + return None + + def fake_scheduler_api_live_migration(context, dest, + block_migration=False, + disk_over_commit=False, instance=None, + instance_id=None, topic=None): + raise exception.ComputeServiceUnavailable(host='host') + + self.stubs.Set(compute_api.API, 'update', fake_update) + self.stubs.Set(scheduler_rpcapi.SchedulerAPI, + 'live_migration', + fake_scheduler_api_live_migration) + + res = req.get_response(app) + self.assertEqual(res.status_int, 400) + self.assertIn( + unicode(exception.ComputeServiceUnavailable(host='host')), + res.body) + class CreateBackupTests(test.TestCase): diff --git a/nova/tests/api/openstack/compute/contrib/test_console_output.py b/nova/tests/api/openstack/compute/contrib/test_console_output.py index d3f80b655..14b61abb7 100644 --- a/nova/tests/api/openstack/compute/contrib/test_console_output.py +++ b/nova/tests/api/openstack/compute/contrib/test_console_output.py @@ -35,6 +35,10 @@ def fake_get_console_output(self, _context, _instance, tail_length): return '\n'.join(fixture) +def fake_get_console_output_not_ready(self, _context, _instance, tail_length): + raise exception.InstanceNotReady(instance_id=_instance["uuid"]) + + def fake_get(self, context, instance_uuid): return {'uuid': instance_uuid} @@ -133,3 +137,15 @@ class ConsoleOutputExtensionTest(test.TestCase): res = req.get_response(self.app) self.assertEqual(res.status_int, 400) + + def test_get_console_output_not_ready(self): + self.stubs.Set(compute_api.API, 'get_console_output', + fake_get_console_output_not_ready) + body = {'os-getConsoleOutput': {'length': 3}} + req = webob.Request.blank('/v2/fake/servers/1/action') + req.method = "POST" + req.body = jsonutils.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(self.app) + self.assertEqual(res.status_int, 409) diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py b/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py index 8ebd810ac..d847e54f9 100644 --- a/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py +++ b/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py @@ -17,6 +17,7 @@ from lxml import etree import webob from nova.api.openstack.compute.contrib import extended_availability_zone +from nova import availability_zones from nova import compute from nova import exception from nova.openstack.common import jsonutils @@ -29,19 +30,20 @@ UUID3 = '00000000-0000-0000-0000-000000000003' def fake_compute_get(*args, **kwargs): - inst = fakes.stub_instance(1, uuid=UUID3, host="host-fake") - inst['availability_zone'] = 'az-i' + inst = fakes.stub_instance(1, uuid=UUID3, host="get-host") return inst def fake_compute_get_all(*args, **kwargs): - inst1 = fakes.stub_instance(1, uuid=UUID1, host="host-1") - inst2 = fakes.stub_instance(2, uuid=UUID2, host="host-2") - inst1['availability_zone'] = 'az-i' - inst2['availability_zone'] = 'az-i' + inst1 = fakes.stub_instance(1, uuid=UUID1, host="all-host") + inst2 = fakes.stub_instance(2, uuid=UUID2, host="all-host") return [inst1, inst2] +def fake_get_host_availability_zone(context, host): + return host + + class ExtendedServerAttributesTest(test.TestCase): content_type = 'application/json' prefix = 'OS-EXT-AZ:' @@ -51,6 +53,8 @@ class ExtendedServerAttributesTest(test.TestCase): fakes.stub_out_nw_api(self.stubs) self.stubs.Set(compute.api.API, 'get', fake_compute_get) self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all) + self.stubs.Set(availability_zones, 'get_host_availability_zone', + fake_get_host_availability_zone) self.flags( osapi_compute_extension=[ @@ -69,20 +73,16 @@ class ExtendedServerAttributesTest(test.TestCase): def _get_servers(self, body): return jsonutils.loads(body).get('servers') - def assertServerAttributes(self, server, az_instance, az_host): + def assertServerAttributes(self, server, az): self.assertEqual(server.get('%savailability_zone' % self.prefix), - az_instance) - self.assertEqual(server.get('%shost_availability_zone' % self.prefix), - az_host) + az) def test_show(self): url = '/v2/fake/servers/%s' % UUID3 res = self._make_request(url) self.assertEqual(res.status_int, 200) - self.assertServerAttributes(self._get_server(res.body), - az_instance='az-i', - az_host='nova') + self.assertServerAttributes(self._get_server(res.body), 'get-host') def test_detail(self): url = '/v2/fake/servers/detail' @@ -90,9 +90,7 @@ class ExtendedServerAttributesTest(test.TestCase): self.assertEqual(res.status_int, 200) for i, server in enumerate(self._get_servers(res.body)): - self.assertServerAttributes(server, - az_instance='az-i', - az_host='nova') + self.assertServerAttributes(server, 'all-host') def test_no_instance_passthrough_404(self): diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_ips.py b/nova/tests/api/openstack/compute/contrib/test_extended_ips.py new file mode 100644 index 000000000..9fd646b91 --- /dev/null +++ b/nova/tests/api/openstack/compute/contrib/test_extended_ips.py @@ -0,0 +1,168 @@ +# Copyright 2013 Nebula, Inc. +# All Rights Reserved. +# +# 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 lxml import etree +import webob + +from nova.api.openstack.compute.contrib import extended_ips +from nova.api.openstack import xmlutil +from nova import compute +from nova.openstack.common import jsonutils +from nova import test +from nova.tests.api.openstack import fakes + +UUID1 = '00000000-0000-0000-0000-000000000001' +UUID2 = '00000000-0000-0000-0000-000000000002' +UUID3 = '00000000-0000-0000-0000-000000000003' +NW_CACHE = [ + { + 'address': 'aa:aa:aa:aa:aa:aa', + 'id': 1, + 'network': { + 'bridge': 'br0', + 'id': 1, + 'label': 'private', + 'subnets': [ + { + 'cidr': '192.168.1.0/24', + 'ips': [ + { + 'address': '192.168.1.100', + 'type': 'fixed', + 'floating_ips': [ + {'address': '5.0.0.1', 'type': 'floating'}, + ], + }, + ], + }, + ] + } + }, + { + 'address': 'bb:bb:bb:bb:bb:bb', + 'id': 2, + 'network': { + 'bridge': 'br1', + 'id': 2, + 'label': 'public', + 'subnets': [ + { + 'cidr': '10.0.0.0/24', + 'ips': [ + { + 'address': '10.0.0.100', + 'type': 'fixed', + 'floating_ips': [ + {'address': '5.0.0.2', 'type': 'floating'}, + ], + } + ], + }, + ] + } + } +] +ALL_IPS = [] +for cache in NW_CACHE: + for subnet in cache['network']['subnets']: + for fixed in subnet['ips']: + sanitized = dict(fixed) + sanitized.pop('floating_ips') + ALL_IPS.append(sanitized) + for floating in fixed['floating_ips']: + ALL_IPS.append(floating) +ALL_IPS.sort() + + +def fake_compute_get(*args, **kwargs): + return fakes.stub_instance(1, uuid=UUID3, nw_cache=NW_CACHE) + + +def fake_compute_get_all(*args, **kwargs): + return [ + fakes.stub_instance(1, uuid=UUID1, nw_cache=NW_CACHE), + fakes.stub_instance(2, uuid=UUID2, nw_cache=NW_CACHE), + ] + + +class ExtendedIpsTest(test.TestCase): + content_type = 'application/json' + prefix = 'OS-EXT-IPS:' + + def setUp(self): + super(ExtendedIpsTest, self).setUp() + fakes.stub_out_nw_api(self.stubs) + self.stubs.Set(compute.api.API, 'get', fake_compute_get) + self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all) + self.flags( + osapi_compute_extension=[ + 'nova.api.openstack.compute.contrib.select_extensions'], + osapi_compute_ext_list=['Extended_ips']) + + def _make_request(self, url): + req = webob.Request.blank(url) + req.headers['Accept'] = self.content_type + res = req.get_response(fakes.wsgi_app(init_only=('servers',))) + return res + + def _get_server(self, body): + return jsonutils.loads(body).get('server') + + def _get_servers(self, body): + return jsonutils.loads(body).get('servers') + + def _get_ips(self, server): + for network in server['addresses'].itervalues(): + for ip in network: + yield ip + + def assertServerStates(self, server): + results = [] + for ip in self._get_ips(server): + results.append({'address': ip.get('addr'), + 'type': ip.get('%stype' % self.prefix)}) + + self.assertEqual(ALL_IPS, sorted(results)) + + def test_show(self): + url = '/v2/fake/servers/%s' % UUID3 + res = self._make_request(url) + + self.assertEqual(res.status_int, 200) + self.assertServerStates(self._get_server(res.body)) + + def test_detail(self): + url = '/v2/fake/servers/detail' + res = self._make_request(url) + + self.assertEqual(res.status_int, 200) + for i, server in enumerate(self._get_servers(res.body)): + self.assertServerStates(server) + + +class ExtendedIpsXmlTest(ExtendedIpsTest): + content_type = 'application/xml' + prefix = '{%s}' % extended_ips.Extended_ips.namespace + + def _get_server(self, body): + return etree.XML(body) + + def _get_servers(self, body): + return etree.XML(body).getchildren() + + def _get_ips(self, server): + for network in server.find('{%s}addresses' % xmlutil.XMLNS_V11): + for ip in network: + yield ip diff --git a/nova/tests/api/openstack/compute/contrib/test_instance_actions.py b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py new file mode 100644 index 000000000..b4db5daba --- /dev/null +++ b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py @@ -0,0 +1,231 @@ +# Copyright 2013 Rackspace Hosting +# All Rights Reserved. +# +# 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. + +import copy +import uuid + +from lxml import etree +from webob import exc + +from nova.api.openstack.compute.contrib import instance_actions +from nova import db +from nova import exception +from nova.openstack.common import policy +from nova import test +from nova.tests.api.openstack import fakes +from nova.tests import fake_instance_actions + +FAKE_UUID = fake_instance_actions.FAKE_UUID +FAKE_REQUEST_ID = fake_instance_actions.FAKE_REQUEST_ID1 + + +def format_action(action): + '''Remove keys that aren't serialized.''' + if 'id' in action: + del(action['id']) + if 'finish_time' in action: + del(action['finish_time']) + return action + + +def format_event(event): + '''Remove keys that aren't serialized.''' + if 'id' in event: + del(event['id']) + return event + + +class InstanceActionsPolicyTest(test.TestCase): + def setUp(self): + super(InstanceActionsPolicyTest, self).setUp() + self.controller = instance_actions.InstanceActionsController() + + def test_list_actions_restricted_by_project(self): + rules = policy.Rules({'compute:get': policy.parse_rule(''), + 'compute_extension:instance_actions': + policy.parse_rule('project_id:%(project_id)s')}) + policy.set_rules(rules) + + def fake_instance_get_by_uuid(context, instance_id): + return {'name': 'fake', 'project_id': '%s_unequal' % + context.project_id} + + self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid) + req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions') + self.assertRaises(exception.NotAuthorized, self.controller.index, req, + str(uuid.uuid4())) + + def test_get_action_restricted_by_project(self): + rules = policy.Rules({'compute:get': policy.parse_rule(''), + 'compute_extension:instance_actions': + policy.parse_rule('project_id:%(project_id)s')}) + policy.set_rules(rules) + + def fake_instance_get_by_uuid(context, instance_id): + return {'name': 'fake', 'project_id': '%s_unequal' % + context.project_id} + + self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid) + req = fakes.HTTPRequest.blank( + '/v2/123/servers/12/os-instance-actions/1') + self.assertRaises(exception.NotAuthorized, self.controller.show, req, + str(uuid.uuid4()), '1') + + +class InstanceActionsTest(test.TestCase): + def setUp(self): + super(InstanceActionsTest, self).setUp() + self.controller = instance_actions.InstanceActionsController() + self.fake_actions = copy.deepcopy(fake_instance_actions.FAKE_ACTIONS) + self.fake_events = copy.deepcopy(fake_instance_actions.FAKE_EVENTS) + + def fake_instance_get_by_uuid(context, instance_id): + return {'name': 'fake', 'project_id': context.project_id} + + self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid) + + def test_list_actions(self): + def fake_get_actions(context, uuid): + return self.fake_actions[uuid].values() + + self.stubs.Set(db, 'actions_get', fake_get_actions) + req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions') + res_dict = self.controller.index(req, FAKE_UUID) + for res in res_dict['instanceActions']: + fake_action = self.fake_actions[FAKE_UUID][res['request_id']] + fake_action = format_action(fake_action) + self.assertEqual(fake_action, res) + + def test_get_action_with_events_allowed(self): + def fake_get_action(context, uuid, request_id): + return self.fake_actions[uuid][request_id] + + def fake_get_events(context, action_id): + return self.fake_events[action_id] + + self.stubs.Set(db, 'action_get_by_request_id', fake_get_action) + self.stubs.Set(db, 'action_events_get', fake_get_events) + req = fakes.HTTPRequest.blank( + '/v2/123/servers/12/os-instance-actions/1', + use_admin_context=True) + res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID) + fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] + fake_events = self.fake_events[fake_action['id']] + fake_events = [format_event(event) for event in fake_events] + fake_action = format_action(fake_action) + fake_action['events'] = fake_events + self.assertEqual(fake_action, res_dict['instanceAction']) + + def test_get_action_with_events_not_allowed(self): + def fake_get_action(context, uuid, request_id): + return self.fake_actions[uuid][request_id] + + def fake_get_events(context, action_id): + return self.fake_events[action_id] + + self.stubs.Set(db, 'action_get_by_request_id', fake_get_action) + self.stubs.Set(db, 'action_events_get', fake_get_events) + rules = policy.Rules({'compute:get': policy.parse_rule(''), + 'compute_extension:instance_actions': + policy.parse_rule(''), + 'compute_extension:instance_actions:events': + policy.parse_rule('is_admin:True')}) + policy.set_rules(rules) + req = fakes.HTTPRequest.blank( + '/v2/123/servers/12/os-instance-actions/1') + res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID) + fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] + fake_action = format_action(fake_action) + self.assertEqual(fake_action, res_dict['instanceAction']) + + def test_action_not_found(self): + def fake_no_action(context, uuid, action_id): + return None + + self.stubs.Set(db, 'action_get_by_request_id', fake_no_action) + req = fakes.HTTPRequest.blank( + '/v2/123/servers/12/os-instance-actions/1') + self.assertRaises(exc.HTTPNotFound, self.controller.show, req, + FAKE_UUID, FAKE_REQUEST_ID) + + +class InstanceActionsSerializerTest(test.TestCase): + def setUp(self): + super(InstanceActionsSerializerTest, self).setUp() + self.fake_actions = copy.deepcopy(fake_instance_actions.FAKE_ACTIONS) + self.fake_events = copy.deepcopy(fake_instance_actions.FAKE_EVENTS) + + def _verify_instance_action_attachment(self, attach, tree): + for key in attach.keys(): + if key != 'events': + self.assertEqual(attach[key], tree.get(key), + '%s did not match' % key) + + def _verify_instance_action_event_attachment(self, attach, tree): + for key in attach.keys(): + self.assertEqual(attach[key], tree.get(key), + '%s did not match' % key) + + def test_instance_action_serializer(self): + serializer = instance_actions.InstanceActionTemplate() + action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] + text = serializer.serialize({'instanceAction': action}) + tree = etree.fromstring(text) + + action = format_action(action) + self.assertEqual('instanceAction', tree.tag) + self._verify_instance_action_attachment(action, tree) + found_events = False + for child in tree: + if child.tag == 'events': + found_events = True + self.assertFalse(found_events) + + def test_instance_action_events_serializer(self): + serializer = instance_actions.InstanceActionTemplate() + action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] + event = self.fake_events[action['id']][0] + action['events'] = [event, event] + text = serializer.serialize({'instanceAction': action}) + tree = etree.fromstring(text) + + action = format_action(action) + self.assertEqual('instanceAction', tree.tag) + self._verify_instance_action_attachment(action, tree) + + event = format_event(event) + found_events = False + for child in tree: + if child.tag == 'events': + found_events = True + for key in event: + self.assertEqual(event[key], child.get(key)) + self.assertTrue(found_events) + + def test_instance_actions_serializer(self): + serializer = instance_actions.InstanceActionsTemplate() + action_list = self.fake_actions[FAKE_UUID].values() + text = serializer.serialize({'instanceActions': action_list}) + tree = etree.fromstring(text) + + action_list = [format_action(action) for action in action_list] + self.assertEqual('instanceActions', tree.tag) + self.assertEqual(len(action_list), len(tree)) + for idx, child in enumerate(tree): + self.assertEqual('instanceAction', child.tag) + request_id = child.get('request_id') + self._verify_instance_action_attachment( + self.fake_actions[FAKE_UUID][request_id], + child) diff --git a/nova/tests/api/openstack/compute/contrib/test_quotas.py b/nova/tests/api/openstack/compute/contrib/test_quotas.py index 8d518b815..6636824fd 100644 --- a/nova/tests/api/openstack/compute/contrib/test_quotas.py +++ b/nova/tests/api/openstack/compute/contrib/test_quotas.py @@ -143,6 +143,45 @@ class QuotaSetsTest(test.TestCase): self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, req, 'update_me', body) + def test_quotas_update_invalid_value(self): + expected_resp = {'quota_set': { + 'instances': 50, 'cores': 50, + 'ram': 51200, 'floating_ips': 10, + 'metadata_items': 128, 'injected_files': 5, + 'injected_file_content_bytes': 10240, + 'injected_file_path_bytes': 255, + 'security_groups': 10, + 'security_group_rules': 20, + 'key_pairs': 100}} + + # when PUT JSON format with empty string for quota + body = {'quota_set': {'instances': 50, 'cores': 50, + 'ram': '', 'floating_ips': 10, + 'metadata_items': 128, 'injected_files': 5, + 'injected_file_content_bytes': 10240, + 'injected_file_path_bytes': 255, + 'security_groups': 10, + 'security_group_rules': 20, + 'key_pairs': 100}} + req = fakes.HTTPRequest.blank('/v2/fake4/os-quota-sets/update_me', + use_admin_context=True) + res_dict = self.controller.update(req, 'update_me', body) + self.assertEqual(res_dict, expected_resp) + + # when PUT XML format with empty string for quota + body = {'quota_set': {'instances': 50, 'cores': 50, + 'ram': {}, 'floating_ips': 10, + 'metadata_items': 128, 'injected_files': 5, + 'injected_file_content_bytes': 10240, + 'injected_file_path_bytes': 255, + 'security_groups': 10, + 'security_group_rules': 20, + 'key_pairs': 100}} + req = fakes.HTTPRequest.blank('/v2/fake4/os-quota-sets/update_me', + use_admin_context=True) + res_dict = self.controller.update(req, 'update_me', body) + self.assertEqual(res_dict, expected_resp) + class QuotaXMLSerializerTest(test.TestCase): def setUp(self): diff --git a/nova/tests/api/openstack/compute/contrib/test_security_groups.py b/nova/tests/api/openstack/compute/contrib/test_security_groups.py index 231923e6d..2823c3e8f 100644 --- a/nova/tests/api/openstack/compute/contrib/test_security_groups.py +++ b/nova/tests/api/openstack/compute/contrib/test_security_groups.py @@ -448,6 +448,9 @@ class TestSecurityGroups(test.TestCase): req, '1') def test_associate_by_non_existing_security_group_name(self): + self.stubs.Set(nova.db, 'instance_get', return_server) + self.assertEquals(return_server(None, '1'), + nova.db.instance_get(None, '1')) body = dict(addSecurityGroup=dict(name='non-existing')) req = fakes.HTTPRequest.blank('/v2/fake/servers/1/action') @@ -537,6 +540,9 @@ class TestSecurityGroups(test.TestCase): self.manager._addSecurityGroup(req, '1', body) def test_disassociate_by_non_existing_security_group_name(self): + self.stubs.Set(nova.db, 'instance_get', return_server) + self.assertEquals(return_server(None, '1'), + nova.db.instance_get(None, '1')) body = dict(removeSecurityGroup=dict(name='non-existing')) req = fakes.HTTPRequest.blank('/v2/fake/servers/1/action') @@ -1011,6 +1017,38 @@ class TestSecurityGroupRules(test.TestCase): self.controller.create, req, {'security_group_rule': rule}) + def test_create_rule_cidr_allow_all(self): + rule = security_group_rule_template(cidr='0.0.0.0/0') + + req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules') + res_dict = self.controller.create(req, {'security_group_rule': rule}) + + security_group_rule = res_dict['security_group_rule'] + self.assertNotEquals(security_group_rule['id'], 0) + self.assertEquals(security_group_rule['parent_group_id'], + self.parent_security_group['id']) + self.assertEquals(security_group_rule['ip_range']['cidr'], + "0.0.0.0/0") + + def test_create_rule_cidr_allow_some(self): + rule = security_group_rule_template(cidr='15.0.0.0/8') + + req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules') + res_dict = self.controller.create(req, {'security_group_rule': rule}) + + security_group_rule = res_dict['security_group_rule'] + self.assertNotEquals(security_group_rule['id'], 0) + self.assertEquals(security_group_rule['parent_group_id'], + self.parent_security_group['id']) + self.assertEquals(security_group_rule['ip_range']['cidr'], + "15.0.0.0/8") + + def test_create_rule_cidr_bad_netmask(self): + rule = security_group_rule_template(cidr='15.0.0.0/0') + req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules') + self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, + req, {'security_group_rule': rule}) + class TestSecurityGroupRulesXMLDeserializer(test.TestCase): diff --git a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py index 554379e74..eb708a574 100644 --- a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py +++ b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py @@ -17,6 +17,7 @@ import webob from nova.api.openstack.compute.contrib import server_start_stop from nova.compute import api as compute_api +from nova import exception from nova import test from nova.tests.api.openstack import fakes @@ -25,6 +26,10 @@ def fake_compute_api_get(self, context, instance_id): return {'id': 1, 'uuid': instance_id} +def fake_start_stop_not_ready(self, context, instance): + raise exception.InstanceNotReady(instance_id=instance["uuid"]) + + class ServerStartStopTest(test.TestCase): def setUp(self): @@ -41,6 +46,14 @@ class ServerStartStopTest(test.TestCase): body = dict(start="") self.controller._start_server(req, 'test_inst', body) + def test_start_not_ready(self): + self.stubs.Set(compute_api.API, 'get', fake_compute_api_get) + self.stubs.Set(compute_api.API, 'start', fake_start_stop_not_ready) + req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action') + body = dict(start="") + self.assertRaises(webob.exc.HTTPConflict, + self.controller._start_server, req, 'test_inst', body) + def test_stop(self): self.stubs.Set(compute_api.API, 'get', fake_compute_api_get) self.mox.StubOutWithMock(compute_api.API, 'stop') @@ -51,6 +64,14 @@ class ServerStartStopTest(test.TestCase): body = dict(stop="") self.controller._stop_server(req, 'test_inst', body) + def test_stop_not_ready(self): + self.stubs.Set(compute_api.API, 'get', fake_compute_api_get) + self.stubs.Set(compute_api.API, 'stop', fake_start_stop_not_ready) + req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action') + body = dict(start="") + self.assertRaises(webob.exc.HTTPConflict, + self.controller._stop_server, req, 'test_inst', body) + def test_start_with_bogus_id(self): req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action') body = dict(start="") diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index a52b0e0fc..9c45edc08 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -167,6 +167,7 @@ class ExtensionControllerTest(ExtensionTestCase): "DeferredDelete", "DiskConfig", "ExtendedAvailabilityZone", + "ExtendedIps", "Evacuate", "ExtendedStatus", "ExtendedServerAttributes", @@ -184,6 +185,7 @@ class ExtensionControllerTest(ExtensionTestCase): "FloatingIpsBulk", "Fox In Socks", "Hosts", + "InstanceActions", "Keypairs", "Multinic", "MultipleCreate", diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index a75ba00cc..5afaa8e3c 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -2640,10 +2640,11 @@ class ComputeTestCase(BaseTestCase): # creating mocks self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance') self.compute.driver.unfilter_instance(inst_ref, []) - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_start') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_start') migration = {'source_compute': srchost, 'dest_compute': dest, } - self.compute.network_api.migrate_instance_start(c, inst_ref, migration) + self.compute.conductor_api.network_migrate_instance_start(c, inst_ref, + migration) self.mox.StubOutWithMock(rpc, 'call') rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest), {"method": "post_live_migration_at_destination", @@ -2684,11 +2685,12 @@ class ComputeTestCase(BaseTestCase): # creating mocks self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance') self.compute.driver.unfilter_instance(inst_ref, []) - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_start') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_start') migration = {'source_compute': srchost, 'dest_compute': dest, } - self.compute.network_api.migrate_instance_start(c, inst_ref, migration) + self.compute.conductor_api.network_migrate_instance_start(c, inst_ref, + migration) self.mox.StubOutWithMock(rpc, 'call') rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest), {"method": "post_live_migration_at_destination", @@ -2710,8 +2712,8 @@ class ComputeTestCase(BaseTestCase): def test_post_live_migration_at_destination(self): self.mox.StubOutWithMock(self.compute.network_api, 'setup_networks_on_host') - self.mox.StubOutWithMock(self.compute.network_api, - 'migrate_instance_finish') + self.mox.StubOutWithMock(self.compute.conductor_api, + 'network_migrate_instance_finish') self.mox.StubOutWithMock(self.compute, '_get_power_state') self.mox.StubOutWithMock(self.compute, '_instance_update') @@ -2726,8 +2728,8 @@ class ComputeTestCase(BaseTestCase): self.compute.host) migration = {'source_compute': instance['host'], 'dest_compute': self.compute.host, } - self.compute.network_api.migrate_instance_finish(admin_ctxt, - instance, migration) + self.compute.conductor_api.network_migrate_instance_finish(admin_ctxt, + instance, migration) fake_net_info = [] fake_block_dev_info = {'foo': 'bar'} self.compute.driver.post_live_migration_at_destination(admin_ctxt, @@ -3804,6 +3806,15 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, instance['uuid']) + def test_start_no_host(self): + instance = self._create_fake_instance(params={'host': ''}) + + self.assertRaises(exception.InstanceNotReady, + self.compute_api.start, + self.context, instance) + + db.instance_destroy(self.context, instance['uuid']) + def test_stop(self): instance = jsonutils.to_primitive(self._create_fake_instance()) instance_uuid = instance['uuid'] @@ -3819,6 +3830,15 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, instance['uuid']) + def test_stop_no_host(self): + instance = self._create_fake_instance(params={'host': ''}) + + self.assertRaises(exception.InstanceNotReady, + self.compute_api.stop, + self.context, instance) + + db.instance_destroy(self.context, instance['uuid']) + def test_start_shutdown(self): def check_state(instance_uuid, power_state_, vm_state_, task_state_): instance = db.instance_get_by_uuid(self.context, instance_uuid) @@ -5657,6 +5677,15 @@ class ComputeAPITestCase(BaseTestCase): fake_instance, tail_length=fake_tail_length) self.assertEqual(output, fake_console_output) + def test_console_output_no_host(self): + instance = self._create_fake_instance(params={'host': ''}) + + self.assertRaises(exception.InstanceNotReady, + self.compute_api.get_console_output, + self.context, instance) + + db.instance_destroy(self.context, instance['uuid']) + def test_attach_volume(self): # Ensure instance can be soft rebooted. @@ -6161,6 +6190,16 @@ class ComputeAPIAggrTestCase(BaseTestCase): self.stubs.Set(rpc, 'call', fake_rpc_method) self.stubs.Set(rpc, 'cast', fake_rpc_method) + def test_aggregate_no_zone(self): + # Ensure we can create an aggregate without an availability zone + aggr = self.api.create_aggregate(self.context, 'fake_aggregate', + None) + self.api.delete_aggregate(self.context, aggr['id']) + db.aggregate_get(self.context.elevated(read_deleted='yes'), + aggr['id']) + self.assertRaises(exception.AggregateNotFound, + self.api.delete_aggregate, self.context, aggr['id']) + def test_update_aggregate_metadata(self): # Ensure metadata can be updated. aggr = self.api.create_aggregate(self.context, 'fake_aggregate', diff --git a/nova/tests/conductor/test_conductor.py b/nova/tests/conductor/test_conductor.py index bd73328e8..ed733599b 100644 --- a/nova/tests/conductor/test_conductor.py +++ b/nova/tests/conductor/test_conductor.py @@ -16,6 +16,7 @@ import mox +from nova.api.ec2 import ec2utils from nova.compute import instance_types from nova.compute import utils as compute_utils from nova.compute import vm_states @@ -31,6 +32,7 @@ from nova import notifications from nova.openstack.common import jsonutils from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils +from nova import quota from nova import test @@ -240,6 +242,15 @@ class _BaseTestCase(object): aggregate, 'fake') + def test_aggregate_metadata_get_by_host(self): + self.mox.StubOutWithMock(db, 'aggregate_metadata_get_by_host') + db.aggregate_metadata_get_by_host(self.context, 'host', + 'key').AndReturn('result') + self.mox.ReplayAll() + result = self.conductor.aggregate_metadata_get_by_host(self.context, + 'host', 'key') + self.assertEqual(result, 'result') + def test_bw_usage_update(self): self.mox.StubOutWithMock(db, 'bw_usage_update') self.mox.StubOutWithMock(db, 'bw_usage_get') @@ -503,6 +514,78 @@ class _BaseTestCase(object): self.conductor.security_groups_trigger_members_refresh(self.context, [1, 2, 3]) + def test_network_migrate_instance_start(self): + self.mox.StubOutWithMock(self.conductor_manager.network_api, + 'migrate_instance_start') + self.conductor_manager.network_api.migrate_instance_start(self.context, + 'instance', + 'migration') + self.mox.ReplayAll() + self.conductor.network_migrate_instance_start(self.context, + 'instance', + 'migration') + + def test_network_migrate_instance_finish(self): + self.mox.StubOutWithMock(self.conductor_manager.network_api, + 'migrate_instance_finish') + self.conductor_manager.network_api.migrate_instance_finish( + self.context, 'instance', 'migration') + self.mox.ReplayAll() + self.conductor.network_migrate_instance_finish(self.context, + 'instance', + 'migration') + + def test_quota_commit(self): + self.mox.StubOutWithMock(quota.QUOTAS, 'commit') + quota.QUOTAS.commit(self.context, 'reservations') + self.mox.ReplayAll() + self.conductor.quota_commit(self.context, 'reservations') + + def test_quota_commit(self): + self.mox.StubOutWithMock(quota.QUOTAS, 'rollback') + quota.QUOTAS.rollback(self.context, 'reservations') + self.mox.ReplayAll() + self.conductor.quota_rollback(self.context, 'reservations') + + def test_get_ec2_ids(self): + expected = { + 'instance-id': 'ec2-inst-id', + 'ami-id': 'ec2-ami-id', + 'kernel-id': 'ami-kernel-ec2-kernelid', + 'ramdisk-id': 'ami-ramdisk-ec2-ramdiskid', + } + inst = { + 'uuid': 'fake-uuid', + 'kernel_id': 'ec2-kernelid', + 'ramdisk_id': 'ec2-ramdiskid', + 'image_ref': 'fake-image', + } + self.mox.StubOutWithMock(ec2utils, 'id_to_ec2_inst_id') + self.mox.StubOutWithMock(ec2utils, 'glance_id_to_ec2_id') + self.mox.StubOutWithMock(ec2utils, 'image_type') + + ec2utils.id_to_ec2_inst_id(inst['uuid']).AndReturn( + expected['instance-id']) + ec2utils.glance_id_to_ec2_id(self.context, + inst['image_ref']).AndReturn( + expected['ami-id']) + for image_type in ['kernel', 'ramdisk']: + image_id = inst['%s_id' % image_type] + ec2utils.image_type(image_type).AndReturn('ami-' + image_type) + ec2utils.glance_id_to_ec2_id(self.context, image_id, + 'ami-' + image_type).AndReturn( + 'ami-%s-ec2-%sid' % (image_type, image_type)) + + self.mox.ReplayAll() + result = self.conductor.get_ec2_ids(self.context, inst) + self.assertEqual(result, expected) + + def test_compute_stop(self): + self.mox.StubOutWithMock(self.conductor_manager.compute_api, 'stop') + self.conductor_manager.compute_api.stop(self.context, 'instance', True) + self.mox.ReplayAll() + self.conductor.compute_stop(self.context, 'instance') + class ConductorTestCase(_BaseTestCase, test.TestCase): """Conductor Manager Tests.""" diff --git a/nova/tests/fake_instance_actions.py b/nova/tests/fake_instance_actions.py index 1667ac62d..f34d9b213 100644 --- a/nova/tests/fake_instance_actions.py +++ b/nova/tests/fake_instance_actions.py @@ -17,6 +17,64 @@ from nova import db +FAKE_UUID = 'b48316c5-71e8-45e4-9884-6c78055b9b13' +FAKE_REQUEST_ID1 = 'req-3293a3f1-b44c-4609-b8d2-d81b105636b8' +FAKE_REQUEST_ID2 = 'req-25517360-b757-47d3-be45-0e8d2a01b36a' +FAKE_ACTION_ID1 = 'f811a359-0c98-4daa-87a4-2948d4c21b78' +FAKE_ACTION_ID2 = '4e9594b5-4ac5-421c-ac60-2d802b11c798' + +FAKE_ACTIONS = { + FAKE_UUID: { + FAKE_REQUEST_ID1: {'id': FAKE_ACTION_ID1, + 'action': 'reboot', + 'instance_uuid': FAKE_UUID, + 'request_id': FAKE_REQUEST_ID1, + 'project_id': '147', + 'user_id': '789', + 'start_time': '2012-12-05 00:00:00.000000', + 'finish_time': '', + 'message': '', + }, + FAKE_REQUEST_ID2: {'id': FAKE_ACTION_ID2, + 'action': 'resize', + 'instance_uuid': FAKE_UUID, + 'request_id': FAKE_REQUEST_ID2, + 'user_id': '789', + 'project_id': '842', + 'start_time': '2012-12-05 01:00:00.000000', + 'finish_time': '', + 'message': '', + } + } +} + +FAKE_EVENTS = { + FAKE_ACTION_ID1: [{'id': '1', + 'event': 'schedule', + 'start_time': '2012-12-05 01:00:02.000000', + 'finish_time': '2012-12-05 01:02:00.000000', + 'result': 'Success', + 'traceback': '', + }, + {'id': '2', + 'event': 'compute_create', + 'start_time': '2012-12-05 01:03:00.000000', + 'finish_time': '2012-12-05 01:04:00.000000', + 'result': 'Success', + 'traceback': '', + } + ], + FAKE_ACTION_ID2: [{'id': '3', + 'event': 'schedule', + 'start_time': '2012-12-05 03:00:00.000000', + 'finish_time': '2012-12-05 03:02:00.000000', + 'result': 'Error', + 'traceback': '' + } + ] +} + + def fake_action_event_start(*args): pass diff --git a/nova/tests/fake_network.py b/nova/tests/fake_network.py index 883466cd6..12d263584 100644 --- a/nova/tests/fake_network.py +++ b/nova/tests/fake_network.py @@ -53,7 +53,7 @@ class FakeVIFDriver(object): def setattr(self, key, val): self.__setattr__(key, val) - def get_config(self, instance, network, mapping): + def get_config(self, instance, network, mapping, image_meta): conf = libvirt_config.LibvirtConfigGuestInterface() for attr, val in conf.__dict__.iteritems(): @@ -372,7 +372,7 @@ def stub_out_nw_api_get_instance_nw_info(stubs, func=None, floating_ips_per_fixed_ip=0, spectacular=False): - def get_instance_nw_info(self, context, instance): + def get_instance_nw_info(self, context, instance, conductor_api=None): return fake_get_instance_nw_info(stubs, num_networks=num_networks, ips_per_vif=ips_per_vif, floating_ips_per_fixed_ip=floating_ips_per_fixed_ip, diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py index 92ce0815a..3878df531 100644 --- a/nova/tests/fake_policy.py +++ b/nova/tests/fake_policy.py @@ -121,6 +121,7 @@ policy_data = """ "compute_extension:extended_server_attributes": "", "compute_extension:extended_status": "", "compute_extension:extended_availability_zone": "", + "compute_extension:extended_ips": "", "compute_extension:fixed_ips": "", "compute_extension:flavor_access": "", "compute_extension:flavor_disabled": "", @@ -142,6 +143,8 @@ policy_data = """ "compute_extension:hide_server_addresses": "", "compute_extension:hosts": "", "compute_extension:hypervisors": "", + "compute_extension:instance_actions": "", + "compute_extension:instance_actions:events": "is_admin:True", "compute_extension:instance_usage_audit_log": "", "compute_extension:keypairs": "", "compute_extension:multinic": "", diff --git a/nova/tests/hyperv/fake.py b/nova/tests/hyperv/fake.py index 9890a5462..e0e5a6bbe 100644 --- a/nova/tests/hyperv/fake.py +++ b/nova/tests/hyperv/fake.py @@ -23,24 +23,50 @@ class PathUtils(object): def open(self, path, mode): return io.BytesIO(b'fake content') - def get_instances_path(self): - return 'C:\\FakePath\\' + def exists(self, path): + return False + + def makedirs(self, path): + pass + + def remove(self, path): + pass + + def rename(self, src, dest): + pass + + def copyfile(self, src, dest): + pass + + def copy(self, src, dest): + pass + + def rmtree(self, path): + pass + + def get_instances_dir(self, remote_server=None): + return 'C:\\FakeInstancesPath\\' + + def get_instance_migr_revert_dir(self, instance_name, create_dir=False, + remove_dir=False): + return os.path.join(self.get_instances_dir(), instance_name, '_revert') - def get_instance_path(self, instance_name): - return os.path.join(self.get_instances_path(), instance_name) + def get_instance_dir(self, instance_name, remote_server=None, + create_dir=True, remove_dir=False): + return os.path.join(self.get_instances_dir(remote_server), + instance_name) def get_vhd_path(self, instance_name): - instance_path = self.get_instance_path(instance_name) - return os.path.join(instance_path, instance_name + ".vhd") + instance_path = self.get_instance_dir(instance_name) + return os.path.join(instance_path, 'root.vhd') - def get_base_vhd_path(self, image_name): - base_dir = os.path.join(self.get_instances_path(), '_base') - return os.path.join(base_dir, image_name + ".vhd") + def get_base_vhd_dir(self): + return os.path.join(self.get_instances_dir(), '_base') - def make_export_path(self, instance_name): - export_folder = os.path.join(self.get_instances_path(), "export", - instance_name) - return export_folder + def get_export_dir(self, instance_name): + export_dir = os.path.join(self.get_instances_dir(), 'export', + instance_name) + return export_dir def vhd_exists(self, path): return False diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl index 25915610d..413f3ce95 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl @@ -2,8 +2,7 @@ "server": { "updated": "%(timestamp)s", "created": "%(timestamp)s", - "OS-EXT-AZ:availability_zone": null, - "OS-EXT-AZ:host_availability_zone": "nova", + "OS-EXT-AZ:availability_zone": "nova", "accessIPv4": "", "accessIPv6": "", "addresses": { diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl index 1cdbd2012..849b9b750 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='UTF-8'?> -<server xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(uuid)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova"> +<server xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(uuid)s" OS-EXT-AZ:availability_zone="nova"> <image id="%(uuid)s"> <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> </image> diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl index 895f0a514..362c85085 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl @@ -3,8 +3,7 @@ { "updated": "%(timestamp)s", "created": "%(timestamp)s", - "OS-EXT-AZ:availability_zone": null, - "OS-EXT-AZ:host_availability_zone": "nova", + "OS-EXT-AZ:availability_zone": "nova", "accessIPv4": "", "accessIPv6": "", "addresses": { diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl index 15cd9b1e1..9cd820cd0 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='UTF-8'?> -<servers xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova"> +<servers xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-AZ:availability_zone="nova"> <image id="%(uuid)s"> <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> </image> diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl new file mode 100644 index 000000000..bea96d4f6 --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl @@ -0,0 +1,55 @@ +{ + "server": { + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "OS-EXT-IPS:type": "fixed", + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "created": "%(timestamp)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(timestamp)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl new file mode 100644 index 000000000..d3f14f6ed --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='UTF-8'?> +<server xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s"> + <image id="%(uuid)s"> + <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> + </image> + <flavor id="1"> + <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/> + </flavor> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <addresses> + <network id="private"> + <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/> + </network> + </addresses> + <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> +</server> diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl new file mode 100644 index 000000000..d3916d1aa --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl @@ -0,0 +1,16 @@ +{ + "server" : { + "name" : "new-server-test", + "imageRef" : "%(host)s/openstack/images/%(image_id)s", + "flavorRef" : "%(host)s/openstack/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl new file mode 100644 index 000000000..f92614984 --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test"> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <personality> + <file path="/etc/banner.txt"> + ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp + dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k + IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs + c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g + QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo + ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv + dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy + c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 + b25zLiINCg0KLVJpY2hhcmQgQmFjaA== + </file> + </personality> +</server> diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl new file mode 100644 index 000000000..d5f030c87 --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl @@ -0,0 +1,16 @@ +{ + "server": { + "adminPass": "%(password)s", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(uuid)s", + "rel": "bookmark" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl new file mode 100644 index 000000000..3bb13e69b --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl @@ -0,0 +1,6 @@ +<?xml version='1.0' encoding='UTF-8'?> +<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s"> + <metadata/> + <atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/> +</server> diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl new file mode 100644 index 000000000..37487e49f --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl @@ -0,0 +1,56 @@ +{ + "servers": [ + { + "status": "ACTIVE", + "updated": "%(timestamp)s", + "user_id": "fake", + "addresses": { + "private": [ + { + "OS-EXT-IPS:type": "fixed", + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "created": "%(timestamp)s", + "name": "new-server-test", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "id": "%(uuid)s", + "accessIPv4": "", + "accessIPv6": "", + "tenant_id": "openstack", + "progress": 0, + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "metadata": { + "My Server Name": "Apache1" + } + }] +} diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl new file mode 100644 index 000000000..5fc5c1f93 --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl @@ -0,0 +1,21 @@ +<?xml version='1.0' encoding='UTF-8'?> +<servers xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> + <server xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s"> + <image id="%(uuid)s"> + <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> + </image> + <flavor id="1"> + <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/> + </flavor> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <addresses> + <network id="private"> + <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/> + </network> + </addresses> + <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> + </server> +</servers> diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.json.tpl index c70192949..c70192949 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.json.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.json.tpl diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.xml.tpl index beec3a12a..beec3a12a 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.xml.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.xml.tpl diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.json.tpl index 1fb8e1a47..1fb8e1a47 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.json.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.json.tpl diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.xml.tpl index 1811882a2..1811882a2 100644 --- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.xml.tpl +++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.xml.tpl diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl new file mode 100644 index 000000000..7ac35024b --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl @@ -0,0 +1,57 @@ +{ + "server": { + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "OS-EXT-STS:power_state": 1, + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "created": "%(timestamp)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(timestamp)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl new file mode 100644 index 000000000..f594be120 --- /dev/null +++ b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='UTF-8'?> +<server xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-STS:vm_state="active" OS-EXT-STS:task_state="None" OS-EXT-STS:power_state="1"> + <image id="%(uuid)s"> + <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> + </image> + <flavor id="1"> + <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/> + </flavor> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <addresses> + <network id="private"> + <ip version="4" addr="%(ip)s"/> + </network> + </addresses> + <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> +</server> diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl deleted file mode 100644 index 8b97dc28d..000000000 --- a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl +++ /dev/null @@ -1,18 +0,0 @@ -{ - "servers": [ - { - "id": "%(id)s", - "links": [ - { - "href": "%(host)s/v2/openstack/servers/%(id)s", - "rel": "self" - }, - { - "href": "%(host)s/openstack/servers/%(id)s", - "rel": "bookmark" - } - ], - "name": "new-server-test" - } - ] -} diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl deleted file mode 100644 index 03bee03a6..000000000 --- a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<servers xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> - <server name="new-server-test" id="%(id)s"> - <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> - <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> - </server> -</servers> diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index 35d50d025..17914de42 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -25,6 +25,14 @@ "updated": "%(timestamp)s" }, { + "alias": "OS-EXT-IPS", + "description": "%(text)s", + "links": [], + "name": "ExtendedIps", + "namespace": "http://docs.openstack.org/compute/ext/extended_ips/api/v1.1", + "updated": "%(timestamp)s" + }, + { "alias": "OS-EXT-SRV-ATTR", "description": "%(text)s", "links": [], @@ -455,6 +463,14 @@ "name": "Volumes", "namespace": "http://docs.openstack.org/compute/ext/volumes/api/v1.1", "updated": "%(timestamp)s" + }, + { + "alias": "os-instance-actions", + "description": "%(text)s", + "links": [], + "name": "InstanceActions", + "namespace": "http://docs.openstack.org/compute/ext/instance-actions/api/v1.1", + "updated": "%(timestamp)s" } ] } diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index 2adc5988c..4492ed3aa 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -9,6 +9,9 @@ <extension alias="OS-EXT-AZ" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" name="ExtendedAvailabilityZone"> <description>%(text)s</description> </extension> + <extension alias="OS-EXT-IPS" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" name="ExtendedIps"> + <description>%(text)s</description> + </extension> <extension alias="OS-EXT-SRV-ATTR" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" name="ExtendedServerAttributes"> <description>%(text)s</description> </extension> @@ -171,4 +174,7 @@ <extension alias="os-volumes" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes"> <description>%(text)s</description> </extension> + <extension alias="os-instance-actions" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/instance-actions/api/v1.1" name="InstanceActions"> + <description>%(text)s</description> + </extension> </extensions> diff --git a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl index 85fc6f605..ccefc2dc7 100644 --- a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl @@ -1,8 +1,7 @@ { "server": { "OS-DCF:diskConfig": "AUTO", - "OS-EXT-AZ:availability_zone": null, - "OS-EXT-AZ:host_availability_zone": "nova", + "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "%(compute_host)s", "OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s", "OS-EXT-SRV-ATTR:instance_name": "instance-00000001", @@ -14,6 +13,7 @@ "addresses": { "private": [ { + "OS-EXT-IPS:type": "fixed", "addr": "%(ip)s", "version": 4 } diff --git a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl index bd73accda..973305854 100644 --- a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='UTF-8'?> -<server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova" OS-DCF:diskConfig="AUTO"> +<server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="nova" OS-DCF:diskConfig="AUTO"> <image id="%(uuid)s"> <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> </image> @@ -11,7 +11,7 @@ </metadata> <addresses> <network id="private"> - <ip version="4" addr="%(ip)s"/> + <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/> </network> </addresses> <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> diff --git a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl index a4918203b..d50088837 100644 --- a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl @@ -2,8 +2,7 @@ "servers": [ { "OS-DCF:diskConfig": "AUTO", - "OS-EXT-AZ:availability_zone": null, - "OS-EXT-AZ:host_availability_zone": "nova", + "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "%(compute_host)s", "OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s", "OS-EXT-SRV-ATTR:instance_name": "instance-00000001", @@ -15,6 +14,7 @@ "addresses": { "private": [ { + "OS-EXT-IPS:type": "fixed", "addr": "%(ip)s", "version": 4 } diff --git a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl index d26eb38ef..e2166c2ff 100644 --- a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl @@ -1,6 +1,6 @@ <?xml version='1.0' encoding='UTF-8'?> -<servers xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> - <server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova" OS-DCF:diskConfig="AUTO"> +<servers xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> + <server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="nova" OS-DCF:diskConfig="AUTO"> <image id="%(uuid)s"> <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> </image> @@ -12,7 +12,7 @@ </metadata> <addresses> <network id="private"> - <ip version="4" addr="%(ip)s"/> + <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/> </network> </addresses> <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl new file mode 100644 index 000000000..ea47da06c --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl @@ -0,0 +1,55 @@ +{ + "server": { + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "config_drive": "%(cdrive)s", + "created": "%(timestamp)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(timestamp)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl new file mode 100644 index 000000000..c6fb338c7 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='UTF-8'?> +<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" config_drive="%(cdrive)s"> + <image id="%(uuid)s"> + <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> + </image> + <flavor id="1"> + <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/> + </flavor> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <addresses> + <network id="private"> + <ip version="4" addr="%(ip)s"/> + </network> + </addresses> + <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> +</server> diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl new file mode 100644 index 000000000..d3916d1aa --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl @@ -0,0 +1,16 @@ +{ + "server" : { + "name" : "new-server-test", + "imageRef" : "%(host)s/openstack/images/%(image_id)s", + "flavorRef" : "%(host)s/openstack/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl new file mode 100644 index 000000000..f92614984 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test"> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <personality> + <file path="/etc/banner.txt"> + ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp + dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k + IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs + c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g + QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo + ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv + dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy + c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 + b25zLiINCg0KLVJpY2hhcmQgQmFjaA== + </file> + </personality> +</server> diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl new file mode 100644 index 000000000..d5f030c87 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl @@ -0,0 +1,16 @@ +{ + "server": { + "adminPass": "%(password)s", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(uuid)s", + "rel": "bookmark" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl new file mode 100644 index 000000000..3bb13e69b --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl @@ -0,0 +1,6 @@ +<?xml version='1.0' encoding='UTF-8'?> +<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s"> + <metadata/> + <atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/> +</server> diff --git a/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl new file mode 100644 index 000000000..535d00410 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl @@ -0,0 +1,57 @@ +{ + "servers": [ + { + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "config_drive": "%(cdrive)s", + "created": "%(timestamp)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(timestamp)s", + "user_id": "fake" + } + ] +} diff --git a/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl new file mode 100644 index 000000000..c2b2fa3ba --- /dev/null +++ b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl @@ -0,0 +1,21 @@ +<?xml version='1.0' encoding='UTF-8'?> +<servers xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> + <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" config_drive="%(cdrive)s"> + <image id="%(uuid)s"> + <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/> + </image> + <flavor id="1"> + <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/> + </flavor> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> + <addresses> + <network id="private"> + <ip version="4" addr="%(ip)s"/> + </network> + </addresses> + <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/> + <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/> + </server> +</servers> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl new file mode 100644 index 000000000..7dc33ddb1 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl @@ -0,0 +1,7 @@ +{ + "dns_entry" : + { + "ip": "%(ip)s", + "dns_type": "%(dns_type)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl new file mode 100644 index 000000000..bd62d3418 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<dns_entry> + <ip>%(ip)s</ip> + <dns_type>%(dns_type)s</dns_type> +</dns_entry> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl new file mode 100644 index 000000000..3ec0743ba --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl @@ -0,0 +1,9 @@ +{ + "dns_entry": { + "domain": "%(domain)s", + "id": null, + "ip": "%(ip)s", + "name": "%(name)s", + "type": "%(dns_type)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl new file mode 100644 index 000000000..38a659b78 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<dns_entry ip="%(ip)s" domain="%(domain)s" type="%(dns_type)s" id="None" name="%(name)s"/> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl new file mode 100644 index 000000000..db73be14a --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl @@ -0,0 +1,8 @@ +{ + "domain_entry" : + { + "domain": "%(domain)s", + "scope": "%(scope)s", + "project": "%(project)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl new file mode 100644 index 000000000..40866a537 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl @@ -0,0 +1,6 @@ +<?xml version='1.0' encoding='UTF-8'?> +<domain_entry> + <domain>%(domain)s</domain> + <scope>%(scope)s</scope> + <project>%(project)s</project> +</domain_entry> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl new file mode 100644 index 000000000..a14d395d2 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl @@ -0,0 +1,8 @@ +{ + "domain_entry": { + "availability_zone": null, + "domain": "%(domain)s", + "project": "%(project)s", + "scope": "%(scope)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl new file mode 100644 index 000000000..1759c403a --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<domain_entry project="%(project)s" scope="%(scope)s" domain="%(domain)s" availability_zone="None"/> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl new file mode 100644 index 000000000..8edd0603f --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl @@ -0,0 +1,9 @@ +{ + "dns_entry": { + "domain": "%(domain)s", + "id": null, + "ip": "%(ip)s", + "name": "%(name)s", + "type": null + } +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl new file mode 100644 index 000000000..a889ef6e2 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<dns_entry ip="%(ip)s" domain="%(domain)s" type="None" id="None" name="%(name)s"/> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl new file mode 100644 index 000000000..831cda7b5 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "dns_entries": [ + { + "domain": "%(domain)s", + "id": null, + "ip": "%(ip)s", + "name": "%(name)s", + "type": null + } + ] +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl new file mode 100644 index 000000000..bf7788f94 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl @@ -0,0 +1,4 @@ +<?xml version='1.0' encoding='UTF-8'?> +<dns_entries> + <dns_entry ip="%(ip)s" domain="%(domain)s" type="None" id="None" name="%(name)s"/> +</dns_entries> diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl new file mode 100644 index 000000000..a6055cfec --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl @@ -0,0 +1,10 @@ +{ + "domain_entries": [ + { + "availability_zone": null, + "domain": "%(domain)s", + "project": "%(project)s", + "scope": "%(scope)s" + } + ] +} diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl new file mode 100644 index 000000000..e57c290cb --- /dev/null +++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl @@ -0,0 +1,4 @@ +<?xml version='1.0' encoding='UTF-8'?> +<domain_entries> + <domain_entry project="%(project)s" scope="%(scope)s" domain="%(domain)s" availability_zone="None"/> +</domain_entries> diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl new file mode 100644 index 000000000..6ba99d264 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl @@ -0,0 +1,27 @@ +{ + "instanceAction": { + "action": "%(action)s", + "instance_uuid": "%(instance_uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(integer_id)s", + "project_id": "%(integer_id)s", + "start_time": "%(start_time)s", + "message": "", + "events": [ + { + "event": "%(event)s", + "start_time": "%(timestamp)s", + "finish_time": "%(timestamp)s", + "result": "%(result)s", + "traceback": "" + }, + { + "event": "%(event)s", + "start_time": "%(timestamp)s", + "finish_time": "%(timestamp)s", + "result": "%(result)s", + "traceback": "" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl new file mode 100644 index 000000000..ef4b7b003 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<instanceAction action="%(action)s" instance_uuid="%(instance_uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(start_time)s" message=""> + <events event="%(event)s" start_time="%(timestamp)s" finish_time="%(timestamp)s" result="%(result)s" traceback=""/> + <events event="%(event)s" start_time="%(timestamp)s" finish_time="%(timestamp)s" result="%(result)s" traceback=""/> +</instanceAction> diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl new file mode 100644 index 000000000..9f64a1b29 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl @@ -0,0 +1,22 @@ +{ + "instanceActions": [ + { + "action": "%(action)s", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(integer_id)s", + "project_id": "%(integer_id)s", + "start_time": "%(timestamp)s", + "message": "" + }, + { + "action": "%(action)s", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(integer_id)s", + "project_id": "%(integer_id)s", + "start_time": "%(timestamp)s", + "message": "" + } + ] +} diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl new file mode 100644 index 000000000..943b1ba74 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<instanceActions> + <instanceAction action="%(action)s" instance_uuid="%(uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(timestamp)s" message=""/> + <instanceAction action="%(action)s" instance_uuid="%(uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(timestamp)s" message=""/> +</instanceActions> diff --git a/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl b/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl new file mode 100644 index 000000000..4d48af1b8 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl @@ -0,0 +1,4 @@ +{ + "host": "%(host)s", + "service": "%(service)s" +} diff --git a/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl new file mode 100644 index 000000000..8219a43f6 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl @@ -0,0 +1,5 @@ +{ + "disabled": true, + "host": "%(host)s", + "service": "%(service)s" +} diff --git a/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl b/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl new file mode 100644 index 000000000..4d48af1b8 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl @@ -0,0 +1,4 @@ +{ + "host": "%(host)s", + "service": "%(service)s" +} diff --git a/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl new file mode 100644 index 000000000..079b9c76e --- /dev/null +++ b/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl @@ -0,0 +1,5 @@ +{ + "disabled": false, + "host": "%(host)s", + "service": "%(service)s" +} diff --git a/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl new file mode 100644 index 000000000..cc6101338 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl @@ -0,0 +1,36 @@ +{ + "services": [ + { + "binary": "nova-scheduler", + "host": "host1", + "state": "up", + "status": "disabled", + "updated_at": "%(timestamp)s", + "zone": "internal" + }, + { + "binary": "nova-compute", + "host": "host1", + "state": "up", + "status": "disabled", + "updated_at": "%(timestamp)s", + "zone": "nova" + }, + { + "binary": "nova-scheduler", + "host": "host2", + "state": "down", + "status": "enabled", + "updated_at": "%(timestamp)s", + "zone": "internal" + }, + { + "binary": "nova-compute", + "host": "host2", + "state": "down", + "status": "disabled", + "updated_at": "%(timestamp)s", + "zone": "nova" + } + ] +} diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index f37b3ac5d..97e38fa0c 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -14,6 +14,7 @@ # under the License. import base64 +import copy import datetime import inspect import json @@ -46,10 +47,14 @@ from nova.servicegroup import api as service_group_api from nova import test from nova.tests.api.openstack.compute.contrib import test_fping from nova.tests.api.openstack.compute.contrib import test_networks +from nova.tests.api.openstack.compute.contrib import test_services +from nova.tests.api.openstack import fakes from nova.tests.baremetal.db import base as bm_db_base +from nova.tests import fake_instance_actions from nova.tests import fake_network from nova.tests.image import fake from nova.tests.integrated import integrated_helpers +from nova.tests import utils as test_utils from nova import utils CONF = cfg.CONF @@ -377,12 +382,9 @@ class ApiSamplesTrap(ApiSampleTestBase): # NOT be allowed to grow, and should shrink to zero (and be # removed) soon. do_not_approve_additions = [] - do_not_approve_additions.append('os-config-drive') do_not_approve_additions.append('os-create-server-ext') do_not_approve_additions.append('os-flavor-access') - do_not_approve_additions.append('os-floating-ip-dns') do_not_approve_additions.append('os-hypervisors') - do_not_approve_additions.append('os-services') do_not_approve_additions.append('os-volumes') tests = self._get_extensions_tested() @@ -1175,7 +1177,7 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase): ".extended_server_attributes" + \ ".Extended_server_attributes" - def test_extended_server_attrs_get(self): + def test_show(self): uuid = self._post_server() response = self._do_get('servers/%s' % uuid) @@ -1184,10 +1186,10 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase): subs['id'] = uuid subs['instance_name'] = 'instance-\d{8}' subs['hypervisor_hostname'] = r'[\w\.\-]+' - return self._verify_response('extended-server-attrs-get', + return self._verify_response('server-get-resp', subs, response) - def test_extended_server_attrs_list(self): + def test_detail(self): uuid = self._post_server() response = self._do_get('servers/detail') @@ -1196,7 +1198,7 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase): subs['id'] = uuid subs['instance_name'] = 'instance-\d{8}' subs['hypervisor_hostname'] = r'[\w\.\-]+' - return self._verify_response('extended-server-attrs-list', + return self._verify_response('servers-detail-resp', subs, response) @@ -1909,6 +1911,61 @@ class MultipleCreateXmlTest(MultipleCreateJsonTest): ctype = 'xml' +class ServicesJsonTest(ApiSampleTestBase): + extension_name = "nova.api.openstack.compute.contrib.services.Services" + + def setUp(self): + super(ServicesJsonTest, self).setUp() + self.stubs.Set(db, "service_get_all", + test_services.fake_service_get_all) + self.stubs.Set(timeutils, "utcnow", test_services.fake_utcnow) + self.stubs.Set(db, "service_get_by_args", + test_services.fake_service_get_by_host_binary) + self.stubs.Set(db, "service_update", + test_services.fake_service_update) + + def tearDown(self): + super(ServicesJsonTest, self).tearDown() + timeutils.clear_time_override() + + def test_services_list(self): + """Return a list of all agent builds.""" + response = self._do_get('os-services') + self.assertEqual(response.status, 200) + subs = {'binary': 'nova-compute', + 'host': 'host1', + 'zone': 'nova', + 'status': 'disabled', + 'state': 'up'} + subs.update(self._get_regexes()) + return self._verify_response('services-list-get-resp', + subs, response) + + def test_service_enable(self): + """Enable an existing agent build.""" + subs = {"host": "host1", + 'service': 'nova-compute'} + response = self._do_put('/os-services/enable', + 'service-enable-put-req', subs) + self.assertEqual(response.status, 200) + subs = {"host": "host1", + "service": "nova-compute"} + return self._verify_response('service-enable-put-resp', + subs, response) + + def test_service_disable(self): + """Disable an existing agent build.""" + subs = {"host": "host1", + 'service': 'nova-compute'} + response = self._do_put('/os-services/disable', + 'service-disable-put-req', subs) + self.assertEqual(response.status, 200) + subs = {"host": "host1", + "service": "nova-compute"} + return self._verify_response('service-disable-put-resp', + subs, response) + + class SimpleTenantUsageSampleJsonTest(ServersSampleBase): extension_name = ("nova.api.openstack.compute.contrib.simple_tenant_usage." "Simple_tenant_usage") @@ -2218,17 +2275,45 @@ class QuotasSampleXmlTests(QuotasSampleJsonTests): ctype = "xml" -class ExtendedStatusSampleJsonTests(ServersSampleBase): +class ExtendedIpsSampleJsonTests(ServersSampleBase): extension_name = ("nova.api.openstack.compute.contrib" - ".extended_status.Extended_status") + ".extended_ips.Extended_ips") def test_show(self): uuid = self._post_server() - response = self._do_get('servers') + response = self._do_get('servers/%s' % uuid) self.assertEqual(response.status, 200) subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' subs['id'] = uuid - return self._verify_response('servers-list-resp', subs, response) + subs['hypervisor_hostname'] = r'[\w\.\-]+' + return self._verify_response('server-get-resp', subs, response) + + def test_detail(self): + uuid = self._post_server() + response = self._do_get('servers/detail') + self.assertEqual(response.status, 200) + subs = self._get_regexes() + subs['id'] = uuid + subs['hostid'] = '[a-f0-9]+' + return self._verify_response('servers-detail-resp', subs, response) + + +class ExtendedIpsSampleXmlTests(ExtendedIpsSampleJsonTests): + ctype = 'xml' + + +class ExtendedStatusSampleJsonTests(ServersSampleBase): + extension_name = ("nova.api.openstack.compute.contrib" + ".extended_status.Extended_status") + + def test_show(self): + uuid = self._post_server() + response = self._do_get('servers/%s' % uuid) + self.assertEqual(response.status, 200) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + return self._verify_response('server-get-resp', subs, response) def test_detail(self): uuid = self._post_server() @@ -2886,7 +2971,7 @@ class ExtendedAvailabilityZoneJsonTests(ServersSampleBase): ".extended_availability_zone" ".Extended_availability_zone") - def test_get(self): + def test_show(self): uuid = self._post_server() response = self._do_get('servers/%s' % uuid) self.assertEqual(response.status, 200) @@ -2938,3 +3023,190 @@ class EvacuateJsonTest(ServersSampleBase): class EvacuateXmlTest(EvacuateJsonTest): ctype = 'xml' + + +class FloatingIpDNSJsonTest(ApiSampleTestBase): + extension_name = ("nova.api.openstack.compute.contrib.floating_ip_dns." + "Floating_ip_dns") + + domain = 'domain1.example.org' + name = 'instance1' + scope = 'public' + project = 'project1' + dns_type = 'A' + ip = '192.168.1.1' + + def _create_or_update(self): + subs = {'domain': self.domain, + 'project': self.project, + 'scope': self.scope} + response = self._do_put('os-floating-ip-dns/%s' % self.domain, + 'floating-ip-dns-create-or-update-req', subs) + self.assertEqual(response.status, 200) + self._verify_response('floating-ip-dns-create-or-update-resp', subs, + response) + + def _create_or_update_entry(self): + subs = {'ip': self.ip, 'dns_type': self.dns_type} + response = self._do_put('os-floating-ip-dns/%s/entries/%s' + % (self.domain, self.name), + 'floating-ip-dns-create-or-update-entry-req', + subs) + self.assertEqual(response.status, 200) + subs.update({'name': self.name, 'domain': self.domain}) + self._verify_response('floating-ip-dns-create-or-update-entry-resp', + subs, response) + + def test_floating_ip_dns_list(self): + self._create_or_update() + response = self._do_get('os-floating-ip-dns') + self.assertEqual(response.status, 200) + subs = {'domain': self.domain, + 'project': self.project, + 'scope': self.scope} + return self._verify_response('floating-ip-dns-list-resp', subs, + response) + + def test_floating_ip_dns_create_or_update(self): + self._create_or_update() + + def test_floating_ip_dns_delete(self): + self._create_or_update() + response = self._do_delete('os-floating-ip-dns/%s' % self.domain) + self.assertEqual(response.status, 202) + + def test_floating_ip_dns_create_or_update_entry(self): + self._create_or_update_entry() + + def test_floating_ip_dns_entry_get(self): + self._create_or_update_entry() + response = self._do_get('os-floating-ip-dns/%s/entries/%s' + % (self.domain, self.name)) + self.assertEqual(response.status, 200) + subs = {'domain': self.domain, + 'ip': self.ip, + 'name': self.name} + return self._verify_response('floating-ip-dns-entry-get-resp', subs, + response) + + def test_floating_ip_dns_entry_delete(self): + self._create_or_update_entry() + response = self._do_delete('os-floating-ip-dns/%s/entries/%s' + % (self.domain, self.name)) + self.assertEqual(response.status, 202) + + def test_floating_ip_dns_entry_list(self): + self._create_or_update_entry() + response = self._do_get('os-floating-ip-dns/%s/entries/%s' + % (self.domain, self.ip)) + self.assertEqual(response.status, 200) + subs = {'domain': self.domain, + 'ip': self.ip, + 'name': self.name} + return self._verify_response('floating-ip-dns-entry-list-resp', subs, + response) + + +class FloatingIpDNSXmlTest(FloatingIpDNSJsonTest): + ctype = 'xml' + + +class InstanceActionsSampleJsonTest(ApiSampleTestBase): + extension_name = ('nova.api.openstack.compute.contrib.instance_actions.' + 'Instance_actions') + + def setUp(self): + super(InstanceActionsSampleJsonTest, self).setUp() + self.actions = fake_instance_actions.FAKE_ACTIONS + self.events = fake_instance_actions.FAKE_EVENTS + self.instance = test_utils.get_test_instance() + + def fake_instance_action_get_by_request_id(context, uuid, request_id): + return copy.deepcopy(self.actions[uuid][request_id]) + + def fake_instance_actions_get(context, uuid): + return [copy.deepcopy(value) for value in + self.actions[uuid].itervalues()] + + def fake_instance_action_events_get(context, action_id): + return copy.deepcopy(self.events[action_id]) + + def fake_instance_get_by_uuid(context, instance_id): + return self.instance + + self.stubs.Set(db, 'action_get_by_request_id', + fake_instance_action_get_by_request_id) + self.stubs.Set(db, 'actions_get', fake_instance_actions_get) + self.stubs.Set(db, 'action_events_get', + fake_instance_action_events_get) + self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid) + + def test_instance_action_get(self): + fake_uuid = fake_instance_actions.FAKE_UUID + fake_request_id = fake_instance_actions.FAKE_REQUEST_ID1 + fake_action = self.actions[fake_uuid][fake_request_id] + + response = self._do_get('servers/%s/os-instance-actions/%s' % + (fake_uuid, fake_request_id)) + subs = self._get_regexes() + subs['action'] = '(reboot)|(resize)' + subs['instance_uuid'] = fake_uuid + subs['integer_id'] = '[0-9]+' + subs['request_id'] = fake_action['request_id'] + subs['start_time'] = fake_action['start_time'] + subs['result'] = '(Success)|(Error)' + subs['event'] = '(schedule)|(compute_create)' + return self._verify_response('instance-action-get-resp', subs, + response) + + def test_instance_actions_list(self): + fake_uuid = fake_instance_actions.FAKE_UUID + response = self._do_get('servers/%s/os-instance-actions' % (fake_uuid)) + subs = self._get_regexes() + subs['action'] = '(reboot)|(resize)' + subs['integer_id'] = '[0-9]+' + subs['request_id'] = ('req-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}' + '-[0-9a-f]{4}-[0-9a-f]{12}') + return self._verify_response('instance-actions-list-resp', subs, + response) + + +class InstanceActionsSampleXmlTest(InstanceActionsSampleJsonTest): + ctype = 'xml' + + +class ConfigDriveSampleJsonTest(ServersSampleBase): + extension_name = ("nova.api.openstack.compute.contrib.config_drive." + "Config_drive") + + def setUp(self): + super(ConfigDriveSampleJsonTest, self).setUp() + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fake.stub_out_image_service(self.stubs) + + def test_config_drive_show(self): + uuid = self._post_server() + response = self._do_get('servers/%s' % uuid) + self.assertEqual(response.status, 200) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + # config drive can be an uuid or empty value + subs['cdrive'] = '(%s)?' % subs['uuid'] + return self._verify_response('server-config-drive-get-resp', subs, + response) + + def test_config_drive_detail(self): + uuid = self._post_server() + response = self._do_get('servers/detail') + self.assertEqual(response.status, 200) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + # config drive can be an uuid or empty value + subs['cdrive'] = '(%s)?' % subs['uuid'] + return self._verify_response('servers-config-drive-details-resp', + subs, response) + + +class ConfigDriveSampleXmlTest(ConfigDriveSampleJsonTest): + ctype = 'xml' diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py index bc21b80ad..50c98e78c 100644 --- a/nova/tests/network/test_linux_net.py +++ b/nova/tests/network/test_linux_net.py @@ -24,6 +24,7 @@ from nova import context from nova import db from nova.network import driver from nova.network import linux_net +from nova.openstack.common import cfg from nova.openstack.common import fileutils from nova.openstack.common import log as logging from nova.openstack.common import timeutils @@ -31,6 +32,7 @@ from nova import test from nova import utils LOG = logging.getLogger(__name__) +CONF = cfg.CONF HOST = "testhost" @@ -472,6 +474,71 @@ class LinuxNetworkTestCase(test.TestCase): driver.plug(network, "fakemac") self.assertEqual(info['passed_interface'], "override_interface") + def _test_dnsmasq_execute(self, extra_expected=None): + network_ref = {'id': 'fake', + 'label': 'fake', + 'multi_host': False, + 'cidr': '10.0.0.0/24', + 'dns1': '8.8.4.4', + 'dhcp_start': '1.0.0.2', + 'dhcp_server': '10.0.0.1'} + executes = [] + + def fake_execute(*args, **kwargs): + executes.append(args) + return "", "" + + self.stubs.Set(linux_net, '_execute', fake_execute) + + self.stubs.Set(os, 'chmod', lambda *a, **kw: None) + self.stubs.Set(linux_net, 'write_to_file', lambda *a, **kw: None) + self.stubs.Set(linux_net, '_dnsmasq_pid_for', lambda *a, **kw: None) + dev = 'br100' + linux_net.restart_dhcp(self.context, dev, network_ref) + expected = ['env', + 'CONFIG_FILE=%s' % CONF.dhcpbridge_flagfile, + 'NETWORK_ID=fake', + 'dnsmasq', + '--strict-order', + '--bind-interfaces', + '--conf-file=%s' % CONF.dnsmasq_config_file, + '--domain=%s' % CONF.dhcp_domain, + '--pid-file=%s' % linux_net._dhcp_file(dev, 'pid'), + '--listen-address=%s' % network_ref['dhcp_server'], + '--except-interface=lo', + "--dhcp-range=set:'%s',%s,static,%ss" % (network_ref['label'], + network_ref['dhcp_start'], + CONF.dhcp_lease_time), + '--dhcp-lease-max=256', + '--dhcp-hostsfile=%s' % linux_net._dhcp_file(dev, 'conf'), + '--dhcp-script=%s' % CONF.dhcpbridge, + '--leasefile-ro'] + if extra_expected: + expected += extra_expected + self.assertEqual([tuple(expected)], executes) + + def test_dnsmasq_execute(self): + self._test_dnsmasq_execute() + + def test_dnsmasq_execute_dns_servers(self): + self.flags(dns_server=['1.1.1.1', '2.2.2.2']) + expected = [ + '--no-hosts', + '--no-resolv', + '--server=1.1.1.1', + '--server=2.2.2.2', + ] + self._test_dnsmasq_execute(expected) + + def test_dnsmasq_execute_use_network_dns_servers(self): + self.flags(use_network_dns_servers=True) + expected = [ + '--no-hosts', + '--no-resolv', + '--server=8.8.4.4', + ] + self._test_dnsmasq_execute(expected) + def test_isolated_host(self): self.flags(fake_network=False, share_dhcp_address=True) diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py index 1805044a1..f3f306694 100644 --- a/nova/tests/network/test_quantumv2.py +++ b/nova/tests/network/test_quantumv2.py @@ -189,6 +189,16 @@ class TestQuantumv2(test.TestCase): 'gateway_ip': '10.0.1.1', 'dns_nameservers': ['8.8.1.1', '8.8.1.2']}] self.subnet_data2 = [] + self.subnet_data_n = [{'id': 'my_subid1', + 'cidr': '10.0.1.0/24', + 'network_id': 'my_netid1', + 'gateway_ip': '10.0.1.1', + 'dns_nameservers': ['8.8.1.1', '8.8.1.2']}, + {'id': 'my_subid2', + 'cidr': '20.0.1.0/24', + 'network_id': 'my_netid2', + 'gateway_ip': '20.0.1.1', + 'dns_nameservers': ['8.8.1.1', '8.8.1.2']}] self.subnet_data2.append({'id': 'my_subid2', 'cidr': '10.0.2.0/24', 'network_id': 'my_netid2', @@ -1010,7 +1020,7 @@ class TestQuantumv2(test.TestCase): network_id = 'my_netid1' search_opts = {'network_id': network_id} self.moxed_client.list_subnets( - **search_opts).AndReturn({'subnets': self.subnet_data1}) + **search_opts).AndReturn({'subnets': self.subnet_data_n}) zone = 'compute:%s' % self.instance['availability_zone'] search_opts = {'device_id': self.instance['uuid'], diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py index b4d73ec0c..4b07581fb 100644 --- a/nova/tests/scheduler/test_filter_scheduler.py +++ b/nova/tests/scheduler/test_filter_scheduler.py @@ -40,6 +40,16 @@ def fake_get_filtered_hosts(hosts, filter_properties): return list(hosts) +def fake_get_group_filtered_hosts(hosts, filter_properties): + group_hosts = filter_properties.get('group_hosts') or [] + if group_hosts: + hosts = list(hosts) + hosts.pop(0) + return hosts + else: + return list(hosts) + + class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase): """Test case for Filter Scheduler.""" @@ -480,3 +490,169 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase): self.assertRaises(exception.MigrationError, self.driver._assert_compute_node_has_enough_memory, self.context, instance, dest) + + def test_basic_schedule_run_instances_anti_affinity(self): + filter_properties = {'scheduler_hints': + {'group': 'cats'}} + # Request spec 1 + instance_opts1 = {'project_id': 1, 'os_type': 'Linux', + 'memory_mb': 512, 'root_gb': 512, + 'ephemeral_gb': 0, 'vcpus': 1, + 'system_metadata': {'system': 'metadata'}} + request_spec1 = {'instance_uuids': ['fake-uuid1-1', 'fake-uuid1-2'], + 'instance_properties': instance_opts1, + 'instance_type': {'memory_mb': 512, 'root_gb': 512, + 'ephemeral_gb': 0, 'vcpus': 1}} + self.next_weight = 1.0 + + def _fake_weigh_objects(_self, functions, hosts, options): + self.next_weight += 2.0 + host_state = hosts[0] + return [weights.WeighedHost(host_state, self.next_weight)] + + sched = fakes.FakeFilterScheduler() + + fake_context = context.RequestContext('user', 'project', + is_admin=True) + + self.stubs.Set(sched.host_manager, 'get_filtered_hosts', + fake_get_group_filtered_hosts) + self.stubs.Set(weights.HostWeightHandler, + 'get_weighed_objects', _fake_weigh_objects) + fakes.mox_host_manager_db_calls(self.mox, fake_context) + + self.mox.StubOutWithMock(driver, 'instance_update_db') + self.mox.StubOutWithMock(compute_rpcapi.ComputeAPI, 'run_instance') + self.mox.StubOutWithMock(sched, 'group_hosts') + + instance1_1 = {'uuid': 'fake-uuid1-1'} + instance1_2 = {'uuid': 'fake-uuid1-2'} + + sched.group_hosts(mox.IgnoreArg(), 'cats').AndReturn([]) + + def inc_launch_index1(*args, **kwargs): + request_spec1['instance_properties']['launch_index'] = ( + request_spec1['instance_properties']['launch_index'] + 1) + + expected_metadata = {'system_metadata': + {'system': 'metadata', 'group': 'cats'}} + driver.instance_update_db(fake_context, instance1_1['uuid'], + extra_values=expected_metadata).WithSideEffects( + inc_launch_index1).AndReturn(instance1_1) + compute_rpcapi.ComputeAPI.run_instance(fake_context, host='host3', + instance=instance1_1, requested_networks=None, + injected_files=None, admin_password=None, is_first_time=None, + request_spec=request_spec1, filter_properties=mox.IgnoreArg(), + node='node3') + + driver.instance_update_db(fake_context, instance1_2['uuid'], + extra_values=expected_metadata).WithSideEffects( + inc_launch_index1).AndReturn(instance1_2) + compute_rpcapi.ComputeAPI.run_instance(fake_context, host='host4', + instance=instance1_2, requested_networks=None, + injected_files=None, admin_password=None, is_first_time=None, + request_spec=request_spec1, filter_properties=mox.IgnoreArg(), + node='node4') + self.mox.ReplayAll() + sched.schedule_run_instance(fake_context, request_spec1, + None, None, None, None, filter_properties) + + def test_schedule_host_pool(self): + """Make sure the scheduler_host_subset_size property works properly.""" + + self.flags(scheduler_host_subset_size=2) + sched = fakes.FakeFilterScheduler() + + fake_context = context.RequestContext('user', 'project', + is_admin=True) + self.stubs.Set(sched.host_manager, 'get_filtered_hosts', + fake_get_filtered_hosts) + fakes.mox_host_manager_db_calls(self.mox, fake_context) + + instance_properties = {'project_id': 1, + 'root_gb': 512, + 'memory_mb': 512, + 'ephemeral_gb': 0, + 'vcpus': 1, + 'os_type': 'Linux'} + + request_spec = dict(instance_properties=instance_properties) + filter_properties = {} + self.mox.ReplayAll() + hosts = sched._schedule(self.context, request_spec, + filter_properties=filter_properties) + + # one host should be chosen + self.assertEqual(len(hosts), 1) + + def test_schedule_large_host_pool(self): + """Hosts should still be chosen if pool size + is larger than number of filtered hosts""" + + sched = fakes.FakeFilterScheduler() + + fake_context = context.RequestContext('user', 'project', + is_admin=True) + self.flags(scheduler_host_subset_size=20) + self.stubs.Set(sched.host_manager, 'get_filtered_hosts', + fake_get_filtered_hosts) + fakes.mox_host_manager_db_calls(self.mox, fake_context) + + instance_properties = {'project_id': 1, + 'root_gb': 512, + 'memory_mb': 512, + 'ephemeral_gb': 0, + 'vcpus': 1, + 'os_type': 'Linux'} + request_spec = dict(instance_properties=instance_properties) + filter_properties = {} + self.mox.ReplayAll() + hosts = sched._schedule(self.context, request_spec, + filter_properties=filter_properties) + + # one host should be chose + self.assertEqual(len(hosts), 1) + + def test_schedule_chooses_best_host(self): + """If scheduler_host_subset_size is 1, the largest host with greatest + weight should be returned""" + + self.flags(scheduler_host_subset_size=1) + + sched = fakes.FakeFilterScheduler() + + fake_context = context.RequestContext('user', 'project', + is_admin=True) + self.stubs.Set(sched.host_manager, 'get_filtered_hosts', + fake_get_filtered_hosts) + fakes.mox_host_manager_db_calls(self.mox, fake_context) + + self.next_weight = 50 + + def _fake_weigh_objects(_self, functions, hosts, options): + this_weight = self.next_weight + self.next_weight = 0 + host_state = hosts[0] + return [weights.WeighedHost(host_state, this_weight)] + + instance_properties = {'project_id': 1, + 'root_gb': 512, + 'memory_mb': 512, + 'ephemeral_gb': 0, + 'vcpus': 1, + 'os_type': 'Linux'} + + request_spec = dict(instance_properties=instance_properties) + + self.stubs.Set(weights.HostWeightHandler, + 'get_weighed_objects', _fake_weigh_objects) + + filter_properties = {} + self.mox.ReplayAll() + hosts = sched._schedule(self.context, request_spec, + filter_properties=filter_properties) + + # one host should be chosen + self.assertEquals(1, len(hosts)) + + self.assertEquals(50, hosts[0].weight) diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py index 230e2ea03..edd2e0d61 100644 --- a/nova/tests/scheduler/test_host_filters.py +++ b/nova/tests/scheduler/test_host_filters.py @@ -1400,3 +1400,17 @@ class HostFiltersTestCase(test.TestCase): {'num_instances': 5}) filter_properties = {} self.assertFalse(filt_cls.host_passes(host, filter_properties)) + + def test_group_anti_affinity_filter_passes(self): + filt_cls = self.class_map['GroupAntiAffinityFilter']() + host = fakes.FakeHostState('host1', 'node1', {}) + filter_properties = {'group_hosts': []} + self.assertTrue(filt_cls.host_passes(host, filter_properties)) + filter_properties = {'group_hosts': ['host2']} + self.assertTrue(filt_cls.host_passes(host, filter_properties)) + + def test_group_anti_affinity_filter_fails(self): + filt_cls = self.class_map['GroupAntiAffinityFilter']() + host = fakes.FakeHostState('host1', 'node1', {}) + filter_properties = {'group_hosts': ['host1']} + self.assertFalse(filt_cls.host_passes(host, filter_properties)) diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 44e1f3537..01d3f6a50 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -24,6 +24,7 @@ import mox from nova.compute import api as compute_api from nova.compute import power_state from nova.compute import rpcapi as compute_rpcapi +from nova.compute import task_states from nova.compute import utils as compute_utils from nova.compute import vm_states from nova.conductor import api as conductor_api @@ -199,6 +200,38 @@ class SchedulerManagerTestCase(test.TestCase): self.manager.run_instance(self.context, request_spec, None, None, None, None, {}) + def test_live_migration_compute_service_notavailable(self): + inst = {"uuid": "fake-instance-id", + "vm_state": vm_states.ACTIVE, + "task_state": task_states.MIGRATING, } + + dest = 'fake_host' + block_migration = False + disk_over_commit = False + + self._mox_schedule_method_helper('schedule_live_migration') + self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc') + self.mox.StubOutWithMock(db, 'instance_update_and_get_original') + + self.manager.driver.schedule_live_migration(self.context, + inst, dest, block_migration, disk_over_commit).AndRaise( + exception.ComputeServiceUnavailable(host="src")) + db.instance_update_and_get_original(self.context, inst["uuid"], + {"vm_state": inst['vm_state'], + "task_state": None, + "expected_task_state": task_states.MIGRATING, + }).AndReturn((inst, inst)) + compute_utils.add_instance_fault_from_exc(self.context, + mox.IsA(conductor_api.LocalAPI), inst, + mox.IsA(exception.ComputeServiceUnavailable), + mox.IgnoreArg()) + + self.mox.ReplayAll() + self.assertRaises(exception.ComputeServiceUnavailable, + self.manager.live_migration, + self.context, inst, dest, block_migration, + disk_over_commit) + def test_prep_resize_no_valid_host_back_in_active_state(self): fake_instance_uuid = 'fake-instance-id' fake_instance = {'uuid': fake_instance_uuid} @@ -510,6 +543,29 @@ class SchedulerTestCase(test.TestCase): block_migration=block_migration, disk_over_commit=disk_over_commit) + def test_live_migration_compute_dest_not_exist(self): + # Raise exception when dest compute node does not exist. + + self.mox.StubOutWithMock(self.driver, '_live_migration_src_check') + self.mox.StubOutWithMock(db, 'service_get_by_compute_host') + + dest = 'fake_host2' + block_migration = False + disk_over_commit = False + instance = self._live_migration_instance() + + self.driver._live_migration_src_check(self.context, instance) + # Compute down + db.service_get_by_compute_host(self.context, + dest).AndRaise(exception.NotFound()) + + self.mox.ReplayAll() + self.assertRaises(exception.ComputeServiceUnavailable, + self.driver.schedule_live_migration, self.context, + instance=instance, dest=dest, + block_migration=block_migration, + disk_over_commit=disk_over_commit) + def test_live_migration_compute_dest_not_alive(self): # Raise exception when dest compute node is not alive. diff --git a/nova/tests/servicegroup/test_zk_driver.py b/nova/tests/servicegroup/test_zk_driver.py new file mode 100644 index 000000000..753153bb5 --- /dev/null +++ b/nova/tests/servicegroup/test_zk_driver.py @@ -0,0 +1,65 @@ +# Copyright (c) AT&T 2012-2013 Yun Mao <yunmao@gmail.com> +# Copyright (c) IBM 2012 Alexey Roytman <roytman at il dot ibm dot com>. +# +# 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. + +"""Test the ZooKeeper driver for servicegroup. + +You need to install ZooKeeper locally and related dependencies +to run the test. It's unclear how to install python-zookeeper lib +in venv so you might have to run the test without it. + +To set up in Ubuntu 12.04: +$ sudo apt-get install zookeeper zookeeperd python-zookeeper +$ sudo pip install evzookeeper +$ nosetests nova.tests.servicegroup.test_zk_driver +""" + +import eventlet + +from nova import servicegroup +from nova import test + + +class ZKServiceGroupTestCase(test.TestCase): + + def setUp(self): + super(ZKServiceGroupTestCase, self).setUp() + servicegroup.API._driver = None + try: + from nova.servicegroup.drivers import zk + _unused = zk + except ImportError: + self.skipTest("Unable to test due to lack of ZooKeeper") + self.flags(servicegroup_driver='zk') + self.flags(address='localhost:2181', group="zk") + + def test_join_leave(self): + self.servicegroup_api = servicegroup.API() + service_id = {'topic': 'unittest', 'host': 'serviceA'} + self.servicegroup_api.join(service_id['host'], service_id['topic']) + self.assertTrue(self.servicegroup_api.service_is_up(service_id)) + self.servicegroup_api.leave(service_id['host'], service_id['topic']) + # make sure zookeeper is updated and watcher is triggered + eventlet.sleep(1) + self.assertFalse(self.servicegroup_api.service_is_up(service_id)) + + def test_stop(self): + self.servicegroup_api = servicegroup.API() + service_id = {'topic': 'unittest', 'host': 'serviceA'} + pulse = self.servicegroup_api.join(service_id['host'], + service_id['topic'], None) + self.assertTrue(self.servicegroup_api.service_is_up(service_id)) + pulse.stop() + eventlet.sleep(1) + self.assertFalse(self.servicegroup_api.service_is_up(service_id)) diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index 11c16d6dd..949f54512 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -22,12 +22,13 @@ import random import StringIO import boto +import boto.connection from boto.ec2 import regioninfo from boto import exception as boto_exc # newer versions of boto use their own wrapper on top of httplib.HTTPResponse -try: - import boto.connection as httplib -except ImportError: +if hasattr(boto.connection, 'HTTPResponse'): + httplib = boto.connection +else: import httplib import fixtures import webob diff --git a/nova/tests/test_crypto.py b/nova/tests/test_crypto.py index 25df336fb..cec3ca9c1 100644 --- a/nova/tests/test_crypto.py +++ b/nova/tests/test_crypto.py @@ -212,3 +212,31 @@ e6fCXWECgYEAqgpGvva5kJ1ISgNwnJbwiNw0sOT9BMOsdNZBElf0kJIIy6FMPvap def test_ssh_encrypt_failure(self): self.assertRaises(exception.EncryptionFailure, crypto.ssh_encrypt_text, '', self.text) + + +class ConversionTests(test.TestCase): + k1 = ("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA4CqmrxfU7x4sJrubpMNxeglul+d" + "ByrsicnvQcHDEjPzdvoz+BaoAG9bjCA5mCeTBIISsVTVXz/hxNeiuBV6LH/UR/c" + "27yl53ypN+821ImoexQZcKItdnjJ3gVZlDob1f9+1qDVy63NJ1c+TstkrCTRVeo" + "9VyE7RpdSS4UCiBe8Xwk3RkedioFxePrI0Ktc2uASw2G0G2Rl7RN7KZOJbCivfF" + "LQMAOu6e+7fYvuE1gxGHHj7dxaBY/ioGOm1W4JmQ1V7AKt19zTBlZKduN8FQMSF" + "r35CDlvoWs0+OP8nwlebKNCi/5sdL8qiSLrAcPB4LqdkAf/blNSVA2Yl83/c4lQ" + "== test@test") + + k2 = ("-----BEGIN PUBLIC KEY-----\n" + "MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA4CqmrxfU7x4sJrubpMNx\n" + "eglul+dByrsicnvQcHDEjPzdvoz+BaoAG9bjCA5mCeTBIISsVTVXz/hxNeiuBV6L\n" + "H/UR/c27yl53ypN+821ImoexQZcKItdnjJ3gVZlDob1f9+1qDVy63NJ1c+TstkrC\n" + "TRVeo9VyE7RpdSS4UCiBe8Xwk3RkedioFxePrI0Ktc2uASw2G0G2Rl7RN7KZOJbC\n" + "ivfFLQMAOu6e+7fYvuE1gxGHHj7dxaBY/ioGOm1W4JmQ1V7AKt19zTBlZKduN8FQ\n" + "MSFr35CDlvoWs0+OP8nwlebKNCi/5sdL8qiSLrAcPB4LqdkAf/blNSVA2Yl83/c4\n" + "lQIBIw==\n" + "-----END PUBLIC KEY-----\n") + + def test_convert_keys(self): + result = crypto.convert_from_sshrsa_to_pkcs8(self.k1) + self.assertEqual(result, self.k2) + + def test_convert_failure(self): + self.assertRaises(exception.EncryptionFailure, + crypto.convert_from_sshrsa_to_pkcs8, '') diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index c6bf2941e..22de9346f 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -685,9 +685,9 @@ class DbApiTestCase(test.TestCase): db.action_start(ctxt2, action_values) actions = db.actions_get(ctxt1, uuid1) - action_id = actions[0]['id'] - action = db.action_get_by_id(ctxt1, uuid1, action_id) - self.assertEqual('resize', action['action']) + request_id = actions[0]['request_id'] + action = db.action_get_by_request_id(ctxt1, uuid1, request_id) + self.assertEqual('run_instance', action['action']) self.assertEqual(ctxt1.request_id, action['request_id']) def test_instance_action_event_start(self): diff --git a/nova/tests/test_hypervapi.py b/nova/tests/test_hypervapi.py index 0c2f90a4d..025d3a454 100644 --- a/nova/tests/test_hypervapi.py +++ b/nova/tests/test_hypervapi.py @@ -80,6 +80,7 @@ class HyperVAPITestCase(test.TestCase): self._instance_ide_disks = [] self._instance_ide_dvds = [] self._instance_volume_disks = [] + self._test_vm_name = None self._setup_stubs() @@ -116,6 +117,14 @@ class HyperVAPITestCase(test.TestCase): self.stubs.Set(pathutils, 'PathUtils', fake.PathUtils) self._mox.StubOutWithMock(fake.PathUtils, 'open') + self._mox.StubOutWithMock(fake.PathUtils, 'copyfile') + self._mox.StubOutWithMock(fake.PathUtils, 'rmtree') + self._mox.StubOutWithMock(fake.PathUtils, 'copy') + self._mox.StubOutWithMock(fake.PathUtils, 'remove') + self._mox.StubOutWithMock(fake.PathUtils, 'rename') + self._mox.StubOutWithMock(fake.PathUtils, 'makedirs') + self._mox.StubOutWithMock(fake.PathUtils, + 'get_instance_migr_revert_dir') self._mox.StubOutWithMock(vmutils.VMUtils, 'vm_exists') self._mox.StubOutWithMock(vmutils.VMUtils, 'create_vm') @@ -137,11 +146,13 @@ class HyperVAPITestCase(test.TestCase): self._mox.StubOutWithMock(vmutils.VMUtils, 'get_mounted_disk_by_drive_number') self._mox.StubOutWithMock(vmutils.VMUtils, 'detach_vm_disk') + self._mox.StubOutWithMock(vmutils.VMUtils, 'get_vm_storage_paths') self._mox.StubOutWithMock(vhdutils.VHDUtils, 'create_differencing_vhd') self._mox.StubOutWithMock(vhdutils.VHDUtils, 'reconnect_parent_vhd') self._mox.StubOutWithMock(vhdutils.VHDUtils, 'merge_vhd') self._mox.StubOutWithMock(vhdutils.VHDUtils, 'get_vhd_parent_path') + self._mox.StubOutWithMock(vhdutils.VHDUtils, 'get_vhd_info') self._mox.StubOutWithMock(hostutils.HostUtils, 'get_cpus_info') self._mox.StubOutWithMock(hostutils.HostUtils, @@ -149,6 +160,7 @@ class HyperVAPITestCase(test.TestCase): self._mox.StubOutWithMock(hostutils.HostUtils, 'get_memory_info') self._mox.StubOutWithMock(hostutils.HostUtils, 'get_volume_info') self._mox.StubOutWithMock(hostutils.HostUtils, 'get_windows_version') + self._mox.StubOutWithMock(hostutils.HostUtils, 'get_local_ips') self._mox.StubOutWithMock(networkutils.NetworkUtils, 'get_external_vswitch') @@ -181,11 +193,6 @@ class HyperVAPITestCase(test.TestCase): self._mox.StubOutWithMock(volumeutilsv2.VolumeUtilsV2, 'execute_log_out') - self._mox.StubOutWithMock(shutil, 'copyfile') - self._mox.StubOutWithMock(shutil, 'rmtree') - - self._mox.StubOutWithMock(os, 'remove') - self._mox.StubOutClassWithMocks(instance_metadata, 'InstanceMetadata') self._mox.StubOutWithMock(instance_metadata.InstanceMetadata, 'metadata_for_config_drive') @@ -332,7 +339,7 @@ class HyperVAPITestCase(test.TestCase): mox.IsA(str), mox.IsA(str), attempts=1) - os.remove(mox.IsA(str)) + fake.PathUtils.remove(mox.IsA(str)) m = vmutils.VMUtils.attach_ide_drive(mox.IsA(str), mox.IsA(str), @@ -490,15 +497,22 @@ class HyperVAPITestCase(test.TestCase): None) self._mox.VerifyAll() - def test_destroy(self): - self._instance_data = self._get_instance_data() - + def _setup_destroy_mocks(self): m = vmutils.VMUtils.vm_exists(mox.Func(self._check_instance_name)) m.AndReturn(True) - m = vmutils.VMUtils.destroy_vm(mox.Func(self._check_instance_name), - True) - m.AndReturn([]) + func = mox.Func(self._check_instance_name) + vmutils.VMUtils.set_vm_state(func, constants.HYPERV_VM_STATE_DISABLED) + + m = vmutils.VMUtils.get_vm_storage_paths(func) + m.AndReturn(([], [])) + + vmutils.VMUtils.destroy_vm(func) + + def test_destroy(self): + self._instance_data = self._get_instance_data() + + self._setup_destroy_mocks() self._mox.ReplayAll() self._conn.destroy(self._instance_data) @@ -562,7 +576,9 @@ class HyperVAPITestCase(test.TestCase): if cow: m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str), None) - m.AndReturn([]) + m.AndReturn(False) + + vhdutils.VHDUtils.get_vhd_info(mox.Func(self._check_img_path)) self._mox.ReplayAll() self._conn.pre_live_migration(self._context, instance_data, @@ -617,7 +633,7 @@ class HyperVAPITestCase(test.TestCase): def copy_dest_disk_path(src, dest): self._fake_dest_disk_path = dest - m = shutil.copyfile(mox.IsA(str), mox.IsA(str)) + m = fake.PathUtils.copyfile(mox.IsA(str), mox.IsA(str)) m.WithSideEffects(copy_dest_disk_path) self._fake_dest_base_disk_path = None @@ -625,7 +641,7 @@ class HyperVAPITestCase(test.TestCase): def copy_dest_base_disk_path(src, dest): self._fake_dest_base_disk_path = dest - m = shutil.copyfile(fake_parent_vhd_path, mox.IsA(str)) + m = fake.PathUtils.copyfile(fake_parent_vhd_path, mox.IsA(str)) m.WithSideEffects(copy_dest_base_disk_path) def check_dest_disk_path(path): @@ -647,7 +663,7 @@ class HyperVAPITestCase(test.TestCase): func = mox.Func(check_snapshot_path) vmutils.VMUtils.remove_vm_snapshot(func) - shutil.rmtree(mox.IsA(str)) + fake.PathUtils.rmtree(mox.IsA(str)) m = fake.PathUtils.open(func2, 'rb') m.AndReturn(io.BytesIO(b'fake content')) @@ -702,65 +718,70 @@ class HyperVAPITestCase(test.TestCase): mounted_disk_path): self._instance_volume_disks.append(mounted_disk_path) - def _setup_spawn_instance_mocks(self, cow, setup_vif_mocks_func=None, - with_exception=False, - block_device_info=None): - self._test_vm_name = None - - def set_vm_name(vm_name): - self._test_vm_name = vm_name - - def check_vm_name(vm_name): - return vm_name == self._test_vm_name - - m = vmutils.VMUtils.vm_exists(mox.IsA(str)) - m.WithSideEffects(set_vm_name).AndReturn(False) - - if not block_device_info: - m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str), - None) - m.AndReturn([]) - else: - m = basevolumeutils.BaseVolumeUtils.volume_in_mapping( - mox.IsA(str), block_device_info) - m.AndReturn(True) - - if cow: - def check_path(parent_path): - return parent_path == self._fetched_image - - vhdutils.VHDUtils.create_differencing_vhd(mox.IsA(str), - mox.Func(check_path)) + def _check_img_path(self, image_path): + return image_path == self._fetched_image - vmutils.VMUtils.create_vm(mox.Func(check_vm_name), mox.IsA(int), + def _setup_create_instance_mocks(self, setup_vif_mocks_func=None, + boot_from_volume=False): + vmutils.VMUtils.create_vm(mox.Func(self._check_vm_name), mox.IsA(int), mox.IsA(int), mox.IsA(bool)) - if not block_device_info: - m = vmutils.VMUtils.attach_ide_drive(mox.Func(check_vm_name), + if not boot_from_volume: + m = vmutils.VMUtils.attach_ide_drive(mox.Func(self._check_vm_name), mox.IsA(str), mox.IsA(int), mox.IsA(int), mox.IsA(str)) m.WithSideEffects(self._add_ide_disk).InAnyOrder() - m = vmutils.VMUtils.create_scsi_controller(mox.Func(check_vm_name)) + func = mox.Func(self._check_vm_name) + m = vmutils.VMUtils.create_scsi_controller(func) m.InAnyOrder() - vmutils.VMUtils.create_nic(mox.Func(check_vm_name), mox.IsA(str), + vmutils.VMUtils.create_nic(mox.Func(self._check_vm_name), mox.IsA(str), mox.IsA(str)).InAnyOrder() if setup_vif_mocks_func: setup_vif_mocks_func() + def _set_vm_name(self, vm_name): + self._test_vm_name = vm_name + + def _check_vm_name(self, vm_name): + return vm_name == self._test_vm_name + + def _setup_spawn_instance_mocks(self, cow, setup_vif_mocks_func=None, + with_exception=False, + block_device_info=None, + boot_from_volume=False): + m = vmutils.VMUtils.vm_exists(mox.IsA(str)) + m.WithSideEffects(self._set_vm_name).AndReturn(False) + + m = basevolumeutils.BaseVolumeUtils.volume_in_mapping( + mox.IsA(str), block_device_info) + m.AndReturn(boot_from_volume) + + if not boot_from_volume: + vhdutils.VHDUtils.get_vhd_info(mox.Func(self._check_img_path)) + + if cow: + vhdutils.VHDUtils.create_differencing_vhd( + mox.IsA(str), mox.Func(self._check_img_path)) + else: + fake.PathUtils.copyfile(mox.IsA(str), mox.IsA(str)) + + self._setup_create_instance_mocks(setup_vif_mocks_func, + boot_from_volume) + # TODO(alexpilotti) Based on where the exception is thrown # some of the above mock calls need to be skipped if with_exception: - m = vmutils.VMUtils.vm_exists(mox.Func(check_vm_name)) + m = vmutils.VMUtils.vm_exists(mox.Func(self._check_vm_name)) m.AndReturn(True) - vmutils.VMUtils.destroy_vm(mox.Func(check_vm_name), True) + vmutils.VMUtils.destroy_vm(mox.Func(self._check_vm_name)) else: - vmutils.VMUtils.set_vm_state(mox.Func(check_vm_name), + vmutils.VMUtils.set_vm_state(mox.Func(self._check_vm_name), constants.HYPERV_VM_STATE_ENABLED) def _test_spawn_instance(self, cow=True, @@ -772,14 +793,14 @@ class HyperVAPITestCase(test.TestCase): with_exception) self._mox.ReplayAll() - self._spawn_instance(cow, ) + self._spawn_instance(cow) self._mox.VerifyAll() self.assertEquals(len(self._instance_ide_disks), expected_ide_disks) self.assertEquals(len(self._instance_ide_dvds), expected_ide_dvds) - if not cow: - self.assertEquals(self._fetched_image, self._instance_ide_disks[0]) + vhd_path = pathutils.PathUtils().get_vhd_path(self._test_vm_name) + self.assertEquals(vhd_path, self._instance_ide_disks[0]) def test_attach_volume(self): instance_data = self._get_instance_data() @@ -897,10 +918,165 @@ class HyperVAPITestCase(test.TestCase): m.WithSideEffects(self._add_volume_disk) self._setup_spawn_instance_mocks(cow=False, - block_device_info=block_device_info) + block_device_info=block_device_info, + boot_from_volume=True) self._mox.ReplayAll() self._spawn_instance(False, block_device_info) self._mox.VerifyAll() self.assertEquals(len(self._instance_volume_disks), 1) + + def _setup_test_migrate_disk_and_power_off_mocks(self, same_host=False, + with_exception=False): + self._instance_data = self._get_instance_data() + instance = db.instance_create(self._context, self._instance_data) + network_info = fake_network.fake_get_instance_nw_info( + self.stubs, spectacular=True) + + fake_local_ip = '10.0.0.1' + if same_host: + fake_dest_ip = fake_local_ip + else: + fake_dest_ip = '10.0.0.2' + + fake_root_vhd_path = 'C:\\FakePath\\root.vhd' + fake_revert_path = ('C:\\FakeInstancesPath\\%s\\_revert' % + instance['name']) + + func = mox.Func(self._check_instance_name) + vmutils.VMUtils.set_vm_state(func, constants.HYPERV_VM_STATE_DISABLED) + + m = vmutils.VMUtils.get_vm_storage_paths(func) + m.AndReturn(([fake_root_vhd_path], [])) + + m = hostutils.HostUtils.get_local_ips() + m.AndReturn([fake_local_ip]) + + m = pathutils.PathUtils.get_instance_migr_revert_dir(instance['name'], + remove_dir=True) + m.AndReturn(fake_revert_path) + + if same_host: + fake.PathUtils.makedirs(mox.IsA(str)) + + m = fake.PathUtils.copy(fake_root_vhd_path, mox.IsA(str)) + if with_exception: + m.AndRaise(shutil.Error('Simulated copy error')) + else: + fake.PathUtils.rename(mox.IsA(str), mox.IsA(str)) + if same_host: + fake.PathUtils.rename(mox.IsA(str), mox.IsA(str)) + + self._setup_destroy_mocks() + + return (instance, fake_dest_ip, network_info) + + def test_migrate_disk_and_power_off(self): + (instance, + fake_dest_ip, + network_info) = self._setup_test_migrate_disk_and_power_off_mocks() + + self._mox.ReplayAll() + self._conn.migrate_disk_and_power_off(self._context, instance, + fake_dest_ip, None, + network_info) + self._mox.VerifyAll() + + def test_migrate_disk_and_power_off_same_host(self): + args = self._setup_test_migrate_disk_and_power_off_mocks( + same_host=True) + (instance, fake_dest_ip, network_info) = args + + self._mox.ReplayAll() + self._conn.migrate_disk_and_power_off(self._context, instance, + fake_dest_ip, None, + network_info) + self._mox.VerifyAll() + + def test_migrate_disk_and_power_off_exception(self): + args = self._setup_test_migrate_disk_and_power_off_mocks( + with_exception=True) + (instance, fake_dest_ip, network_info) = args + + self._mox.ReplayAll() + self.assertRaises(shutil.Error, self._conn.migrate_disk_and_power_off, + self._context, instance, fake_dest_ip, None, + network_info) + self._mox.VerifyAll() + + def test_finish_migration(self): + self._instance_data = self._get_instance_data() + instance = db.instance_create(self._context, self._instance_data) + network_info = fake_network.fake_get_instance_nw_info( + self.stubs, spectacular=True) + + m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str), + None) + m.AndReturn(False) + + self._mox.StubOutWithMock(fake.PathUtils, 'exists') + m = fake.PathUtils.exists(mox.IsA(str)) + m.AndReturn(True) + + fake_parent_vhd_path = (os.path.join('FakeParentPath', '%s.vhd' % + instance["image_ref"])) + + m = vhdutils.VHDUtils.get_vhd_info(mox.IsA(str)) + m.AndReturn({'ParentPath': fake_parent_vhd_path, + 'MaxInternalSize': 1}) + + m = fake.PathUtils.exists(mox.IsA(str)) + m.AndReturn(True) + + vhdutils.VHDUtils.reconnect_parent_vhd(mox.IsA(str), mox.IsA(str)) + + self._set_vm_name(instance['name']) + self._setup_create_instance_mocks(None, False) + + vmutils.VMUtils.set_vm_state(mox.Func(self._check_instance_name), + constants.HYPERV_VM_STATE_ENABLED) + + self._mox.ReplayAll() + self._conn.finish_migration(self._context, None, instance, "", + network_info, None, False, None) + self._mox.VerifyAll() + + def test_confirm_migration(self): + self._instance_data = self._get_instance_data() + instance = db.instance_create(self._context, self._instance_data) + network_info = fake_network.fake_get_instance_nw_info( + self.stubs, spectacular=True) + + pathutils.PathUtils.get_instance_migr_revert_dir(instance['name'], + remove_dir=True) + self._mox.ReplayAll() + self._conn.confirm_migration(None, instance, network_info) + self._mox.VerifyAll() + + def test_finish_revert_migration(self): + self._instance_data = self._get_instance_data() + instance = db.instance_create(self._context, self._instance_data) + network_info = fake_network.fake_get_instance_nw_info( + self.stubs, spectacular=True) + + fake_revert_path = ('C:\\FakeInstancesPath\\%s\\_revert' % + instance['name']) + + m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str), + None) + m.AndReturn(False) + + m = pathutils.PathUtils.get_instance_migr_revert_dir(instance['name']) + m.AndReturn(fake_revert_path) + fake.PathUtils.rename(fake_revert_path, mox.IsA(str)) + + self._set_vm_name(instance['name']) + self._setup_create_instance_mocks(None, False) + + vmutils.VMUtils.set_vm_state(mox.Func(self._check_instance_name), + constants.HYPERV_VM_STATE_ENABLED) + + self._mox.ReplayAll() + self._conn.finish_revert_migration(instance, network_info, None) + self._mox.VerifyAll() diff --git a/nova/tests/test_imagebackend.py b/nova/tests/test_imagebackend.py index 76fd1d5b6..87e51819d 100644 --- a/nova/tests/test_imagebackend.py +++ b/nova/tests/test_imagebackend.py @@ -241,8 +241,8 @@ class LvmTestCase(_ImageTestCase, test.TestCase): sparse=sparse) self.disk.get_disk_size(self.TEMPLATE_PATH ).AndReturn(self.TEMPLATE_SIZE) - cmd = ('dd', 'if=%s' % self.TEMPLATE_PATH, - 'of=%s' % self.PATH, 'bs=4M') + cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH, + self.PATH) self.utils.execute(*cmd, run_as_root=True) self.mox.ReplayAll() @@ -271,8 +271,8 @@ class LvmTestCase(_ImageTestCase, test.TestCase): self.SIZE, sparse=sparse) self.disk.get_disk_size(self.TEMPLATE_PATH ).AndReturn(self.TEMPLATE_SIZE) - cmd = ('dd', 'if=%s' % self.TEMPLATE_PATH, - 'of=%s' % self.PATH, 'bs=4M') + cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH, + self.PATH) self.utils.execute(*cmd, run_as_root=True) self.disk.resize2fs(self.PATH, run_as_root=True) self.mox.ReplayAll() diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py index 0829df2c6..6ae28a1c9 100644 --- a/nova/tests/test_instance_types.py +++ b/nova/tests/test_instance_types.py @@ -142,6 +142,17 @@ class InstanceTypeTestCase(test.TestCase): self.assertRaises(exception.InvalidInput, instance_types.create, name, 256, 1, 120, 100, flavorid) + def test_instance_type_create_with_long_flavor_name(self): + # Flavor name with 255 characters or less is valid. + name = 'a' * 255 + inst_type = instance_types.create(name, 64, 1, 120, flavorid=11) + self.assertEqual(inst_type['name'], name) + + # Flavor name which is more than 255 characters will cause error. + name = 'a' * 256 + self.assertRaises(exception.InvalidInput, instance_types.create, + name, 64, 1, 120, flavorid=11) + def test_add_instance_type_access(self): user_id = 'fake' project_id = 'fake' diff --git a/nova/tests/test_libvirt_blockinfo.py b/nova/tests/test_libvirt_blockinfo.py index e8d548399..68f1fa394 100644 --- a/nova/tests/test_libvirt_blockinfo.py +++ b/nova/tests/test_libvirt_blockinfo.py @@ -421,7 +421,7 @@ class LibvirtBlockInfoTest(test.TestCase): self.assertEqual(bus, 'usb') image_meta = {'properties': {'disk_bus': 'xen'}} - self.assertRaises(exception.NovaException, + self.assertRaises(exception.UnsupportedHardware, blockinfo.get_disk_bus_for_device_type, 'kvm', image_meta) diff --git a/nova/tests/test_libvirt_vif.py b/nova/tests/test_libvirt_vif.py index 916b961da..749fda33a 100644 --- a/nova/tests/test_libvirt_vif.py +++ b/nova/tests/test_libvirt_vif.py @@ -171,7 +171,7 @@ class LibvirtVifTestCase(test.TestCase): self.stubs.Set(utils, 'execute', fake_execute) - def _get_instance_xml(self, driver, net, mapping): + def _get_instance_xml(self, driver, net, mapping, image_meta=None): conf = vconfig.LibvirtConfigGuest() conf.virt_type = "qemu" conf.name = "fake-name" @@ -179,7 +179,7 @@ class LibvirtVifTestCase(test.TestCase): conf.memory = 100 * 1024 conf.vcpus = 4 - nic = driver.get_config(self.instance, net, mapping) + nic = driver.get_config(self.instance, net, mapping, image_meta) conf.add_device(nic) return conf.to_xml() @@ -269,6 +269,46 @@ class LibvirtVifTestCase(test.TestCase): ret = node.findall("driver") self.assertEqual(len(ret), 0) + def test_model_kvm_custom(self): + self.flags(libvirt_use_virtio_for_bridges=True, + libvirt_type='kvm') + + def get_connection(): + return fakelibvirt.Connection("qemu:///session", + False) + d = vif.LibvirtGenericVIFDriver(get_connection) + image_meta = {'properties': {'vif_model': 'e1000'}} + xml = self._get_instance_xml(d, + self.net_bridge, + self.mapping_bridge, + image_meta) + + doc = etree.fromstring(xml) + ret = doc.findall('./devices/interface') + self.assertEqual(len(ret), 1) + node = ret[0] + + model = node.find("model").get("type") + self.assertEqual(model, "e1000") + ret = node.findall("driver") + self.assertEqual(len(ret), 0) + + def test_model_kvm_bogus(self): + self.flags(libvirt_use_virtio_for_bridges=True, + libvirt_type='kvm') + + def get_connection(): + return fakelibvirt.Connection("qemu:///session", + False) + d = vif.LibvirtGenericVIFDriver(get_connection) + image_meta = {'properties': {'vif_model': 'acme'}} + self.assertRaises(exception.UnsupportedHardware, + self._get_instance_xml, + d, + self.net_bridge, + self.mapping_bridge, + image_meta) + def test_model_qemu(self): self.flags(libvirt_use_virtio_for_bridges=True, libvirt_type='qemu') diff --git a/nova/tests/test_libvirt_volume.py b/nova/tests/test_libvirt_volume.py index b9f95735f..0098215b2 100644 --- a/nova/tests/test_libvirt_volume.py +++ b/nova/tests/test_libvirt_volume.py @@ -364,3 +364,59 @@ class LibvirtVolumeTestCase(test.TestCase): ('stat', export_mnt_base), ('mount', '-t', 'nfs', export_string, export_mnt_base)] self.assertEqual(self.executes, expected_commands) + + def aoe_connection(self, shelf, lun): + return { + 'driver_volume_type': 'aoe', + 'data': { + 'target_shelf': shelf, + 'target_lun': lun, + } + } + + def test_libvirt_aoe_driver(self): + # NOTE(jbr_) exists is to make driver assume connecting worked + self.stubs.Set(os.path, 'exists', lambda x: True) + libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn) + shelf = '100' + lun = '1' + connection_info = self.aoe_connection(shelf, lun) + disk_info = { + "bus": "virtio", + "dev": "vde", + "type": "disk", + } + conf = libvirt_driver.connect_volume(connection_info, disk_info) + tree = conf.format_dom() + aoedevpath = '/dev/etherd/e%s.%s' % (shelf, lun) + self.assertEqual(tree.get('type'), 'block') + self.assertEqual(tree.find('./source').get('dev'), aoedevpath) + libvirt_driver.disconnect_volume(connection_info, "vde") + + def test_libvirt_glusterfs_driver(self): + mnt_base = '/mnt' + self.flags(glusterfs_mount_point_base=mnt_base) + + libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn) + export_string = '192.168.1.1:/volume-00001' + name = 'volume-00001' + export_mnt_base = os.path.join(mnt_base, + libvirt_driver.get_hash_str(export_string)) + file_path = os.path.join(export_mnt_base, name) + + connection_info = {'data': {'export': export_string, 'name': name}} + disk_info = { + "bus": "virtio", + "dev": "vde", + "type": "disk", + } + conf = libvirt_driver.connect_volume(connection_info, disk_info) + tree = conf.format_dom() + self.assertEqual(tree.get('type'), 'file') + self.assertEqual(tree.find('./source').get('file'), file_path) + libvirt_driver.disconnect_volume(connection_info, "vde") + + expected_commands = [ + ('stat', export_mnt_base), + ('mount', '-t', 'glusterfs', export_string, export_mnt_base)] + self.assertEqual(self.executes, expected_commands) diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py index 827bfb398..95399e33d 100644 --- a/nova/tests/test_metadata.py +++ b/nova/tests/test_metadata.py @@ -31,6 +31,7 @@ from nova.api.metadata import base from nova.api.metadata import handler from nova.api.metadata import password from nova import block_device +from nova.conductor import api as conductor_api from nova import db from nova.db.sqlalchemy import api from nova import exception @@ -118,6 +119,7 @@ class MetadataTestCase(test.TestCase): def setUp(self): super(MetadataTestCase, self).setUp() self.instance = INSTANCES[0] + self.flags(use_local=True, group='conductor') fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, spectacular=True) @@ -191,10 +193,11 @@ class MetadataTestCase(test.TestCase): 'swap': '/dev/sdc', 'ebs0': '/dev/sdh'} - self.assertEqual(base._format_instance_mapping(ctxt, instance_ref0), - block_device._DEFAULT_MAPPINGS) - self.assertEqual(base._format_instance_mapping(ctxt, instance_ref1), - expected) + capi = conductor_api.LocalAPI() + self.assertEqual(base._format_instance_mapping(capi, ctxt, + instance_ref0), block_device._DEFAULT_MAPPINGS) + self.assertEqual(base._format_instance_mapping(capi, ctxt, + instance_ref1), expected) def test_pubkey(self): md = fake_InstanceMetadata(self.stubs, copy.copy(self.instance)) @@ -247,6 +250,7 @@ class OpenStackMetadataTestCase(test.TestCase): def setUp(self): super(OpenStackMetadataTestCase, self).setUp() self.instance = INSTANCES[0] + self.flags(use_local=True, group='conductor') fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, spectacular=True) @@ -382,6 +386,7 @@ class MetadataHandlerTestCase(test.TestCase): fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, spectacular=True) self.instance = INSTANCES[0] + self.flags(use_local=True, group='conductor') self.mdinst = fake_InstanceMetadata(self.stubs, self.instance, address=None, sgroups=None) @@ -547,6 +552,7 @@ class MetadataPasswordTestCase(test.TestCase): fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs, spectacular=True) self.instance = copy.copy(INSTANCES[0]) + self.flags(use_local=True, group='conductor') self.mdinst = fake_InstanceMetadata(self.stubs, self.instance, address=None, sgroups=None) self.flags(use_local=True, group='conductor') diff --git a/nova/tests/test_migration_utils.py b/nova/tests/test_migration_utils.py new file mode 100644 index 000000000..45b6d86d4 --- /dev/null +++ b/nova/tests/test_migration_utils.py @@ -0,0 +1,126 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2013 Boris Pavlovic (boris@pavlovic.me). +# All Rights Reserved. +# +# 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 migrate.changeset import UniqueConstraint +from sqlalchemy import MetaData, Table, Column, Integer, BigInteger + +from nova.db.sqlalchemy import utils +from nova import exception +from nova.tests import test_migrations + + +class TestMigrationUtils(test_migrations.BaseMigrationTestCase): + """Class for testing utils that are used in db migrations.""" + + def test_utils_drop_unique_constraint(self): + table_name = "__test_tmp_table__" + uc_name = 'uniq_foo' + values = [ + {'id': 1, 'a': 3, 'foo': 10}, + {'id': 2, 'a': 2, 'foo': 20}, + {'id': 3, 'a': 1, 'foo': 30} + ] + for key, engine in self.engines.items(): + meta = MetaData() + meta.bind = engine + test_table = Table(table_name, meta, + Column('id', Integer, primary_key=True, + nullable=False), + Column('a', Integer), + Column('foo', Integer), + UniqueConstraint('a', name='uniq_a'), + UniqueConstraint('foo', name=uc_name)) + test_table.create() + + engine.execute(test_table.insert(), values) + # NOTE(boris-42): This method is generic UC dropper. + utils.drop_unique_constraint(engine, table_name, uc_name, 'foo') + + s = test_table.select().order_by(test_table.c.id) + rows = engine.execute(s).fetchall() + + for i in xrange(0, len(values)): + v = values[i] + self.assertEqual((v['id'], v['a'], v['foo']), rows[i]) + + # NOTE(boris-42): Update data about Table from DB. + meta = MetaData() + meta.bind = engine + test_table = Table(table_name, meta, autoload=True) + constraints = filter(lambda c: c.name == uc_name, + test_table.constraints) + self.assertEqual(len(constraints), 0) + self.assertEqual(len(test_table.constraints), 1) + + test_table.drop() + + def test_util_drop_unique_constraint_with_not_supported_sqlite_type(self): + table_name = "__test_tmp_table__" + uc_name = 'uniq_foo' + values = [ + {'id': 1, 'a': 3, 'foo': 10}, + {'id': 2, 'a': 2, 'foo': 20}, + {'id': 3, 'a': 1, 'foo': 30} + ] + + for key, engine in self.engines.items(): + meta = MetaData() + meta.bind = engine + test_table = Table(table_name, meta, + Column('id', Integer, primary_key=True, + nullable=False), + Column('a', Integer), + Column('foo', BigInteger, default=0), + UniqueConstraint('a', name='uniq_a'), + UniqueConstraint('foo', name=uc_name)) + test_table.create() + + engine.execute(test_table.insert(), values) + if key == "sqlite": + # NOTE(boris-42): Missing info about column `foo` that has + # unsupported type BigInteger. + self.assertRaises(exception.NovaException, + utils.drop_unique_constraint, + engine, table_name, uc_name, 'foo') + + # NOTE(boris-42): Wrong type of foo instance. it should be + # instance of sqlalchemy.Column. + self.assertRaises(exception.NovaException, + utils.drop_unique_constraint, + engine, table_name, uc_name, 'foo', + foo=Integer()) + + foo = Column('foo', BigInteger, default=0) + utils.drop_unique_constraint(engine, table_name, uc_name, 'foo', + foo=foo) + + s = test_table.select().order_by(test_table.c.id) + rows = engine.execute(s).fetchall() + + for i in xrange(0, len(values)): + v = values[i] + self.assertEqual((v['id'], v['a'], v['foo']), rows[i]) + + # NOTE(boris-42): Update data about Table from DB. + meta = MetaData() + meta.bind = engine + test_table = Table(table_name, meta, autoload=True) + constraints = filter(lambda c: c.name == uc_name, + test_table.constraints) + self.assertEqual(len(constraints), 0) + self.assertEqual(len(test_table.constraints), 1) + test_table.drop() diff --git a/nova/tests/test_migrations.py b/nova/tests/test_migrations.py index 02d7462d2..a0c5db9c4 100644 --- a/nova/tests/test_migrations.py +++ b/nova/tests/test_migrations.py @@ -43,6 +43,7 @@ postgres=# create database openstack_citest with owner openstack_citest; import collections import commands import ConfigParser +import datetime import os import urlparse @@ -53,6 +54,7 @@ import nova.db.migration as migration import nova.db.sqlalchemy.migrate_repo from nova.db.sqlalchemy.migration import versioning_api as migration_api from nova.openstack.common import log as logging +from nova.openstack.common import timeutils from nova import test @@ -116,8 +118,8 @@ def get_table(engine, name): return sqlalchemy.Table(name, metadata, autoload=True) -class TestMigrations(test.TestCase): - """Test sqlalchemy-migrate migrations.""" +class BaseMigrationTestCase(test.TestCase): + """Base class fort testing migrations and migration utils.""" DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'test_migrations.conf') @@ -130,18 +132,18 @@ class TestMigrations(test.TestCase): os.path.abspath(os.path.dirname(MIGRATE_FILE))) def setUp(self): - super(TestMigrations, self).setUp() + super(BaseMigrationTestCase, self).setUp() self.snake_walk = False self.test_databases = {} # Load test databases from the config file. Only do this # once. No need to re-run this on each test... - LOG.debug('config_path is %s' % TestMigrations.CONFIG_FILE_PATH) - if os.path.exists(TestMigrations.CONFIG_FILE_PATH): + LOG.debug('config_path is %s' % BaseMigrationTestCase.CONFIG_FILE_PATH) + if os.path.exists(BaseMigrationTestCase.CONFIG_FILE_PATH): cp = ConfigParser.RawConfigParser() try: - cp.read(TestMigrations.CONFIG_FILE_PATH) + cp.read(BaseMigrationTestCase.CONFIG_FILE_PATH) defaults = cp.defaults() for key, value in defaults.items(): self.test_databases[key] = value @@ -165,7 +167,7 @@ class TestMigrations(test.TestCase): # and recreate it, which ensures that we have no side-effects # from the tests self._reset_databases() - super(TestMigrations, self).tearDown() + super(BaseMigrationTestCase, self).tearDown() def _reset_databases(self): def execute_cmd(cmd=None): @@ -232,6 +234,10 @@ class TestMigrations(test.TestCase): os.unsetenv('PGPASSWORD') os.unsetenv('PGUSER') + +class TestMigrations(BaseMigrationTestCase): + """Test sqlalchemy-migrate migrations.""" + def test_walk_versions(self): """ Walks all version scripts for each tested database, ensuring @@ -381,18 +387,70 @@ class TestMigrations(test.TestCase): (version, engine)) raise + def _prerun_134(self, engine): + now = timeutils.utcnow() + data = [{ + 'id': 1, + 'uuid': '1d739808-d7ec-4944-b252-f8363e119755', + 'mac': '00:00:00:00:00:01', + 'start_period': now, + 'last_refreshed': now + datetime.timedelta(seconds=10), + 'bw_in': 100000, + 'bw_out': 200000, + }, { + 'id': 2, + 'uuid': '1d739808-d7ec-4944-b252-f8363e119756', + 'mac': '2a:f2:48:31:c1:60', + 'start_period': now, + 'last_refreshed': now + datetime.timedelta(seconds=20), + 'bw_in': 1000000000, + 'bw_out': 200000000, + }, { + 'id': 3, + # This is intended to be the same as above. + 'uuid': '1d739808-d7ec-4944-b252-f8363e119756', + 'mac': '00:00:00:00:00:02', + 'start_period': now, + 'last_refreshed': now + datetime.timedelta(seconds=30), + 'bw_in': 0, + 'bw_out': 0, + }] + + bw_usage_cache = get_table(engine, 'bw_usage_cache') + engine.execute(bw_usage_cache.insert(), data) + return data + + def _check_134(self, engine, data): + bw_usage_cache = get_table(engine, 'bw_usage_cache') + + # Checks if both columns have been successfuly created. + self.assertIn('last_ctr_in', bw_usage_cache.c) + self.assertIn('last_ctr_out', bw_usage_cache.c) + + # Checks if all rows have been inserted. + bw_items = bw_usage_cache.select().execute().fetchall() + self.assertEqual(len(bw_items), 3) + + bw = bw_usage_cache.select( + bw_usage_cache.c.id == 1).execute().first() + + # New columns have 'NULL' as default value. + self.assertEqual(bw['last_ctr_in'], None) + self.assertEqual(bw['last_ctr_out'], None) + + self.assertEqual(data[0]['mac'], bw['mac']) + # migration 146, availability zone transition def _prerun_146(self, engine): data = { 'availability_zone': 'custom_az', - 'aggregate_name': 1, 'name': 'name', } aggregates = get_table(engine, 'aggregates') result = aggregates.insert().values(data).execute() # NOTE(sdague) it's important you don't insert keys by value in - # postgresql, because it's autoincrement counter won't get updated + # postgresql, because its autoincrement counter won't get updated data['id'] = result.inserted_primary_key[0] return data diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py index aaa826a70..0aa2a310c 100644 --- a/nova/tests/test_utils.py +++ b/nova/tests/test_utils.py @@ -25,6 +25,7 @@ import StringIO import tempfile import mox +import netaddr import nova from nova import exception @@ -481,6 +482,29 @@ class GenericUtilsTestCase(test.TestCase): self.assertFalse(utils.is_valid_ipv4('::1')) self.assertFalse(utils.is_valid_ipv4('bacon')) + def test_is_valid_ipv6(self): + self.assertTrue(utils.is_valid_ipv6("::1")) + self.assertTrue(utils.is_valid_ipv6( + "abcd:ef01:2345:6789:abcd:ef01:192.168.254.254")) + self.assertTrue(utils.is_valid_ipv6( + "0000:0000:0000:0000:0000:0000:0000:0001")) + self.assertFalse(utils.is_valid_ipv6("foo")) + self.assertFalse(utils.is_valid_ipv6("127.0.0.1")) + + def test_get_shortened_ipv6(self): + self.assertEquals("abcd:ef01:2345:6789:abcd:ef01:c0a8:fefe", + utils.get_shortened_ipv6( + "abcd:ef01:2345:6789:abcd:ef01:192.168.254.254")) + self.assertEquals("::1", utils.get_shortened_ipv6( + "0000:0000:0000:0000:0000:0000:0000:0001")) + self.assertEquals("caca::caca:0:babe:201:102", + utils.get_shortened_ipv6( + "caca:0000:0000:caca:0000:babe:0201:0102")) + self.assertRaises(netaddr.AddrFormatError, utils.get_shortened_ipv6, + "127.0.0.1") + self.assertRaises(netaddr.AddrFormatError, utils.get_shortened_ipv6, + "failure") + class MonkeyPatchTestCase(test.TestCase): """Unit test for utils.monkey_patch().""" @@ -964,3 +988,18 @@ class GetCallArgsTestCase(test.TestCase): self.assertEqual(3, callargs['red']) self.assertTrue('blue' in callargs) self.assertEqual(None, callargs['blue']) + + +class StringLengthTestCase(test.TestCase): + def test_check_string_length(self): + self.assertIsNone(utils.check_string_length( + 'test', 'name', max_length=255)) + self.assertRaises(exception.InvalidInput, + utils.check_string_length, + 11, 'name', max_length=255) + self.assertRaises(exception.InvalidInput, + utils.check_string_length, + '', 'name', min_length=1) + self.assertRaises(exception.InvalidInput, + utils.check_string_length, + 'a' * 256, 'name', max_length=255) diff --git a/nova/tests/test_versions.py b/nova/tests/test_versions.py index 5568ff0de..780e5ae12 100644 --- a/nova/tests/test_versions.py +++ b/nova/tests/test_versions.py @@ -24,38 +24,14 @@ 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() - 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} - self.version.NOVA_PACKAGE = "g9ec3421" - - 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 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_version_string_with_package_is_good(self): - # Ensure uninstalled code get version string. - self.assertEqual("2012.10-g9ec3421", - self.version.version_string_with_package()) + """Ensure uninstalled code get version string.""" + + self.stubs.Set(version.version_info, 'version', '5.5.5.5') + self.stubs.Set(version, 'NOVA_PACKAGE', 'g9ec3421') + self.assertEqual("5.5.5.5-g9ec3421", + version.version_string_with_package()) def test_release_file(self): version.loaded = False diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py index 22544fd2d..e20a5a7b7 100644 --- a/nova/tests/test_vmwareapi.py +++ b/nova/tests/test_vmwareapi.py @@ -28,6 +28,7 @@ from nova import exception from nova import test import nova.tests.image.fake from nova.tests import matchers +from nova.tests import utils from nova.tests.vmwareapi import db_fakes from nova.tests.vmwareapi import stubs from nova.virt.vmwareapi import driver @@ -54,24 +55,7 @@ class VMwareAPIVMTestCase(test.TestCase): self.conn = driver.VMwareESXDriver(None, False) # NOTE(vish): none of the network plugging code is actually # being tested - self.network_info = [({'bridge': 'fa0', - 'id': 0, - 'vlan': None, - 'bridge_interface': None, - 'injected': True}, - {'broadcast': '192.168.0.255', - 'dns': ['192.168.0.1'], - 'gateway': '192.168.0.1', - 'gateway_v6': 'dead:beef::1', - 'ip6s': [{'enabled': '1', - 'ip': 'dead:beef::dcad:beff:feef:0', - 'netmask': '64'}], - 'ips': [{'enabled': '1', - 'ip': '192.168.0.100', - 'netmask': '255.255.255.0'}], - 'label': 'fake', - 'mac': 'DE:AD:BE:EF:00:00', - 'rxtx_cap': 3})] + self.network_info = utils.get_test_network_info(legacy_model=False) self.image = { 'id': 'c1c8ce3d-c2e0-4247-890c-ccf5cc1c004c', diff --git a/nova/tests/test_vmwareapi_vmops.py b/nova/tests/test_vmwareapi_vmops.py new file mode 100644 index 000000000..ad83cd21d --- /dev/null +++ b/nova/tests/test_vmwareapi_vmops.py @@ -0,0 +1,62 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2013 OpenStack LLC. +# All Rights Reserved. +# +# 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.network import model as network_model +from nova import test +from nova.virt.vmwareapi import vmops + + +class VMwareVMOpsTestCase(test.TestCase): + def setUp(self): + super(VMwareVMOpsTestCase, self).setUp() + subnet_4 = network_model.Subnet(cidr='192.168.0.1/24', + dns=[network_model.IP('192.168.0.1')], + gateway= + network_model.IP('192.168.0.1'), + ips=[ + network_model.IP('192.168.0.100')], + routes=None) + subnet_6 = network_model.Subnet(cidr='dead:beef::1/64', + dns=None, + gateway= + network_model.IP('dead:beef::1'), + ips=[network_model.IP( + 'dead:beef::dcad:beff:feef:0')], + routes=None) + network = network_model.Network(id=0, + bridge='fa0', + label='fake', + subnets=[subnet_4, subnet_6], + vlan=None, + bridge_interface=None, + injected=True) + self.network_info = network_model.NetworkInfo([ + network_model.VIF(id=None, + address='DE:AD:BE:EF:00:00', + network=network, + type=None, + devname=None, + ovs_interfaceid=None, + rxtx_cap=3) + ]) + + def test_get_machine_id_str(self): + result = vmops.VMwareVMOps._get_machine_id_str(self.network_info) + print result + self.assertEqual(result, + 'DE:AD:BE:EF:00:00;192.168.0.100;255.255.255.0;' + '192.168.0.1;192.168.0.255;192.168.0.1#') diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index cc71ba31e..2a484d832 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -2677,9 +2677,10 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBase): 'destination_sr_ref': None, 'migrate_send_data': None }} - self.conn.check_can_live_migrate_source(self.context, - {'host': 'host'}, - dest_check_data) + result = self.conn.check_can_live_migrate_source(self.context, + {'host': 'host'}, + dest_check_data) + self.assertEqual(dest_check_data, result) def test_check_can_live_migrate_source_with_block_migrate_fails(self): stubs.stubout_session(self.stubs, diff --git a/nova/tests/utils.py b/nova/tests/utils.py index a5d4b4712..56be3ab71 100644 --- a/nova/tests/utils.py +++ b/nova/tests/utils.py @@ -89,7 +89,7 @@ def get_test_instance(context=None, instance_type=None): return instance_ref -def get_test_network_info(count=1): +def get_test_network_info(count=1, legacy_model=True): ipv6 = CONF.use_ipv6 fake = 'fake' fake_ip = '0.0.0.0/0' @@ -98,26 +98,69 @@ def get_test_network_info(count=1): fake_netmask = '255.255.255.255' fake_vlan = 100 fake_bridge_interface = 'eth0' - network = {'bridge': fake, - 'cidr': fake_ip, - 'cidr_v6': fake_ip, - 'vlan': fake_vlan, - 'bridge_interface': fake_bridge_interface, - 'injected': False} - mapping = {'mac': fake, - 'vif_type': network_model.VIF_TYPE_BRIDGE, - 'vif_uuid': 'vif-xxx-yyy-zzz', - 'dhcp_server': fake, - 'dns': ['fake1', 'fake2'], - 'gateway': fake, - 'gateway_v6': fake, - 'ips': [{'ip': fake_ip, 'netmask': fake_netmask}, - {'ip': fake_ip, 'netmask': fake_netmask}]} - if ipv6: - mapping['ip6s'] = [{'ip': fake_ip, 'netmask': fake_netmask}, - {'ip': fake_ip_2}, - {'ip': fake_ip_3}] - return [(network, mapping) for x in xrange(0, count)] + + def legacy(): + network = {'bridge': fake, + 'cidr': fake_ip, + 'cidr_v6': fake_ip, + 'vlan': fake_vlan, + 'bridge_interface': fake_bridge_interface, + 'injected': False} + mapping = {'mac': fake, + 'vif_type': network_model.VIF_TYPE_BRIDGE, + 'vif_uuid': 'vif-xxx-yyy-zzz', + 'dhcp_server': fake, + 'dns': ['fake1', 'fake2'], + 'gateway': fake, + 'gateway_v6': fake, + 'ips': [{'ip': fake_ip, 'netmask': fake_netmask}, + {'ip': fake_ip, 'netmask': fake_netmask}]} + if ipv6: + mapping['ip6s'] = [{'ip': fake_ip, 'netmask': fake_netmask}, + {'ip': fake_ip_2}, + {'ip': fake_ip_3}] + return network, mapping + + def current(): + fake_ip = '0.0.0.0' + subnet_4 = network_model.Subnet(cidr=fake_ip, + dns=[network_model.IP(fake_ip), + network_model.IP(fake_ip)], + gateway=network_model.IP(fake_ip), + ips=[network_model.IP(fake_ip), + network_model.IP(fake_ip)], + routes=None, + dhcp_server=network_model.IP(fake_ip)) + subnet_6 = network_model.Subnet(cidr=fake_ip, + gateway=network_model.IP(fake_ip), + ips=[network_model.IP(fake_ip), + network_model.IP(fake_ip), + network_model.IP(fake_ip)], + routes=None, + version=6) + subnets = [subnet_4] + if ipv6: + subnets.append(subnet_6) + network = network_model.Network(id=None, + bridge=fake, + label=None, + subnets=subnets, + vlan=fake_vlan, + bridge_interface=fake_bridge_interface, + injected=False) + vif = network_model.VIF(id='vif-xxx-yyy-zzz', + address=fake, + network=network, + type=network_model.VIF_TYPE_BRIDGE, + devname=None, + ovs_interfaceid=None) + + return vif + + if legacy_model: + return [legacy() for x in xrange(0, count)] + else: + return network_model.NetworkInfo([current() for x in xrange(0, count)]) def is_osx(): diff --git a/nova/tests/virt/xenapi/test_volumeops.py b/nova/tests/virt/xenapi/test_volumeops.py index 844ae8459..3497babf2 100644 --- a/nova/tests/virt/xenapi/test_volumeops.py +++ b/nova/tests/virt/xenapi/test_volumeops.py @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +import collections + from nova import test from nova.tests.xenapi import stubs from nova.virt.xenapi import volumeops @@ -125,31 +127,33 @@ class VolumeAttachTestCase(test.TestCase): vm_ref = 'vm_ref' dev_number = 1 - called = {'xenapi': False} + called = collections.defaultdict(bool) - def fake_call_xenapi(self, *args, **kwargs): - # Only used for VBD.plug in this code path. - called['xenapi'] = True - raise Exception() + def fake_call_xenapi(self, method, *args, **kwargs): + called[method] = True self.stubs.Set(ops._session, 'call_xenapi', fake_call_xenapi) self.mox.StubOutWithMock(volumeops.volume_utils, 'parse_sr_info') - self.mox.StubOutWithMock( - volumeops.volume_utils, 'introduce_sr_unless_present') - self.mox.StubOutWithMock(volumeops.volume_utils, 'introduce_vdi') - self.mox.StubOutWithMock(volumeops.vm_utils, 'create_vbd') - volumeops.volume_utils.parse_sr_info( connection_data, sr_label).AndReturn( tuple([sr_uuid, sr_label, sr_params])) - volumeops.volume_utils.introduce_sr_unless_present( + self.mox.StubOutWithMock( + volumeops.volume_utils, 'find_sr_by_uuid') + volumeops.volume_utils.find_sr_by_uuid(session, sr_uuid).AndReturn( + None) + + self.mox.StubOutWithMock( + volumeops.volume_utils, 'introduce_sr') + volumeops.volume_utils.introduce_sr( session, sr_uuid, sr_label, sr_params).AndReturn(sr_ref) + self.mox.StubOutWithMock(volumeops.volume_utils, 'introduce_vdi') volumeops.volume_utils.introduce_vdi( - session, sr_ref, vdi_uuid, None).AndReturn(vdi_ref) + session, sr_ref, vdi_uuid=vdi_uuid).AndReturn(vdi_ref) + self.mox.StubOutWithMock(volumeops.vm_utils, 'create_vbd') volumeops.vm_utils.create_vbd( session, vm_ref, vdi_ref, dev_number, bootable=False, osvol=True).AndReturn(vbd_ref) @@ -157,6 +161,6 @@ class VolumeAttachTestCase(test.TestCase): self.mox.ReplayAll() ops._connect_volume(connection_data, dev_number, instance_name, - vm_ref, hotplug=False) + vm_ref, hotplug=False) - self.assertEquals(False, called['xenapi']) + self.assertEquals(False, called['VBD.plug']) |