Introduce new validation rules for tags and roles

Change-Id: Ia45c81a46e9323faa6471438acbfa6d65d01b7f4
Implements: blueprint role-decomposition
(cherry picked from commit 70aafb4aa8)
This commit is contained in:
Mikhail 2016-11-18 17:46:08 +03:00
parent d04c1108b2
commit c56620fda8
18 changed files with 581 additions and 54 deletions

View File

@ -70,7 +70,7 @@ LIMITS = {
ROLE_META_INFO = {
"type": "object",
"required": ["name", "description"],
"required": ["name", "description", "tags"],
"properties": {
"name": {
"type": "string",

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql as psql
@ -27,7 +29,9 @@ from nailgun import errors
class ReleaseValidator(BasicValidator):
@classmethod
def _validate_common(cls, d):
def _validate_common(cls, d, instance=None):
if not instance:
instance = {}
if "networks_metadata" in d:
# TODO(enchantner): additional validation
meta = d["networks_metadata"]["nova_network"]
@ -37,6 +41,21 @@ class ReleaseValidator(BasicValidator):
"Invalid network data: {0}".format(network),
log_message=True
)
if 'roles_metadata' in d:
roles_meta = d['roles_metadata']
tags_meta = d.get('tags_metadata',
instance.get('tags_metadata', {}))
available_tags = set(tags_meta)
for role_name, meta in six.iteritems(roles_meta):
role_tags = set(meta.get('tags', []))
missing_tags = role_tags - available_tags
if missing_tags:
raise errors.InvalidData(
"Tags {} are present for role {}, but, absent in "
"release tags metadata".format(missing_tags,
role_name),
log_message=True
)
@classmethod
def validate(cls, data):
@ -79,7 +98,7 @@ class ReleaseValidator(BasicValidator):
@classmethod
def validate_update(cls, data, instance):
d = cls.validate_json(data)
cls._validate_common(d)
cls._validate_common(d, instance)
if db().query(models.Release).filter_by(
name=d.get("name", instance.name),

View File

@ -38,6 +38,13 @@ class RoleValidator(BasicValidator):
@classmethod
def validate_update(cls, data, instance_cls, instance):
parsed = cls.validate(data, instance=instance)
tags_meta = instance_cls.get_tags_metadata(instance)
for tag in parsed.get('meta', {}).get('tags', []):
if tag not in tags_meta:
raise errors.InvalidData(
"Role {} contains non-existent tag {}".format(
parsed['name'], tag)
)
volumes_meta = instance_cls.get_volumes_metadata(instance)
allowed_ids = [m['id'] for m in volumes_meta.get('volumes', [])]

View File

@ -99,8 +99,9 @@ class Node(Base):
default=[], nullable=False, server_default='{}')
pending_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
default=[], nullable=False, server_default='{}')
primary_tags = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
default=[], nullable=False, server_default='{}')
primary_tags = Column(
MutableList.as_mutable(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE))),
default=[], nullable=False, server_default='{}')
nic_interfaces = relationship("NodeNICInterface", backref="node",
cascade="all, delete-orphan",

View File

@ -393,7 +393,12 @@ class Cluster(NailgunObject):
:param role: a role dict
:returns: None
"""
old_role = instance.roles_metadata.get(role['name'], {})
instance.roles_metadata[role['name']] = role['meta']
if old_role:
deleted_tags = set(old_role['tags']) - set(role['meta']['tags'])
for tag in deleted_tags:
cls.remove_primary_tag(instance, tag)
instance.volumes_metadata.setdefault(
'volumes_roles_mapping', {}).update(
{role['name']: role.get('volumes_roles_mapping', [])})
@ -415,19 +420,26 @@ class Cluster(NailgunObject):
Previous ones are deleted.
:param instance: a Cluster instance
:param role: a tag dict
:param tag: a tag dict
:returns: None
"""
instance.tags_metadata[tag['name']] = tag['meta']
@classmethod
def remove_tag(cls, instance, tag_name):
res = instance.tags_metadata.pop(tag_name, None)
if tag_name not in instance.release.tags_metadata:
cls.remove_tag_from_roles(instance, tag_name)
cls.remove_primary_tag(instance, tag_name)
return bool(res)
@classmethod
def remove_tag_from_roles(cls, instance, tag_name):
for role, meta in six.iteritems(cls.get_own_roles(instance)):
tags = meta.get('tags', [])
if tag_name in tags:
tags.remove(tag_name)
instance.roles_metadata.changed()
return bool(instance.tags_metadata.pop(tag_name, None))
@classmethod
def _create_public_map(cls, instance, roles_metadata=None):
@ -841,6 +853,14 @@ class Cluster(NailgunObject):
PluginManager.get_plugins_node_roles(instance))
return available_roles
@classmethod
def get_roles_by_tag(cls, tag_name, instance):
roles = set()
for role, meta in six.iteritems(cls.get_own_roles(instance)):
if tag_name in meta.get('tags', {}):
roles.add(role)
return roles
@classmethod
def get_own_roles(cls, instance):
return instance.roles_metadata
@ -849,6 +869,12 @@ class Cluster(NailgunObject):
def get_own_tags(cls, instance):
return instance.tags_metadata
@classmethod
def remove_primary_tag(cls, instance, tag):
node = cls.get_primary_node(instance, tag)
if node:
node.primary_tags.remove(tag)
@classmethod
def set_primary_tag(cls, instance, nodes, tag):
"""Method for assigning primary attribute for specific tag.
@ -875,7 +901,6 @@ class Cluster(NailgunObject):
if node.status == consts.NODE_STATUSES.ready),
filtered_nodes[0])
primary_node.primary_tags = list(primary_node.primary_tags)
primary_node.primary_tags.append(tag)
db().flush()

View File

@ -921,7 +921,7 @@ class Node(NailgunObject):
"""
if not instance.cluster_id:
logger.warning(
u"Attempting to assign peimary tags to node "
u"Attempting to assign primary tags to node "
u"'{0}' which isn't added to cluster".format(
instance.full_name))
return

