diff --git a/magnum/api/controllers/v1/cluster.py b/magnum/api/controllers/v1/cluster.py index 06a7061c22..eb7d5bc636 100755 --- a/magnum/api/controllers/v1/cluster.py +++ b/magnum/api/controllers/v1/cluster.py @@ -147,6 +147,12 @@ class Cluster(base.APIBase): container_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the container software. Example: docker version.""" + project_id = wsme.wsattr(wtypes.text, readonly=True) + """Project id of the cluster belongs to""" + + user_id = wsme.wsattr(wtypes.text, readonly=True) + """User id of the cluster belongs to""" + node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster slave nodes""" @@ -272,6 +278,23 @@ class ClustersController(base.Controller): sort_key, sort_dir, expand=False, resource_url=None): + context = pecan.request.context + if context.is_admin: + if expand: + policy.enforce(context, "cluster:detail_all_projects", + action="cluster:detail_all_projects") + else: + policy.enforce(context, "cluster:get_all_all_projects", + action="cluster:get_all_all_projects") + # TODO(flwang): Instead of asking an extra 'all_project's + # parameter, currently the design is allowing admin user to list + # all clusters from all projects. But the all_tenants is one of + # the condition to do project filter in DB API. And it's also used + # by periodic tasks. So the could be removed in the future and + # a new parameter 'project_id' would be added so that admin user + # can list clusters for a particular project. + context.all_tenants = True + limit = api_utils.validate_limit(limit) sort_dir = api_utils.validate_sort_dir(sort_dir) @@ -362,6 +385,18 @@ class ClustersController(base.Controller): :param cluster_ident: UUID or logical name of the Cluster. """ context = pecan.request.context + if context.is_admin: + policy.enforce(context, "cluster:get_one_all_projects", + action="cluster:get_one_all_projects") + # TODO(flwang): Instead of asking an extra 'all_project's + # parameter, currently the design is allowing admin user to list + # all clusters from all projects. But the all_tenants is one of + # the condition to do project filter in DB API. And it's also used + # by periodic tasks. So the could be removed in the future and + # a new parameter 'project_id' would be added so that admin user + # can list clusters for a particular project. + context.all_tenants = True + cluster = api_utils.get_resource('Cluster', cluster_ident) policy.enforce(context, 'cluster:get', cluster.as_dict(), action='cluster:get') diff --git a/magnum/api/controllers/v1/cluster_template.py b/magnum/api/controllers/v1/cluster_template.py index fe0d942761..d85c43d4bc 100644 --- a/magnum/api/controllers/v1/cluster_template.py +++ b/magnum/api/controllers/v1/cluster_template.py @@ -139,6 +139,12 @@ class ClusterTemplate(base.APIBase): floating_ip_enabled = wsme.wsattr(types.boolean, default=True) """Indicates whether created clusters should have a floating ip or not.""" + project_id = wsme.wsattr(wtypes.text, readonly=True) + """Project id of the cluster belongs to""" + + user_id = wsme.wsattr(wtypes.text, readonly=True) + """User id of the cluster belongs to""" + def __init__(self, **kwargs): self.fields = [] for field in objects.ClusterTemplate.fields: @@ -249,6 +255,23 @@ class ClusterTemplatesController(base.Controller): sort_key, sort_dir, resource_url=None): + context = pecan.request.context + if context.is_admin: + if resource_url == '/'.join(['clustertemplates', 'detail']): + policy.enforce(context, "clustertemplate:detail_all_projects", + action="clustertemplate:detail_all_projects") + else: + policy.enforce(context, "clustertemplate:get_all_all_projects", + action="clustertemplate:get_all_all_projects") + # TODO(flwang): Instead of asking an extra 'all_project's + # parameter, currently the design is allowing admin user to list + # all clusters from all projects. But the all_tenants is one of + # the condition to do project filter in DB API. And it's also used + # by periodic tasks. So the could be removed in the future and + # a new parameter 'project_id' would be added so that admin user + # can list clusters for a particular project. + context.all_tenants = True + limit = api_utils.validate_limit(limit) sort_dir = api_utils.validate_sort_dir(sort_dir) @@ -317,8 +340,22 @@ class ClusterTemplatesController(base.Controller): ClusterTemplate. """ context = pecan.request.context + + if context.is_admin: + policy.enforce(context, "clustertemplate:get_one_all_projects", + action="clustertemplate:get_one_all_projects") + # TODO(flwang): Instead of asking an extra 'all_project's + # parameter, currently the design is allowing admin user to list + # all clusters from all projects. But the all_tenants is one of + # the condition to do project filter in DB API. And it's also used + # by periodic tasks. So the could be removed in the future and + # a new parameter 'project_id' would be added so that admin user + # can list clusters for a particular project. + context.all_tenants = True + cluster_template = api_utils.get_resource('ClusterTemplate', cluster_template_ident) + if not cluster_template.public: policy.enforce(context, 'clustertemplate:get', cluster_template.as_dict(), diff --git a/magnum/common/policies/cluster.py b/magnum/common/policies/cluster.py index 84eff7db0a..70cd6cb3f6 100644 --- a/magnum/common/policies/cluster.py +++ b/magnum/common/policies/cluster.py @@ -51,6 +51,17 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER % 'detail_all_projects', + check_str=base.RULE_ADMIN_API, + description='Retrieve a list of clusters with detail across projects.', + operations=[ + { + 'path': '/v1/clusters', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER % 'get', check_str=base.RULE_DENY_CLUSTER_USER, @@ -62,6 +73,18 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER % 'get_one_all_projects', + check_str=base.RULE_ADMIN_API, + description=('Retrieve information about the given cluster across ' + 'projects.'), + operations=[ + { + 'path': '/v1/clusters/{cluster_ident}', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER % 'get_all', check_str=base.RULE_DENY_CLUSTER_USER, @@ -73,6 +96,17 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER % 'get_all_all_projects', + check_str=base.RULE_ADMIN_API, + description='Retrieve a list of all clusters across projects.', + operations=[ + { + 'path': '/v1/clusters/', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER % 'update', check_str=base.RULE_DENY_CLUSTER_USER, diff --git a/magnum/common/policies/cluster_template.py b/magnum/common/policies/cluster_template.py index 027063796d..eec530f280 100644 --- a/magnum/common/policies/cluster_template.py +++ b/magnum/common/policies/cluster_template.py @@ -40,6 +40,18 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER_TEMPLATE % 'detail_all_projects', + check_str=base.RULE_ADMIN_API, + description=('Retrieve a list of cluster templates with detail across ' + 'projects.'), + operations=[ + { + 'path': '/v1/clustertemplates', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'detail', check_str=base.RULE_DENY_CLUSTER_USER, @@ -62,6 +74,18 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER_TEMPLATE % 'get_one_all_projects', + check_str=base.RULE_ADMIN_API, + description=('Retrieve information about the given cluster template ' + 'across project.'), + operations=[ + { + 'path': '/v1/clustertemplate/{clustertemplate_ident}', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'get_all', check_str=base.RULE_DENY_CLUSTER_USER, @@ -73,6 +97,17 @@ rules = [ } ] ), + policy.DocumentedRuleDefault( + name=CLUSTER_TEMPLATE % 'get_all_all_projects', + check_str=base.RULE_ADMIN_API, + description='Retrieve a list of cluster templates across projects.', + operations=[ + { + 'path': '/v1/clustertemplates', + 'method': 'GET' + } + ] + ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'update', check_str=base.RULE_DENY_CLUSTER_USER, diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster.py b/magnum/tests/unit/api/controllers/v1/test_cluster.py index fb015a6ad6..391e74c038 100644 --- a/magnum/tests/unit/api/controllers/v1/test_cluster.py +++ b/magnum/tests/unit/api/controllers/v1/test_cluster.py @@ -144,6 +144,17 @@ class TestListCluster(api_base.FunctionalTest): self.assertEqual('application/json', response.content_type) self.assertTrue(response.json['errors']) + @mock.patch("magnum.common.policy.enforce") + @mock.patch("magnum.common.context.make_context") + def test_get_one_by_uuid_admin(self, mock_context, mock_policy): + temp_uuid = uuidutils.generate_uuid() + obj_utils.create_test_cluster(self.context, uuid=temp_uuid, + project_id=temp_uuid) + self.context.is_admin = True + response = self.get_json( + '/clusters/%s' % temp_uuid) + self.assertEqual(temp_uuid, response['uuid']) + def test_get_one_by_name_multiple_cluster(self): obj_utils.create_test_cluster(self.context, name='test_cluster', uuid=uuidutils.generate_uuid()) @@ -169,6 +180,19 @@ class TestListCluster(api_base.FunctionalTest): self.assertEqual(cluster_list[-1].uuid, response['clusters'][0]['uuid']) + @mock.patch("magnum.common.policy.enforce") + @mock.patch("magnum.common.context.make_context") + def test_get_all_with_all_projects(self, mock_context, mock_policy): + for id_ in range(4): + temp_uuid = uuidutils.generate_uuid() + obj_utils.create_test_cluster(self.context, id=id_, + uuid=temp_uuid, + project_id=id_) + + self.context.is_admin = True + response = self.get_json('/clusters') + self.assertEqual(4, len(response['clusters'])) + def test_detail(self): cluster = obj_utils.create_test_cluster(self.context) response = self.get_json('/clusters/detail') diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster_template.py b/magnum/tests/unit/api/controllers/v1/test_cluster_template.py index fdc0af6fdb..a7c0b4161e 100644 --- a/magnum/tests/unit/api/controllers/v1/test_cluster_template.py +++ b/magnum/tests/unit/api/controllers/v1/test_cluster_template.py @@ -114,6 +114,17 @@ class TestListClusterTemplate(api_base.FunctionalTest): self.assertEqual('application/json', response.content_type) self.assertTrue(response.json['errors']) + @mock.patch("magnum.common.policy.enforce") + @mock.patch("magnum.common.context.make_context") + def test_get_one_by_uuid_admin(self, mock_context, mock_policy): + temp_uuid = uuidutils.generate_uuid() + obj_utils.create_test_cluster_template(self.context, uuid=temp_uuid, + project_id=temp_uuid) + self.context.is_admin = True + response = self.get_json( + '/clustertemplates/%s' % temp_uuid) + self.assertEqual(temp_uuid, response['uuid']) + def test_get_one_by_name_multiple_cluster_template(self): obj_utils.create_test_cluster_template( self.context, name='test_clustertemplate', @@ -142,6 +153,18 @@ class TestListClusterTemplate(api_base.FunctionalTest): self.assertEqual(bm_list[-1].uuid, response['clustertemplates'][0]['uuid']) + @mock.patch("magnum.common.policy.enforce") + @mock.patch("magnum.common.context.make_context") + def test_get_all_with_all_projects(self, mock_context, mock_policy): + for id_ in range(4): + obj_utils.create_test_cluster_template( + self.context, id=id_, project_id=id_, + uuid=uuidutils.generate_uuid()) + + self.context.is_admin = True + response = self.get_json('/clustertemplates') + self.assertEqual(4, len(response['clustertemplates'])) + def test_detail(self): cluster_template = obj_utils.create_test_cluster_template(self.context) response = self.get_json('/clustertemplates/detail') diff --git a/releasenotes/notes/support-all-tenants-for-admin-a042f5c520d35837.yaml b/releasenotes/notes/support-all-tenants-for-admin-a042f5c520d35837.yaml new file mode 100644 index 0000000000..bc0c82799f --- /dev/null +++ b/releasenotes/notes/support-all-tenants-for-admin-a042f5c520d35837.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Now admin user can access all clusters across projects. +