diff --git a/magnum/api/controllers/v1/cluster_actions.py b/magnum/api/controllers/v1/cluster_actions.py index e068cca380..abe27068f3 100644 --- a/magnum/api/controllers/v1/cluster_actions.py +++ b/magnum/api/controllers/v1/cluster_actions.py @@ -135,6 +135,11 @@ class ActionsController(base.Controller): :param cluster_ident: UUID of a cluster or logical name of the cluster. """ context = pecan.request.context + if context.is_admin: + policy.enforce(context, "cluster:upgrade_all_projects", + action="cluster:upgrade_all_projects") + context.all_tenants = True + cluster = api_utils.get_resource('Cluster', cluster_ident) policy.enforce(context, 'cluster:upgrade', cluster, action='cluster:upgrade') diff --git a/magnum/common/policies/cluster.py b/magnum/common/policies/cluster.py index bc20e44e47..15b63226b2 100644 --- a/magnum/common/policies/cluster.py +++ b/magnum/common/policies/cluster.py @@ -172,7 +172,19 @@ rules = [ 'method': 'POST' } ] + ), + policy.DocumentedRuleDefault( + name=CLUSTER % 'upgrade_all_projects', + check_str=base.RULE_ADMIN_API, + description='Upgrade an existing cluster across all projects.', + operations=[ + { + 'path': '/v1/clusters/{cluster_ident}/actions/upgrade', + 'method': 'POST' + } + ] ) + ] diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py index 41fdac53e1..8a512ca0e0 100644 --- a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py +++ b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py @@ -12,6 +12,9 @@ from unittest import mock +from oslo_utils import uuidutils + +from magnum.common import context as magnum_context from magnum.conductor import api as rpcapi import magnum.conf from magnum.tests.unit.api import base as api_base @@ -143,8 +146,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): project_id=self.cluster_obj.project_id, is_default=False) p = mock.patch.object(rpcapi.API, 'cluster_upgrade') - self.mock_cluster_resize = p.start() - self.mock_cluster_resize.side_effect = self._sim_rpc_cluster_upgrade + self.mock_cluster_upgrade = p.start() + self.mock_cluster_upgrade.side_effect = self._sim_rpc_cluster_upgrade self.addCleanup(p.stop) def _sim_rpc_cluster_upgrade(self, cluster, cluster_template, batch_size, @@ -162,6 +165,38 @@ class TestClusterUpgrade(api_base.FunctionalTest): "container-infra latest"}) self.assertEqual(202, response.status_code) + def test_upgrade_cluster_as_admin(self): + token_info = { + 'token': { + 'project': {'id': 'fake_project_1'}, + 'user': {'id': 'fake_user_1'} + } + } + user_context = magnum_context.RequestContext( + auth_token_info=token_info, + project_id='fake_project_1', + user_id='fake_user_1', + is_admin=False) + cluster_uuid = uuidutils.generate_uuid() + cluster_template_uuid = uuidutils.generate_uuid() + obj_utils.create_test_cluster_template( + user_context, + public=True, uuid=cluster_template_uuid) + obj_utils.create_test_cluster( + user_context, + uuid=cluster_uuid, + cluster_template_id=cluster_template_uuid) + + cluster_upgrade_req = {"cluster_template": "test_2"} + self.context.is_admin = True + response = self.post_json( + '/clusters/%s/actions/upgrade' % + cluster_uuid, + cluster_upgrade_req, + headers={"Openstack-Api-Version": "container-infra latest"}) + + self.assertEqual(202, response.status_int) + def test_upgrade_default_worker(self): cluster_upgrade_req = { "cluster_template": "test_2", diff --git a/releasenotes/notes/support-upgrade-on-behalf-of-user-c04994831360f8c1.yaml b/releasenotes/notes/support-upgrade-on-behalf-of-user-c04994831360f8c1.yaml new file mode 100644 index 0000000000..d3fc72d7ba --- /dev/null +++ b/releasenotes/notes/support-upgrade-on-behalf-of-user-c04994831360f8c1.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Cloud admin user now can do rolling upgrade on behalf of end + user so as to do urgent security patching when it's necessary.