From 908d9263eea580099073a3adfe6fd23b9ea8188b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Mar 2024 20:03:11 +0000 Subject: [PATCH] api: Add response body schemas for server action APIs At least those that don't return bodies (plus rescue, which is easy) since they're tedious but simple, thus providing a good test ground for this effort. Change-Id: I78003b1d2c1515e5fd5e17405df6a219878bdb8a Signed-off-by: Stephen Finucane --- nova/api/openstack/compute/admin_actions.py | 12 +- nova/api/openstack/compute/admin_password.py | 5 +- nova/api/openstack/compute/deferred_delete.py | 2 + nova/api/openstack/compute/fixed_ips.py | 8 +- nova/api/openstack/compute/floating_ips.py | 2 + nova/api/openstack/compute/lock_server.py | 2 + nova/api/openstack/compute/migrate_server.py | 14 ++- nova/api/openstack/compute/multinic.py | 8 +- nova/api/openstack/compute/pause_server.py | 2 + nova/api/openstack/compute/rescue.py | 8 +- .../compute/schemas/admin_actions.py | 8 ++ .../compute/schemas/admin_password.py | 4 + .../compute/schemas/deferred_delete.py | 8 ++ .../openstack/compute/schemas/floating_ips.py | 8 ++ .../openstack/compute/schemas/lock_server.py | 8 ++ .../compute/schemas/migrate_server.py | 16 ++- .../api/openstack/compute/schemas/multinic.py | 9 +- .../openstack/compute/schemas/pause_server.py | 8 ++ nova/api/openstack/compute/schemas/rescue.py | 14 +++ .../compute/schemas/security_groups.py | 8 ++ .../compute/schemas/server_migrations.py | 4 + nova/api/openstack/compute/schemas/servers.py | 29 ++++- nova/api/openstack/compute/schemas/shelve.py | 12 ++ .../compute/schemas/suspend_server.py | 8 ++ nova/api/openstack/compute/security_groups.py | 10 +- .../openstack/compute/server_migrations.py | 9 +- nova/api/openstack/compute/servers.py | 109 ++++++++++-------- nova/api/openstack/compute/shelve.py | 3 + nova/api/openstack/compute/suspend_server.py | 2 + .../openstack/compute/test_remote_consoles.py | 15 ++- 30 files changed, 258 insertions(+), 97 deletions(-) diff --git a/nova/api/openstack/compute/admin_actions.py b/nova/api/openstack/compute/admin_actions.py index 92ee855ed3..bbeff226d1 100644 --- a/nova/api/openstack/compute/admin_actions.py +++ b/nova/api/openstack/compute/admin_actions.py @@ -25,11 +25,6 @@ from nova import exception from nova import objects from nova.policies import admin_actions as aa_policies -# States usable in resetState action -# NOTE: It is necessary to update the schema of nova/api/openstack/compute/ -# schemas/reset_server_state.py, when updating this state_map. -state_map = dict(active=vm_states.ACTIVE, error=vm_states.ERROR) - _removal_reason = """\ This action only works with the Xen virt driver, which was deprecated in the 20.0.0 (Train) release. @@ -54,6 +49,7 @@ class AdminActionsController(wsgi.Controller): @wsgi.expected_errors((404, 409)) @wsgi.action('injectNetworkInfo') @validation.schema(schema.inject_network_info) + @validation.response_body_schema(schema.inject_network_info_response) def _inject_network_info(self, req, id, body): """Permit admins to inject network info into a server.""" context = req.environ['nova.context'] @@ -69,6 +65,7 @@ class AdminActionsController(wsgi.Controller): @wsgi.expected_errors(404) @wsgi.action('os-resetState') @validation.schema(schema.reset_state) + @validation.response_body_schema(schema.reset_state_response) def _reset_state(self, req, id, body): """Permit admins to reset the state of a server.""" context = req.environ["nova.context"] @@ -81,7 +78,10 @@ class AdminActionsController(wsgi.Controller): context, instance.uuid, instance_actions.RESET_STATE) # Identify the desired state from the body - state = state_map[body["os-resetState"]["state"]] + state = { + 'active': vm_states.ACTIVE, + 'error': vm_states.ERROR, + }[body["os-resetState"]["state"]] instance.vm_state = state instance.task_state = None diff --git a/nova/api/openstack/compute/admin_password.py b/nova/api/openstack/compute/admin_password.py index 36c6cbcf1e..7a1728fab9 100644 --- a/nova/api/openstack/compute/admin_password.py +++ b/nova/api/openstack/compute/admin_password.py @@ -15,7 +15,7 @@ from webob import exc from nova.api.openstack import common -from nova.api.openstack.compute.schemas import admin_password +from nova.api.openstack.compute.schemas import admin_password as schema from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute @@ -36,7 +36,8 @@ class AdminPasswordController(wsgi.Controller): @wsgi.action('changePassword') @wsgi.response(202) @wsgi.expected_errors((404, 409, 501)) - @validation.schema(admin_password.change_password) + @validation.schema(schema.change_password) + @validation.response_body_schema(schema.change_password_response) def change_password(self, req, id, body): context = req.environ['nova.context'] instance = common.get_instance(self.compute_api, context, id) diff --git a/nova/api/openstack/compute/deferred_delete.py b/nova/api/openstack/compute/deferred_delete.py index ec0fa5eba8..54d5c54648 100644 --- a/nova/api/openstack/compute/deferred_delete.py +++ b/nova/api/openstack/compute/deferred_delete.py @@ -35,6 +35,7 @@ class DeferredDeleteController(wsgi.Controller): @wsgi.expected_errors((403, 404, 409)) @wsgi.action('restore') @validation.schema(schema.restore) + @validation.response_body_schema(schema.restore_response) def _restore(self, req, id, body): """Restore a previously deleted instance.""" context = req.environ["nova.context"] @@ -53,6 +54,7 @@ class DeferredDeleteController(wsgi.Controller): @wsgi.expected_errors((404, 409)) @wsgi.action('forceDelete') @validation.schema(schema.force_delete) + @validation.response_body_schema(schema.force_delete_response) def _force_delete(self, req, id, body): """Force delete of instance before deferred cleanup.""" context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/fixed_ips.py b/nova/api/openstack/compute/fixed_ips.py index b279c35839..be9adcb72a 100644 --- a/nova/api/openstack/compute/fixed_ips.py +++ b/nova/api/openstack/compute/fixed_ips.py @@ -14,7 +14,7 @@ from webob import exc -from nova.api.openstack.compute.schemas import fixed_ips as schema_fixed_ips +from nova.api.openstack.compute.schemas import fixed_ips as schema from nova.api.openstack import wsgi from nova.api import validation @@ -30,20 +30,20 @@ class FixedIPController(wsgi.Controller): @wsgi.expected_errors((410)) @wsgi.removed('18.0.0', _removal_reason) - @validation.query_schema(schema_fixed_ips.show_query) + @validation.query_schema(schema.show_query) def show(self, req, id): raise exc.HTTPGone() @wsgi.expected_errors((410)) @wsgi.action('reserve') @wsgi.removed('18.0.0', _removal_reason) - @validation.schema(schema_fixed_ips.reserve) + @validation.schema(schema.reserve) def reserve(self, req, id, body): raise exc.HTTPGone() @wsgi.expected_errors((410)) @wsgi.action('unreserve') @wsgi.removed('18.0.0', _removal_reason) - @validation.schema(schema_fixed_ips.unreserve) + @validation.schema(schema.unreserve) def unreserve(self, req, id, body): raise exc.HTTPGone() diff --git a/nova/api/openstack/compute/floating_ips.py b/nova/api/openstack/compute/floating_ips.py index 2ca2ec848a..6b59317096 100644 --- a/nova/api/openstack/compute/floating_ips.py +++ b/nova/api/openstack/compute/floating_ips.py @@ -190,6 +190,7 @@ class FloatingIPActionController(wsgi.Controller): @wsgi.expected_errors((400, 403, 404)) @wsgi.action('addFloatingIp') @validation.schema(schema.add_floating_ip) + @validation.response_body_schema(schema.add_floating_ip_response) def _add_floating_ip(self, req, id, body): """Associate floating_ip to an instance.""" context = req.environ['nova.context'] @@ -270,6 +271,7 @@ class FloatingIPActionController(wsgi.Controller): @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('removeFloatingIp') @validation.schema(schema.remove_floating_ip) + @validation.response_body_schema(schema.remove_floating_ip_response) def _remove_floating_ip(self, req, id, body): """Dissociate floating_ip from an instance.""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/lock_server.py b/nova/api/openstack/compute/lock_server.py index a42e7ec603..b44675d68f 100644 --- a/nova/api/openstack/compute/lock_server.py +++ b/nova/api/openstack/compute/lock_server.py @@ -32,6 +32,7 @@ class LockServerController(wsgi.Controller): @wsgi.action('lock') @validation.schema(schema.lock, "2.1", "2.72") @validation.schema(schema.lock_v273, "2.73") + @validation.response_body_schema(schema.lock_response) def _lock(self, req, id, body): """Lock a server instance.""" context = req.environ['nova.context'] @@ -49,6 +50,7 @@ class LockServerController(wsgi.Controller): @wsgi.expected_errors(404) @wsgi.action('unlock') @validation.schema(schema.unlock, "2.1", "2.72") + @validation.response_body_schema(schema.unlock_response) def _unlock(self, req, id, body): """Unlock a server instance.""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/migrate_server.py b/nova/api/openstack/compute/migrate_server.py index 67f3d42139..b4401b0b53 100644 --- a/nova/api/openstack/compute/migrate_server.py +++ b/nova/api/openstack/compute/migrate_server.py @@ -20,7 +20,7 @@ from webob import exc from nova.api.openstack import api_version_request from nova.api.openstack import common -from nova.api.openstack.compute.schemas import migrate_server +from nova.api.openstack.compute.schemas import migrate_server as schema from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute @@ -39,7 +39,8 @@ class MigrateServerController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('migrate') - @validation.schema(migrate_server.migrate_v2_56, "2.56") + @validation.schema(schema.migrate, "2.56") + @validation.response_body_schema(schema.migrate_response) def _migrate(self, req, id, body): """Permit admins to migrate a server to a new host.""" context = req.environ['nova.context'] @@ -84,10 +85,11 @@ class MigrateServerController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('os-migrateLive') - @validation.schema(migrate_server.migrate_live, "2.0", "2.24") - @validation.schema(migrate_server.migrate_live_v2_25, "2.25", "2.29") - @validation.schema(migrate_server.migrate_live_v2_30, "2.30", "2.67") - @validation.schema(migrate_server.migrate_live_v2_68, "2.68") + @validation.schema(schema.migrate_live, "2.0", "2.24") + @validation.schema(schema.migrate_live_v2_25, "2.25", "2.29") + @validation.schema(schema.migrate_live_v2_30, "2.30", "2.67") + @validation.schema(schema.migrate_live_v2_68, "2.68") + @validation.response_body_schema(schema.migrate_live_response) def _migrate_live(self, req, id, body): """Permit admins to (live) migrate a server to a new host.""" context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/multinic.py b/nova/api/openstack/compute/multinic.py index afe11e0baa..a73e31fea5 100644 --- a/nova/api/openstack/compute/multinic.py +++ b/nova/api/openstack/compute/multinic.py @@ -18,7 +18,7 @@ from webob import exc from nova.api.openstack import common -from nova.api.openstack.compute.schemas import multinic +from nova.api.openstack.compute.schemas import multinic as schema from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute @@ -37,7 +37,8 @@ class MultinicController(wsgi.Controller): @wsgi.response(202) @wsgi.action('addFixedIp') @wsgi.expected_errors((400, 404)) - @validation.schema(multinic.add_fixed_ip) + @validation.schema(schema.add_fixed_ip) + @validation.response_body_schema(schema.add_fixed_ip_response) def _add_fixed_ip(self, req, id, body): """Adds an IP on a given network to an instance.""" context = req.environ['nova.context'] @@ -55,7 +56,8 @@ class MultinicController(wsgi.Controller): @wsgi.response(202) @wsgi.action('removeFixedIp') @wsgi.expected_errors((400, 404)) - @validation.schema(multinic.remove_fixed_ip) + @validation.schema(schema.remove_fixed_ip) + @validation.response_body_schema(schema.remove_fixed_ip_response) def _remove_fixed_ip(self, req, id, body): """Removes an IP from an instance.""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/pause_server.py b/nova/api/openstack/compute/pause_server.py index b09a6303d9..4035b29f63 100644 --- a/nova/api/openstack/compute/pause_server.py +++ b/nova/api/openstack/compute/pause_server.py @@ -33,6 +33,7 @@ class PauseServerController(wsgi.Controller): @wsgi.expected_errors((404, 409, 501)) @wsgi.action('pause') @validation.schema(schema.pause) + @validation.response_body_schema(schema.pause_response) def _pause(self, req, id, body): """Permit Admins to pause the server.""" ctxt = req.environ['nova.context'] @@ -56,6 +57,7 @@ class PauseServerController(wsgi.Controller): @wsgi.expected_errors((404, 409, 501)) @wsgi.action('unpause') @validation.schema(schema.unpause) + @validation.response_body_schema(schema.unpause_response) def _unpause(self, req, id, body): """Permit Admins to unpause the server.""" ctxt = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/rescue.py b/nova/api/openstack/compute/rescue.py index e1c16a94a1..554884694d 100644 --- a/nova/api/openstack/compute/rescue.py +++ b/nova/api/openstack/compute/rescue.py @@ -18,7 +18,7 @@ from webob import exc from nova.api.openstack import api_version_request from nova.api.openstack import common -from nova.api.openstack.compute.schemas import rescue +from nova.api.openstack.compute.schemas import rescue as schema from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute @@ -40,7 +40,8 @@ class RescueController(wsgi.Controller): # for backwards compatibility reasons. @wsgi.expected_errors((400, 404, 409, 501)) @wsgi.action('rescue') - @validation.schema(rescue.rescue) + @validation.schema(schema.rescue) + @validation.response_body_schema(schema.rescue_response) def _rescue(self, req, id, body): """Rescue an instance.""" context = req.environ["nova.context"] @@ -85,7 +86,8 @@ class RescueController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((404, 409, 501)) @wsgi.action('unrescue') - @validation.schema(rescue.unrescue) + @validation.schema(schema.unrescue) + @validation.response_body_schema(schema.unrescue_response) def _unrescue(self, req, id, body): """Unrescue an instance.""" context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/schemas/admin_actions.py b/nova/api/openstack/compute/schemas/admin_actions.py index b73e0e30cf..940f0624d3 100644 --- a/nova/api/openstack/compute/schemas/admin_actions.py +++ b/nova/api/openstack/compute/schemas/admin_actions.py @@ -44,3 +44,11 @@ reset_state = { 'required': ['os-resetState'], 'additionalProperties': False, } + +inject_network_info_response = { + 'type': 'null', +} + +reset_state_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/admin_password.py b/nova/api/openstack/compute/schemas/admin_password.py index a36b70950c..22c0b622f6 100644 --- a/nova/api/openstack/compute/schemas/admin_password.py +++ b/nova/api/openstack/compute/schemas/admin_password.py @@ -30,3 +30,7 @@ change_password = { 'required': ['changePassword'], 'additionalProperties': False, } + +change_password_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/deferred_delete.py b/nova/api/openstack/compute/schemas/deferred_delete.py index ce748b5341..7ada90f375 100644 --- a/nova/api/openstack/compute/schemas/deferred_delete.py +++ b/nova/api/openstack/compute/schemas/deferred_delete.py @@ -29,3 +29,11 @@ force_delete = { 'required': ['forceDelete'], 'additionalProperties': False, } + +restore_response = { + 'type': 'null', +} + +force_delete_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/floating_ips.py b/nova/api/openstack/compute/schemas/floating_ips.py index 531f1fb3b4..f2996315f3 100644 --- a/nova/api/openstack/compute/schemas/floating_ips.py +++ b/nova/api/openstack/compute/schemas/floating_ips.py @@ -61,3 +61,11 @@ remove_floating_ip = { # deprecated proxy APIs show_query = {} index_query = {} + +add_floating_ip_response = { + 'type': 'null', +} + +remove_floating_ip_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/lock_server.py b/nova/api/openstack/compute/schemas/lock_server.py index 6fc089c84e..dd74f27e9b 100644 --- a/nova/api/openstack/compute/schemas/lock_server.py +++ b/nova/api/openstack/compute/schemas/lock_server.py @@ -45,3 +45,11 @@ unlock = { 'required': ['unlock'], 'additionalProperties': False, } + +lock_response = { + 'type': 'null', +} + +unlock_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/migrate_server.py b/nova/api/openstack/compute/schemas/migrate_server.py index 8a274fbc6e..34538947a7 100644 --- a/nova/api/openstack/compute/schemas/migrate_server.py +++ b/nova/api/openstack/compute/schemas/migrate_server.py @@ -20,7 +20,7 @@ from nova.api.validation import parameter_types host = copy.deepcopy(parameter_types.fqdn) host['type'] = ['string', 'null'] -migrate_v2_56 = { +migrate = { 'type': 'object', 'properties': { 'migrate': { @@ -53,15 +53,15 @@ migrate_live = { 'additionalProperties': False, } -block_migration = copy.deepcopy(parameter_types.boolean) -block_migration['enum'].append('auto') +_block_migration = copy.deepcopy(parameter_types.boolean) +_block_migration['enum'].append('auto') migrate_live_v2_25 = copy.deepcopy(migrate_live) del migrate_live_v2_25['properties']['os-migrateLive']['properties'][ 'disk_over_commit'] migrate_live_v2_25['properties']['os-migrateLive']['properties'][ - 'block_migration'] = block_migration + 'block_migration'] = _block_migration migrate_live_v2_25['properties']['os-migrateLive']['required'] = ( ['block_migration', 'host']) @@ -72,3 +72,11 @@ migrate_live_v2_30['properties']['os-migrateLive']['properties'][ # v2.68 removes the 'force' parameter added in v2.30, meaning it is identical # to v2.25 migrate_live_v2_68 = copy.deepcopy(migrate_live_v2_25) + +migrate_response = { + 'type': 'null', +} + +migrate_live_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/multinic.py b/nova/api/openstack/compute/schemas/multinic.py index 1940dedb09..ea01390be5 100644 --- a/nova/api/openstack/compute/schemas/multinic.py +++ b/nova/api/openstack/compute/schemas/multinic.py @@ -34,7 +34,6 @@ add_fixed_ip = { 'additionalProperties': False, } - remove_fixed_ip = { 'type': 'object', 'properties': { @@ -50,3 +49,11 @@ remove_fixed_ip = { 'required': ['removeFixedIp'], 'additionalProperties': False, } + +add_fixed_ip_response = { + 'type': 'null', +} + +remove_fixed_ip_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/pause_server.py b/nova/api/openstack/compute/schemas/pause_server.py index ef091501e9..6d427c5e15 100644 --- a/nova/api/openstack/compute/schemas/pause_server.py +++ b/nova/api/openstack/compute/schemas/pause_server.py @@ -29,3 +29,11 @@ unpause = { 'required': ['unpause'], 'additionalProperties': False } + +pause_response = { + 'type': 'null', +} + +unpause_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/rescue.py b/nova/api/openstack/compute/schemas/rescue.py index db61f4400b..dc22efd2ee 100644 --- a/nova/api/openstack/compute/schemas/rescue.py +++ b/nova/api/openstack/compute/schemas/rescue.py @@ -40,3 +40,17 @@ unrescue = { 'required': ['unrescue'], 'additionalProperties': False, } + +rescue_response = { + 'type': 'object', + 'properties': { + 'adminPass': { + 'type': 'string', + }, + }, + 'additionalProperties': False, +} + +unrescue_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/security_groups.py b/nova/api/openstack/compute/schemas/security_groups.py index d6303aabad..6b762b259e 100644 --- a/nova/api/openstack/compute/schemas/security_groups.py +++ b/nova/api/openstack/compute/schemas/security_groups.py @@ -130,3 +130,11 @@ remove_security_group = { }, 'additionalProperties': True, } + +add_security_group_response = { + 'type': 'null', +} + +remove_security_group_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/server_migrations.py b/nova/api/openstack/compute/schemas/server_migrations.py index 9504322962..03a9be4009 100644 --- a/nova/api/openstack/compute/schemas/server_migrations.py +++ b/nova/api/openstack/compute/schemas/server_migrations.py @@ -37,3 +37,7 @@ show_query = { 'properties': {}, 'additionalProperties': True, } + +force_complete_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/servers.py b/nova/api/openstack/compute/schemas/servers.py index 39ac826841..900ea4e42c 100644 --- a/nova/api/openstack/compute/schemas/servers.py +++ b/nova/api/openstack/compute/schemas/servers.py @@ -574,7 +574,6 @@ trigger_crash_dump = { 'additionalProperties': False } - JOINED_TABLE_QUERY_PARAMS_SERVERS = { 'block_device_mapping': parameter_types.common_query_param, 'services': parameter_types.common_query_param, @@ -744,3 +743,31 @@ show_query = { 'properties': {}, 'additionalProperties': True, } + +resize_response = { + 'type': 'null', +} + +confirm_resize_response = { + 'type': 'null', +} + +revert_resize_response = { + 'type': 'null', +} + +reboot_response = { + 'type': 'null', +} + +start_server_response = { + 'type': 'null', +} + +stop_server_response = { + 'type': 'null', +} + +trigger_crash_dump_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/shelve.py b/nova/api/openstack/compute/schemas/shelve.py index 4e67ef4e35..9033724f41 100644 --- a/nova/api/openstack/compute/schemas/shelve.py +++ b/nova/api/openstack/compute/schemas/shelve.py @@ -116,3 +116,15 @@ unshelve_v291 = { "required": ["unshelve"], "additionalProperties": False } + +shelve_response = { + 'type': 'null', +} + +shelve_offload_response = { + 'type': 'null', +} + +unshelve_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/suspend_server.py b/nova/api/openstack/compute/schemas/suspend_server.py index 0ef4ddc25f..aacceb8178 100644 --- a/nova/api/openstack/compute/schemas/suspend_server.py +++ b/nova/api/openstack/compute/schemas/suspend_server.py @@ -29,3 +29,11 @@ resume = { 'required': ['resume'], 'additionalProperties': False } + +suspend_response = { + 'type': 'null', +} + +resume_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/security_groups.py b/nova/api/openstack/compute/security_groups.py index a58ee1a4e9..3d6577a360 100644 --- a/nova/api/openstack/compute/security_groups.py +++ b/nova/api/openstack/compute/security_groups.py @@ -411,6 +411,7 @@ class SecurityGroupActionController(wsgi.Controller): @wsgi.response(202) @wsgi.action('addSecurityGroup') @validation.schema(schema.add_security_group) + @validation.response_body_schema(schema.add_security_group_response) def _addSecurityGroup(self, req, id, body): context = req.environ['nova.context'] instance = common.get_instance(self.compute_api, context, id) @@ -419,8 +420,8 @@ class SecurityGroupActionController(wsgi.Controller): group_name = self._parse(body, 'addSecurityGroup') try: - return security_group_api.add_to_instance(context, instance, - group_name) + security_group_api.add_to_instance( + context, instance, group_name) except (exception.SecurityGroupNotFound, exception.InstanceNotFound) as exp: raise exc.HTTPNotFound(explanation=exp.format_message()) @@ -434,6 +435,7 @@ class SecurityGroupActionController(wsgi.Controller): @wsgi.response(202) @wsgi.action('removeSecurityGroup') @validation.schema(schema.remove_security_group) + @validation.response_body_schema(schema.remove_security_group_response) def _removeSecurityGroup(self, req, id, body): context = req.environ['nova.context'] instance = common.get_instance(self.compute_api, context, id) @@ -443,8 +445,8 @@ class SecurityGroupActionController(wsgi.Controller): group_name = self._parse(body, 'removeSecurityGroup') try: - return security_group_api.remove_from_instance(context, instance, - group_name) + security_group_api.remove_from_instance( + context, instance, group_name) except (exception.SecurityGroupNotFound, exception.InstanceNotFound) as exp: raise exc.HTTPNotFound(explanation=exp.format_message()) diff --git a/nova/api/openstack/compute/server_migrations.py b/nova/api/openstack/compute/server_migrations.py index d4acbb54ff..0015bf1455 100644 --- a/nova/api/openstack/compute/server_migrations.py +++ b/nova/api/openstack/compute/server_migrations.py @@ -17,7 +17,7 @@ from webob import exc from nova.api.openstack import api_version_request from nova.api.openstack import common -from nova.api.openstack.compute.schemas import server_migrations +from nova.api.openstack.compute.schemas import server_migrations as schema from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute @@ -69,7 +69,8 @@ class ServerMigrationsController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('force_complete') - @validation.schema(server_migrations.force_complete) + @validation.schema(schema.force_complete) + @validation.response_body_schema(schema.force_complete_response) def _force_complete(self, req, id, server_id, body): context = req.environ['nova.context'] instance = common.get_instance(self.compute_api, context, server_id) @@ -92,7 +93,7 @@ class ServerMigrationsController(wsgi.Controller): @wsgi.Controller.api_version("2.23") @wsgi.expected_errors(404) - @validation.query_schema(server_migrations.index_query) + @validation.query_schema(schema.index_query) def index(self, req, server_id): """Return all migrations of an instance in progress.""" context = req.environ['nova.context'] @@ -115,7 +116,7 @@ class ServerMigrationsController(wsgi.Controller): @wsgi.Controller.api_version("2.23") @wsgi.expected_errors(404) - @validation.query_schema(server_migrations.show_query) + @validation.query_schema(schema.show_query) def show(self, req, server_id, id): """Return the migration of an instance in progress by id.""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 2831427844..28ec348856 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -27,7 +27,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 helpers -from nova.api.openstack.compute.schemas import servers as schema_servers +from nova.api.openstack.compute.schemas import servers as schema from nova.api.openstack.compute.views import servers as views_servers from nova.api.openstack import wsgi from nova.api import validation @@ -114,11 +114,11 @@ class ServersController(wsgi.Controller): self.compute_api = compute.API() @wsgi.expected_errors((400, 403)) - @validation.query_schema(schema_servers.query_params_v275, '2.75') - @validation.query_schema(schema_servers.query_params_v273, '2.73', '2.74') - @validation.query_schema(schema_servers.query_params_v266, '2.66', '2.72') - @validation.query_schema(schema_servers.query_params_v226, '2.26', '2.65') - @validation.query_schema(schema_servers.query_params_v21, '2.1', '2.25') + @validation.query_schema(schema.query_params_v275, '2.75') + @validation.query_schema(schema.query_params_v273, '2.73', '2.74') + @validation.query_schema(schema.query_params_v266, '2.66', '2.72') + @validation.query_schema(schema.query_params_v226, '2.26', '2.65') + @validation.query_schema(schema.query_params_v21, '2.1', '2.25') def index(self, req): """Returns a list of server names and ids for a given user.""" context = req.environ['nova.context'] @@ -130,11 +130,11 @@ class ServersController(wsgi.Controller): return servers @wsgi.expected_errors((400, 403)) - @validation.query_schema(schema_servers.query_params_v275, '2.75') - @validation.query_schema(schema_servers.query_params_v273, '2.73', '2.74') - @validation.query_schema(schema_servers.query_params_v266, '2.66', '2.72') - @validation.query_schema(schema_servers.query_params_v226, '2.26', '2.65') - @validation.query_schema(schema_servers.query_params_v21, '2.1', '2.25') + @validation.query_schema(schema.query_params_v275, '2.75') + @validation.query_schema(schema.query_params_v273, '2.73', '2.74') + @validation.query_schema(schema.query_params_v266, '2.66', '2.72') + @validation.query_schema(schema.query_params_v226, '2.26', '2.65') + @validation.query_schema(schema.query_params_v21, '2.1', '2.25') def detail(self, req): """Returns a list of server details for a given user.""" context = req.environ['nova.context'] @@ -185,7 +185,7 @@ class ServersController(wsgi.Controller): for search_opt in search_opts: if (search_opt in - schema_servers.JOINED_TABLE_QUERY_PARAMS_SERVERS.keys() or + schema.JOINED_TABLE_QUERY_PARAMS_SERVERS.keys() or search_opt.startswith('_')): msg = _("Invalid filter field: %s.") % search_opt raise exc.HTTPBadRequest(explanation=msg) @@ -301,9 +301,9 @@ class ServersController(wsgi.Controller): limit, marker = common.get_limit_and_marker(req) sort_keys, sort_dirs = common.get_sort_params(req.params) - blacklist = schema_servers.SERVER_LIST_IGNORE_SORT_KEY + blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY if api_version_request.is_supported(req, min_version='2.73'): - blacklist = schema_servers.SERVER_LIST_IGNORE_SORT_KEY_V273 + blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY_V273 sort_keys, sort_dirs = remove_invalid_sort_keys( context, sort_keys, sort_dirs, blacklist, ('host', 'node')) @@ -459,7 +459,7 @@ class ServersController(wsgi.Controller): return objects.NetworkRequestList(objects=networks) @wsgi.expected_errors(404) - @validation.query_schema(schema_servers.show_query) + @validation.query_schema(schema.show_query) def show(self, req, id): """Returns server details by server id.""" context = req.environ['nova.context'] @@ -667,20 +667,20 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 409)) - @validation.schema(schema_servers.create_v20, '2.0', '2.0') - @validation.schema(schema_servers.create, '2.1', '2.18') - @validation.schema(schema_servers.create_v219, '2.19', '2.31') - @validation.schema(schema_servers.create_v232, '2.32', '2.32') - @validation.schema(schema_servers.create_v233, '2.33', '2.36') - @validation.schema(schema_servers.create_v237, '2.37', '2.41') - @validation.schema(schema_servers.create_v242, '2.42', '2.51') - @validation.schema(schema_servers.create_v252, '2.52', '2.56') - @validation.schema(schema_servers.create_v257, '2.57', '2.62') - @validation.schema(schema_servers.create_v263, '2.63', '2.66') - @validation.schema(schema_servers.create_v267, '2.67', '2.73') - @validation.schema(schema_servers.create_v274, '2.74', '2.89') - @validation.schema(schema_servers.create_v290, '2.90', '2.93') - @validation.schema(schema_servers.create_v294, '2.94') + @validation.schema(schema.create_v20, '2.0', '2.0') + @validation.schema(schema.create, '2.1', '2.18') + @validation.schema(schema.create_v219, '2.19', '2.31') + @validation.schema(schema.create_v232, '2.32', '2.32') + @validation.schema(schema.create_v233, '2.33', '2.36') + @validation.schema(schema.create_v237, '2.37', '2.41') + @validation.schema(schema.create_v242, '2.42', '2.51') + @validation.schema(schema.create_v252, '2.52', '2.56') + @validation.schema(schema.create_v257, '2.57', '2.62') + @validation.schema(schema.create_v263, '2.63', '2.66') + @validation.schema(schema.create_v267, '2.67', '2.73') + @validation.schema(schema.create_v274, '2.74', '2.89') + @validation.schema(schema.create_v290, '2.90', '2.93') + @validation.schema(schema.create_v294, '2.94') def create(self, req, body): """Creates a new server for a given user.""" context = req.environ['nova.context'] @@ -906,11 +906,11 @@ class ServersController(wsgi.Controller): self.compute_api.delete(context, instance) @wsgi.expected_errors(404) - @validation.schema(schema_servers.update_v20, '2.0', '2.0') - @validation.schema(schema_servers.update, '2.1', '2.18') - @validation.schema(schema_servers.update_v219, '2.19', '2.89') - @validation.schema(schema_servers.update_v290, '2.90', '2.93') - @validation.schema(schema_servers.update_v294, '2.94') + @validation.schema(schema.update_v20, '2.0', '2.0') + @validation.schema(schema.update, '2.1', '2.18') + @validation.schema(schema.update_v219, '2.19', '2.89') + @validation.schema(schema.update_v290, '2.90', '2.93') + @validation.schema(schema.update_v294, '2.94') def update(self, req, id, body): """Update server then pass on to version-specific controller.""" @@ -983,7 +983,8 @@ class ServersController(wsgi.Controller): @wsgi.response(204) @wsgi.expected_errors((400, 404, 409)) @wsgi.action('confirmResize') - @validation.schema(schema_servers.confirm_resize) + @validation.schema(schema.confirm_resize) + @validation.response_body_schema(schema.confirm_resize_response) def _action_confirm_resize(self, req, id, body): context = req.environ['nova.context'] instance = self._get_server(context, req, id) @@ -1006,7 +1007,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 404, 409)) @wsgi.action('revertResize') - @validation.schema(schema_servers.revert_resize) + @validation.schema(schema.revert_resize) + @validation.response_body_schema(schema.revert_resize_response) def _action_revert_resize(self, req, id, body): context = req.environ['nova.context'] instance = self._get_server(context, req, id) @@ -1029,7 +1031,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((404, 409)) @wsgi.action('reboot') - @validation.schema(schema_servers.reboot) + @validation.schema(schema.reboot) + @validation.response_body_schema(schema.reboot_response) def _action_reboot(self, req, id, body): reboot_type = body['reboot']['type'].upper() @@ -1137,7 +1140,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 401, 403, 404, 409)) @wsgi.action('resize') - @validation.schema(schema_servers.resize) + @validation.schema(schema.resize) + @validation.response_body_schema(schema.resize_response) def _action_resize(self, req, id, body): """Resizes a given instance to the flavor size requested.""" resize_dict = body['resize'] @@ -1151,14 +1155,14 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('rebuild') - @validation.schema(schema_servers.rebuild_v20, '2.0', '2.0') - @validation.schema(schema_servers.rebuild, '2.1', '2.18') - @validation.schema(schema_servers.rebuild_v219, '2.19', '2.53') - @validation.schema(schema_servers.rebuild_v254, '2.54', '2.56') - @validation.schema(schema_servers.rebuild_v257, '2.57', '2.62') - @validation.schema(schema_servers.rebuild_v263, '2.63', '2.89') - @validation.schema(schema_servers.rebuild_v290, '2.90', '2.93') - @validation.schema(schema_servers.rebuild_v294, '2.94') + @validation.schema(schema.rebuild_v20, '2.0', '2.0') + @validation.schema(schema.rebuild, '2.1', '2.18') + @validation.schema(schema.rebuild_v219, '2.19', '2.53') + @validation.schema(schema.rebuild_v254, '2.54', '2.56') + @validation.schema(schema.rebuild_v257, '2.57', '2.62') + @validation.schema(schema.rebuild_v263, '2.63', '2.89') + @validation.schema(schema.rebuild_v290, '2.90', '2.93') + @validation.schema(schema.rebuild_v294, '2.94') def _action_rebuild(self, req, id, body): """Rebuild an instance with the given attributes.""" rebuild_dict = body['rebuild'] @@ -1327,8 +1331,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 403, 404, 409)) @wsgi.action('createImage') - @validation.schema(schema_servers.create_image, '2.0', '2.0') - @validation.schema(schema_servers.create_image, '2.1') + @validation.schema(schema.create_image, '2.0', '2.0') + @validation.schema(schema.create_image, '2.1') def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['nova.context'] @@ -1438,7 +1442,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((404, 409)) @wsgi.action('os-start') - @validation.schema(schema_servers.start_server) + @validation.schema(schema.start_server) + @validation.response_body_schema(schema.start_server_response) def _start_server(self, req, id, body): """Start an instance.""" context = req.environ['nova.context'] @@ -1457,7 +1462,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((404, 409)) @wsgi.action('os-stop') - @validation.schema(schema_servers.stop_server) + @validation.schema(schema.stop_server) + @validation.response_body_schema(schema.stop_server_response) def _stop_server(self, req, id, body): """Stop an instance.""" context = req.environ['nova.context'] @@ -1478,7 +1484,8 @@ class ServersController(wsgi.Controller): @wsgi.response(202) @wsgi.expected_errors((400, 404, 409)) @wsgi.action('trigger_crash_dump') - @validation.schema(schema_servers.trigger_crash_dump) + @validation.schema(schema.trigger_crash_dump) + @validation.response_body_schema(schema.trigger_crash_dump_response) def _action_trigger_crash_dump(self, req, id, body): """Trigger crash dump in an instance""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/shelve.py b/nova/api/openstack/compute/shelve.py index 60f3af9f0e..a471786da1 100644 --- a/nova/api/openstack/compute/shelve.py +++ b/nova/api/openstack/compute/shelve.py @@ -38,6 +38,7 @@ class ShelveController(wsgi.Controller): @wsgi.expected_errors((404, 403, 409, 400)) @wsgi.action('shelve') @validation.schema(schema.shelve) + @validation.response_body_schema(schema.shelve_response) def _shelve(self, req, id, body): """Move an instance into shelved mode.""" context = req.environ["nova.context"] @@ -63,6 +64,7 @@ class ShelveController(wsgi.Controller): @wsgi.expected_errors((400, 404, 409)) @wsgi.action('shelveOffload') @validation.schema(schema.shelve_offload) + @validation.response_body_schema(schema.shelve_offload_response) def _shelve_offload(self, req, id, body): """Force removal of a shelved instance from the compute node.""" context = req.environ["nova.context"] @@ -95,6 +97,7 @@ class ShelveController(wsgi.Controller): # 'availability_zone' = None is supported as well to unpin the # availability zone of an instance bonded to this availability_zone @validation.schema(schema.unshelve_v291, '2.91') + @validation.response_body_schema(schema.unshelve_response) def _unshelve(self, req, id, body): """Restore an instance from shelved mode.""" context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/suspend_server.py b/nova/api/openstack/compute/suspend_server.py index cfa8f406a6..3afbeaaac5 100644 --- a/nova/api/openstack/compute/suspend_server.py +++ b/nova/api/openstack/compute/suspend_server.py @@ -32,6 +32,7 @@ class SuspendServerController(wsgi.Controller): @wsgi.expected_errors((403, 404, 409, 400)) @wsgi.action('suspend') @validation.schema(schema.suspend) + @validation.response_body_schema(schema.suspend_response) def _suspend(self, req, id, body): """Permit admins to suspend the server.""" context = req.environ['nova.context'] @@ -53,6 +54,7 @@ class SuspendServerController(wsgi.Controller): @wsgi.expected_errors((404, 409)) @wsgi.action('resume') @validation.schema(schema.resume) + @validation.response_body_schema(schema.resume_response) def _resume(self, req, id, body): """Permit admins to resume the server from suspend.""" context = req.environ['nova.context'] diff --git a/nova/tests/unit/api/openstack/compute/test_remote_consoles.py b/nova/tests/unit/api/openstack/compute/test_remote_consoles.py index 35ea22343c..150bd76001 100644 --- a/nova/tests/unit/api/openstack/compute/test_remote_consoles.py +++ b/nova/tests/unit/api/openstack/compute/test_remote_consoles.py @@ -65,8 +65,8 @@ class ConsolesExtensionTestV21(test.NoDBTestCase): req = fakes.HTTPRequest.blank('') output = self.controller.get_vnc_console(req, fakes.FAKE_UUID, body=body) - self.assertEqual(output, - {u'console': {u'url': u'http://fake', u'type': u'novnc'}}) + self.assertEqual( + output, {'console': {'url': 'http://fake', 'type': 'novnc'}}) mock_get_vnc_console.assert_called_once_with( req.environ['nova.context'], self.instance, 'novnc') @@ -146,8 +146,8 @@ class ConsolesExtensionTestV21(test.NoDBTestCase): req = fakes.HTTPRequest.blank('') output = self.controller.get_spice_console(req, fakes.FAKE_UUID, body=body) - self.assertEqual(output, - {u'console': {u'url': u'http://fake', u'type': u'spice-html5'}}) + self.assertEqual( + output, {'console': {'url': 'http://fake', 'type': 'spice-html5'}}) mock_get_spice_console.assert_called_once_with( req.environ['nova.context'], self.instance, 'spice-html5') @@ -224,7 +224,7 @@ class ConsolesExtensionTestV21(test.NoDBTestCase): def test_get_spice_console_with_undefined_param(self): body = {'os-getSPICEConsole': {'type': 'spice-html5', - 'undefined': 'foo'}} + 'undefined': 'foo'}} self._check_console_failure( self.controller.get_spice_console, self.validation_error, @@ -237,9 +237,8 @@ class ConsolesExtensionTestV21(test.NoDBTestCase): req = fakes.HTTPRequest.blank('') output = self.controller.get_serial_console(req, fakes.FAKE_UUID, body=body) - self.assertEqual({u'console': {u'url': u'ws://fake', - u'type': u'serial'}}, - output) + self.assertEqual( + output, {'console': {'url': 'ws://fake', 'type': 'serial'}}) mock_get_serial_console.assert_called_once_with( req.environ['nova.context'], self.instance, 'serial')