Merge "Support accessing all clusters/templates across projects"

This commit is contained in:
Zuul 2018-02-07 23:36:51 +00:00 committed by Gerrit Code Review
commit 4c4d7db96c
7 changed files with 193 additions and 0 deletions

View File

@ -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')

View File

@ -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(),

View File

@ -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,

View File

@ -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,

View File

@ -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')

View File

@ -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')

View File

@ -0,0 +1,5 @@
---
features:
- |
Now admin user can access all clusters across projects.