From abc656d3d549c555cf7c94d0ae0e5d50768bd366 Mon Sep 17 00:00:00 2001 From: Alexandre Levine Date: Thu, 19 Feb 2015 03:42:42 +0400 Subject: [PATCH] Add info for Standalone EC2 API to cut access to Nova DB. This change adds properties to v2.1 os-extended-server-properties and os-extended-volumes nova APIs in order to expose information which is required for the standalone EC2 API implementation (resides on stackforge/ec2-api) to use only public APIs. Right now this information is taken by directly accessing internal Nova DB. It adds proposed microversion v2.3. It implements the spec "Nova changes required for standalone EC2 API implementation" in this review: https://review.openstack.org/#/c/153636/ APIImpact Implements: blueprint ec2-api Change-Id: I850e51e730c82906f68fddb14fb0004d7091eb91 --- .../v2.3/server-get-resp.json | 65 ++++++++++++++ .../v2.3/servers-detail-resp.json | 67 ++++++++++++++ .../v2.3/server-get-resp.json | 65 ++++++++++++++ .../v2.3/servers-detail-resp.json | 67 ++++++++++++++ nova/api/openstack/api_version_request.py | 4 +- .../plugins/v3/extended_server_attributes.py | 16 +++- .../compute/plugins/v3/extended_volumes.py | 21 +++-- .../openstack/rest_api_version_history.rst | 11 +++ .../test_extended_server_attributes.py | 89 ++++++++++++++++++- .../compute/contrib/test_extended_volumes.py | 17 +++- nova/tests/unit/api/openstack/fakes.py | 11 +-- 11 files changed, 412 insertions(+), 21 deletions(-) create mode 100644 doc/v3/api_samples/os-extended-server-attributes/v2.3/server-get-resp.json create mode 100644 doc/v3/api_samples/os-extended-server-attributes/v2.3/servers-detail-resp.json create mode 100644 doc/v3/api_samples/os-extended-volumes/v2.3/server-get-resp.json create mode 100644 doc/v3/api_samples/os-extended-volumes/v2.3/servers-detail-resp.json diff --git a/doc/v3/api_samples/os-extended-server-attributes/v2.3/server-get-resp.json b/doc/v3/api_samples/os-extended-server-attributes/v2.3/server-get-resp.json new file mode 100644 index 0000000000..b11dba20cf --- /dev/null +++ b/doc/v3/api_samples/os-extended-server-attributes/v2.3/server-get-resp.json @@ -0,0 +1,65 @@ +{ + "server": { + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-16T02:55:07Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "3bf189131c61d0e71b0a8686a897a0f50d1693b48c47b721fe77155b", + "id": "c278163e-36f9-4cf2-b1ac-80db4c63f7a8", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/c278163e-36f9-4cf2-b1ac-80db4c63f7a8", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/c278163e-36f9-4cf2-b1ac-80db4c63f7a8", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "OS-EXT-SRV-ATTR:host": "c5f474bf81474f9dbbc404d5b2e4e9b3", + "OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini", + "OS-EXT-SRV-ATTR:instance_name": "instance-00000001", + "OS-EXT-SRV-ATTR:reservation_id": "r-00000001", + "OS-EXT-SRV-ATTR:launch_index": 0, + "OS-EXT-SRV-ATTR:kernel_id": "a5f474bf81474f9dbbc404d5b2e4e9b3", + "OS-EXT-SRV-ATTR:ramdisk_id": "b5f474bf81474f9dbbc404d5b2e4e9b3", + "OS-EXT-SRV-ATTR:hostname": "fake-hostname", + "OS-EXT-SRV-ATTR:root_device_name": "/dev/vda", + "OS-EXT-SRV-ATTR:userdata": "fake", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2013-09-16T02:55:08Z", + "user_id": "fake" + } +} diff --git a/doc/v3/api_samples/os-extended-server-attributes/v2.3/servers-detail-resp.json b/doc/v3/api_samples/os-extended-server-attributes/v2.3/servers-detail-resp.json new file mode 100644 index 0000000000..2226210175 --- /dev/null +++ b/doc/v3/api_samples/os-extended-server-attributes/v2.3/servers-detail-resp.json @@ -0,0 +1,67 @@ +{ + "servers": [ + { + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-16T02:55:03Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "63cf07a9fd82e1d2294926ec5c0d2e1e0ca449224246df75e16f23dc", + "id": "a8c1c13d-ec7e-47c7-b4ff-077f72c1ca46", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/a8c1c13d-ec7e-47c7-b4ff-077f72c1ca46", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/a8c1c13d-ec7e-47c7-b4ff-077f72c1ca46", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "OS-EXT-SRV-ATTR:host": "bc8efe4fdb7148a4bb921a2b03d17de6", + "OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini", + "OS-EXT-SRV-ATTR:instance_name": "instance-00000001", + "OS-EXT-SRV-ATTR:reservation_id": "r-00000001", + "OS-EXT-SRV-ATTR:launch_index": 0, + "OS-EXT-SRV-ATTR:kernel_id": "a5f474bf81474f9dbbc404d5b2e4e9b3", + "OS-EXT-SRV-ATTR:ramdisk_id": "b5f474bf81474f9dbbc404d5b2e4e9b3", + "OS-EXT-SRV-ATTR:hostname": "fake-hostname", + "OS-EXT-SRV-ATTR:root_device_name": "/dev/vda", + "OS-EXT-SRV-ATTR:userdata": "fake", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2013-09-16T02:55:05Z", + "user_id": "fake" + } + ] +} diff --git a/doc/v3/api_samples/os-extended-volumes/v2.3/server-get-resp.json b/doc/v3/api_samples/os-extended-volumes/v2.3/server-get-resp.json new file mode 100644 index 0000000000..a662db4adf --- /dev/null +++ b/doc/v3/api_samples/os-extended-volumes/v2.3/server-get-resp.json @@ -0,0 +1,65 @@ +{ + "server": { + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-16T03:22:28Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "8feef92e2152b9970b51dbdade024afbec7f8f03daf7cb335a3c1cb9", + "id": "7d62983e-23df-4320-bc89-bbc77f2a2e40", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/7d62983e-23df-4320-bc89-bbc77f2a2e40", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/7d62983e-23df-4320-bc89-bbc77f2a2e40", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "os-extended-volumes:volumes_attached": [ + { + "id": "volume_id1", + "delete_on_termination": True + }, + { + "id": "volume_id2", + "delete_on_termination": False + } + ], + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2013-09-16T03:22:29Z", + "user_id": "fake" + } +} diff --git a/doc/v3/api_samples/os-extended-volumes/v2.3/servers-detail-resp.json b/doc/v3/api_samples/os-extended-volumes/v2.3/servers-detail-resp.json new file mode 100644 index 0000000000..4d50de1db9 --- /dev/null +++ b/doc/v3/api_samples/os-extended-volumes/v2.3/servers-detail-resp.json @@ -0,0 +1,67 @@ +{ + "servers": [ + { + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-16T03:22:32Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "f9622ec1b5ab6e3785661ea1c1e0294f95aecbcf27ac4cb60b06bd02", + "id": "8e479732-7701-48cd-af7a-04d84f51b742", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/8e479732-7701-48cd-af7a-04d84f51b742", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/8e479732-7701-48cd-af7a-04d84f51b742", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "os-extended-volumes:volumes_attached": [ + { + "id": "volume_id1", + "delete_on_termination": True + }, + { + "id": "volume_id2", + "delete_on_termination": False + } + ], + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2013-09-16T03:22:34Z", + "user_id": "fake" + } + ] +} diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index d75970bc8e..c167076ef3 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -40,6 +40,8 @@ REST_API_VERSION_HISTORY = """REST API Version History: * 2.1 - Initial version. Equivalent to v2.0 code * 2.2 - Adds (keypair) type parameter for os-keypairs plugin Fixes success status code for create/delete a keypair method + * 2.3 - Exposes additional os-extended-server-attributes + Exposes delete_on_termination for os-extended-volumes """ # The minimum and maximum versions of the API supported @@ -48,7 +50,7 @@ REST_API_VERSION_HISTORY = """REST API Version History: # Note(cyeoh): This only applies for the v2.1 API once microversions # support is fully merged. It does not affect the V2 API. _MIN_API_VERSION = "2.1" -_MAX_API_VERSION = "2.2" +_MAX_API_VERSION = "2.3" DEFAULT_API_VERSION = _MIN_API_VERSION diff --git a/nova/api/openstack/compute/plugins/v3/extended_server_attributes.py b/nova/api/openstack/compute/plugins/v3/extended_server_attributes.py index 7ea524384e..c00a9362fa 100644 --- a/nova/api/openstack/compute/plugins/v3/extended_server_attributes.py +++ b/nova/api/openstack/compute/plugins/v3/extended_server_attributes.py @@ -14,6 +14,7 @@ """The Extended Server Attributes API extension.""" +from nova.api.openstack import api_version_request from nova.api.openstack import extensions from nova.api.openstack import wsgi @@ -23,11 +24,16 @@ authorize = extensions.soft_extension_authorizer('compute', 'v3:' + ALIAS) class ExtendedServerAttributesController(wsgi.Controller): - def _extend_server(self, context, server, instance): + def _extend_server(self, context, server, instance, requested_version): key = "OS-EXT-SRV-ATTR:hypervisor_hostname" server[key] = instance.node - for attr in ['host', 'name']: + properties = ['host', 'name'] + if requested_version >= api_version_request.APIVersionRequest("2.3"): + properties += ['reservation_id', 'launch_index', + 'hostname', 'kernel_id', 'ramdisk_id', + 'root_device_name', 'user_data'] + for attr in properties: if attr == 'name': key = "OS-EXT-SRV-ATTR:instance_%s" % attr else: @@ -42,7 +48,8 @@ class ExtendedServerAttributesController(wsgi.Controller): db_instance = req.get_db_instance(server['id']) # server['id'] is guaranteed to be in the cache due to # the core API adding it in its 'show' method. - self._extend_server(context, server, db_instance) + self._extend_server(context, server, db_instance, + req.api_version_request) @wsgi.extends def detail(self, req, resp_obj): @@ -53,7 +60,8 @@ class ExtendedServerAttributesController(wsgi.Controller): db_instance = req.get_db_instance(server['id']) # server['id'] is guaranteed to be in the cache due to # the core API adding it in its 'detail' method. - self._extend_server(context, server, db_instance) + self._extend_server(context, server, db_instance, + req.api_version_request) class ExtendedServerAttributes(extensions.V3APIExtensionBase): diff --git a/nova/api/openstack/compute/plugins/v3/extended_volumes.py b/nova/api/openstack/compute/plugins/v3/extended_volumes.py index 1c1bbe9618..6389de052f 100644 --- a/nova/api/openstack/compute/plugins/v3/extended_volumes.py +++ b/nova/api/openstack/compute/plugins/v3/extended_volumes.py @@ -13,6 +13,7 @@ # under the License. """The Extended Volumes API extension.""" +from nova.api.openstack import api_version_request from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova import compute @@ -29,12 +30,20 @@ class ExtendedVolumesController(wsgi.Controller): self.compute_api = compute.API() self.volume_api = volume.API() - def _extend_server(self, context, server, instance): + def _extend_server(self, context, server, instance, requested_version): bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) - volume_ids = [bdm['volume_id'] for bdm in bdms if bdm['volume_id']] + volumes_attached = [] + api_version = api_version_request.APIVersionRequest('2.3') + for bdm in bdms: + if bdm.get('volume_id'): + volume_attached = {'id': bdm['volume_id']} + if requested_version >= api_version: + volume_attached['delete_on_termination'] = ( + bdm['delete_on_termination']) + volumes_attached.append(volume_attached) key = "%s:volumes_attached" % ExtendedVolumes.alias - server[key] = [{'id': volume_id} for volume_id in volume_ids] + server[key] = volumes_attached @wsgi.extends def show(self, req, resp_obj, id): @@ -44,7 +53,8 @@ class ExtendedVolumesController(wsgi.Controller): db_instance = req.get_db_instance(server['id']) # server['id'] is guaranteed to be in the cache due to # the core API adding it in its 'show' method. - self._extend_server(context, server, db_instance) + self._extend_server(context, server, db_instance, + req.api_version_request) @wsgi.extends def detail(self, req, resp_obj): @@ -55,7 +65,8 @@ class ExtendedVolumesController(wsgi.Controller): db_instance = req.get_db_instance(server['id']) # server['id'] is guaranteed to be in the cache due to # the core API adding it in its 'detail' method. - self._extend_server(context, server, db_instance) + self._extend_server(context, server, db_instance, + req.api_version_request) class ExtendedVolumes(extensions.V3APIExtensionBase): diff --git a/nova/api/openstack/rest_api_version_history.rst b/nova/api/openstack/rest_api_version_history.rst index 4b2f567c88..fc47331672 100644 --- a/nova/api/openstack/rest_api_version_history.rst +++ b/nova/api/openstack/rest_api_version_history.rst @@ -35,3 +35,14 @@ user documentation. Fixes status code for os-keypairs delete method from 202 to 204 +- **2.3** + + Exposed additional attributes in os-extended-server-attributes: + reservation_id, launch_index, ramdisk_id, kernel_id, hostname, + root_device_name, userdata. + + Exposed delete_on_termination for attached_volumes in os-extended-volumes. + + This change is required for the extraction of EC2 API into a standalone + service. It exposes necessary properties absent in public nova APIs yet. + Add info for Standalone EC2 API to cut access to Nova DB. diff --git a/nova/tests/unit/api/openstack/compute/contrib/test_extended_server_attributes.py b/nova/tests/unit/api/openstack/compute/contrib/test_extended_server_attributes.py index 53bfdebae5..2ea17fa6aa 100644 --- a/nova/tests/unit/api/openstack/compute/contrib/test_extended_server_attributes.py +++ b/nova/tests/unit/api/openstack/compute/contrib/test_extended_server_attributes.py @@ -17,6 +17,7 @@ from oslo_config import cfg from oslo_serialization import jsonutils import webob +from nova.api.openstack import wsgi as os_wsgi from nova import compute from nova import db from nova import exception @@ -30,6 +31,8 @@ NAME_FMT = cfg.CONF.instance_name_template UUID1 = '00000000-0000-0000-0000-000000000001' UUID2 = '00000000-0000-0000-0000-000000000002' UUID3 = '00000000-0000-0000-0000-000000000003' +UUID4 = '00000000-0000-0000-0000-000000000004' +UUID5 = '00000000-0000-0000-0000-000000000005' def fake_compute_get(*args, **kwargs): @@ -37,13 +40,28 @@ def fake_compute_get(*args, **kwargs): return objects.Instance._from_db_object( args[1], objects.Instance(), fakes.stub_instance(1, uuid=UUID3, host="host-fake", - node="node-fake"), fields) + node="node-fake", + reservation_id="r-1", launch_index=0, + kernel_id=UUID4, ramdisk_id=UUID5, + display_name="hostname-1", + root_device_name="/dev/vda", + user_data="userdata"), fields) def fake_compute_get_all(*args, **kwargs): db_list = [ - fakes.stub_instance(1, uuid=UUID1, host="host-1", node="node-1"), - fakes.stub_instance(2, uuid=UUID2, host="host-2", node="node-2") + fakes.stub_instance(1, uuid=UUID1, host="host-1", node="node-1", + reservation_id="r-1", launch_index=0, + kernel_id=UUID4, ramdisk_id=UUID5, + display_name="hostname-1", + root_device_name="/dev/vda", + user_data="userdata"), + fakes.stub_instance(2, uuid=UUID2, host="host-2", node="node-2", + reservation_id="r-2", launch_index=1, + kernel_id=UUID4, ramdisk_id=UUID5, + display_name="hostname-2", + root_device_name="/dev/vda", + user_data="userdata") ] fields = instance_obj.INSTANCE_DEFAULT_FIELDS return instance_obj._make_instance_list(args[1], @@ -55,6 +73,7 @@ class ExtendedServerAttributesTestV21(test.TestCase): content_type = 'application/json' prefix = 'OS-EXT-SRV-ATTR:' fake_url = '/v2/fake' + wsgi_api_version = os_wsgi.DEFAULT_API_VERSION def setUp(self): super(ExtendedServerAttributesTestV21, self).setUp() @@ -64,8 +83,10 @@ class ExtendedServerAttributesTestV21(test.TestCase): self.stubs.Set(db, 'instance_get_by_uuid', fake_compute_get) def _make_request(self, url): - req = webob.Request.blank(url) + req = fakes.HTTPRequest.blank(url) req.headers['Accept'] = self.content_type + req.headers = {os_wsgi.API_VERSION_REQUEST_HEADER: + self.wsgi_api_version} res = req.get_response( fakes.wsgi_app_v21(init_only=('servers', 'os-extended-server-attributes'))) @@ -131,3 +152,63 @@ class ExtendedServerAttributesTestV2(ExtendedServerAttributesTestV21): req.headers['Accept'] = self.content_type res = req.get_response(fakes.wsgi_app(init_only=('servers',))) return res + + +class ExtendedServerAttributesTestV23(ExtendedServerAttributesTestV21): + wsgi_api_version = '2.3' + + def assertServerAttributes(self, server, host, node, instance_name, + reservation_id, launch_index, kernel_id, + ramdisk_id, hostname, root_device_name, + user_data): + super(ExtendedServerAttributesTestV23, self).assertServerAttributes( + server, host, node, instance_name) + self.assertEqual(server.get('%sreservation_id' % self.prefix), + reservation_id) + self.assertEqual(server.get('%slaunch_index' % self.prefix), + launch_index) + self.assertEqual(server.get('%skernel_id' % self.prefix), + kernel_id) + self.assertEqual(server.get('%sramdisk_id' % self.prefix), + ramdisk_id) + self.assertEqual(server.get('%shostname' % self.prefix), + hostname) + self.assertEqual(server.get('%sroot_device_name' % self.prefix), + root_device_name) + self.assertEqual(server.get('%suser_data' % self.prefix), + user_data) + + def test_show(self): + url = self.fake_url + '/servers/%s' % UUID3 + res = self._make_request(url) + + self.assertEqual(res.status_int, 200) + self.assertServerAttributes(self._get_server(res.body), + host='host-fake', + node='node-fake', + instance_name=NAME_FMT % 1, + reservation_id="r-1", + launch_index=0, + kernel_id=UUID4, + ramdisk_id=UUID5, + hostname="hostname-1", + root_device_name="/dev/vda", + user_data="userdata") + + def test_detail(self): + url = self.fake_url + '/servers/detail' + res = self._make_request(url) + + self.assertEqual(res.status_int, 200) + for i, server in enumerate(self._get_servers(res.body)): + self.assertServerAttributes(server, + host='host-%s' % (i + 1), + node='node-%s' % (i + 1), + instance_name=NAME_FMT % (i + 1), + reservation_id="r-%s" % (i + 1), + launch_index=i, + kernel_id=UUID4, + ramdisk_id=UUID5, + hostname="hostname-%s" % (i + 1), + root_device_name="/dev/vda", + user_data="userdata") diff --git a/nova/tests/unit/api/openstack/compute/contrib/test_extended_volumes.py b/nova/tests/unit/api/openstack/compute/contrib/test_extended_volumes.py index 9e1bd0b33c..2645c962d6 100644 --- a/nova/tests/unit/api/openstack/compute/contrib/test_extended_volumes.py +++ b/nova/tests/unit/api/openstack/compute/contrib/test_extended_volumes.py @@ -18,6 +18,7 @@ import webob from nova.api.openstack.compute.plugins.v3 import (extended_volumes as extended_volumes_v21) +from nova.api.openstack import wsgi as os_wsgi from nova import compute from nova import db from nova import objects @@ -49,10 +50,12 @@ def fake_compute_get_all(*args, **kwargs): def fake_bdms_get_all_by_instance(*args, **kwargs): return [fake_block_device.FakeDbBlockDeviceDict( {'volume_id': UUID1, 'source_type': 'volume', - 'destination_type': 'volume', 'id': 1}), + 'destination_type': 'volume', 'id': 1, + 'delete_on_termination': True}), fake_block_device.FakeDbBlockDeviceDict( {'volume_id': UUID2, 'source_type': 'volume', - 'destination_type': 'volume', 'id': 2})] + 'destination_type': 'volume', 'id': 2, + 'delete_on_termination': False})] def fake_volume_get(*args, **kwargs): @@ -63,6 +66,7 @@ class ExtendedVolumesTestV21(test.TestCase): content_type = 'application/json' prefix = 'os-extended-volumes:' exp_volumes = [{'id': UUID1}, {'id': UUID2}] + wsgi_api_version = os_wsgi.DEFAULT_API_VERSION def setUp(self): super(ExtendedVolumesTestV21, self).setUp() @@ -88,6 +92,8 @@ class ExtendedVolumesTestV21(test.TestCase): def _make_request(self, url, body=None): req = webob.Request.blank('/v2/fake/servers' + url) req.headers['Accept'] = self.content_type + req.headers = {os_wsgi.API_VERSION_REQUEST_HEADER: + self.wsgi_api_version} if body: req.body = jsonutils.dumps(body) req.method = 'POST' @@ -128,3 +134,10 @@ class ExtendedVolumesTestV2(ExtendedVolumesTestV21): osapi_compute_extension=['nova.api.openstack.compute.' 'contrib.select_extensions'], osapi_compute_ext_list=['Extended_volumes']) + + +class ExtendedVolumesTestV23(ExtendedVolumesTestV21): + + exp_volumes = [{'id': UUID1, 'delete_on_termination': True}, + {'id': UUID2, 'delete_on_termination': False}] + wsgi_api_version = '2.3' diff --git a/nova/tests/unit/api/openstack/fakes.py b/nova/tests/unit/api/openstack/fakes.py index 2819e1f1ef..ff7e65dd80 100644 --- a/nova/tests/unit/api/openstack/fakes.py +++ b/nova/tests/unit/api/openstack/fakes.py @@ -440,7 +440,8 @@ def stub_instance(id, user_id=None, project_id=None, host=None, terminated_at=timeutils.utcnow(), availability_zone='', locked_by=None, cleaned=False, memory_mb=0, vcpus=0, root_gb=0, ephemeral_gb=0, - instance_type=None): + instance_type=None, launch_index=0, kernel_id="", + ramdisk_id="", user_data=None): if user_id is None: user_id = 'fake_user' if project_id is None: @@ -495,9 +496,9 @@ def stub_instance(id, user_id=None, project_id=None, host=None, "user_id": user_id, "project_id": project_id, "image_ref": image_ref, - "kernel_id": "", - "ramdisk_id": "", - "launch_index": 0, + "kernel_id": kernel_id, + "ramdisk_id": ramdisk_id, + "launch_index": launch_index, "key_name": key_name, "key_data": key_data, "config_drive": config_drive, @@ -514,7 +515,7 @@ def stub_instance(id, user_id=None, project_id=None, host=None, "node": node, "instance_type_id": 1, "instance_type": inst_type, - "user_data": "", + "user_data": user_data, "reservation_id": reservation_id, "mac_address": "", "scheduled_at": timeutils.utcnow(),