ng-5: APIs for listing and showing nodegroups
This adds all needed changes to support listing and showing nodegroups in an existing cluster. Change-Id: I5607c27eb0e84677acda29af006335374b60dd27
This commit is contained in:
parent
3f80cbab06
commit
18119fb3d1
|
@ -103,6 +103,9 @@ class V1(controllers_base.APIBase):
|
||||||
# Links to the federations resources
|
# Links to the federations resources
|
||||||
federations = [link.Link]
|
federations = [link.Link]
|
||||||
|
|
||||||
|
nodegroups = [link.Link]
|
||||||
|
"""Links to the nodegroups resource"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convert():
|
def convert():
|
||||||
v1 = V1()
|
v1 = V1()
|
||||||
|
@ -171,6 +174,14 @@ class V1(controllers_base.APIBase):
|
||||||
pecan.request.host_url,
|
pecan.request.host_url,
|
||||||
'federations', '',
|
'federations', '',
|
||||||
bookmark=True)]
|
bookmark=True)]
|
||||||
|
v1.nodegroups = [link.Link.make_link('self', pecan.request.host_url,
|
||||||
|
'clusters/{cluster_id}',
|
||||||
|
'nodegroups'),
|
||||||
|
link.Link.make_link('bookmark',
|
||||||
|
pecan.request.host_url,
|
||||||
|
'clusters/{cluster_id}',
|
||||||
|
'nodegroups',
|
||||||
|
bookmark=True)]
|
||||||
|
|
||||||
return v1
|
return v1
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ from magnum.api.controllers import base
|
||||||
from magnum.api.controllers import link
|
from magnum.api.controllers import link
|
||||||
from magnum.api.controllers.v1 import cluster_actions
|
from magnum.api.controllers.v1 import cluster_actions
|
||||||
from magnum.api.controllers.v1 import collection
|
from magnum.api.controllers.v1 import collection
|
||||||
|
from magnum.api.controllers.v1 import nodegroup
|
||||||
from magnum.api.controllers.v1 import types
|
from magnum.api.controllers.v1 import types
|
||||||
from magnum.api import expose
|
from magnum.api import expose
|
||||||
from magnum.api import utils as api_utils
|
from magnum.api import utils as api_utils
|
||||||
|
@ -334,6 +335,8 @@ class ClustersController(base.Controller):
|
||||||
sort_key=sort_key,
|
sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
|
nodegroups = nodegroup.NodeGroupController()
|
||||||
|
|
||||||
@expose.expose(ClusterCollection, types.uuid, int, wtypes.text,
|
@expose.expose(ClusterCollection, types.uuid, int, wtypes.text,
|
||||||
wtypes.text)
|
wtypes.text)
|
||||||
def get_all(self, marker=None, limit=None, sort_key='id',
|
def get_all(self, marker=None, limit=None, sort_key='id',
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
# Copyright (c) 2018 European Organization for Nuclear Research.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import pecan
|
||||||
|
import wsme
|
||||||
|
from wsme import types as wtypes
|
||||||
|
|
||||||
|
from magnum.api.controllers import base
|
||||||
|
from magnum.api.controllers import link
|
||||||
|
from magnum.api.controllers.v1 import collection
|
||||||
|
from magnum.api.controllers.v1 import types
|
||||||
|
from magnum.api import expose
|
||||||
|
from magnum.api import utils as api_utils
|
||||||
|
from magnum.common import policy
|
||||||
|
from magnum import objects
|
||||||
|
|
||||||
|
|
||||||
|
class NodeGroup(base.APIBase):
|
||||||
|
"""API representation of a Node group.
|
||||||
|
|
||||||
|
This class enforces type checking and value constraints, and converts
|
||||||
|
between the internal object model and the API representation of NodeGroup.
|
||||||
|
"""
|
||||||
|
id = wsme.wsattr(wtypes.IntegerType(minimum=1))
|
||||||
|
"""unique id"""
|
||||||
|
|
||||||
|
uuid = types.uuid
|
||||||
|
"""Unique UUID for this nodegroup"""
|
||||||
|
|
||||||
|
name = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255),
|
||||||
|
default=None)
|
||||||
|
"""Name of this nodegroup"""
|
||||||
|
|
||||||
|
cluster_id = types.uuid
|
||||||
|
"""Unique UUID for the cluster where the nodegroup belongs to"""
|
||||||
|
|
||||||
|
project_id = wsme.wsattr(wtypes.text, readonly=True)
|
||||||
|
"""Project UUID for this nodegroup"""
|
||||||
|
|
||||||
|
docker_volume_size = wtypes.IntegerType(minimum=1)
|
||||||
|
"""The size in GB of the docker volume"""
|
||||||
|
|
||||||
|
labels = wtypes.DictType(str, str)
|
||||||
|
"""One or more key/value pairs"""
|
||||||
|
|
||||||
|
links = wsme.wsattr([link.Link], readonly=True)
|
||||||
|
"""A list containing a self link and associated nodegroup links"""
|
||||||
|
|
||||||
|
flavor_id = wtypes.StringType(min_length=1, max_length=255)
|
||||||
|
"""The flavor of this nodegroup"""
|
||||||
|
|
||||||
|
image_id = wtypes.StringType(min_length=1, max_length=255)
|
||||||
|
"""The image used for this nodegroup"""
|
||||||
|
|
||||||
|
node_addresses = wsme.wsattr([wtypes.text], readonly=True)
|
||||||
|
"""IP addresses of nodegroup nodes"""
|
||||||
|
|
||||||
|
node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1)
|
||||||
|
"""The node count for this nodegroup. Default to 1 if not set"""
|
||||||
|
|
||||||
|
role = wtypes.StringType(min_length=1, max_length=255)
|
||||||
|
"""The role of the nodes included in this nodegroup"""
|
||||||
|
|
||||||
|
min_node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1)
|
||||||
|
"""The minimum allowed nodes for this nodegroup. Default to 1 if not set"""
|
||||||
|
|
||||||
|
max_node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=None)
|
||||||
|
"""The maximum allowed nodes for this nodegroup. Default to 1 if not set"""
|
||||||
|
|
||||||
|
is_default = types.BooleanType()
|
||||||
|
"""Specifies is a nodegroup was created by default or not"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(NodeGroup, self).__init__()
|
||||||
|
self.fields = []
|
||||||
|
for field in objects.NodeGroup.fields:
|
||||||
|
# Skip fields we do not expose.
|
||||||
|
if not hasattr(self, field):
|
||||||
|
continue
|
||||||
|
self.fields.append(field)
|
||||||
|
setattr(self, field, kwargs.get(field, wtypes.Unset))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def convert(cls, nodegroup, expand=True):
|
||||||
|
url = pecan.request.host_url
|
||||||
|
cluster_path = 'clusters/%s' % nodegroup.cluster_id
|
||||||
|
nodegroup_path = 'nodegroups/%s' % nodegroup.uuid
|
||||||
|
|
||||||
|
ng = NodeGroup(**nodegroup.as_dict())
|
||||||
|
if not expand:
|
||||||
|
ng.unset_fields_except(["uuid", "name", "flavor_id", "node_count",
|
||||||
|
"role", "is_default", "image_id"])
|
||||||
|
else:
|
||||||
|
ng.links = [link.Link.make_link('self', url, cluster_path,
|
||||||
|
nodegroup_path),
|
||||||
|
link.Link.make_link('bookmark', url,
|
||||||
|
cluster_path, nodegroup_path,
|
||||||
|
bookmark=True)]
|
||||||
|
return ng
|
||||||
|
|
||||||
|
|
||||||
|
class NodeGroupCollection(collection.Collection):
|
||||||
|
"""API representation of a collection of Node Groups."""
|
||||||
|
|
||||||
|
nodegroups = [NodeGroup]
|
||||||
|
"""A list containing quota objects"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self._type = 'nodegroups'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert(nodegroups, limit, expand=True, **kwargs):
|
||||||
|
collection = NodeGroupCollection()
|
||||||
|
collection.nodegroups = [NodeGroup.convert(ng, expand)
|
||||||
|
for ng in nodegroups]
|
||||||
|
collection.next = collection.get_next(limit,
|
||||||
|
marker_attribute='id',
|
||||||
|
**kwargs)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
class NodeGroupController(base.Controller):
|
||||||
|
"""REST controller for Node Groups."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(NodeGroupController, self).__init__()
|
||||||
|
|
||||||
|
def _get_nodegroup_collection(self, cluster_id, marker, limit, sort_key,
|
||||||
|
sort_dir, filters, expand=True):
|
||||||
|
|
||||||
|
limit = api_utils.validate_limit(limit)
|
||||||
|
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
||||||
|
|
||||||
|
marker_obj = None
|
||||||
|
if marker:
|
||||||
|
marker_obj = objects.NodeGroup.list(pecan.request.context,
|
||||||
|
cluster_id,
|
||||||
|
marker)
|
||||||
|
|
||||||
|
nodegroups = objects.NodeGroup.list(pecan.request.context,
|
||||||
|
cluster_id,
|
||||||
|
limit,
|
||||||
|
marker_obj,
|
||||||
|
sort_key=sort_key,
|
||||||
|
sort_dir=sort_dir,
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
|
return NodeGroupCollection.convert(nodegroups,
|
||||||
|
limit,
|
||||||
|
expand=expand,
|
||||||
|
sort_key=sort_key,
|
||||||
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
|
@expose.expose(NodeGroupCollection, types.uuid_or_name, int, int,
|
||||||
|
wtypes.text, wtypes.text, wtypes.text)
|
||||||
|
def get_all(self, cluster_id, marker=None, limit=None, sort_key='id',
|
||||||
|
sort_dir='asc', role=None):
|
||||||
|
"""Retrieve a list of nodegroups.
|
||||||
|
|
||||||
|
:param cluster_id: the cluster id or name
|
||||||
|
:param marker: pagination marker for large data sets.
|
||||||
|
:param limit: maximum number of resources to return in a single result.
|
||||||
|
:param sort_key: column to sort results by. Default: id.
|
||||||
|
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
|
||||||
|
:param role: list all nodegroups with the specified role.
|
||||||
|
"""
|
||||||
|
context = pecan.request.context
|
||||||
|
policy.enforce(context, 'nodegroup:get_all',
|
||||||
|
action='nodegroup:get_all')
|
||||||
|
|
||||||
|
if context.is_admin:
|
||||||
|
policy.enforce(context, 'nodegroup:get_all_all_projects',
|
||||||
|
action='nodegroup:get_all_all_projects')
|
||||||
|
context.all_tenants = True
|
||||||
|
|
||||||
|
cluster = api_utils.get_resource('Cluster', cluster_id)
|
||||||
|
|
||||||
|
filters = {}
|
||||||
|
if not context.is_admin:
|
||||||
|
filters = {"project_id": context.project_id}
|
||||||
|
if role:
|
||||||
|
filters.update({'role': role})
|
||||||
|
|
||||||
|
return self._get_nodegroup_collection(cluster.uuid,
|
||||||
|
marker,
|
||||||
|
limit,
|
||||||
|
sort_key,
|
||||||
|
sort_dir,
|
||||||
|
filters,
|
||||||
|
expand=False)
|
||||||
|
|
||||||
|
@expose.expose(NodeGroup, types.uuid_or_name, types.uuid_or_name)
|
||||||
|
def get_one(self, cluster_id, nodegroup_id):
|
||||||
|
"""Retrieve information for the given nodegroup in a cluster.
|
||||||
|
|
||||||
|
:param id: cluster id.
|
||||||
|
:param resource: nodegroup id.
|
||||||
|
"""
|
||||||
|
context = pecan.request.context
|
||||||
|
policy.enforce(context, 'nodegroup:get', action='nodegroup:get')
|
||||||
|
if context.is_admin:
|
||||||
|
policy.enforce(context, "nodegroup:get_one_all_projects",
|
||||||
|
action="nodegroup:get_one_all_projects")
|
||||||
|
context.all_tenants = True
|
||||||
|
cluster = api_utils.get_resource('Cluster', cluster_id)
|
||||||
|
nodegroup = objects.NodeGroup.get(context, cluster.uuid, nodegroup_id)
|
||||||
|
return NodeGroup.convert(nodegroup)
|
|
@ -22,6 +22,7 @@ from magnum.common.policies import cluster
|
||||||
from magnum.common.policies import cluster_template
|
from magnum.common.policies import cluster_template
|
||||||
from magnum.common.policies import federation
|
from magnum.common.policies import federation
|
||||||
from magnum.common.policies import magnum_service
|
from magnum.common.policies import magnum_service
|
||||||
|
from magnum.common.policies import nodegroup
|
||||||
from magnum.common.policies import quota
|
from magnum.common.policies import quota
|
||||||
from magnum.common.policies import stats
|
from magnum.common.policies import stats
|
||||||
|
|
||||||
|
@ -37,5 +38,6 @@ def list_rules():
|
||||||
federation.list_rules(),
|
federation.list_rules(),
|
||||||
magnum_service.list_rules(),
|
magnum_service.list_rules(),
|
||||||
quota.list_rules(),
|
quota.list_rules(),
|
||||||
stats.list_rules()
|
stats.list_rules(),
|
||||||
|
nodegroup.list_rules()
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Copyright (c) 2018 European Organization for Nuclear Research.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_policy import policy
|
||||||
|
|
||||||
|
from magnum.common.policies import base
|
||||||
|
|
||||||
|
|
||||||
|
NODEGROUP = 'nodegroup:%s'
|
||||||
|
|
||||||
|
|
||||||
|
rules = [
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=NODEGROUP % 'get',
|
||||||
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
description='Retrieve information about the given nodegroup.',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v1/clusters/{cluster_id}/nodegroup/{nodegroup}',
|
||||||
|
'method': 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=NODEGROUP % 'get_all',
|
||||||
|
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||||
|
description='Retrieve a list of nodegroups that belong to a cluster.',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v1/clusters/{cluster_id}/nodegroups/',
|
||||||
|
'method': 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=NODEGROUP % 'get_all_all_projects',
|
||||||
|
check_str=base.RULE_ADMIN_API,
|
||||||
|
description='Retrieve a list of nodegroups across projects.',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v1/clusters/{cluster_id}/nodegroups/',
|
||||||
|
'method': 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=NODEGROUP % 'get_one_all_projects',
|
||||||
|
check_str=base.RULE_ADMIN_API,
|
||||||
|
description='Retrieve infornation for a given nodegroup.',
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'path': '/v1/clusters/{cluster_id}/nodegroups/{nodegroup}',
|
||||||
|
'method': 'GET'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def list_rules():
|
||||||
|
return rules
|
|
@ -90,7 +90,13 @@ class TestRootController(api_base.FunctionalTest):
|
||||||
u'federations': [{u'href': u'http://localhost/v1/federations/',
|
u'federations': [{u'href': u'http://localhost/v1/federations/',
|
||||||
u'rel': u'self'},
|
u'rel': u'self'},
|
||||||
{u'href': u'http://localhost/federations/',
|
{u'href': u'http://localhost/federations/',
|
||||||
u'rel': u'bookmark'}]}
|
u'rel': u'bookmark'}],
|
||||||
|
u'nodegroups': [{u'href': u'http://localhost/v1/clusters/'
|
||||||
|
'{cluster_id}/nodegroups',
|
||||||
|
u'rel': u'self'},
|
||||||
|
{u'href': u'http://localhost/clusters/'
|
||||||
|
'{cluster_id}/nodegroups',
|
||||||
|
u'rel': u'bookmark'}]}
|
||||||
|
|
||||||
def make_app(self, paste_file):
|
def make_app(self, paste_file):
|
||||||
file_name = self.get_path(paste_file)
|
file_name = self.get_path(paste_file)
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
# Copyright (c) 2018 European Organization for Nuclear Research.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
from magnum.api.controllers.v1 import nodegroup as api_nodegroup
|
||||||
|
import magnum.conf
|
||||||
|
from magnum import objects
|
||||||
|
from magnum.tests import base
|
||||||
|
from magnum.tests.unit.api import base as api_base
|
||||||
|
from magnum.tests.unit.api import utils as apiutils
|
||||||
|
from magnum.tests.unit.db import utils as db_utils
|
||||||
|
from magnum.tests.unit.objects import utils as obj_utils
|
||||||
|
|
||||||
|
CONF = magnum.conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class TestNodegroupObject(base.TestCase):
|
||||||
|
def test_nodegroup_init(self):
|
||||||
|
nodegroup_dict = apiutils.nodegroup_post_data()
|
||||||
|
del nodegroup_dict['node_count']
|
||||||
|
del nodegroup_dict['min_node_count']
|
||||||
|
del nodegroup_dict['max_node_count']
|
||||||
|
nodegroup = api_nodegroup.NodeGroup(**nodegroup_dict)
|
||||||
|
self.assertEqual(1, nodegroup.node_count)
|
||||||
|
self.assertEqual(1, nodegroup.min_node_count)
|
||||||
|
self.assertIsNone(nodegroup.max_node_count)
|
||||||
|
|
||||||
|
|
||||||
|
class TestListNodegroups(api_base.FunctionalTest):
|
||||||
|
_expanded_attrs = ["id", "project_id", "docker_volume_size", "labels",
|
||||||
|
"node_addresses", "links"]
|
||||||
|
|
||||||
|
_nodegroup_attrs = ["uuid", "name", "flavor_id", "node_count", "role",
|
||||||
|
"is_default", "image_id", "min_node_count",
|
||||||
|
"max_node_count"]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListNodegroups, self).setUp()
|
||||||
|
obj_utils.create_test_cluster_template(self.context)
|
||||||
|
self.cluster_uuid = uuidutils.generate_uuid()
|
||||||
|
obj_utils.create_test_cluster(
|
||||||
|
self.context, uuid=self.cluster_uuid)
|
||||||
|
self.cluster = objects.Cluster.get_by_uuid(self.context,
|
||||||
|
self.cluster_uuid)
|
||||||
|
|
||||||
|
def _test_list_nodegroups(self, cluster_id, filters=None, expected=None):
|
||||||
|
url = '/clusters/%s/nodegroups' % cluster_id
|
||||||
|
if filters is not None:
|
||||||
|
filter_list = ['%s=%s' % (k, v) for k, v in filters.items()]
|
||||||
|
url += '?' + '&'.join(f for f in filter_list)
|
||||||
|
response = self.get_json(url)
|
||||||
|
if expected is None:
|
||||||
|
expected = []
|
||||||
|
ng_uuids = [ng['uuid'] for ng in response['nodegroups']]
|
||||||
|
self.assertEqual(expected, ng_uuids)
|
||||||
|
for ng in response['nodegroups']:
|
||||||
|
self._verify_attrs(self._nodegroup_attrs, ng)
|
||||||
|
self._verify_attrs(self._expanded_attrs, ng, positive=False)
|
||||||
|
|
||||||
|
def test_get_all(self):
|
||||||
|
expected = [ng.uuid for ng in self.cluster.nodegroups]
|
||||||
|
self._test_list_nodegroups(self.cluster_uuid, expected=expected)
|
||||||
|
|
||||||
|
def test_get_all_by_name(self):
|
||||||
|
expected = [ng.uuid for ng in self.cluster.nodegroups]
|
||||||
|
self._test_list_nodegroups(self.cluster.name, expected=expected)
|
||||||
|
|
||||||
|
def test_get_all_by_name_non_default_ngs(self):
|
||||||
|
db_utils.create_test_nodegroup(cluster_id=self.cluster_uuid,
|
||||||
|
name='non_default_ng')
|
||||||
|
expected = [ng.uuid for ng in self.cluster.nodegroups]
|
||||||
|
self._test_list_nodegroups(self.cluster.name, expected=expected)
|
||||||
|
|
||||||
|
def test_get_all_by_role(self):
|
||||||
|
filters = {'role': 'master'}
|
||||||
|
expected = [self.cluster.default_ng_master.uuid]
|
||||||
|
self._test_list_nodegroups(self.cluster.name, filters=filters,
|
||||||
|
expected=expected)
|
||||||
|
filters = {'role': 'worker'}
|
||||||
|
expected = [self.cluster.default_ng_worker.uuid]
|
||||||
|
self._test_list_nodegroups(self.cluster.name, filters=filters,
|
||||||
|
expected=expected)
|
||||||
|
|
||||||
|
def test_get_all_by_non_existent_role(self):
|
||||||
|
filters = {'role': 'non-existent'}
|
||||||
|
self._test_list_nodegroups(self.cluster.name, filters=filters)
|
||||||
|
|
||||||
|
@mock.patch("magnum.common.policy.enforce")
|
||||||
|
@mock.patch("magnum.common.context.make_context")
|
||||||
|
def test_get_all_as_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
|
||||||
|
self.context.all_tenants = True
|
||||||
|
cluster = objects.Cluster.get_by_uuid(self.context, temp_uuid)
|
||||||
|
expected = [ng.uuid for ng in cluster.nodegroups]
|
||||||
|
self._test_list_nodegroups(cluster.uuid, expected=expected)
|
||||||
|
|
||||||
|
def test_get_all_non_existent_cluster(self):
|
||||||
|
response = self.get_json('/clusters/not-here/nodegroups',
|
||||||
|
expect_errors=True)
|
||||||
|
self.assertEqual(404, response.status_code)
|
||||||
|
|
||||||
|
def test_get_one(self):
|
||||||
|
worker = self.cluster.default_ng_worker
|
||||||
|
url = '/clusters/%s/nodegroups/%s' % (self.cluster.uuid, worker.uuid)
|
||||||
|
response = self.get_json(url)
|
||||||
|
self.assertEqual(worker.name, response['name'])
|
||||||
|
self._verify_attrs(self._nodegroup_attrs, response)
|
||||||
|
self._verify_attrs(self._expanded_attrs, response)
|
||||||
|
|
||||||
|
def test_get_one_non_existent_ng(self):
|
||||||
|
url = '/clusters/%s/nodegroups/not-here' % self.cluster.uuid
|
||||||
|
response = self.get_json(url, expect_errors=True)
|
||||||
|
self.assertEqual(404, response.status_code)
|
||||||
|
|
||||||
|
@mock.patch("magnum.common.policy.enforce")
|
||||||
|
@mock.patch("magnum.common.context.make_context")
|
||||||
|
def test_get_one_as_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
|
||||||
|
self.context.all_tenants = True
|
||||||
|
cluster = objects.Cluster.get_by_uuid(self.context, temp_uuid)
|
||||||
|
worker = cluster.default_ng_worker
|
||||||
|
url = '/clusters/%s/nodegroups/%s' % (cluster.uuid, worker.uuid)
|
||||||
|
response = self.get_json(url)
|
||||||
|
self.assertEqual(worker.name, response['name'])
|
||||||
|
self._verify_attrs(self._nodegroup_attrs, response)
|
||||||
|
self._verify_attrs(self._expanded_attrs, response)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNodeGroupPolicyEnforcement(api_base.FunctionalTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNodeGroupPolicyEnforcement, self).setUp()
|
||||||
|
obj_utils.create_test_cluster_template(self.context)
|
||||||
|
self.cluster_uuid = uuidutils.generate_uuid()
|
||||||
|
obj_utils.create_test_cluster(
|
||||||
|
self.context, uuid=self.cluster_uuid)
|
||||||
|
self.cluster = objects.Cluster.get_by_uuid(self.context,
|
||||||
|
self.cluster_uuid)
|
||||||
|
|
||||||
|
def _common_policy_check(self, rule, func, *arg, **kwarg):
|
||||||
|
self.policy.set_rules({rule: "project:non_fake"})
|
||||||
|
response = func(*arg, **kwarg)
|
||||||
|
self.assertEqual(403, response.status_int)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
self.assertTrue(
|
||||||
|
"Policy doesn't allow %s to be performed." % rule,
|
||||||
|
response.json['errors'][0]['detail'])
|
||||||
|
|
||||||
|
def test_policy_disallow_get_all(self):
|
||||||
|
self._common_policy_check(
|
||||||
|
"nodegroup:get_all", self.get_json,
|
||||||
|
'/clusters/%s/nodegroups' % self.cluster_uuid, expect_errors=True)
|
||||||
|
|
||||||
|
def test_policy_disallow_get_one(self):
|
||||||
|
worker = self.cluster.default_ng_worker
|
||||||
|
self._common_policy_check(
|
||||||
|
"nodegroup:get", self.get_json,
|
||||||
|
'/clusters/%s/nodegroups/%s' % (self.cluster.uuid, worker.uuid),
|
||||||
|
expect_errors=True)
|
|
@ -95,3 +95,8 @@ def federation_post_data(**kw):
|
||||||
federation = utils.get_test_federation(**kw)
|
federation = utils.get_test_federation(**kw)
|
||||||
internal = federation_controller.FederationPatchType.internal_attrs()
|
internal = federation_controller.FederationPatchType.internal_attrs()
|
||||||
return remove_internal(federation, internal)
|
return remove_internal(federation, internal)
|
||||||
|
|
||||||
|
|
||||||
|
def nodegroup_post_data(**kw):
|
||||||
|
nodegroup = utils.get_test_nodegroup(**kw)
|
||||||
|
return nodegroup
|
||||||
|
|
Loading…
Reference in New Issue