diff options
author | Sandy Walsh <sandy@sandywalsh.com> | 2012-01-30 13:10:50 -0800 |
---|---|---|
committer | Chris Behrens <cbehrens@codestud.com> | 2012-02-16 17:53:00 +0000 |
commit | 26227b79e9246a87eeb83766cfcc8e96d294d28b (patch) | |
tree | cba29636bf65611a2816acfd455b503d79c43309 /nova/tests/api/openstack | |
parent | f5e17bbc155203feb8bba4f34ed93d22b1b8e95b (diff) | |
download | nova-26227b79e9246a87eeb83766cfcc8e96d294d28b.tar.gz |
Removed zones from api and distributed scheduler
There is a new Zones implementation coming that will use AMQP-to-AMQP
channels vs. the public API. This is being done for three reasons:
1. remove complications in the OpenStack API (and possibly allow EC2 Zones)
2. remove dependencies on keystone and novaclient
3. faster scheduling (fewer chances for race conditions)
Learn more here:
http://wiki.openstack.org/EssexSchedulerImprovements
Change-Id: I6fe538923dd5ae19276afac2ac3311a285fd5c99
Diffstat (limited to 'nova/tests/api/openstack')
5 files changed, 35 insertions, 400 deletions
diff --git a/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py index 1edec954c6..ba832cfe78 100644 --- a/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py +++ b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py @@ -51,7 +51,7 @@ class ExtendedStatusTest(test.TestCase): def setUp(self): super(ExtendedStatusTest, self).setUp() fakes.stub_out_nw_api(self.stubs) - self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get) + self.stubs.Set(compute.api.API, 'get', fake_compute_get) self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all) def _make_request(self, url): @@ -94,7 +94,7 @@ class ExtendedStatusTest(test.TestCase): def fake_compute_get(*args, **kwargs): raise exception.InstanceNotFound() - self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get) + self.stubs.Set(compute.api.API, 'get', fake_compute_get) url = '/v2/fake/servers/70f6db34-de8d-4fbd-aafb-4065bdfa6115' res = self._make_request(url) diff --git a/nova/tests/api/openstack/compute/contrib/test_zones.py b/nova/tests/api/openstack/compute/contrib/test_zones.py deleted file mode 100644 index 9f887cb0d0..0000000000 --- a/nova/tests/api/openstack/compute/contrib/test_zones.py +++ /dev/null @@ -1,283 +0,0 @@ -# Copyright 2011 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. - - -import json - -from lxml import etree - -from nova.api.openstack.compute.contrib import zones -from nova.api.openstack import xmlutil -from nova import crypto -import nova.db -from nova import flags -from nova.scheduler import api -from nova import test -from nova.tests.api.openstack import fakes - - -FLAGS = flags.FLAGS - - -def zone_get(context, zone_id): - return dict(id=1, api_url='http://example.com', username='bob', - password='xxx', weight_scale=1.0, weight_offset=0.0, - name='darksecret') - - -def zone_create(context, values): - zone = dict(id=1) - zone.update(values) - return zone - - -def zone_update(context, zone_id, values): - zone = dict(id=zone_id, api_url='http://example.com', username='bob', - password='xxx') - zone.update(values) - return zone - - -def zone_delete(context, zone_id): - pass - - -def zone_get_all_scheduler(*args): - return [ - dict(id=1, api_url='http://example.com', username='bob', - password='xxx', weight_scale=1.0, weight_offset=0.0), - dict(id=2, api_url='http://example.org', username='alice', - password='qwerty', weight_scale=1.0, weight_offset=0.0), - ] - - -def zone_get_all_scheduler_empty(*args): - return [] - - -def zone_get_all_db(context): - return [ - dict(id=1, api_url='http://example.com', username='bob', - password='xxx', weight_scale=1.0, weight_offset=0.0), - dict(id=2, api_url='http://example.org', username='alice', - password='qwerty', weight_scale=1.0, weight_offset=0.0), - ] - - -def zone_capabilities(method, context): - return dict() - - -GLOBAL_BUILD_PLAN = [ - dict(name='host1', weight=10, ip='10.0.0.1', zone='zone1'), - dict(name='host2', weight=9, ip='10.0.0.2', zone='zone2'), - dict(name='host3', weight=8, ip='10.0.0.3', zone='zone3'), - dict(name='host4', weight=7, ip='10.0.0.4', zone='zone4'), - ] - - -def zone_select(context, specs): - return GLOBAL_BUILD_PLAN - - -class ZonesTest(test.TestCase): - def setUp(self): - super(ZonesTest, self).setUp() - fakes.stub_out_networking(self.stubs) - fakes.stub_out_rate_limiting(self.stubs) - - self.stubs.Set(nova.db, 'zone_get', zone_get) - self.stubs.Set(nova.db, 'zone_update', zone_update) - self.stubs.Set(nova.db, 'zone_create', zone_create) - self.stubs.Set(nova.db, 'zone_delete', zone_delete) - - self.controller = zones.Controller() - - def test_get_zone_list_scheduler(self): - self.stubs.Set(api, '_call_scheduler', zone_get_all_scheduler) - - req = fakes.HTTPRequest.blank('/v2/fake/zones') - res_dict = self.controller.index(req) - - self.assertEqual(len(res_dict['zones']), 2) - - def test_get_zone_list_db(self): - self.stubs.Set(api, '_call_scheduler', zone_get_all_scheduler_empty) - self.stubs.Set(nova.db, 'zone_get_all', zone_get_all_db) - - req = fakes.HTTPRequest.blank('/v2/fake/zones') - res_dict = self.controller.index(req) - - self.assertEqual(len(res_dict['zones']), 2) - - def test_get_zone_by_id(self): - req = fakes.HTTPRequest.blank('/v2/fake/zones/1') - res_dict = self.controller.show(req, 1) - - self.assertEqual(res_dict['zone']['id'], 1) - self.assertEqual(res_dict['zone']['api_url'], 'http://example.com') - self.assertFalse('password' in res_dict['zone']) - - def test_zone_delete(self): - req = fakes.HTTPRequest.blank('/v2/fake/zones/1') - self.controller.delete(req, 1) - - def test_zone_create(self): - body = dict(zone=dict(api_url='http://example.com', username='fred', - password='fubar')) - - req = fakes.HTTPRequest.blank('/v2/fake/zones') - res_dict = self.controller.create(req, body) - - self.assertEqual(res_dict['zone']['id'], 1) - self.assertEqual(res_dict['zone']['api_url'], 'http://example.com') - self.assertFalse('username' in res_dict['zone']) - - def test_zone_update(self): - body = dict(zone=dict(username='zeb', password='sneaky')) - - req = fakes.HTTPRequest.blank('/v2/fake/zones/1') - res_dict = self.controller.update(req, 1, body) - - self.assertEqual(res_dict['zone']['id'], 1) - self.assertEqual(res_dict['zone']['api_url'], 'http://example.com') - self.assertFalse('username' in res_dict['zone']) - - def test_zone_info(self): - caps = ['cap1=a;b', 'cap2=c;d'] - self.flags(zone_name='darksecret', zone_capabilities=caps) - self.stubs.Set(api, '_call_scheduler', zone_capabilities) - - req = fakes.HTTPRequest.blank('/v2/fake/zones/info') - res_dict = self.controller.info(req) - - self.assertEqual(res_dict['zone']['name'], 'darksecret') - self.assertEqual(res_dict['zone']['cap1'], 'a;b') - self.assertEqual(res_dict['zone']['cap2'], 'c;d') - - def test_zone_select(self): - key = 'c286696d887c9aa0611bbb3e2025a45a' - self.flags(build_plan_encryption_key=key) - self.stubs.Set(api, 'select', zone_select) - - # Select queries end up being JSON encoded twice. - # Once to a string and again as an HTTP POST Body - body = json.dumps({}) - - req = fakes.HTTPRequest.blank('/v2/fake/zones/select') - res_dict = self.controller.select(req, body) - - self.assertTrue('weights' in res_dict) - - for item in res_dict['weights']: - blob = item['blob'] - decrypt = crypto.decryptor(FLAGS.build_plan_encryption_key) - secret_item = json.loads(decrypt(blob)) - found = False - for original_item in GLOBAL_BUILD_PLAN: - if original_item['name'] != secret_item['name']: - continue - found = True - for key in ('weight', 'ip', 'zone'): - self.assertEqual(secret_item[key], original_item[key]) - - self.assertTrue(found) - self.assertEqual(len(item), 2) - self.assertTrue('weight' in item) - - -class TestZonesXMLSerializer(test.TestCase): - - def test_select(self): - serializer = zones.WeightsTemplate() - - key = 'c286696d887c9aa0611bbb3e2025a45a' - - encrypt = crypto.encryptor(key) - decrypt = crypto.decryptor(key) - - item = GLOBAL_BUILD_PLAN[0] - fixture = {'weights': {'blob': encrypt(json.dumps(item)), - 'weight': item['weight']}} - - output = serializer.serialize(fixture) - res_tree = etree.XML(output) - - self.assertEqual(res_tree.tag, '{%s}weights' % xmlutil.XMLNS_V10) - - for item in res_tree: - self.assertEqual(item.tag, '{%s}weight' % xmlutil.XMLNS_V10) - blob = None - weight = None - for chld in item: - if chld.tag.endswith('blob'): - blob = chld.text - elif chld.tag.endswith('weight'): - weight = chld.text - - secret_item = json.loads(decrypt(blob)) - found = False - for original_item in GLOBAL_BUILD_PLAN: - if original_item['name'] != secret_item['name']: - continue - found = True - for key in ('weight', 'ip', 'zone'): - self.assertEqual(secret_item[key], original_item[key]) - - self.assertTrue(found) - self.assertEqual(len(item), 2) - self.assertTrue(weight) - - def test_index(self): - serializer = zones.ZonesTemplate() - - fixture = {'zones': zone_get_all_scheduler()} - - output = serializer.serialize(fixture) - res_tree = etree.XML(output) - - self.assertEqual(res_tree.tag, '{%s}zones' % xmlutil.XMLNS_V10) - self.assertEqual(len(res_tree), 2) - self.assertEqual(res_tree[0].tag, '{%s}zone' % xmlutil.XMLNS_V10) - self.assertEqual(res_tree[1].tag, '{%s}zone' % xmlutil.XMLNS_V10) - - def test_show(self): - serializer = zones.ZoneTemplate() - - zone = {'id': 1, - 'api_url': 'http://example.com', - 'name': 'darksecret', - 'cap1': 'a;b', - 'cap2': 'c;d'} - fixture = {'zone': zone} - - output = serializer.serialize(fixture) - print repr(output) - res_tree = etree.XML(output) - - self.assertEqual(res_tree.tag, '{%s}zone' % xmlutil.XMLNS_V10) - self.assertEqual(res_tree.get('id'), '1') - self.assertEqual(res_tree.get('api_url'), 'http://example.com') - self.assertEqual(res_tree.get('password'), None) - - self.assertEqual(res_tree.get('name'), 'darksecret') - for elem in res_tree: - self.assertEqual(elem.tag in ('{%s}cap1' % xmlutil.XMLNS_V10, - '{%s}cap2' % xmlutil.XMLNS_V10), - True) - if elem.tag == '{%s}cap1' % xmlutil.XMLNS_V10: - self.assertEqual(elem.text, 'a;b') - elif elem.tag == '{%s}cap2' % xmlutil.XMLNS_V10: - self.assertEqual(elem.text, 'c;d') diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index 7341cd4832..bd292c5332 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -172,6 +172,7 @@ class ExtensionControllerTest(ExtensionTestCase): "Hosts", "Keypairs", "Multinic", + "Networks", "Quotas", "Rescue", "SchedulerHints", @@ -185,8 +186,6 @@ class ExtensionControllerTest(ExtensionTestCase): "VirtualInterfaces", "Volumes", "VolumeTypes", - "Zones", - "Networks", ] self.ext_list.sort() diff --git a/nova/tests/api/openstack/compute/test_server_actions.py b/nova/tests/api/openstack/compute/test_server_actions.py index 82dcf65e49..7a1f3c4940 100644 --- a/nova/tests/api/openstack/compute/test_server_actions.py +++ b/nova/tests/api/openstack/compute/test_server_actions.py @@ -52,8 +52,12 @@ def instance_update(context, instance_id, kwargs): return stub_instance(instance_id) -def return_server_with_attributes(**kwargs): - def _return_server(context, id): +def return_server_with_attributes(id, **kwargs): + """NOTE: This won't work unless you stub out both + nova.db.instance_get() and nova.db.instance_get_by_uuid() + to be safe. Most all tests only require instance_get_by_uuid(). + """ + def _return_server(context, id_or_uuid): return stub_instance(id, **kwargs) return _return_server @@ -280,8 +284,9 @@ class ServerActionsControllerTest(test.TestCase): req, FAKE_UUID, body) def test_rebuild_accepted_minimum(self): - new_return_server = return_server_with_attributes(image_ref='2') + new_return_server = return_server_with_attributes(id=1, image_ref='2') self.stubs.Set(nova.db, 'instance_get', new_return_server) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) self_href = 'http://localhost/v2/fake/servers/%s' % FAKE_UUID body = { @@ -305,8 +310,9 @@ class ServerActionsControllerTest(test.TestCase): # is missing from response. See lp bug 921814 self.flags(enable_instance_password=False) - new_return_server = return_server_with_attributes(image_ref='2') + new_return_server = return_server_with_attributes(id=1, image_ref='2') self.stubs.Set(nova.db, 'instance_get', new_return_server) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) self_href = 'http://localhost/v2/fake/servers/%s' % FAKE_UUID body = { @@ -344,8 +350,10 @@ class ServerActionsControllerTest(test.TestCase): def test_rebuild_accepted_with_metadata(self): metadata = {'new': 'metadata'} - new_return_server = return_server_with_attributes(metadata=metadata) + new_return_server = return_server_with_attributes(id=1, + metadata=metadata) self.stubs.Set(nova.db, 'instance_get', new_return_server) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) body = { "rebuild": { @@ -417,8 +425,9 @@ class ServerActionsControllerTest(test.TestCase): self.assertTrue('personality' not in body['server']) def test_rebuild_admin_pass(self): - new_return_server = return_server_with_attributes(image_ref='2') + new_return_server = return_server_with_attributes(id=1, image_ref='2') self.stubs.Set(nova.db, 'instance_get', new_return_server) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) body = { "rebuild": { @@ -438,8 +447,9 @@ class ServerActionsControllerTest(test.TestCase): # is missing from response. See lp bug 921814 self.flags(enable_instance_password=False) - new_return_server = return_server_with_attributes(image_ref='2') + new_return_server = return_server_with_attributes(id=1, image_ref='2') self.stubs.Set(nova.db, 'instance_get', new_return_server) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) body = { "rebuild": { @@ -458,6 +468,7 @@ class ServerActionsControllerTest(test.TestCase): def server_not_found(self, instance_id): raise exception.InstanceNotFound(instance_id=instance_id) self.stubs.Set(nova.db, 'instance_get', server_not_found) + self.stubs.Set(nova.db, 'instance_get_by_uuid', server_not_found) body = { "rebuild": { diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index 3540a006ca..45a726f39e 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -38,7 +38,6 @@ from nova.db.sqlalchemy.models import InstanceMetadata from nova import flags import nova.image.fake import nova.rpc -import nova.scheduler.api from nova import test from nova.tests import fake_network from nova.tests.api.openstack import fakes @@ -120,28 +119,6 @@ def return_servers_by_reservation_empty(context, reservation_id=""): return [] -def return_servers_from_child_zones_empty(*args, **kwargs): - return [] - - -def return_servers_from_child_zones(*args, **kwargs): - class Server(object): - pass - - zones = [] - for zone in xrange(3): - servers_list = [] - for server_id in xrange(5): - server = Server() - server._info = fakes.stub_instance( - server_id, reservation_id="child", - project_id='fake_project') - servers_list.append(server) - - zones.append(("Zone%d" % zone, servers_list)) - return zones - - def return_security_group(context, instance_id, security_group_id): pass @@ -192,28 +169,6 @@ class ServersControllerTest(test.TestCase): spectacular=True) def test_get_server_by_uuid(self): - """ - The steps involved with resolving a UUID are pretty complicated; - here's what's happening in this scenario: - - 1. Show is calling `routing_get` - - 2. `routing_get` is wrapped by `reroute_compute` which does the work - of resolving requests to child zones. - - 3. `reroute_compute` looks up the UUID by hitting the stub - (returns_server_by_uuid) - - 4. Since the stub return that the record exists, `reroute_compute` - considers the request to be 'zone local', so it replaces the UUID - in the argument list with an integer ID and then calls the inner - function ('get'). - - 5. The call to `get` hits the other stub 'returns_server_by_id` which - has the UUID set to FAKE_UUID - - So, counterintuitively, we call `get` twice on the `show` command. - """ req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID) res_dict = self.controller.show(req, FAKE_UUID) self.assertEqual(res_dict['server']['id'], FAKE_UUID) @@ -312,6 +267,9 @@ class ServersControllerTest(test.TestCase): new_return_server = return_server_with_attributes( vm_state=vm_states.ACTIVE, progress=100) self.stubs.Set(nova.db, 'instance_get', new_return_server) + new_return_server = return_server_with_attributes_by_uuid( + vm_state=vm_states.ACTIVE, progress=100) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) uuid = FAKE_UUID req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % uuid) @@ -383,6 +341,10 @@ class ServersControllerTest(test.TestCase): vm_state=vm_states.ACTIVE, image_ref=image_ref, flavor_id=flavor_id, progress=100) self.stubs.Set(nova.db, 'instance_get', new_return_server) + new_return_server = return_server_with_attributes_by_uuid( + vm_state=vm_states.ACTIVE, image_ref=image_ref, + flavor_id=flavor_id, progress=100) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) uuid = FAKE_UUID req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % uuid) @@ -615,8 +577,6 @@ class ServersControllerTest(test.TestCase): def test_get_server_list_with_reservation_id(self): self.stubs.Set(nova.db, 'instance_get_all_by_reservation', return_servers_by_reservation) - self.stubs.Set(nova.scheduler.api, 'call_zone_method', - return_servers_from_child_zones) req = fakes.HTTPRequest.blank('/v2/fake/servers?reservation_id=foo') res_dict = self.controller.index(req) @@ -633,8 +593,6 @@ class ServersControllerTest(test.TestCase): def test_get_server_list_with_reservation_id_empty(self): self.stubs.Set(nova.db, 'instance_get_all_by_reservation', return_servers_by_reservation_empty) - self.stubs.Set(nova.scheduler.api, 'call_zone_method', - return_servers_from_child_zones_empty) req = fakes.HTTPRequest.blank('/v2/fake/servers/detail?' 'reservation_id=foo') @@ -651,8 +609,6 @@ class ServersControllerTest(test.TestCase): def test_get_server_list_with_reservation_id_details(self): self.stubs.Set(nova.db, 'instance_get_all_by_reservation', return_servers_by_reservation) - self.stubs.Set(nova.scheduler.api, 'call_zone_method', - return_servers_from_child_zones) req = fakes.HTTPRequest.blank('/v2/fake/servers/detail?' 'reservation_id=foo') @@ -963,7 +919,8 @@ class ServersControllerTest(test.TestCase): self.assertNotEqual(search_opts, None) # Allowed by user self.assertTrue('name' in search_opts) - self.assertTrue('status' in search_opts) + # OSAPI converts status to vm_state + self.assertTrue('vm_state' in search_opts) # Allowed only by admins with admin API on self.assertFalse('ip' in search_opts) self.assertFalse('unknown_option' in search_opts) @@ -989,7 +946,8 @@ class ServersControllerTest(test.TestCase): self.assertNotEqual(search_opts, None) # Allowed by user self.assertTrue('name' in search_opts) - self.assertTrue('status' in search_opts) + # OSAPI converts status to vm_state + self.assertTrue('vm_state' in search_opts) # Allowed only by admins with admin API on self.assertTrue('ip' in search_opts) self.assertTrue('unknown_option' in search_opts) @@ -1340,6 +1298,9 @@ class ServersControllerTest(test.TestCase): new_return_server = return_server_with_attributes( vm_state=vm_states.RESIZING) self.stubs.Set(nova.db, 'instance_get', new_return_server) + new_return_server = return_server_with_attributes_by_uuid( + vm_state=vm_states.RESIZING) + self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server) def instance_destroy_mock(context, id): self.server_delete_called = True @@ -1638,59 +1599,6 @@ class ServersControllerCreateTest(test.TestCase): self.assertNotEqual(reservation_id, None) self.assertTrue(len(reservation_id) > 1) - def test_create_instance_with_user_supplied_reservation_id(self): - """Non-admin supplied reservation_id should be ignored.""" - image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' - flavor_ref = 'http://localhost/123/flavors/3' - body = { - 'server': { - 'name': 'server_test', - 'imageRef': image_href, - 'flavorRef': flavor_ref, - 'metadata': {'hello': 'world', - 'open': 'stack'}, - 'personality': [], - 'reservation_id': 'myresid', - 'return_reservation_id': True - } - } - - req = fakes.HTTPRequest.blank('/v2/fake/servers') - req.method = 'POST' - req.body = json.dumps(body) - req.headers["content-type"] = "application/json" - res = self.controller.create(req, body) - - self.assertIn('reservation_id', res) - self.assertNotEqual(res['reservation_id'], 'myresid') - - def test_create_instance_with_admin_supplied_reservation_id(self): - """Admin supplied reservation_id should be honored.""" - image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' - flavor_ref = 'http://localhost/123/flavors/3' - body = { - 'server': { - 'name': 'server_test', - 'imageRef': image_href, - 'flavorRef': flavor_ref, - 'metadata': {'hello': 'world', - 'open': 'stack'}, - 'personality': [], - 'reservation_id': 'myresid', - 'return_reservation_id': True - } - } - - req = fakes.HTTPRequest.blank('/v2/fake/servers', - use_admin_context=True) - req.method = 'POST' - req.body = json.dumps(body) - req.headers["content-type"] = "application/json" - res = self.controller.create(req, body) - - reservation_id = res['reservation_id'] - self.assertEqual(reservation_id, "myresid") - def test_create_instance_image_ref_is_bookmark(self): image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' image_href = 'http://localhost/fake/images/%s' % image_uuid |