View File

@ -72,13 +72,46 @@ class Plugin(NailgunObject):
# todo(ikutukov): this update is a smell from the current plugins
# installation schema. Remove it.
cls.update(plugin_obj, plugin_adapter.get_metadata())
plugin_meta = cls._process_tags(plugin_adapter.get_metadata())
cls.update(plugin_obj, plugin_meta)
ClusterPlugin.add_compatible_clusters(plugin_obj)
return plugin_obj
@staticmethod
def _process_tags(data):
roles_meta = data.get('roles_metadata')
# nothing to check if no roles is introduced
if not roles_meta:
return data
tags_meta = data.get('tags_metadata')
if tags_meta is not None:
return data
# add creation of so-called tags for roles if tags are not
# present in role's metadata. it's necessary for compatibility
# with plugins without tags feature
tags_meta = {}
for role, meta in six.iteritems(roles_meta):
# if developer specified 'tags' field then he is in charge
# of tags management
if 'tags' in meta:
continue
# it's necessary for auto adding tag when we are
# assigning the role
roles_meta[role]['tags'] = [role]
# so-called tags should be added to plugin tags_metadata as well
tags_meta[role] = {
'has_primary': meta.get('has_primary', False)
}
# update changed data
data['roles_metadata'] = roles_meta
data['tags_metadata'] = tags_meta
return data
@classmethod
def update(cls, instance, data):
graphs = {}

View File

