Support accessing all clusters/templates across projects
As an admin user, I'd like to access all clusters or templates across all projects for operation purpose. Similar function is supported by most of the other services, like Nova, Neutron, Cinder, Heat, etc. Related-Bug: #1740982 Change-Id: Icaba09de79a3452286fb60fee80a53430317cba0
This commit is contained in:
parent
e644a20e81
commit
198fce72e5
|
@ -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')
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Now admin user can access all clusters across projects.
|
||||
|
Loading…
Reference in New Issue