diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 80380d5467a9..1ffec0251819 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -65,8 +65,6 @@ "os_compute_api:os-create-backup": "rule:admin_or_owner", "os_compute_api:os-deferred-delete": "rule:admin_or_owner", "os_compute_api:os-deferred-delete:discoverable": "@", - "os_compute_api:os-disk-config": "rule:admin_or_owner", - "os_compute_api:os-disk-config:discoverable": "@", "os_compute_api:os-evacuate": "rule:admin_api", "os_compute_api:os-evacuate:discoverable": "@", "os_compute_api:os-extended-server-attributes": "rule:admin_api", diff --git a/nova/api/openstack/compute/disk_config.py b/nova/api/openstack/compute/disk_config.py deleted file mode 100644 index 9760702ec219..000000000000 --- a/nova/api/openstack/compute/disk_config.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# -# 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. - -"""Disk Config extension.""" - -from webob import exc - -from nova.api.openstack import extensions -from nova.i18n import _ - -ALIAS = 'os-disk-config' -API_DISK_CONFIG = "OS-DCF:diskConfig" -INTERNAL_DISK_CONFIG = "auto_disk_config" -authorize = extensions.os_compute_soft_authorizer(ALIAS) - - -def disk_config_to_api(value): - return 'AUTO' if value else 'MANUAL' - - -def disk_config_from_api(value): - if value == 'AUTO': - return True - elif value == 'MANUAL': - return False - else: - msg = _("%s must be either 'MANUAL' or 'AUTO'.") % API_DISK_CONFIG - raise exc.HTTPBadRequest(explanation=msg) - - -class DiskConfig(extensions.V21APIExtensionBase): - """Disk Management Extension.""" - - name = "DiskConfig" - alias = ALIAS - version = 1 - - def get_controller_extensions(self): - return [] - - def get_resources(self): - return [] diff --git a/nova/api/openstack/compute/extension_info.py b/nova/api/openstack/compute/extension_info.py index 8f0dcfee82ce..64d291db7dd4 100644 --- a/nova/api/openstack/compute/extension_info.py +++ b/nova/api/openstack/compute/extension_info.py @@ -99,6 +99,18 @@ v21_to_v2_alias_mapping = { 'os-instance-usage-audit-log': 'os-instance_usage_audit_log', } +# NOTE(sdague): this is the list of extension metadata that we display +# to the user for features that we provide. This exists for legacy +# purposes because applications were once asked to look for these +# things to decide if a feature is enabled. As we remove extensions +# completely from the code we're going to have a static list here to +# keep the surface metadata the same. +hardcoded_extensions = [ + {'name': 'DiskConfig', + 'alias': 'os-disk-config', + 'description': 'Disk Management Extension.'} +] + # V2.1 does not support XML but we need to keep an entry in the # /extensions information returned to the user for backwards # compatibility @@ -107,10 +119,10 @@ FAKE_UPDATED_DATE = "2014-12-03T00:00:00Z" class FakeExtension(object): - def __init__(self, name, alias): + def __init__(self, name, alias, description=""): self.name = name self.alias = alias - self.__doc__ = "" + self.__doc__ = description self.version = -1 @@ -129,8 +141,8 @@ class ExtensionInfoController(wsgi.Controller): ext_data["links"] = [] return ext_data - def _create_fake_ext(self, alias, name): - return FakeExtension(alias, name) + def _create_fake_ext(self, name, alias, description=""): + return FakeExtension(name, alias, description) def _add_vif_extension(self, discoverable_extensions): vif_extension = {} @@ -144,6 +156,14 @@ class ExtensionInfoController(wsgi.Controller): """Filter extensions list based on policy.""" discoverable_extensions = dict() + + for item in hardcoded_extensions: + discoverable_extensions[item['alias']] = self._create_fake_ext( + item['name'], + item['alias'], + item['description'] + ) + for alias, ext in six.iteritems(self.extension_info.get_extensions()): authorize = extensions.os_compute_soft_authorizer(alias) if authorize(context, action='discoverable'): diff --git a/nova/api/openstack/compute/helpers.py b/nova/api/openstack/compute/helpers.py new file mode 100644 index 000000000000..af4f4e390314 --- /dev/null +++ b/nova/api/openstack/compute/helpers.py @@ -0,0 +1,61 @@ +# Copyright 2016 HPE, Inc. +# +# 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 webob import exc + +from nova.i18n import _ + +API_DISK_CONFIG = "OS-DCF:diskConfig" + + +def disk_config_from_api(value): + if value == 'AUTO': + return True + elif value == 'MANUAL': + return False + else: + msg = _("%s must be either 'MANUAL' or 'AUTO'.") % API_DISK_CONFIG + raise exc.HTTPBadRequest(explanation=msg) + + +def translate_attributes(server_dict, operation_kwargs): + """Translate REST attributes on create to server object kwargs. + + Our REST API is relatively fixed, but internal representations + change over time, this is a translator for inbound REST request + attributes that modifies the server dict that we get and adds + appropriate attributes to ``operation_kwargs`` that will be passed + down to instance objects later. + + It's done in a common function as this is used for create / resize + / rebuild / update + + The ``server_dict`` is a representation of the server in + question. During ``create`` and ``update`` operations this will + actually be the ``server`` element of the request body. + + During actions, such as ``rebuild`` and ``resize`` this will be + the attributes passed to the action object during the + operation. This is equivalent to the ``server`` object. + + Not all operations support all attributes listed here. Which is + why it's important to only set operation_kwargs if there is + something to set. Input validation will ensure that we are only + operating on appropriate attributes for each operation. + """ + # Disk config + auto_disk_config_raw = server_dict.pop(API_DISK_CONFIG, None) + if auto_disk_config_raw is not None: + auto_disk_config = disk_config_from_api(auto_disk_config_raw) + operation_kwargs['auto_disk_config'] = auto_disk_config diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 4e45cabfff7a..564b29105dc2 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -29,7 +29,7 @@ from webob import exc from nova.api.openstack import api_version_request from nova.api.openstack import common -from nova.api.openstack.compute import disk_config +from nova.api.openstack.compute import helpers from nova.api.openstack.compute.schemas import servers as schema_servers from nova.api.openstack.compute.views import servers as views_servers from nova.api.openstack import extensions @@ -55,16 +55,6 @@ CONF = nova.conf.CONF LOG = logging.getLogger(__name__) -def translate_attributes(server_dict, server_kwargs): - # Disk config - # Translate create kwargs to internal representation - auto_disk_config_raw = server_dict.pop("OS-DCF:diskConfig", None) - if auto_disk_config_raw is not None: - auto_disk_config = disk_config.disk_config_from_api( - auto_disk_config_raw) - server_kwargs['auto_disk_config'] = auto_disk_config - - class ServersController(wsgi.Controller): """The Server API base controller class for the OpenStack API.""" @@ -567,7 +557,7 @@ class ServersController(wsgi.Controller): availability_zone = create_kwargs.pop("availability_zone", None) - translate_attributes(server_dict, create_kwargs) + helpers.translate_attributes(server_dict, create_kwargs) target = { 'project_id': context.project_id, @@ -815,7 +805,7 @@ class ServersController(wsgi.Controller): self.update_extension_manager.map(self._update_extension_point, body['server'], update_dict) - translate_attributes(body['server'], update_dict) + helpers.translate_attributes(body['server'], update_dict) instance = self._get_server(ctxt, req, id, is_detail=True) try: @@ -980,7 +970,7 @@ class ServersController(wsgi.Controller): flavor_ref = str(resize_dict["flavorRef"]) resize_kwargs = {} - translate_attributes(resize_dict, resize_kwargs) + helpers.translate_attributes(resize_dict, resize_kwargs) self._resize(req, id, flavor_ref, **resize_kwargs) @@ -1015,7 +1005,7 @@ class ServersController(wsgi.Controller): self.rebuild_extension_manager.map(self._rebuild_extension_point, rebuild_dict, rebuild_kwargs) - translate_attributes(rebuild_dict, rebuild_kwargs) + helpers.translate_attributes(rebuild_dict, rebuild_kwargs) for request_attribute, instance_attribute in attr_map.items(): try: diff --git a/nova/api/openstack/compute/views/images.py b/nova/api/openstack/compute/views/images.py index e311934d9e3a..0e73f8d4a867 100644 --- a/nova/api/openstack/compute/views/images.py +++ b/nova/api/openstack/compute/views/images.py @@ -17,7 +17,6 @@ from oslo_utils import strutils from nova.api.openstack import common -from nova.api.openstack.compute import disk_config from nova.image import glance from nova import utils @@ -76,8 +75,8 @@ class ViewBuilder(common.ViewBuilder): auto_disk_config = image_dict['metadata'].get("auto_disk_config", None) if auto_disk_config is not None: value = strutils.bool_from_string(auto_disk_config) - image_dict["OS-DCF:diskConfig"] = \ - disk_config.disk_config_to_api(value) + image_dict["OS-DCF:diskConfig"] = ( + 'AUTO' if value else 'MANUAL') return dict(image=image_dict) diff --git a/nova/tests/unit/api/openstack/compute/test_extension_info.py b/nova/tests/unit/api/openstack/compute/test_extension_info.py index b1b099dc4a94..f6088d427c35 100644 --- a/nova/tests/unit/api/openstack/compute/test_extension_info.py +++ b/nova/tests/unit/api/openstack/compute/test_extension_info.py @@ -25,6 +25,10 @@ from nova.tests.unit.api.openstack import fakes FAKE_UPDATED_DATE = extension_info.FAKE_UPDATED_DATE +# NOTE(sdague): this whole test module is short term while we shift +# the extensions into main path code. Some short cuts are taken in the +# interim to keep these extension tests. + class fake_extension(object): def __init__(self, name, alias, description, version): @@ -76,8 +80,15 @@ class ExtensionInfoTest(test.NoDBTestCase): self.stubs.Set(policy, 'enforce', fake_policy_enforce) req = fakes.HTTPRequestV21.blank('/extensions') res_dict = self.controller.index(req) - self.assertEqual(3, len(res_dict['extensions'])) - for e in res_dict['extensions']: + # NOTE(sdague): because of hardcoded extensions the count is + # going to grow, and that's fine. We'll just check that it's + # greater than the 3 that we inserted. + self.assertGreaterEqual(len(res_dict['extensions']), 3) + + # NOTE(sdague): filter the extension list by only ones that + # are the fake alias names, otherwise we get errors as we + # migrate extensions into the hardcoded list. + for e in [x for x in res_dict['extensions'] if '-alias' in x['alias']]: self.assertIn(e['alias'], fake_extensions) self.assertEqual(e['name'], fake_extensions[e['alias']].name) self.assertEqual(e['alias'], fake_extensions[e['alias']].alias) @@ -106,8 +117,15 @@ class ExtensionInfoTest(test.NoDBTestCase): self.stubs.Set(policy, 'enforce', fake_policy_enforce_selective) req = fakes.HTTPRequestV21.blank('/extensions') res_dict = self.controller.index(req) - self.assertEqual(2, len(res_dict['extensions'])) - for e in res_dict['extensions']: + # NOTE(sdague): because of hardcoded extensions the count is + # going to grow, and that's fine. We'll just check that it's + # greater than the 2 that we inserted. + self.assertGreaterEqual(len(res_dict['extensions']), 2) + + # NOTE(sdague): filter the extension list by only ones that + # are the fake alias names, otherwise we get errors as we + # migrate extensions into the hardcoded list. + for e in [x for x in res_dict['extensions'] if '-alias' in x['alias']]: self.assertNotEqual('ext1-alias', e['alias']) self.assertIn(e['alias'], fake_extensions) self.assertEqual(e['name'], fake_extensions[e['alias']].name) @@ -131,7 +149,10 @@ class ExtensionInfoV21Test(test.NoDBTestCase): def test_extension_info_list(self): req = fakes.HTTPRequest.blank('/extensions') res_dict = self.controller.index(req) - self.assertEqual(12, len(res_dict['extensions'])) + # NOTE(sdague): because of hardcoded extensions the count is + # going to grow, and that's fine. We'll just check that it's + # greater than the 12 that we inserted. + self.assertGreaterEqual(len(res_dict['extensions']), 12) expected_output = copy.deepcopy(simulated_extension_list) del expected_output['images'] @@ -155,7 +176,10 @@ class ExtensionInfoV21Test(test.NoDBTestCase): expected_output['os-server-start-stop'] = fake_extension( 'ServerStartStop', 'os-server-start-stop', '', -1) - for e in res_dict['extensions']: + # NOTE(sdague): filter the extension list by only ones that + # are the fake alias names, otherwise we get errors as we + # migrate extensions into the hardcoded list. + for e in [x for x in res_dict['extensions'] if '-alias' in x['alias']]: self.assertIn(e['alias'], expected_output) self.assertEqual(e['name'], expected_output[e['alias']].name) self.assertEqual(e['alias'], expected_output[e['alias']].alias) diff --git a/nova/tests/unit/fake_policy.py b/nova/tests/unit/fake_policy.py index c76308219829..add9270c48da 100644 --- a/nova/tests/unit/fake_policy.py +++ b/nova/tests/unit/fake_policy.py @@ -59,7 +59,6 @@ policy_data = """ "os_compute_api:os-consoles:show": "", "os_compute_api:os-create-backup": "", "os_compute_api:os-deferred-delete": "", - "os_compute_api:os-disk-config": "", "os_compute_api:os-evacuate": "is_admin:True", "os_compute_api:os-extended-server-attributes": "", "os_compute_api:os-extended-status": "", diff --git a/nova/tests/unit/test_policy.py b/nova/tests/unit/test_policy.py index 51bd24567df7..1b04d7b600a9 100644 --- a/nova/tests/unit/test_policy.py +++ b/nova/tests/unit/test_policy.py @@ -376,7 +376,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase): "os_compute_api:os-console-output", "os_compute_api:os-remote-consoles", "os_compute_api:os-deferred-delete", -"os_compute_api:os-disk-config", "os_compute_api:os-extended-status", "os_compute_api:os-extended-availability-zone", "os_compute_api:os-extended-volumes", @@ -435,7 +434,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase): "os_compute_api:os-remote-consoles:discoverable", "os_compute_api:os-create-backup:discoverable", "os_compute_api:os-deferred-delete:discoverable", -"os_compute_api:os-disk-config:discoverable", "os_compute_api:os-evacuate:discoverable", "os_compute_api:os-extended-server-attributes:discoverable", "os_compute_api:os-extended-status:discoverable", diff --git a/releasenotes/notes/extensions_remove-37e9d4092981abbe.yaml b/releasenotes/notes/extensions_remove-37e9d4092981abbe.yaml new file mode 100644 index 000000000000..12a8637d1f3b --- /dev/null +++ b/releasenotes/notes/extensions_remove-37e9d4092981abbe.yaml @@ -0,0 +1,16 @@ +--- +upgrade: + - | + + The following policy enforcement points have been removed as part + of the restructuring of the Nova API code. The attributes that + could have been hidden with these policy points will now always be + shown / accepted. + + * os_compute_api:os-disk-config - show / accept + ``OS-DCF:diskConfig`` parameter + + The following entry points have been removed + + * nova.api.v21.extensions.server.resize - allowed accepting + additional parameters on resize requests. diff --git a/setup.cfg b/setup.cfg index f775bd821c8e..73bc8debb397 100644 --- a/setup.cfg +++ b/setup.cfg @@ -84,7 +84,6 @@ nova.api.v21.extensions = consoles = nova.api.openstack.compute.consoles:Consoles create_backup = nova.api.openstack.compute.create_backup:CreateBackup deferred_delete = nova.api.openstack.compute.deferred_delete:DeferredDelete - disk_config = nova.api.openstack.compute.disk_config:DiskConfig evacuate = nova.api.openstack.compute.evacuate:Evacuate extended_availability_zone = nova.api.openstack.compute.extended_availability_zone:ExtendedAvailabilityZone extended_server_attributes = nova.api.openstack.compute.extended_server_attributes:ExtendedServerAttributes