Improve cluster extensions handlers
There handlers available under api/v1/clusters/{id}/extensions
* Re-work GET handler. Since now it's possible to enable extensions
in more granular way which doesn't affect already enabled
extensions.
* Add DELETE handler. Accepts comma separated list of extension
names to disable via query string under 'extension_names' param.
Change-Id: Idd5680b489b4003bb2f58b5279a7257a128cc4e1
Related-Bug: #1614526
(back ported from commit d9f01a6472
)
This commit is contained in:
parent
df40b377c0
commit
21f2a940fe
|
@ -42,7 +42,8 @@ from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
|
|||
from nailgun.api.v1.validators.extension import ExtensionValidator
|
||||
|
||||
from nailgun import errors
|
||||
from nailgun.extensions import set_extensions_for_object
|
||||
from nailgun.extensions import remove_extensions_from_object
|
||||
from nailgun.extensions import update_extensions_for_object
|
||||
|
||||
from nailgun.logger import logger
|
||||
from nailgun import objects
|
||||
|
@ -531,6 +532,32 @@ class ClusterExtensionsHandler(BaseHandler):
|
|||
* 404 (cluster not found in db)
|
||||
"""
|
||||
cluster = self._get_cluster_obj(cluster_id)
|
||||
data = set(self.checked_data())
|
||||
set_extensions_for_object(cluster, data)
|
||||
data = self.checked_data()
|
||||
update_extensions_for_object(cluster, data)
|
||||
return cluster.extensions
|
||||
|
||||
@handle_errors
|
||||
@validate
|
||||
def DELETE(self, cluster_id):
|
||||
"""Disables the extensions for specified cluster
|
||||
|
||||
Takes (JSONed) list of extension names to disable.
|
||||
|
||||
:http: * 204 (OK)
|
||||
* 400 (there is no such extension enabled)
|
||||
* 404 (cluster not found in db)
|
||||
"""
|
||||
cluster = self._get_cluster_obj(cluster_id)
|
||||
# TODO(agordeev): web.py does not support parsing of array arguments
|
||||
# in the queryset so we specify the input as comma-separated list
|
||||
extension_names = list(self.get_param_as_set('extension_names',
|
||||
default=[]))
|
||||
|
||||
try:
|
||||
data = self.validator.validate_delete(extension_names,
|
||||
cluster)
|
||||
except errors.CannotFindExtension as exc:
|
||||
raise self.http(400, exc.message)
|
||||
|
||||
remove_extensions_from_object(cluster, data)
|
||||
raise self.http(204)
|
||||
|
|
|
@ -35,4 +35,14 @@ class ExtensionValidator(BasicValidator):
|
|||
"No such extensions: {0}".format(
|
||||
", ".join(sorted(not_found_extensions))))
|
||||
|
||||
return data
|
||||
return list(data)
|
||||
|
||||
@classmethod
|
||||
def validate_delete(cls, extension_names, cluster):
|
||||
not_found_extensions = set(extension_names) - set(cluster.extensions)
|
||||
if not_found_extensions:
|
||||
raise errors.CannotFindExtension(
|
||||
"No such extensions to disable: {0}".format(
|
||||
", ".join(sorted(not_found_extensions))))
|
||||
|
||||
return list(extension_names)
|
||||
|
|
|
@ -33,5 +33,7 @@ from nailgun.extensions.manager import \
|
|||
fire_callback_on_cluster_serialization_for_provisioning
|
||||
from nailgun.extensions.manager import \
|
||||
fire_callback_on_node_serialization_for_provisioning
|
||||
from nailgun.extensions.manager import set_extensions_for_object
|
||||
from nailgun.extensions.manager import node_extension_call
|
||||
from nailgun.extensions.manager import remove_extensions_from_object
|
||||
from nailgun.extensions.manager import setup_yaql_context
|
||||
from nailgun.extensions.manager import update_extensions_for_object
|
||||
|
|
|
@ -60,8 +60,13 @@ def get_extension(name):
|
|||
"Cannot find extension with name '{0}'".format(name))
|
||||
|
||||
|
||||
def set_extensions_for_object(obj, extensions_names):
|
||||
obj.extensions = extensions_names
|
||||
def remove_extensions_from_object(obj, extensions_names):
|
||||
obj.extensions = list(set(obj.extensions) - set(extensions_names))
|
||||
db().flush()
|
||||
|
||||
|
||||
def update_extensions_for_object(obj, extensions_names):
|
||||
obj.extensions = list(set(obj.extensions + extensions_names))
|
||||
db().flush()
|
||||
|
||||
|
||||
|
|
|
@ -425,7 +425,8 @@ class TestClusterExtension(BaseIntegrationTest):
|
|||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.db.refresh(self.cluster)
|
||||
self.assertItemsEqual(self.cluster.extensions, extensions)
|
||||
for ext in extensions:
|
||||
self.assertIn(ext, self.cluster.extensions)
|
||||
|
||||
def test_enabling_extensions(self):
|
||||
extensions = 'bareon', 'volume_manager'
|
||||
|
@ -443,7 +444,8 @@ class TestClusterExtension(BaseIntegrationTest):
|
|||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.db.refresh(self.cluster)
|
||||
self.assertItemsEqual(self.cluster.extensions, extensions)
|
||||
for ext in extensions:
|
||||
self.assertIn(ext, self.cluster.extensions)
|
||||
|
||||
def test_enabling_invalid_extensions(self):
|
||||
existed_extensions = 'bareon', 'volume_manager'
|
||||
|
@ -464,3 +466,64 @@ class TestClusterExtension(BaseIntegrationTest):
|
|||
self.assertIn(u"No such extensions:", resp.json_body['message'])
|
||||
self.assertIn(requested_extensions[0], resp.json_body['message'])
|
||||
self.assertNotIn(requested_extensions[1], resp.json_body['message'])
|
||||
|
||||
def test_disabling_invalid_extensions(self):
|
||||
requested_extensions = 'network_manager', 'bareon'
|
||||
|
||||
self.cluster.extensions = 'volume_manager', 'bareon'
|
||||
self.db.commit()
|
||||
url = reverse('ClusterExtensionsHandler',
|
||||
kwargs={'cluster_id': self.cluster.id})
|
||||
query_str = 'extension_names={0}'.format(
|
||||
','.join(requested_extensions))
|
||||
|
||||
resp = self.app.delete(
|
||||
'{0}?{1}'.format(url, query_str),
|
||||
headers=self.default_headers,
|
||||
expect_errors=True,
|
||||
)
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
self.assertIn(u"No such extensions to disable:",
|
||||
resp.json_body['message'])
|
||||
self.assertIn(requested_extensions[0], resp.json_body['message'])
|
||||
self.assertNotIn(requested_extensions[1], resp.json_body['message'])
|
||||
|
||||
def test_disabling_extensions(self):
|
||||
existed_extensions = 'network_manager', 'volume_manager', 'bareon'
|
||||
requested_extensions = 'network_manager', 'bareon'
|
||||
|
||||
self.cluster.extensions = existed_extensions
|
||||
self.db.commit()
|
||||
url = reverse('ClusterExtensionsHandler',
|
||||
kwargs={'cluster_id': self.cluster.id})
|
||||
query_str = 'extension_names={0}'.format(
|
||||
','.join(requested_extensions))
|
||||
|
||||
self.app.delete(
|
||||
'{0}?{1}'.format(url, query_str),
|
||||
headers=self.default_headers,
|
||||
)
|
||||
|
||||
self.db.refresh(self.cluster)
|
||||
for ext in requested_extensions:
|
||||
self.assertNotIn(ext, self.cluster.extensions)
|
||||
|
||||
def test_disabling_dublicated_extensions(self):
|
||||
existed_extensions = 'network_manager', 'volume_manager', 'bareon'
|
||||
requested_extensions = 'network_manager', 'bareon'
|
||||
|
||||
self.cluster.extensions = existed_extensions
|
||||
self.db.commit()
|
||||
url = reverse('ClusterExtensionsHandler',
|
||||
kwargs={'cluster_id': self.cluster.id})
|
||||
query_str = 'extension_names={0}'.format(
|
||||
','.join(2 * requested_extensions))
|
||||
|
||||
self.app.delete(
|
||||
'{0}?{1}'.format(url, query_str),
|
||||
headers=self.default_headers,
|
||||
)
|
||||
|
||||
self.db.refresh(self.cluster)
|
||||
for ext in requested_extensions:
|
||||
self.assertNotIn(ext, self.cluster.extensions)
|
||||
|
|
|
@ -242,6 +242,23 @@ class TestPipeline(BaseExtensionCase):
|
|||
|
||||
class TestExtensionValidator(BaseTestCase):
|
||||
|
||||
def test_validate_delete_extensions(self):
|
||||
global_exts = 'volume_manager', 'bareon', 'ultralogger'
|
||||
cluster = mock.Mock()
|
||||
cluster.extensions = global_exts
|
||||
|
||||
ExtensionValidator.validate_delete(global_exts[:2], cluster)
|
||||
|
||||
def test_invalid_delete_extensions(self):
|
||||
global_exts = 'volume_manager', 'bareon', 'ultralogger'
|
||||
data = 'volume_manager', 'bareon', 'invalid'
|
||||
cluster = mock.Mock()
|
||||
cluster.extensions = global_exts
|
||||
|
||||
with self.assertRaisesRegexp(errors.CannotFindExtension,
|
||||
'No such extensions to disable: invalid'):
|
||||
ExtensionValidator.validate_delete(data, cluster)
|
||||
|
||||
def test_validate_extensions(self):
|
||||
global_exts = 'volume_manager', 'bareon', 'ultralogger'
|
||||
|
||||
|
|
Loading…
Reference in New Issue