Fix role validation in release PUT handler

Plugins' roles can be assigned to some nodes, so we can't
assume that release roles is be a superset of node roles
everywhere.

So check that there are no nodes in all clusters, which
have roles assigned, that we are trying top delete.

Change-Id: Ia10f7b0662866da0872863bba7f97c8ad361fcf4
Closes-Bug: #1625592
This commit is contained in:
Dmitry Guryanov 2016-09-21 15:54:07 +03:00
parent c173e7c693
commit 78fbccc9ac
3 changed files with 54 additions and 13 deletions

View File

@ -94,27 +94,29 @@ class ReleaseValidator(BasicValidator):
)
if 'roles_metadata' in d:
new_roles = set(d['roles_metadata'])
clusters = [cluster.id for cluster in instance.clusters]
deleted_roles = (set(instance.roles_metadata) -
set(d['roles_metadata']))
clusters_ids = (cluster.id for cluster in instance.clusters)
new_roles_array = sa.cast(
psql.array(new_roles),
deleted_roles_array = sa.cast(
psql.array(deleted_roles),
psql.ARRAY(sa.String(consts.ROLE_NAME_MAX_SIZE)))
node = db().query(models.Node).filter(
models.Node.cluster_id.in_(clusters)
).filter(sa.not_(sa.and_(
models.Node.roles.contained_by(new_roles_array),
models.Node.pending_roles.contained_by(new_roles_array)
))).first()
models.Node.cluster_id.in_(clusters_ids)
).filter(sa.or_(
models.Node.roles.overlap(deleted_roles_array),
models.Node.pending_roles.overlap(deleted_roles_array)
)).first()
if node:
used_role = set(node.roles + node.pending_roles)
used_role -= new_roles
used_role = used_role.intersection(deleted_roles)
raise errors.CannotDelete(
"Cannot delete roles already assigned "
"to nodes: {0}".format(','.join(used_role))
"The following roles: {0} cannot be deleted "
"since they are already assigned "
"to nodes.".format(','.join(used_role))
)
return d

View File

@ -146,5 +146,6 @@ class TestRoles(BaseIntegrationTest):
self.assertEqual(resp.status_code, 400)
self.assertEqual(
resp.json_body["message"],
"Cannot delete roles already assigned to nodes: controller"
"The following roles: controller cannot be deleted "
"since they are already assigned to nodes."
)

View File

@ -16,6 +16,7 @@ from oslo_serialization import jsonutils
from nailgun.api.v1.validators.release import ReleaseValidator
from nailgun import errors
from nailgun.test.base import BaseTestCase
from nailgun.utils import reverse
class TestReleaseValidator(BaseTestCase):
@ -62,3 +63,40 @@ class TestReleaseValidator(BaseTestCase):
def test_default_are_good(self):
self.validator.validate(self.get_release(self.release))
def test_release_delete_role(self):
cluster = self.env.create(
nodes_kwargs=[{
"roles": ['test_plugin_role_1'],
"pending_roles": ['cinder', 'test_plugin_role_2'],
}])
resp = self.app.get(
reverse('ReleaseHandler',
kwargs={'obj_id': cluster.release.id}),
headers=self.default_headers
)
data = dict(resp.json_body)
resp = self.app.put(
reverse('ReleaseHandler',
kwargs={'obj_id': cluster.release.id}),
params=jsonutils.dumps(data),
headers=self.default_headers,
expect_errors=False
)
data['roles_metadata'].pop('cinder')
resp = self.app.put(
reverse('ReleaseHandler',
kwargs={'obj_id': cluster.release.id}),
params=jsonutils.dumps(data),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(resp.status_code, 400)
self.assertIn(
"The following roles: cinder cannot be deleted",
resp.json_body["message"],
)