diff --git a/api-ref/source/servers-admin-action.inc b/api-ref/source/servers-admin-action.inc index 03a40d38ce57..6d4c38ee84ca 100644 --- a/api-ref/source/servers-admin-action.inc +++ b/api-ref/source/servers-admin-action.inc @@ -75,8 +75,9 @@ automatically confirms the migrate operation after the configured interval. .. _resize_confirm_window: https://docs.openstack.org/nova/latest/configuration/config.html#DEFAULT.resize_confirm_window -Policy defaults enable only users with the administrative role to -perform this operation. Cloud providers can change these permissions +There are two different policies for this action, depending on whether the host +parameter is set. Both defaults enable only users with the administrative role +to perform this operation. Cloud providers can change these permissions through the ``policy.json`` file. Normal response codes: 202 diff --git a/nova/api/openstack/compute/migrate_server.py b/nova/api/openstack/compute/migrate_server.py index 59b9c384df60..67f3d42139d4 100644 --- a/nova/api/openstack/compute/migrate_server.py +++ b/nova/api/openstack/compute/migrate_server.py @@ -46,14 +46,17 @@ class MigrateServerController(wsgi.Controller): instance = common.get_instance(self.compute_api, context, id, expected_attrs=['flavor', 'services']) - context.can(ms_policies.POLICY_ROOT % 'migrate', - target={'project_id': instance.project_id}) - host_name = None if (api_version_request.is_supported(req, min_version='2.56') and body['migrate'] is not None): host_name = body['migrate'].get('host') + if host_name: + context.can(ms_policies.POLICY_ROOT % 'migrate:host', + target={'project_id': instance.project_id}) + else: + context.can(ms_policies.POLICY_ROOT % 'migrate', + target={'project_id': instance.project_id}) try: self.compute_api.resize(req.environ['nova.context'], instance, host_name=host_name) diff --git a/nova/policies/migrate_server.py b/nova/policies/migrate_server.py index 0b3d7c8bd1e9..55c54a72e1cf 100644 --- a/nova/policies/migrate_server.py +++ b/nova/policies/migrate_server.py @@ -25,7 +25,18 @@ migrate_server_policies = [ policy.DocumentedRuleDefault( name=POLICY_ROOT % 'migrate', check_str=base.ADMIN, - description="Cold migrate a server to a host", + description="Cold migrate a server without specifying a host", + operations=[ + { + 'method': 'POST', + 'path': '/servers/{server_id}/action (migrate)' + } + ], + scope_types=['project']), + policy.DocumentedRuleDefault( + name=POLICY_ROOT % 'migrate:host', + check_str=base.ADMIN, + description="Cold migrate a server to a specified host", operations=[ { 'method': 'POST', diff --git a/nova/tests/unit/fake_policy.py b/nova/tests/unit/fake_policy.py index 2f8c483554bf..be3c07dad824 100644 --- a/nova/tests/unit/fake_policy.py +++ b/nova/tests/unit/fake_policy.py @@ -125,6 +125,7 @@ policy_data = """ "os_compute_api:os-lock-server:lock": "", "os_compute_api:os-lock-server:unlock": "", "os_compute_api:os-migrate-server:migrate": "", + "os_compute_api:os-migrate-server:migrate:host": "", "os_compute_api:os-migrate-server:migrate_live": "", "os_compute_api:os-migrations:index": "", "os_compute_api:os-multinic:add": "", diff --git a/nova/tests/unit/policies/test_migrate_server.py b/nova/tests/unit/policies/test_migrate_server.py index 0f750770d96c..d226ba1586a2 100644 --- a/nova/tests/unit/policies/test_migrate_server.py +++ b/nova/tests/unit/policies/test_migrate_server.py @@ -62,6 +62,16 @@ class MigrateServerPolicyTest(base.BasePolicyTest): self.req, self.instance.uuid, body={'migrate': None}) + @mock.patch('nova.compute.api.API.resize') + def test_migrate_server_host_policy(self, mock_resize): + rule_name = ms_policies.POLICY_ROOT % 'migrate:host' + # the host parameter was added by the 2.56 microversion. + req = fakes.HTTPRequest.blank('', version='2.56') + self.common_policy_auth(self.project_admin_authorized_contexts, + rule_name, self.controller._migrate, + req, self.instance.uuid, + body={'migrate': {"host": "hostname"}}) + @mock.patch('nova.compute.api.API.live_migrate') def test_migrate_live_server_policy(self, mock_live_migrate): rule_name = ms_policies.POLICY_ROOT % 'migrate_live' @@ -122,11 +132,13 @@ class MigrateServerOverridePolicyTest( def setUp(self): super(MigrateServerOverridePolicyTest, self).setUp() rule_migrate = ms_policies.POLICY_ROOT % 'migrate' + rule_migrate_host = ms_policies.POLICY_ROOT % 'migrate:host' rule_live_migrate = ms_policies.POLICY_ROOT % 'migrate_live' # NOTE(gmann): override the rule to project member and verify it # work as policy is system and project scoped. self.policy.set_rules({ rule_migrate: base_policy.PROJECT_MEMBER, + rule_migrate_host: base_policy.PROJECT_MEMBER, rule_live_migrate: base_policy.PROJECT_MEMBER}, overwrite=False) diff --git a/nova/tests/unit/test_policy.py b/nova/tests/unit/test_policy.py index 752b8723810b..26cbf709eac3 100644 --- a/nova/tests/unit/test_policy.py +++ b/nova/tests/unit/test_policy.py @@ -350,6 +350,7 @@ class RealRolePolicyTestCase(test.NoDBTestCase): "os_compute_api:os-instance-actions:events", "os_compute_api:os-lock-server:unlock:unlock_override", "os_compute_api:os-migrate-server:migrate", +"os_compute_api:os-migrate-server:migrate:host", "os_compute_api:os-migrate-server:migrate_live", "os_compute_api:os-quota-sets:update", "os_compute_api:os-quota-sets:delete", diff --git a/releasenotes/notes/bp-cold-migrate-to-host-policy-a28b648dc16d2e3b.yaml b/releasenotes/notes/bp-cold-migrate-to-host-policy-a28b648dc16d2e3b.yaml new file mode 100644 index 000000000000..42859b77085e --- /dev/null +++ b/releasenotes/notes/bp-cold-migrate-to-host-policy-a28b648dc16d2e3b.yaml @@ -0,0 +1,6 @@ +--- +features: + - A new `os_compute_api:os-migrate-server:migrate:host` policy is created, + being by default only an admin-only policy. This will help operators to + have different policies between cold-migrate without providing a host or + not.