@ -117,6 +117,7 @@ class Release(NailgunObject):
@classmethod
def update_role(cls, instance, role):
from nailgun.objects import Cluster
"""Update existing Release instance with specified role.
Previous ones are deleted.
@ -125,7 +126,14 @@ class Release(NailgunObject):
:param role: a role dict
:returns: None
"""
old_role = instance.roles_metadata.get(role['name'], {})
instance.roles_metadata[role['name']] = role['meta']
if old_role:
deleted_tags = set(old_role['tags']) - set(role['meta']['tags'])
for cluster in instance.clusters:
for tag in deleted_tags:
if role['name'] not in cluster.roles_metadata:
Cluster.remove_primary_tag(cluster, tag)
instance.volumes_metadata['volumes_roles_mapping'][role['name']] = \
role.get('volumes_roles_mapping', [])
# notify about changes
@ -141,24 +149,34 @@ class Release(NailgunObject):
@classmethod
def update_tag(cls, instance, tag):
"""Update existing Cluster instance with specified tag.
"""Update existing Release instance with specified tag.
Previous ones are deleted.
:param instance: a Cluster instance
:param role: a tag dict
:param instance: a Release instance
:param tag: a tag dict
:returns: None
"""
instance.tags_metadata[tag['name']] = tag['meta']
@classmethod
def remove_tag(cls, instance, tag_name):
from nailgun.objects import Cluster
cls.remove_tag_from_roles(instance, tag_name)
res = instance.tags_metadata.pop(tag_name, None)
for cluster in instance.clusters:
if tag_name not in cluster.tags_metadata:
Cluster.remove_tag_from_roles(cluster, tag_name)
Cluster.remove_primary_tag(cluster, tag_name)
return bool(res)
@classmethod
def remove_tag_from_roles(cls, instance, tag_name):
for role, meta in six.iteritems(cls.get_own_roles(instance)):
tags = meta.get('tags', [])
if tag_name in tags:
tags.remove(tag_name)
instance.roles_metadata.changed()
return bool(instance.tags_metadata.pop(tag_name, None))
@classmethod
def is_deployable(cls, instance):

View File

@ -28,6 +28,7 @@ class ReleaseSerializer(BasicSerializer):
"operating_system",
"modes_metadata",
"roles_metadata",
"tags_metadata",
"state",
"attributes_metadata",
"vmware_attributes_metadata",

View File

@ -60,6 +60,7 @@ from nailgun.db.sqlalchemy.models import IPAddr
from nailgun.db.sqlalchemy.models import NodeNICInterface
from nailgun.db.sqlalchemy.models import Notification
from nailgun.db.sqlalchemy.models import PluginLink
from nailgun.db.sqlalchemy.models import Release as ReleaseModel
from nailgun.db.sqlalchemy.models import Task
@ -144,7 +145,7 @@ class EnvironmentManager(object):
)
return cluster
def create_release(self, api=False, **kwargs):
def create_release(self, api=False, expect_errors=False, **kwargs):
os = kwargs.get(
'operating_system', consts.RELEASE_OS.centos)
version = kwargs.get(
@ -176,13 +177,14 @@ class EnvironmentManager(object):
resp = self.app.post(
reverse('ReleaseCollectionHandler'),
params=jsonutils.dumps(release_data),
headers=self.default_headers
headers=self.default_headers,
expect_errors=expect_errors
)
self.tester.assertEqual(resp.status_code, 201)
release = resp.json_body
self.releases.append(
self.db.query(Release).get(release['id'])
)
if not expect_errors:
self.releases.append(
self.db.query(ReleaseModel).get(release['id'])
)
else:
release = Release.create(release_data)
db().commit()

View File

@ -42,6 +42,7 @@ class TestClusterRolesHandler(base.BaseTestCase):
meta:
name: My Role
description: Something goes here
tags: []
volumes_roles_mapping:
- id: os
allocate_size: all

View File

@ -77,6 +77,40 @@ class TestPluginManager(base.BaseIntegrationTest):
volumes_metadata['volumes'],
expected_volumes_metadata['volumes'])
def test_plugin_role_with_empty_tags(self):
role_name = 'test'
roles_meta = {
role_name: {
'has_primary': True,
'tags': []
}
}
plugin = self.env.create_plugin(
cluster=self.cluster,
package_version='3.0.0',
roles_metadata=roles_meta
)
self.assertEqual(
plugin.roles_metadata[role_name]['tags'], [])
def test_plugin_legacy_tags(self):
role_name = 'test'
roles_meta = {
role_name: {
'has_primary': True
}
}
plugin = self.env.create_plugin(
cluster=self.cluster,
package_version='3.0.0',
roles_metadata=roles_meta
)
self.assertEqual(
plugin.roles_metadata[role_name]['tags'], [role_name])
self.assertEqual(
plugin.tags_metadata[role_name]['has_primary'],
roles_meta[role_name]['has_primary'])
def test_get_empty_plugin_volumes_metadata_for_cluster(self):
cluster = self.env.create_cluster(api=False)
self.env.create_plugin(

View File

@ -17,6 +17,7 @@
import yaml
from nailgun import objects
from nailgun.test import base
@ -26,8 +27,10 @@ class BaseRoleTest(base.BaseIntegrationTest):
def setUp(self):
super(BaseRoleTest, self).setUp()
self.release = self.env.create_release()
self.cluster = self.env.create()
self.release = self.cluster.release
self.role_data = yaml.load(self.ROLE)
self.tag_data = {'name': 'my_tag', 'meta': {'has_primary': True}}
class TestRoleApi(BaseRoleTest):
@ -37,13 +40,40 @@ class TestRoleApi(BaseRoleTest):
meta:
name: My Role
description: Something goes here
tags: [my_tag]
volumes_roles_mapping:
- id: os
allocate_size: all
"""
ROLE_WITH_EMPTY_TAGS = """
name: my_role
meta:
name: My Role
description: Something goes here
tags: []
volumes_roles_mapping:
- id: os
allocate_size: all
"""
def test_get_all_roles(self):
def test_create_release_role_without_tags(self):
owner_type, owner_id = 'releases', self.release.id
role_data = yaml.load(self.ROLE_WITH_EMPTY_TAGS)
role_data['meta'].pop('tags')
resp = self.env.create_role(owner_type, owner_id, role_data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('is a required property', resp.body)
def test_create_release_role_with_empty_tags(self):
owner_type, owner_id = 'releases', self.release.id
role_data = yaml.load(self.ROLE_WITH_EMPTY_TAGS)
resp = self.env.create_role(owner_type, owner_id, role_data)
self.assertEqual(resp.json['meta'], role_data['meta'])
def test_get_all_release_roles(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
resp = self.env.get_all_roles(owner_type, owner_id)
@ -57,15 +87,53 @@ class TestRoleApi(BaseRoleTest):
for role in resp.json if role['name'] == self.role_data['name']))
self.assertEqual(created_role, self.role_data)
def test_create_role(self):
def test_get_all_cluster_roles(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
resp = self.env.get_all_roles(owner_type, owner_id)
self.assertEqual(
len(self.release.roles_metadata.keys())
+ len(self.cluster.roles_metadata.keys()),
len(resp.json))
created_role = next((
role
for role in resp.json if role['name'] == self.role_data['name']))
self.assertEqual(created_role, self.role_data)
def test_create_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
self.assertEqual(resp.json['meta'], self.role_data['meta'])
def test_update_role(self):
def test_create_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
self.assertEqual(resp.json['meta'], self.role_data['meta'])
def test_create_release_role_with_nonexistent_tag(self):
owner_type, owner_id = 'releases', self.release.id
resp = self.env.create_role(owner_type, owner_id, self.role_data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('contains non-existent tag', resp.body)
def test_create_cluster_role_with_nonexistent_tag(self):
owner_type, owner_id = 'clusters', self.cluster.id
resp = self.env.create_role(owner_type, owner_id, self.role_data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('contains non-existent tag', resp.body)
def test_update_release_role(self):
changed_name = 'Another name'
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
data = resp.json
@ -74,33 +142,103 @@ class TestRoleApi(BaseRoleTest):
resp = self.env.update_role(owner_type, owner_id, data['name'], data)
self.assertEqual(resp.json['meta']['name'], changed_name)
def test_create_role_wo_volumes(self):
def test_update_cluster_role(self):
changed_name = 'Another name'
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
data = resp.json
data['meta']['name'] = changed_name
resp = self.env.update_role(owner_type, owner_id, data['name'], data)
self.assertEqual(resp.json['meta']['name'], changed_name)
def test_update_release_role_with_nonexistent_tag(self):
tag = 'nonexistent_tag'
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
data = resp.json
data['meta']['tags'] = [tag]
resp = self.env.update_role(owner_type, owner_id, data['name'], data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('contains non-existent tag', resp.body)
def test_update_cluster_role_with_nonexistent_tag(self):
tag = 'nonexistent_tag'
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
data = resp.json
data['meta']['tags'] = [tag]
resp = self.env.update_role(owner_type, owner_id, data['name'], data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('contains non-existent tag', resp.body)
def test_create_release_role_wo_volumes(self):
owner_type, owner_id = 'releases', self.release.id
self.role_data['volumes_roles_mapping'] = []
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(resp.status_code, 400)
def test_create_role_w_invalid_volumes_allocate_size(self):
def test_create_cluster_role_wo_volumes(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.role_data['volumes_roles_mapping'] = []
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(resp.status_code, 400)
def test_create_release_role_w_invalid_volumes_allocate_size(self):
owner_type, owner_id = 'releases', self.release.id
self.role_data['volumes_roles_mapping'][0]['allocate_size'] = \
'some_string'
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('Failed validating', resp.body)
self.assertIn('volumes_roles_mapping', resp.body)
self.assertIn(
"Failed validating 'enum' in schema['properties']"
"['volumes_roles_mapping']", resp.body)
def test_create_role_w_invalid_id(self):
def test_create_cluster_role_w_invalid_volumes_allocate_size(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.role_data['volumes_roles_mapping'][0]['allocate_size'] = \
'some_string'
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn(
"Failed validating 'enum' in schema['properties']"
"['volumes_roles_mapping']", resp.body)
def test_create_release_role_w_invalid_id(self):
owner_type, owner_id = 'releases', self.release.id
self.role_data['volumes_roles_mapping'][0]['id'] = 'invalid_id'
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('Wrong data in volumes_roles_mapping', resp.body)
def test_update_role_w_invalid_volumes_id(self):
def test_create_cluster_role_w_invalid_id(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.role_data['volumes_roles_mapping'][0]['id'] = 'invalid_id'
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('Wrong data in volumes_roles_mapping', resp.body)
def test_update_release_role_w_invalid_volumes_id(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
self.role_data['volumes_roles_mapping'][0]['id'] = 'some_string'
resp = self.env.update_role(owner_type,
@ -111,8 +249,22 @@ class TestRoleApi(BaseRoleTest):
self.assertEqual(400, resp.status_code)
self.assertIn('Wrong data in volumes_roles_mapping', resp.body)
def test_update_role_not_present(self):
def test_update_cluster_role_w_invalid_volumes_id(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
self.role_data['volumes_roles_mapping'][0]['id'] = 'some_string'
resp = self.env.update_role(owner_type,
owner_id,
self.role_data['name'],
self.role_data,
expect_errors=True)
self.assertEqual(400, resp.status_code)
self.assertIn('Wrong data in volumes_roles_mapping', resp.body)
def test_update_release_role_not_present(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
resp = self.env.update_role(owner_type,
@ -123,16 +275,40 @@ class TestRoleApi(BaseRoleTest):
self.assertEqual(404, resp.status_code)
self.assertIn('is not found for the release', resp.body)
def test_delete_role(self):
def test_update_cluster_role_not_present(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
resp = self.env.update_role(owner_type,
owner_id,
role_name,
self.role_data,
expect_errors=True)
self.assertEqual(404, resp.status_code)
self.assertIn('is not found for the cluster', resp.body)
def test_delete_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
delete_resp = self.env.delete_role(
owner_type, owner_id, self.role_data['name'])
self.assertEqual(delete_resp.status_code, 204)
def test_delete_role_not_present(self):
def test_delete_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
delete_resp = self.env.delete_role(
owner_type, owner_id, self.role_data['name'])
self.assertEqual(delete_resp.status_code, 204)
def test_delete_release_role_not_present(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
delete_resp = self.env.delete_role(
@ -140,12 +316,23 @@ class TestRoleApi(BaseRoleTest):
self.assertEqual(delete_resp.status_code, 404)
self.assertIn('is not found for the release', delete_resp.body)
def test_delete_assigned_role(self):
def test_delete_cluster_role_not_present(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
delete_resp = self.env.delete_role(
owner_type, owner_id, role_name, expect_errors=True)
self.assertEqual(delete_resp.status_code, 404)
self.assertIn('is not found for the cluster', delete_resp.body)
def test_delete_assigned_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create(
nodes_kwargs=[
{'roles': [role['name']], 'pending_addition': True},
{'pending_roles': [role['name']]},
],
cluster_kwargs={'release_id': self.release.id},
)
@ -154,14 +341,25 @@ class TestRoleApi(BaseRoleTest):
owner_type, owner_id, role['name'], expect_errors=True)
self.assertEqual(delete_resp.status_code, 400)
def test_delete_role_when_assigned_another_role(self):
def test_delete_assigned_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create_node(api=False, cluster_id=self.cluster.id,
pending_roles=[role['name']])
delete_resp = self.env.delete_role(
owner_type, owner_id, role['name'], expect_errors=True)
self.assertEqual(delete_resp.status_code, 400)
def test_delete_release_role_when_assigned_another_role(self):
# There was bug with such validation
# https://bugs.launchpad.net/fuel/+bug/1488091
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create(
nodes_kwargs=[
{'roles': ['compute'], 'pending_addition': True},
{'pending_roles': ['compute']},
],
cluster_kwargs={'release_id': self.release.id},
)
@ -169,12 +367,29 @@ class TestRoleApi(BaseRoleTest):
delete_resp = self.env.delete_role(owner_type, owner_id, role['name'])
self.assertEqual(delete_resp.status_code, 204)
def test_delete_pending_assigned_role(self):
owner_type, owner_id = 'releases', self.release.id
def test_delete_cluster_role_when_assigned_another_role(self):
# There was bug with such validation
# https://bugs.launchpad.net/fuel/+bug/1488091
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create(
nodes_kwargs=[
{'pending_roles': [role['name']], 'pending_addition': True},
{'pending_roles': ['compute']},
],
cluster_kwargs={'release_id': self.release.id},
)
delete_resp = self.env.delete_role(owner_type, owner_id, role['name'])
self.assertEqual(delete_resp.status_code, 204)
def test_delete_pending_assigned_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create(
nodes_kwargs=[
{'pending_roles': [role['name']]},
],
cluster_kwargs={'release_id': self.release.id},
)
@ -183,16 +398,39 @@ class TestRoleApi(BaseRoleTest):
owner_type, owner_id, role['name'], expect_errors=True)
self.assertEqual(delete_resp.status_code, 400)
def test_get_role(self):
def test_delete_pending_assigned_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
role = self.env.create_role(owner_type, owner_id, self.role_data).json
self.env.create_node(api=False, cluster_id=self.cluster.id,
pending_addition=True,
pending_roles=[role['name']])
delete_resp = self.env.delete_role(
owner_type, owner_id, role['name'], expect_errors=True)
self.assertEqual(delete_resp.status_code, 400)
def test_get_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role = self.env.get_role(owner_type, owner_id, self.role_data['name'])
self.assertEqual(role.status_code, 200)
self.assertEqual(role.json['name'], self.role_data['name'])
def test_get_role_not_present(self):
def test_get_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role = self.env.get_role(owner_type, owner_id, self.role_data['name'])
self.assertEqual(role.status_code, 200)
self.assertEqual(role.json['name'], self.role_data['name'])
def test_get_release_role_not_present(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
resp = self.env.get_role(
@ -200,7 +438,17 @@ class TestRoleApi(BaseRoleTest):
self.assertEqual(resp.status_code, 404)
self.assertIn('is not found for the release', resp.body)
def test_create_role_with_special_symbols(self):
def test_get_cluster_role_not_present(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
role_name = 'blah_role'
resp = self.env.get_role(
owner_type, owner_id, role_name, expect_errors=True)
self.assertEqual(resp.status_code, 404)
self.assertIn('is not found for the cluster', resp.body)
def test_create_release_role_with_special_symbols(self):
owner_type, owner_id = 'releases', self.release.id
self.role_data['name'] = '@#$%^&*()'
resp = self.env.create_role(
@ -208,6 +456,14 @@ class TestRoleApi(BaseRoleTest):
self.assertEqual(resp.status_code, 400)
def test_create_cluster_role_with_special_symbols(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.role_data['name'] = '@#$%^&*()'
resp = self.env.create_role(
owner_type, owner_id, self.role_data, expect_errors=True)
self.assertEqual(resp.status_code, 400)
class TestFullDataRole(BaseRoleTest):
@ -235,12 +491,68 @@ meta:
- condition: "cluster:mode == 'multinode'"
action: hide
message: "Multi-node environment can not have more."
tags:
- my_tag
volumes_roles_mapping:
- id: os
allocate_size: all
"""
def test_create_role(self):
def test_create_release_role(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
self.assertEqual(resp.json['meta'], self.role_data['meta'])
def test_create_cluster_role(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
self.assertEqual(resp.json['meta'], self.role_data['meta'])
def test_update_release_role_delete_tag(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
cluster = self.env.create(
api=False,
cluster_kwargs={
'release_id': owner_id
},
nodes_kwargs=[
{'pending_roles': [self.role_data['name']]},
{'pending_roles': [self.role_data['name']]},
{'pending_roles': [self.role_data['name']]}])
objects.Cluster.set_primary_tags(cluster, cluster.nodes)
self.assertIsNotNone(
objects.Cluster.get_primary_node(cluster, self.tag_data['name']))
data = resp.json
data['meta']['tags'].remove(self.tag_data['name'])
self.env.update_role(owner_type, owner_id, self.role_data['name'],
data)
self.assertIsNone(
objects.Cluster.get_primary_node(cluster, self.tag_data['name']))
def test_update_cluster_role_delete_tag(self):
owner_type, owner_id = 'clusters', self.cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
resp = self.env.create_role(owner_type, owner_id, self.role_data)
self.env.create_node(api=False, cluster_id=self.cluster.id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=self.cluster.id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=self.cluster.id,
pending_roles=[self.role_data['name']])
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
self.assertIsNotNone(
objects.Cluster.get_primary_node(self.cluster,
self.tag_data['name']))
data = resp.json
data['meta']['tags'].remove(self.tag_data['name'])
self.env.update_role(owner_type, owner_id, self.role_data['name'],
data)
self.assertIsNone(
objects.Cluster.get_primary_node(self.cluster,
self.tag_data['name']))

View File

@ -85,7 +85,8 @@ class TestRoles(BaseIntegrationTest):
"name": duplicated_role,
"meta": {
"name": "yep role",
"description": ""
"description": "",
"tags": []
},
"volumes_roles_mapping": [{
"id": "os",

View File

@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from nailgun import objects
from nailgun.test import base
@ -21,8 +22,22 @@ class TestReleaseTagsHandler(base.BaseTestCase):
def setUp(self):
super(TestReleaseTagsHandler, self).setUp()
self.release = self.env.create_release()
self.tag_data = {'name': 'my_tag', 'meta': {'has_primary': False}}
self.cluster = self.env.create(api=False,
nodes_kwargs=[
{'pending_roles': ['controller']},
{'pending_roles': ['controller']},
{'pending_roles': ['controller']}])
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
self.release = self.cluster.release
self.tag_data = {'name': 'my_tag', 'meta': {'has_primary': True}}
self.role_data = {'name': 'my_role',
'meta': {'name': 'My Role',
'description': 'Something goes here',
'tags': ['my_tag']
},
'volumes_roles_mapping':
[{'id': 'os', 'allocate_size': 'all'}]}
def test_get_all_tags(self):
owner_type, owner_id = 'releases', self.release.id
@ -71,10 +86,26 @@ class TestReleaseTagsHandler(base.BaseTestCase):
def test_delete_tag(self):
owner_type, owner_id = 'releases', self.release.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
cluster = self.env.create(
cluster_kwargs={'release_id': self.release.id})
self.env.create_role('clusters', cluster.id, self.role_data)
self.env.create_node(api=False, cluster_id=cluster.id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=cluster.id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=cluster.id,
pending_roles=[self.role_data['name']])
objects.Cluster.set_primary_tags(cluster, cluster.nodes)
delete_resp = self.env.delete_tag(
owner_type, owner_id, self.tag_data['name'])
self.assertEqual(delete_resp.status_code, 204)
self.assertNotIn(
self.tag_data['name'],
cluster.roles_metadata[self.role_data['name']]['tags'])
for node in cluster.nodes:
self.assertNotIn(self.tag_data['name'], node.primary_tags)
def test_delete_tag_not_present(self):
owner_type, owner_id = 'releases', self.release.id
@ -115,8 +146,21 @@ class TestClusterTagsHandler(base.BaseTestCase):
def setUp(self):
super(TestClusterTagsHandler, self).setUp()
self.cluster = self.env.create_cluster(api=False)
self.tag_data = {'name': 'my_tag', 'meta': {'has_primary': False}}
self.cluster = self.env.create(api=False,
nodes_kwargs=[
{'pending_roles': ['controller']},
{'pending_roles': ['controller']},
{'pending_roles': ['controller']}])
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
self.tag_data = {'name': 'my_tag', 'meta': {'has_primary': True}}
self.release = self.cluster.release
self.role_data = {'name': 'my_role',
'meta': {'name': 'My Role',
'description': 'Something goes here',
'tags': ['my_tag']
},
'volumes_roles_mapping':
[{'id': 'os', 'allocate_size': 'all'}]}
def test_get_all_tags(self):
owner_type, owner_id = 'clusters', self.cluster.id
@ -160,12 +204,26 @@ class TestClusterTagsHandler(base.BaseTestCase):
self.assertEqual(tag.json['name'], self.tag_data['name'])
def test_delete_tag(self):
owner_type, owner_id = 'clusters', self.cluster.id
cluster = self.env.create(
cluster_kwargs={'release_id': self.release.id})
owner_type, owner_id = 'clusters', cluster.id
self.env.create_tag(owner_type, owner_id, self.tag_data)
self.env.create_role(owner_type, owner_id, self.role_data)
self.env.create_node(api=False, cluster_id=owner_id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=owner_id,
pending_roles=[self.role_data['name']])
self.env.create_node(api=False, cluster_id=owner_id,
pending_roles=[self.role_data['name']])
objects.Cluster.set_primary_tags(cluster, cluster.nodes)
delete_resp = self.env.delete_tag(
owner_type, owner_id, self.tag_data['name'])
self.assertEqual(delete_resp.status_code, 204)
self.assertNotIn(
self.tag_data['name'],
cluster.roles_metadata[self.role_data['name']]['tags'])
for node in cluster.nodes:
self.assertNotIn(self.tag_data['name'], node.primary_tags)
def test_error_tag_not_present(self):
owner_type, owner_id = 'clusters', self.cluster.id

View File

@ -207,6 +207,7 @@ class TestAssignmentHandlers(BaseIntegrationTest):
name: "Some plugin role"
description: "Some description"
conflicts: "*"
tags: []
volumes_roles_mapping:
- id: os
allocate_size: all

View File

@ -53,6 +53,18 @@ class TestHandlers(BaseIntegrationTest):
expect_errors=True)
self.assertEqual(resp.status_code, 400)
def test_release_non_existent_tag_present_in_role(self):
roles_meta = {
'controller': {
'tags': ['test']
}
}
resp = self.env.create_release(api=True,
expect_errors=True,
roles_metadata=roles_meta)
self.assertIn("are present for role controller, but, absent in",
resp['message'])
def test_release_delete_returns_400_if_clusters(self):
cluster = self.env.create_cluster(api=False)
resp = self.app.delete(

View File

@ -53,5 +53,7 @@ class TestRoleVolumeAllocationsValidationBySchema(BaseUnitTest):
RoleValidator.validate_schema(restrictions, base_types.RESTRICTIONS)
def test_meta_info(self):
meta = {'name': 'Some Name', 'description': 'Some Description'}
meta = {'name': 'Some Name',
'description': 'Some Description',
'tags': []}
RoleValidator.validate_schema(meta, role.ROLE_META_INFO)