Versions of a plugin have been placed in a separate container
Closes-Bug: #1440046
Closes-Bug: #1518993
Change-Id: I76655541fd7c00cdd863e145b28fba804b4ed801
(cherry picked from commit f83c4ea23b
)
This commit is contained in:
parent
d35b2728ba
commit
fe13a32863
|
@ -21,22 +21,20 @@ Handlers dealing with clusters
|
|||
import traceback
|
||||
|
||||
from nailgun.api.v1.handlers.base import BaseHandler
|
||||
from nailgun.api.v1.handlers.base import CollectionHandler
|
||||
from nailgun.api.v1.handlers.base import content
|
||||
from nailgun.api.v1.handlers.base import DeferredTaskHandler
|
||||
from nailgun.api.v1.handlers.base import DeploymentTasksHandler
|
||||
|
||||
from nailgun.api.v1.handlers.base import CollectionHandler
|
||||
from nailgun.api.v1.handlers.base import SingleHandler
|
||||
|
||||
from nailgun import objects
|
||||
|
||||
from nailgun.api.v1.handlers.base import content
|
||||
|
||||
from nailgun.api.v1.validators.cluster import AttributesValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterChangesValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterValidator
|
||||
from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
|
||||
|
||||
from nailgun.logger import logger
|
||||
from nailgun import objects
|
||||
|
||||
from nailgun.task.manager import ApplyChangesTaskManager
|
||||
from nailgun.task.manager import ClusterDeletionManager
|
||||
from nailgun.task.manager import ResetEnvironmentTaskManager
|
||||
|
@ -159,6 +157,7 @@ class ClusterAttributesHandler(BaseHandler):
|
|||
|
||||
:http: * 200 (OK)
|
||||
* 400 (wrong attributes data specified)
|
||||
* 403 (attribute changing is not allowed)
|
||||
* 404 (cluster not found in db)
|
||||
* 500 (cluster has no attributes)
|
||||
"""
|
||||
|
@ -168,24 +167,8 @@ class ClusterAttributesHandler(BaseHandler):
|
|||
raise self.http(500, "No attributes found!")
|
||||
|
||||
data = self.checked_data(cluster=cluster)
|
||||
|
||||
# if cluster is locked we have to check which attributes
|
||||
# we want to change and block an entire operation if there
|
||||
# one with always_editable=False.
|
||||
if cluster.is_locked:
|
||||
editable = objects.Cluster.get_editable_attributes(
|
||||
cluster, all_plugins_versions=True)
|
||||
|
||||
for group_name in data.get('editable', {}):
|
||||
# we need bunch of gets because the attribute may not
|
||||
# even exist (user adds a new one)
|
||||
metadata = editable.get(group_name, {}).get('metadata', {})
|
||||
if not metadata.get('always_editable'):
|
||||
raise self.http(403, (
|
||||
"Environment attribute '{0}' couldn't be changed "
|
||||
"after or during deployment.".format(group_name)))
|
||||
|
||||
objects.Cluster.patch_attributes(cluster, data)
|
||||
|
||||
return {
|
||||
'editable': objects.Cluster.get_editable_attributes(
|
||||
cluster, all_plugins_versions=True)
|
||||
|
|
|
@ -26,11 +26,11 @@ from nailgun.api.v1.validators.json_schema import cluster as cluster_schema
|
|||
from nailgun.api.v1.validators.node import ProvisionSelectedNodesValidator
|
||||
|
||||
from nailgun import consts
|
||||
|
||||
from nailgun.db import db
|
||||
from nailgun.db.sqlalchemy.models import Node
|
||||
from nailgun.errors import errors
|
||||
from nailgun import objects
|
||||
from nailgun.plugins.manager import PluginManager
|
||||
from nailgun.utils import restrictions
|
||||
|
||||
|
||||
|
@ -274,31 +274,30 @@ class AttributesValidator(BasicValidator):
|
|||
attrs = d
|
||||
if cluster is not None:
|
||||
attrs = objects.Cluster.get_updated_editable_attributes(cluster, d)
|
||||
|
||||
# NOTE(agordeev): disable classic provisioning for 7.0 or higher
|
||||
if StrictVersion(cluster.release.environment_version) >= \
|
||||
StrictVersion(consts.FUEL_IMAGE_BASED_ONLY):
|
||||
provision_data = attrs['editable'].get('provision')
|
||||
if provision_data:
|
||||
if provision_data['method']['value'] != \
|
||||
consts.PROVISION_METHODS.image:
|
||||
raise errors.InvalidData(
|
||||
u"Cannot use classic provisioning for adding "
|
||||
u"nodes to environment",
|
||||
log_message=True)
|
||||
else:
|
||||
raise errors.InvalidData(
|
||||
u"Provisioning method is not set. Unable to continue",
|
||||
log_message=True)
|
||||
|
||||
cls.validate_plugin_attributes(
|
||||
cluster, attrs.get('editable', {})
|
||||
)
|
||||
|
||||
cls.validate_provision(cluster, attrs)
|
||||
cls.validate_allowed_attributes(cluster, d)
|
||||
cls.validate_editable_attributes(attrs)
|
||||
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def validate_provision(cls, cluster, attrs):
|
||||
# NOTE(agordeev): disable classic provisioning for 7.0 or higher
|
||||
if StrictVersion(cluster.release.environment_version) >= \
|
||||
StrictVersion(consts.FUEL_IMAGE_BASED_ONLY):
|
||||
provision_data = attrs['editable'].get('provision')
|
||||
if provision_data:
|
||||
if provision_data['method']['value'] != \
|
||||
consts.PROVISION_METHODS.image:
|
||||
raise errors.InvalidData(
|
||||
u"Cannot use classic provisioning for adding "
|
||||
u"nodes to environment",
|
||||
log_message=True)
|
||||
else:
|
||||
raise errors.InvalidData(
|
||||
u"Provisioning method is not set. Unable to continue",
|
||||
log_message=True)
|
||||
|
||||
@classmethod
|
||||
def validate_editable_attributes(cls, data):
|
||||
"""Validate 'editable' attributes."""
|
||||
|
@ -366,52 +365,62 @@ class AttributesValidator(BasicValidator):
|
|||
'[{0}] {1}'.format(attr_name, regex_err))
|
||||
|
||||
@classmethod
|
||||
def validate_plugin_attributes(cls, cluster, attributes):
|
||||
"""Validates Cluster-Plugins relations attributes
|
||||
def validate_allowed_attributes(cls, cluster, data):
|
||||
"""Validates if attributes are hot pluggable or not.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:param attributes: The editable attributes of the Cluster
|
||||
:type attributes: dict
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
:param data: Changed attributes of cluster
|
||||
:type data: dict
|
||||
:raises: errors.NotAllowed
|
||||
"""
|
||||
|
||||
# TODO(need to enable restrictions check for cluster attributes[1])
|
||||
# [1] https://bugs.launchpad.net/fuel/+bug/1519904
|
||||
# Validates only that plugin can be installed on deployed env.
|
||||
|
||||
# If cluster is locked we have to check which attributes
|
||||
# we want to change and block an entire operation if there
|
||||
# one with always_editable=False.
|
||||
if not cluster.is_locked:
|
||||
return
|
||||
|
||||
enabled_plugins = set(
|
||||
p.id for p in objects.ClusterPlugins.get_enabled(cluster.id)
|
||||
)
|
||||
editable_cluster = objects.Cluster.get_editable_attributes(
|
||||
cluster, all_plugins_versions=True)
|
||||
editable_request = data.get('editable', {})
|
||||
|
||||
for attrs in six.itervalues(attributes):
|
||||
if not isinstance(attrs, dict):
|
||||
continue
|
||||
for attr_name, attr_request in six.iteritems(editable_request):
|
||||
attr_cluster = editable_cluster.get(attr_name, {})
|
||||
meta_cluster = attr_cluster.get('metadata', {})
|
||||
meta_request = attr_request.get('metadata', {})
|
||||
|
||||
plugin_versions = attrs.get('plugin_versions', None)
|
||||
if plugin_versions is None:
|
||||
continue
|
||||
|
||||
if not attrs.get('metadata', {}).get('enabled'):
|
||||
continue
|
||||
|
||||
for version in plugin_versions['values']:
|
||||
plugin_id = version.get('data')
|
||||
plugin = objects.Plugin.get_by_uid(plugin_id)
|
||||
if not plugin:
|
||||
if PluginManager.is_plugin_data(attr_cluster):
|
||||
if meta_request['enabled']:
|
||||
changed_ids = [meta_request['chosen_id']]
|
||||
if meta_cluster['enabled']:
|
||||
changed_ids.append(meta_cluster['chosen_id'])
|
||||
changed_ids = set(changed_ids)
|
||||
elif meta_cluster['enabled']:
|
||||
changed_ids = [meta_cluster['chosen_id']]
|
||||
else:
|
||||
continue
|
||||
|
||||
if plugin_id != plugin_versions['value']:
|
||||
continue
|
||||
|
||||
if plugin.is_hotpluggable or plugin.id in enabled_plugins:
|
||||
break
|
||||
for plugin in meta_cluster['versions']:
|
||||
plugin_id = plugin['metadata']['plugin_id']
|
||||
always_editable = plugin['metadata']\
|
||||
.get('always_editable', False)
|
||||
if plugin_id in changed_ids and not always_editable:
|
||||
raise errors.NotAllowed(
|
||||
"Plugin '{0}' version '{1}' couldn't be changed "
|
||||
"after or during deployment."
|
||||
.format(attr_name,
|
||||
plugin['metadata']['plugin_version']),
|
||||
log_message=True
|
||||
)
|
||||
|
||||
elif not meta_cluster.get('always_editable', False):
|
||||
raise errors.NotAllowed(
|
||||
"This plugin version can be enabled only "
|
||||
"before environment is deployed.",
|
||||
"Environment attribute '{0}' couldn't be changed "
|
||||
"after or during deployment.".format(attr_name),
|
||||
log_message=True
|
||||
)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
from nailgun.api.v1.validators.base import BasicValidator
|
||||
from nailgun.api.v1.validators.json_schema import plugin
|
||||
from nailgun.errors import errors
|
||||
from nailgun.objects import ClusterPlugins
|
||||
from nailgun.objects import Plugin
|
||||
|
||||
|
||||
|
@ -24,7 +25,7 @@ class PluginValidator(BasicValidator):
|
|||
|
||||
@classmethod
|
||||
def validate_delete(cls, data, instance):
|
||||
if instance.clusters:
|
||||
if ClusterPlugins.is_plugin_used(instance.id):
|
||||
raise errors.CannotDelete(
|
||||
"Can't delete plugin which is enabled "
|
||||
"for some environment."
|
||||
|
|
|
@ -40,6 +40,13 @@
|
|||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
},
|
||||
{
|
||||
"os": "ubuntu",
|
||||
"version": "2016.1.0-9.0",
|
||||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
}
|
||||
],
|
||||
"package_version": "2.0.0",
|
||||
|
@ -86,6 +93,13 @@
|
|||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
},
|
||||
{
|
||||
"os": "ubuntu",
|
||||
"version": "2016.1.0-9.0",
|
||||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
}
|
||||
],
|
||||
"package_version": "2.0.0"
|
||||
|
@ -126,10 +140,25 @@
|
|||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
},
|
||||
{
|
||||
"os": "ubuntu",
|
||||
"version": "2016.1.0-9.0",
|
||||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
}
|
||||
],
|
||||
"package_version": "2.0.0",
|
||||
"attributes_metadata": {
|
||||
"metadata": {
|
||||
"restrictions": [
|
||||
{
|
||||
"condition": "settings:common.use_vcenter.value == true",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
},
|
||||
"zabbix_text_1": {
|
||||
"value": "value 1.1",
|
||||
"type": "text",
|
||||
|
@ -175,23 +204,89 @@
|
|||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
},
|
||||
{
|
||||
"os": "ubuntu",
|
||||
"version": "2016.1.0-9.0",
|
||||
"mode": ["ha"],
|
||||
"deployment_scripts_path": "deployment_scripts/",
|
||||
"repository_path": "repositories/ubuntu"
|
||||
}
|
||||
],
|
||||
"package_version": "2.0.0",
|
||||
"attributes_metadata": {
|
||||
"metadata": {
|
||||
"restrictions": [
|
||||
{
|
||||
"condition": "cluster:net_provider != 'neutron'",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
},
|
||||
"zabbix_text_1": {
|
||||
"value": "value 2.1",
|
||||
"type": "text",
|
||||
"description": "description 2.1",
|
||||
"weight": 25,
|
||||
"label": "label 2.1"
|
||||
"label": "Label of text field 2.1",
|
||||
"description": "Description of text field 2.1",
|
||||
"weight": 20,
|
||||
"type": "text"
|
||||
},
|
||||
"zabbix_text_2": {
|
||||
"value": "value 2.2",
|
||||
"label": "Label of text field 2.2",
|
||||
"description": "Description of text field 2.2",
|
||||
"weight": 21,
|
||||
"type": "text"
|
||||
},
|
||||
"zabbix_text_with_regex": {
|
||||
"value": "",
|
||||
"label": "Label of text field with regex (type 'aa-aa')",
|
||||
"description": "Some description of text field with regex",
|
||||
"weight": 30,
|
||||
"type": "text",
|
||||
"description": "description 2.2",
|
||||
"weight": 26,
|
||||
"label": "label 2.2"
|
||||
"regex": {
|
||||
"source": "^(?:[a-z]+-[a-z0-9]+)(?:,[a-z]+-[a-z0-9]+)*",
|
||||
"error": "Invalid value in text field with regex"
|
||||
}
|
||||
},
|
||||
"zabbix_checkbox": {
|
||||
"value": false,
|
||||
"label": "Hide file selector",
|
||||
"description": "If True then file field will be hidden",
|
||||
"weight": 40,
|
||||
"type": "checkbox"
|
||||
},
|
||||
"zabbix_file": {
|
||||
"value": "",
|
||||
"label": "Select file",
|
||||
"description": "Description of file field",
|
||||
"weight": 41,
|
||||
"type": "file",
|
||||
"restrictions": [
|
||||
{
|
||||
"condition": "settings:zabbix_monitoring.zabbix_checkbox.value == true",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
},
|
||||
"zabbix_checkbox_long_name": {
|
||||
"value": true,
|
||||
"label": "Show text field",
|
||||
"description": "If True then text field will be shown",
|
||||
"weight": 50,
|
||||
"type": "checkbox"
|
||||
},
|
||||
"zabbix_text_3": {
|
||||
"value": "",
|
||||
"label": "Label of text field 2.3",
|
||||
"description": "Description of text field 2.3",
|
||||
"weight": 51,
|
||||
"type": "text",
|
||||
"restrictions": [
|
||||
{
|
||||
"condition": "settings:zabbix_monitoring.zabbix_checkbox_long_name.value == false",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,9 +131,9 @@ class ClusterPlugins(NailgunObject):
|
|||
- release version
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
:param plugin: A plugin instance
|
||||
:type plugin: nailgun.objects.plugin.Plugin
|
||||
:type plugin: nailgun.db.sqlalchemy.models.plugins.Plugin
|
||||
:return: True if compatible, False if not
|
||||
:rtype: bool
|
||||
"""
|
||||
|
@ -176,7 +176,7 @@ class ClusterPlugins(NailgunObject):
|
|||
"""Returns a list of plugins that are compatible with a given cluster.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
:return: A list of plugin instances
|
||||
:rtype: list
|
||||
"""
|
||||
|
@ -189,14 +189,16 @@ class ClusterPlugins(NailgunObject):
|
|||
"""Populates 'cluster_plugins' table with compatible plugins.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
"""
|
||||
for plugin in cls.get_compatible_plugins(cluster):
|
||||
plugin_attributes = dict(plugin.attributes_metadata)
|
||||
plugin_attributes.pop('metadata', None)
|
||||
cls.create({
|
||||
'cluster_id': cluster.id,
|
||||
'plugin_id': plugin.id,
|
||||
'enabled': False,
|
||||
'attributes': plugin.attributes_metadata
|
||||
'attributes': plugin_attributes
|
||||
})
|
||||
|
||||
@classmethod
|
||||
|
@ -204,7 +206,7 @@ class ClusterPlugins(NailgunObject):
|
|||
"""Returns a list of clusters that are compatible with a given plugin.
|
||||
|
||||
:param plugin: A plugin instance
|
||||
:type plugin: nailgun.objects.plugin.Plugin
|
||||
:type plugin: nailgun.db.sqlalchemy.models.plugins.Plugin
|
||||
:return: A list of cluster instances
|
||||
:rtype: list
|
||||
"""
|
||||
|
@ -217,14 +219,16 @@ class ClusterPlugins(NailgunObject):
|
|||
"""Populates 'cluster_plugins' table with compatible cluster.
|
||||
|
||||
:param plugin: A plugin instance
|
||||
:type plugin: nailgun.objects.plugin.Plugin
|
||||
:type plugin: nailgun.db.sqlalchemy.models.plugins.Plugin
|
||||
"""
|
||||
plugin_attributes = dict(plugin.attributes_metadata)
|
||||
plugin_attributes.pop('metadata', None)
|
||||
for cluster in cls.get_compatible_clusters(plugin):
|
||||
cls.create({
|
||||
'cluster_id': cluster.id,
|
||||
'plugin_id': plugin.id,
|
||||
'enabled': False,
|
||||
'attributes': plugin.attributes_metadata
|
||||
'attributes': plugin_attributes
|
||||
})
|
||||
|
||||
@classmethod
|
||||
|
@ -324,3 +328,18 @@ class ClusterPlugins(NailgunObject):
|
|||
.filter(cls.model.cluster_id == cluster_id)\
|
||||
.filter(cls.model.enabled.is_(True))\
|
||||
.order_by(models.Plugin.id)
|
||||
|
||||
@classmethod
|
||||
def is_plugin_used(cls, plugin_id):
|
||||
"""Check if plugin is used for any cluster or not.
|
||||
|
||||
:param plugin_id: Plugin ID
|
||||
:type plugin_id: int
|
||||
:return: True if some cluster uses this plugin
|
||||
:rtype: bool
|
||||
"""
|
||||
q = db().query(cls.model)\
|
||||
.filter(cls.model.plugin_id == plugin_id)\
|
||||
.filter(cls.model.enabled.is_(True))
|
||||
|
||||
return db().query(q.exists()).scalar()
|
||||
|
|
|
@ -28,58 +28,40 @@ class PluginManager(object):
|
|||
|
||||
@classmethod
|
||||
def process_cluster_attributes(cls, cluster, attributes):
|
||||
"""Generate Cluster-Plugins relation based on attributes
|
||||
"""Generate Cluster-Plugins relation based on attributes.
|
||||
|
||||
Iterates through plugins attributes, creates
|
||||
or deletes Cluster <-> Plugins relation if plugin
|
||||
is enabled or disabled.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
:param attributes: Cluster attributes
|
||||
:type attributes: dict
|
||||
"""
|
||||
def _convert_attrs(plugin_id, attrs):
|
||||
prefix = "#{0}_".format(plugin_id)
|
||||
result = dict((title[len(prefix):], attrs[title])
|
||||
for title in attrs
|
||||
if title.startswith(prefix))
|
||||
for attr in six.itervalues(result):
|
||||
if 'restrictions' not in attr:
|
||||
continue
|
||||
if len(attr['restrictions']) == 1:
|
||||
attr.pop('restrictions')
|
||||
else:
|
||||
attr['restrictions'].pop()
|
||||
return result
|
||||
plugins = {}
|
||||
|
||||
for attrs in six.itervalues(attributes):
|
||||
if not isinstance(attrs, dict):
|
||||
continue
|
||||
# Detach plugins data
|
||||
for k in list(attributes):
|
||||
if cls.is_plugin_data(attributes[k]):
|
||||
plugins[k] = attributes.pop(k)['metadata']
|
||||
cluster.attributes.editable.pop(k, None)
|
||||
|
||||
plugin_versions = attrs.pop('plugin_versions', None)
|
||||
if plugin_versions is None:
|
||||
continue
|
||||
|
||||
metadata = attrs.pop('metadata', {})
|
||||
plugin_enabled = metadata.get('enabled', False)
|
||||
default = metadata.get('default', False)
|
||||
|
||||
for version in plugin_versions['values']:
|
||||
pid = version.get('data')
|
||||
plugin = Plugin.get_by_uid(pid)
|
||||
for container in six.itervalues(plugins):
|
||||
default = container.get('default', False)
|
||||
for attrs in container.get('versions', []):
|
||||
version_metadata = attrs.pop('metadata')
|
||||
plugin_id = version_metadata['plugin_id']
|
||||
plugin = Plugin.get_by_uid(plugin_id)
|
||||
if not plugin:
|
||||
logger.warning(
|
||||
'Plugin with id "%s" is not found, skip it', pid)
|
||||
'Plugin with id "%s" is not found, skip it', plugin_id)
|
||||
continue
|
||||
|
||||
enabled = plugin_enabled and\
|
||||
pid == plugin_versions['value']
|
||||
|
||||
enabled = container['enabled']\
|
||||
and plugin_id == container['chosen_id']
|
||||
ClusterPlugins.set_attributes(
|
||||
cluster.id, plugin.id, enabled=enabled,
|
||||
attrs=_convert_attrs(plugin.id, attrs)
|
||||
if enabled or default else None
|
||||
attrs=attrs if enabled or default else None
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -88,7 +70,7 @@ class PluginManager(object):
|
|||
"""Gets attributes of all plugins connected with given cluster.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: nailgun.objects.cluster.Cluster
|
||||
:type cluster: nailgun.db.sqlalchemy.models.cluster.Cluster
|
||||
:param all_versions: True to get attributes of all versions of plugins
|
||||
:type all_versions: bool
|
||||
:param default: True to return a default plugins attributes (for UI)
|
||||
|
@ -96,80 +78,87 @@ class PluginManager(object):
|
|||
:return: Plugins attributes
|
||||
:rtype: dict
|
||||
"""
|
||||
versions = {
|
||||
'type': 'radio',
|
||||
'values': [],
|
||||
'weight': 10,
|
||||
'value': None,
|
||||
'label': 'Choose a plugin version'
|
||||
}
|
||||
|
||||
plugins_attributes = {}
|
||||
for plugin in ClusterPlugins.get_connected_plugins_data(cluster.id):
|
||||
plugin_id = str(plugin.id)
|
||||
enabled = plugin.enabled and not (all_versions and default)
|
||||
plugin_attributes = plugins_attributes.setdefault(plugin.name, {})
|
||||
metadata = plugin_attributes.setdefault('metadata', {
|
||||
'toggleable': True,
|
||||
'weight': 70
|
||||
})
|
||||
metadata['enabled'] = enabled or metadata.get('enabled', False)
|
||||
metadata['label'] = plugin.title
|
||||
if plugin.is_hotpluggable:
|
||||
metadata["always_editable"] = True
|
||||
default_attrs = plugin.attributes_metadata
|
||||
|
||||
if all_versions:
|
||||
metadata['default'] = default
|
||||
container = plugins_attributes.setdefault(plugin.name, {})
|
||||
enabled = plugin.enabled and not (all_versions and default)
|
||||
cls.create_common_metadata(plugin, container, enabled)
|
||||
container['metadata']['default'] = default
|
||||
|
||||
plugin_attributes.update(
|
||||
cls.convert_plugin_attributes(
|
||||
plugin,
|
||||
plugin.attributes_metadata
|
||||
if default else plugin.attributes
|
||||
)
|
||||
)
|
||||
|
||||
plugin_version = {
|
||||
'data': plugin_id,
|
||||
'description': '',
|
||||
'label': plugin.version,
|
||||
}
|
||||
if not plugin.is_hotpluggable:
|
||||
plugin_version['restrictions'] = [{
|
||||
'action': 'disable',
|
||||
'condition': 'cluster:is_locked'
|
||||
}]
|
||||
|
||||
plugin_versions = plugin_attributes.get('plugin_versions')
|
||||
if plugin_versions is not None:
|
||||
if enabled:
|
||||
plugin_versions['value'] = plugin_id
|
||||
versions = container['metadata'].setdefault('versions', [])
|
||||
if default:
|
||||
actual_attrs = copy.deepcopy(default_attrs)
|
||||
actual_attrs.setdefault('metadata', {})
|
||||
else:
|
||||
plugin_versions = copy.deepcopy(versions)
|
||||
plugin_versions['value'] = plugin_id
|
||||
plugin_attributes['plugin_versions'] = plugin_versions
|
||||
actual_attrs = copy.deepcopy(plugin.attributes)
|
||||
actual_attrs['metadata'] = default_attrs.get('metadata',
|
||||
{})
|
||||
cls.fill_plugin_metadata(
|
||||
plugin, actual_attrs['metadata'], True)
|
||||
versions.append(actual_attrs)
|
||||
|
||||
plugin_versions['values'].append(plugin_version)
|
||||
elif enabled:
|
||||
plugin_attributes.update(plugin.attributes)
|
||||
container['metadata'].setdefault('chosen_id', plugin.id)
|
||||
if enabled:
|
||||
container['metadata']['chosen_id'] = plugin.id
|
||||
|
||||
elif plugin.enabled:
|
||||
container = plugins_attributes.setdefault(plugin.name, {})
|
||||
cls.create_common_metadata(plugin, container)
|
||||
container['metadata'].update(default_attrs.get('metadata', {}))
|
||||
cls.fill_plugin_metadata(plugin, container['metadata'])
|
||||
container.update(plugin.attributes)
|
||||
|
||||
return plugins_attributes
|
||||
|
||||
@classmethod
|
||||
def convert_plugin_attributes(cls, plugin, attributes):
|
||||
def converter(plugin_id, plugin_name, title, attr):
|
||||
restrictions = attr.setdefault('restrictions', [])
|
||||
restrictions.append({
|
||||
'action': 'hide',
|
||||
'condition': "settings:{0}.plugin_versions.value != '{1}'"
|
||||
.format(plugin_name, plugin_id)
|
||||
})
|
||||
return "#{0}_{1}".format(plugin_id, title), attr
|
||||
def is_plugin_data(cls, attributes):
|
||||
"""Looking for a plugins hallmark.
|
||||
|
||||
return (
|
||||
converter(plugin.id, plugin.name, k, v)
|
||||
for k, v in six.iteritems(attributes)
|
||||
)
|
||||
:param attributes: Item of editable attributes of cluster
|
||||
:type attributes: dict
|
||||
:return: True if it's a plugins container
|
||||
:rtype: bool
|
||||
"""
|
||||
return attributes.get('metadata', {}).get('class') == 'plugin'
|
||||
|
||||
@classmethod
|
||||
def create_common_metadata(cls, plugin, attributes, enabled=None):
|
||||
"""Create common metadata attribute for all versions of plugin.
|
||||
|
||||
:param plugin: A plugin instance
|
||||
:type plugin: nailgun.db.sqlalchemy.models.plugins.Plugin
|
||||
:param attributes: Common attributes of plugin versions
|
||||
:type attributes: dict
|
||||
:param enabled: Plugin status
|
||||
:type enabled: bool
|
||||
"""
|
||||
metadata = attributes.setdefault('metadata', {
|
||||
'class': 'plugin',
|
||||
'toggleable': True,
|
||||
'weight': 70
|
||||
})
|
||||
metadata['label'] = plugin.title
|
||||
if enabled is None:
|
||||
enabled = plugin.enabled
|
||||
metadata['enabled'] = enabled or metadata.get('enabled', False)
|
||||
|
||||
@classmethod
|
||||
def fill_plugin_metadata(cls, plugin, metadata, all_versions=False):
|
||||
"""Fill a plugin's metadata attribute.
|
||||
|
||||
:param plugin: A plugin instance
|
||||
:type plugin: nailgun.db.sqlalchemy.models.plugins.Plugin
|
||||
:param metadata: Plugin metadata
|
||||
:type metadata: dict
|
||||
:param all_versions: Create for all versions of plugin or not
|
||||
:type all_versions: bool
|
||||
"""
|
||||
metadata['plugin_id'] = plugin.id
|
||||
metadata['plugin_version'] = plugin.version
|
||||
metadata['always_editable'] = plugin.is_hotpluggable
|
||||
|
||||
@classmethod
|
||||
def get_cluster_plugins_with_tasks(cls, cluster):
|
||||
|
@ -367,14 +356,13 @@ class PluginManager(object):
|
|||
|
||||
@classmethod
|
||||
def enable_plugins_by_components(cls, cluster):
|
||||
"""Enable plugin by components
|
||||
"""Enable plugin by components.
|
||||
|
||||
:param cluster: A cluster instance
|
||||
:type cluster: Cluster model
|
||||
:return: None
|
||||
"""
|
||||
cluster_components = set(cluster.components)
|
||||
plugin_ids = set(p.id for p in PluginCollection.all_newest())
|
||||
plugin_ids = [p.id for p in PluginCollection.all_newest()]
|
||||
|
||||
for plugin in ClusterPlugins.get_connected_plugins(
|
||||
cluster, plugin_ids):
|
||||
|
@ -383,6 +371,6 @@ class PluginManager(object):
|
|||
component['name']
|
||||
for component in plugin_adapter.components_metadata)
|
||||
|
||||
for component in cluster_components & plugin_components:
|
||||
if cluster_components & plugin_components:
|
||||
ClusterPlugins.set_attributes(
|
||||
cluster.id, plugin.id, enabled=True)
|
||||
|
|
|
@ -87,14 +87,14 @@ class TestAttributes(BaseIntegrationTest):
|
|||
kwargs={'cluster_id': cluster_id}),
|
||||
params=jsonutils.dumps({
|
||||
'editable': {
|
||||
"foo": "bar"
|
||||
'foo': {'bar': None}
|
||||
},
|
||||
}),
|
||||
headers=self.default_headers
|
||||
)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
attrs = objects.Cluster.get_editable_attributes(cluster_db)
|
||||
self.assertEqual("bar", attrs["foo"])
|
||||
self.assertEqual({'bar': None}, attrs["foo"])
|
||||
attrs.pop('foo')
|
||||
|
||||
# 400 on generated update
|
||||
|
@ -140,14 +140,14 @@ class TestAttributes(BaseIntegrationTest):
|
|||
kwargs={'cluster_id': cluster_id}),
|
||||
params=jsonutils.dumps({
|
||||
'editable': {
|
||||
"foo": "bar"
|
||||
'foo': {'bar': None}
|
||||
},
|
||||
}),
|
||||
headers=self.default_headers
|
||||
)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
attrs = objects.Cluster.get_editable_attributes(cluster_db)
|
||||
self.assertEqual("bar", attrs["foo"])
|
||||
self.assertEqual({'bar': None}, attrs["foo"])
|
||||
attrs.pop('foo')
|
||||
self.assertNotEqual(attrs, {})
|
||||
|
||||
|
@ -210,7 +210,7 @@ class TestAttributes(BaseIntegrationTest):
|
|||
kwargs={'cluster_id': cluster['id']}),
|
||||
params=jsonutils.dumps({
|
||||
'editable': {
|
||||
"foo": "bar"
|
||||
'foo': {'bar': None}
|
||||
},
|
||||
}),
|
||||
headers=self.default_headers,
|
||||
|
@ -218,7 +218,7 @@ class TestAttributes(BaseIntegrationTest):
|
|||
)
|
||||
self.assertEqual(200, resp.status_code, resp.body)
|
||||
attrs = objects.Cluster.get_editable_attributes(cluster_db)
|
||||
self.assertEqual("bar", attrs["foo"])
|
||||
self.assertEqual({'bar': None}, attrs['foo'])
|
||||
# Set attributes to defaults.
|
||||
resp = self.app.put(
|
||||
reverse(
|
||||
|
@ -758,7 +758,6 @@ class TestAttributesWithPlugins(BaseIntegrationTest):
|
|||
def test_change_plugins_attributes(self):
|
||||
plugin = self.env.create_plugin(cluster=self.cluster,
|
||||
**self.plugin_data)
|
||||
attr = '#{0}_attr'.format(plugin.id)
|
||||
|
||||
def _modify_plugin(enabled=True):
|
||||
return self.app.put(
|
||||
|
@ -769,30 +768,27 @@ class TestAttributesWithPlugins(BaseIntegrationTest):
|
|||
'editable': {
|
||||
plugin.name: {
|
||||
'metadata': {
|
||||
'class': 'plugin',
|
||||
'label': 'Test plugin',
|
||||
'toggleable': True,
|
||||
'weight': 70,
|
||||
'enabled': enabled
|
||||
'enabled': enabled,
|
||||
'chosen_id': plugin.id,
|
||||
'versions': [{
|
||||
'metadata': {
|
||||
'plugin_id': plugin.id,
|
||||
'plugin_version': plugin.version
|
||||
},
|
||||
'attr': {
|
||||
'type': 'text',
|
||||
'description': 'description',
|
||||
'label': 'label',
|
||||
'value': '1',
|
||||
'weight': 25,
|
||||
'restrictions': [{'action': 'hide'}]
|
||||
}
|
||||
}]
|
||||
},
|
||||
'plugin_versions': {
|
||||
'type': 'radio',
|
||||
'values': [{
|
||||
'data': str(plugin.id),
|
||||
'description': '',
|
||||
'label': '0.1.0'
|
||||
}],
|
||||
'weight': 10,
|
||||
'value': str(plugin.id),
|
||||
'label': 'Choose a plugin version'
|
||||
},
|
||||
attr: {
|
||||
'type': 'text',
|
||||
'description': 'description',
|
||||
'label': 'label',
|
||||
'value': '1',
|
||||
'weight': 25,
|
||||
'restrictions': [{'action': 'hide'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
@ -809,11 +805,9 @@ class TestAttributesWithPlugins(BaseIntegrationTest):
|
|||
resp = _modify_plugin(enabled=False)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
editable = objects.Cluster.get_editable_attributes(self.cluster)
|
||||
self.assertIn(plugin.name, editable)
|
||||
self.assertFalse(editable[plugin.name]['metadata']['enabled'])
|
||||
self.assertNotIn(attr, editable[plugin.name])
|
||||
self.assertNotIn(plugin.name, editable)
|
||||
|
||||
def _modify_plugin(self, plugin, enabled, **kwargs):
|
||||
def _modify_plugin(self, plugin, enabled):
|
||||
return self.app.put(
|
||||
reverse(
|
||||
'ClusterAttributesHandler',
|
||||
|
@ -821,18 +815,19 @@ class TestAttributesWithPlugins(BaseIntegrationTest):
|
|||
),
|
||||
params=jsonutils.dumps({
|
||||
'editable': {
|
||||
plugin.name: dict(
|
||||
metadata={'enabled': enabled},
|
||||
plugin_versions={
|
||||
'type': 'radio',
|
||||
'values': [{
|
||||
'data': str(plugin.id),
|
||||
'label': plugin.version
|
||||
}],
|
||||
'value': str(plugin.id),
|
||||
},
|
||||
**kwargs
|
||||
)
|
||||
plugin.name: {
|
||||
'metadata': {
|
||||
'class': 'plugin',
|
||||
'enabled': enabled,
|
||||
'chosen_id': plugin.id,
|
||||
'versions': [{
|
||||
'metadata': {
|
||||
'plugin_id': plugin.id,
|
||||
'plugin_version': plugin.version
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
headers=self.default_headers,
|
||||
|
|
|
@ -106,7 +106,7 @@ class TestClusterChanges(BaseIntegrationTest):
|
|||
kwargs={'cluster_id': cluster['id']}),
|
||||
jsonutils.dumps({
|
||||
'editable': {
|
||||
"foo": "bar"
|
||||
'foo': {'bar': None}
|
||||
}
|
||||
}),
|
||||
headers=self.default_headers
|
||||
|
|
|
@ -91,7 +91,7 @@ class TestNetworkModels(BaseIntegrationTest):
|
|||
kwargs={'cluster_id': self.env.clusters[0].id}),
|
||||
jsonutils.dumps({
|
||||
'editable': {
|
||||
"foo": "bar"
|
||||
"foo": {"bar": None}
|
||||
}
|
||||
}),
|
||||
headers=self.default_headers,
|
||||
|
|
|
@ -302,67 +302,65 @@ class TestPluginManager(base.BaseIntegrationTest):
|
|||
cluster=cluster, enabled=False
|
||||
)
|
||||
plugin_b = self.env.create_plugin(
|
||||
name='plugin_b', title='plugin_a_title', cluster=cluster
|
||||
name='plugin_b', title='plugin_a_title', cluster=cluster,
|
||||
attributes_metadata={
|
||||
'metadata': {
|
||||
'restrictions': [
|
||||
{
|
||||
"condition": "cluster:net_provider != 'neutron'",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
cluster.status = consts.CLUSTER_STATUSES.operational
|
||||
self.db.flush()
|
||||
self.assertTrue(cluster.is_locked)
|
||||
attributes = PluginManager.get_plugins_attributes(
|
||||
cluster, True, True
|
||||
cluster, all_versions=True, default=True
|
||||
)
|
||||
|
||||
pl_a1 = attributes['plugin_a']['metadata']['versions'][0]
|
||||
pl_a2 = attributes['plugin_a']['metadata']['versions'][1]
|
||||
pl_b = attributes['plugin_b']['metadata']['versions'][0]
|
||||
|
||||
self.assertItemsEqual(['plugin_a', 'plugin_b'], attributes)
|
||||
self.assertItemsEqual(
|
||||
{
|
||||
'plugin_id': plugin_a1.id,
|
||||
'plugin_version': plugin_a1.version,
|
||||
'always_editable': False
|
||||
}, pl_a1['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
['plugin_a', 'plugin_b'], attributes
|
||||
)
|
||||
self.assertTrue(
|
||||
attributes['plugin_a']['metadata']['always_editable']
|
||||
{
|
||||
'plugin_id': plugin_a2.id,
|
||||
'plugin_version': plugin_a2.version,
|
||||
'always_editable': True
|
||||
},
|
||||
pl_a2['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
[
|
||||
{
|
||||
'data': str(plugin_a1.id),
|
||||
'description': '',
|
||||
'label': plugin_a1.version,
|
||||
'restrictions': [
|
||||
{
|
||||
'action': 'disable',
|
||||
'condition': 'cluster:is_locked'
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'data': str(plugin_a2.id),
|
||||
'description': '',
|
||||
'label': plugin_a2.version
|
||||
}
|
||||
],
|
||||
attributes['plugin_a']['plugin_versions']['values']
|
||||
{
|
||||
'plugin_id': plugin_b.id,
|
||||
'plugin_version': plugin_b.version,
|
||||
'always_editable': False,
|
||||
'restrictions': [
|
||||
{
|
||||
"condition": "cluster:net_provider != 'neutron'",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
}, pl_b['metadata']
|
||||
)
|
||||
self.assertEqual(
|
||||
str(plugin_a1.id),
|
||||
attributes['plugin_a']['plugin_versions']['value']
|
||||
)
|
||||
self.assertNotIn(
|
||||
'always_editable', attributes['plugin_b']['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
[
|
||||
{
|
||||
'restrictions': [
|
||||
{
|
||||
'action': 'disable',
|
||||
'condition': 'cluster:is_locked'
|
||||
}
|
||||
],
|
||||
'data': str(plugin_b.id),
|
||||
'description': '',
|
||||
'label': plugin_b.version,
|
||||
},
|
||||
],
|
||||
attributes['plugin_b']['plugin_versions']['values']
|
||||
plugin_a1.id,
|
||||
attributes['plugin_a']['metadata']['chosen_id']
|
||||
)
|
||||
self.assertEqual(
|
||||
str(plugin_b.id),
|
||||
attributes['plugin_b']['plugin_versions']['value']
|
||||
plugin_b.id,
|
||||
attributes['plugin_b']['metadata']['chosen_id']
|
||||
)
|
||||
|
||||
def test_get_plugins_attributes_when_cluster_is_not_locked(self):
|
||||
|
@ -377,69 +375,67 @@ class TestPluginManager(base.BaseIntegrationTest):
|
|||
cluster=cluster, enabled=True
|
||||
)
|
||||
plugin_b = self.env.create_plugin(
|
||||
name='plugin_b', title='plugin_a_title', cluster=cluster
|
||||
name='plugin_b', title='plugin_a_title', cluster=cluster,
|
||||
attributes_metadata={
|
||||
'metadata': {
|
||||
'restrictions': [
|
||||
{
|
||||
"condition": "cluster:net_provider != 'neutron'",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertFalse(plugin_a1.is_hotpluggable)
|
||||
self.assertTrue(plugin_a2.is_hotpluggable)
|
||||
self.assertFalse(plugin_b.is_hotpluggable)
|
||||
self.assertFalse(cluster.is_locked)
|
||||
attributes = PluginManager.get_plugins_attributes(
|
||||
cluster, True, True
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
['plugin_a', 'plugin_b'], attributes
|
||||
)
|
||||
self.assertTrue(
|
||||
attributes['plugin_a']['metadata']['always_editable']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
[
|
||||
{
|
||||
'data': str(plugin_a1.id),
|
||||
'description': '',
|
||||
'label': plugin_a1.version,
|
||||
'restrictions': [
|
||||
{
|
||||
'action': 'disable',
|
||||
'condition': 'cluster:is_locked'
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'data': str(plugin_a2.id),
|
||||
'description': '',
|
||||
'label': plugin_a2.version
|
||||
}
|
||||
],
|
||||
attributes['plugin_a']['plugin_versions']['values']
|
||||
)
|
||||
self.assertEqual(
|
||||
str(plugin_a1.id),
|
||||
attributes['plugin_a']['plugin_versions']['value']
|
||||
)
|
||||
self.assertNotIn(
|
||||
'always_editable', attributes['plugin_b']['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
[
|
||||
{
|
||||
'restrictions': [
|
||||
{
|
||||
'action': 'disable',
|
||||
'condition': 'cluster:is_locked'
|
||||
}
|
||||
],
|
||||
'data': str(plugin_b.id),
|
||||
'description': '',
|
||||
'label': plugin_b.version,
|
||||
},
|
||||
],
|
||||
attributes['plugin_b']['plugin_versions']['values']
|
||||
cluster, all_versions=True, default=True
|
||||
)
|
||||
|
||||
pl_a1 = attributes['plugin_a']['metadata']['versions'][0]
|
||||
pl_a2 = attributes['plugin_a']['metadata']['versions'][1]
|
||||
pl_b = attributes['plugin_b']['metadata']['versions'][0]
|
||||
|
||||
self.assertItemsEqual(['plugin_a', 'plugin_b'], attributes)
|
||||
|
||||
self.assertItemsEqual(
|
||||
{
|
||||
'plugin_id': plugin_a1.id,
|
||||
'plugin_version': plugin_a1.version,
|
||||
'always_editable': False
|
||||
}, pl_a1['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
{
|
||||
'plugin_id': plugin_a2.id,
|
||||
'plugin_version': plugin_a2.version,
|
||||
'always_editable': True,
|
||||
},
|
||||
pl_a2['metadata']
|
||||
)
|
||||
self.assertItemsEqual(
|
||||
{
|
||||
'plugin_id': plugin_b.id,
|
||||
'plugin_version': plugin_b.version,
|
||||
'always_editable': False,
|
||||
'restrictions': [
|
||||
{
|
||||
"condition": "cluster:net_provider != 'neutron'",
|
||||
"action": "hide"
|
||||
}
|
||||
]
|
||||
}, pl_b['metadata']
|
||||
)
|
||||
self.assertEqual(
|
||||
str(plugin_b.id),
|
||||
attributes['plugin_b']['plugin_versions']['value']
|
||||
plugin_a1.id,
|
||||
attributes['plugin_a']['metadata']['chosen_id']
|
||||
)
|
||||
self.assertEqual(
|
||||
plugin_b.id,
|
||||
attributes['plugin_b']['metadata']['chosen_id']
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -123,8 +123,7 @@ class BasePluginTest(base.BaseIntegrationTest):
|
|||
editable_attrs = objects.Cluster.get_editable_attributes(
|
||||
cluster, all_plugins_versions=True)
|
||||
editable_attrs[plugin_name]['metadata']['enabled'] = enabled
|
||||
editable_attrs[plugin_name]['plugin_versions']['value'] = \
|
||||
str(plugin_id)
|
||||
editable_attrs[plugin_name]['metadata']['chosen_id'] = plugin_id
|
||||
|
||||
resp = self.app.put(
|
||||
base.reverse('ClusterAttributesHandler',
|
||||
|
@ -229,6 +228,12 @@ class TestPluginsApi(BasePluginTest):
|
|||
del_resp = self.delete_plugin(resp.json['id'])
|
||||
self.assertEqual(del_resp.status_code, 204)
|
||||
|
||||
def test_delete_unused_plugin(self):
|
||||
self.create_cluster()
|
||||
resp = self.create_plugin()
|
||||
del_resp = self.delete_plugin(resp.json['id'])
|
||||
self.assertEqual(del_resp.status_code, 204)
|
||||
|
||||
def test_no_delete_of_used_plugin(self):
|
||||
resp = self.create_plugin()
|
||||
plugin = objects.Plugin.get_by_uid(resp.json['id'])
|
||||
|
@ -262,8 +267,8 @@ class TestPluginsApi(BasePluginTest):
|
|||
default_attributes.json_body['editable'])
|
||||
|
||||
def test_attributes_after_plugin_is_created(self):
|
||||
sample = dict({
|
||||
"attributes_metadata": {
|
||||
sample = dict(
|
||||
attributes_metadata={
|
||||
"attr_text": {
|
||||
"value": "value",
|
||||
"type": "text",
|
||||
|
@ -271,13 +276,14 @@ class TestPluginsApi(BasePluginTest):
|
|||
"weight": 25,
|
||||
"label": "label"
|
||||
}
|
||||
}
|
||||
}, **self.sample_plugin)
|
||||
plugin = self.create_plugin(sample=sample).json_body
|
||||
}, **self.sample_plugin)
|
||||
self.create_plugin(sample=sample).json_body
|
||||
cluster = self.create_cluster()
|
||||
editable = self.default_attributes(cluster).json_body['editable']
|
||||
attr_name = "#{0}_{1}".format(plugin['id'], 'attr_text')
|
||||
self.assertIn(attr_name, editable[self.sample_plugin['name']])
|
||||
self.assertIn(
|
||||
'attr_text',
|
||||
editable[self.sample_plugin['name']]['metadata']['versions'][0]
|
||||
)
|
||||
|
||||
def test_plugins_multiversioning(self):
|
||||
def create_with_version(plugin_version):
|
||||
|
|
|
@ -164,3 +164,12 @@ class TestClusterPlugins(ExtraFunctions):
|
|||
|
||||
enabled_plugin = ClusterPlugins.get_enabled(cluster.id).first()
|
||||
self.assertEqual(plugin.id, enabled_plugin.id)
|
||||
|
||||
def test_is_plugin_used(self):
|
||||
self._create_test_plugins()
|
||||
cluster = self._create_test_cluster()
|
||||
|
||||
plugin = ClusterPlugins.get_connected_plugins(cluster).first()
|
||||
self.assertFalse(ClusterPlugins.is_plugin_used(plugin.id))
|
||||
ClusterPlugins.set_attributes(cluster.id, plugin.id, enabled=True)
|
||||
self.assertTrue(ClusterPlugins.is_plugin_used(plugin.id))
|
||||
|
|
Loading…
Reference in New Issue