def validate_allowed_attributes(cls, cluster, data): """Validates if attributes are hot pluggable or not. :param cluster: A cluster instance :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 editable_cluster = objects.Cluster.get_editable_attributes( cluster, all_plugins_versions=True) editable_request = data.get('editable', {}) 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', {}) 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 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( "Environment attribute '{0}' couldn't be changed " "after or during deployment.".format(attr_name), log_message=True )
def validate(cls, data): # TODO(enchantner): rewrite validators to use Node object data = cls.validate_json(data) if data.get("status", "") != "discover": raise errors.NotAllowed( "Only bootstrap nodes are allowed to be registered.") if 'mac' not in data: raise errors.InvalidData("No mac address specified", log_message=True) if cls.does_node_exist_in_db(data): raise errors.AlreadyExists("Node with mac {0} already " "exists - doing nothing".format( data["mac"]), log_level="info") if cls.validate_existent_node_mac_create(data): raise errors.AlreadyExists("Node with mac {0} already " "exists - doing nothing".format( data["mac"]), log_level="info") if 'meta' in data: MetaValidator.validate_create(data['meta']) return data
def validate(cls, data): data = cls.validate_json(data) cluster = objects.Cluster.get_by_uid(data['cluster_id'], fail_if_not_found=True) cls._validate_unique_name(data) if data.get('is_default'): raise errors.NotAllowed( "Default node group is created only by Nailgun.") if cluster.net_provider == consts.CLUSTER_NET_PROVIDERS.nova_network: raise errors.NotAllowed( "Node groups can only be created when using Neutron.") return data
def _validate_common(cls, data, instance=None): d = cls.validate_json(data) release_id = d.get("release", d.get("release_id")) if release_id: release = objects.Release.get_by_uid(release_id) if not release: raise errors.InvalidData("Invalid release ID", log_message=True) if not objects.Release.is_deployable(release): raise errors.NotAllowed( "Release with ID '{0}' is not deployable.".format( release_id), log_message=True) cls._validate_mode(d, release) pend_release_id = d.get("pending_release_id") if pend_release_id: pend_release = objects.Release.get_by_uid(pend_release_id, fail_if_not_found=True) if not release_id: if not instance: raise errors.InvalidData( "Cannot set pending release when " "there is no current release", log_message=True) release_id = instance.release_id curr_release = objects.Release.get_by_uid(release_id) if not cls._can_update_release(curr_release, pend_release): raise errors.InvalidData( "Cannot set pending release as " "it cannot update current release", log_message=True) return d
def validate(cls, data): data = cls.validate_json(data) cluster = objects.Cluster.get_by_uid(data['cluster_id']) if cluster.net_provider == consts.CLUSTER_NET_PROVIDERS.nova_network: raise errors.NotAllowed( "Node groups can only be created when using Neutron.") return data
def validate(cls, data): data = cls.validate_json(data) cluster = objects.Cluster.get_by_uid(data['cluster_id']) if (cluster.net_provider == consts.CLUSTER_NET_PROVIDERS.nova_network or cluster.network_config.segmentation_type != consts.NEUTRON_SEGMENT_TYPES.gre): raise errors.NotAllowed( "Node groups can only be created when using Neutron GRE.") return data
def _check_for_deployed_nodes(cls, cluster): """Check if nodes reconfiguration is allowed for cluster""" env_version = cluster.release.environment_version if not StrictVersion(env_version) >= StrictVersion('8.0'): if any( objects.Cluster.get_nodes_by_status( cluster, consts.NODE_STATUSES.ready)): raise errors.NotAllowed("Reconfiguration of nodes after the " "deployment is allowed only for " "environments 8.0 or greater.")
def _validate_default_flag(self, data): """Vadidate default flag Since changing of 'is_default' flag for node group is forbidden this method validate such case :param data: input request data :type data: dict """ nodegroup = objects.NodeGroupCollection.filter_by( None, name=data['name'], cluster_id=data['cluster_id']).first() if nodegroup and data['is_default'] != nodegroup.is_default: raise errors.NotAllowed( "'default' flag for node group cannot be changed")
def validate_update(cls, data, instance): data = cls.validate_json(data) cls._validate_unique_name(data, objects.NodeGroup.model.id != instance.id) if 'is_default' in data: cls._validate_default_flag(data) if 'cluster_id' in data and data['cluster_id'] != instance.cluster_id: raise errors.NotAllowed( "Node group cannot be assigned to other cluster " "after creation.") return data
def validate_plugin_attributes(cls, cluster, attributes): """Validates Cluster-Plugins relations attributes :param cluster: A cluster instance :type cluster: nailgun.objects.cluster.Cluster :param attributes: The editable attributes of the Cluster :type attributes: 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 not cluster.is_locked: return enabled_plugins = set( p.id for p in objects.ClusterPlugins.get_enabled(cluster.id) ) for attrs in six.itervalues(attributes): if not isinstance(attrs, dict): continue 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: continue if plugin_id != plugin_versions['value']: continue if plugin.is_hotpluggable or plugin.id in enabled_plugins: break raise errors.NotAllowed( "This plugin version can be enabled only " "before environment is deployed.", log_message=True )
def _check_no_running_deploy_tasks(cluster): """Check that no deploy tasks are running at the moment If there are running deploy tasks in cluster, NotAllowed exception raises. """ deploy_task_ids = [ six.text_type(task.id) for task in objects.TaskCollection.get_by_name_and_cluster( cluster, (consts.TASK_NAMES.deployment, )).filter( models.Task.status.in_(( consts.TASK_STATUSES.pending, consts.TASK_STATUSES.running))).all() ] if deploy_task_ids: raise errors.NotAllowed( "Cannot perform the action because there are " "running deployment tasks '{0}'" "".format(', '.join(deploy_task_ids)))
def validate_hostname(cls, hostname, instance): if hostname == instance.hostname: return if instance.status != consts.NODE_STATUSES.discover: raise errors.NotAllowed( "Node hostname may be changed only before provisioning.") if instance.cluster: cluster = instance.cluster public_ssl_endpoint = cluster.attributes.editable.get( 'public_ssl', {}).get('hostname', {}).get('value', "") if public_ssl_endpoint in ( hostname, objects.Node.generate_fqdn_by_hostname(hostname)): raise errors.InvalidData( "New hostname '{0}' conflicts with public TLS endpoint". format(hostname)) if objects.Node.get_by_hostname(hostname, instance.cluster_id): raise errors.AlreadyExists( "Duplicate hostname '{0}'.".format(hostname))
def _validate_unique_name(cls, data, *filters): """Validate node group name to be unique. Validate whether node group name is unique for specific environment. Prevent to have duplicated node group names for the same environment. :param data: data which contains node group name and cluster_id. :param filters: additional filters for the query which is used in the method for validation. :type data: dict :type filters: list :returns: None """ nodegroup_query = objects.NodeGroupCollection.filter_by( None, name=data['name'], cluster_id=data['cluster_id']) if filters: nodegroup_query = nodegroup_query.filter(*filters) nodegroup_exists = db.query(nodegroup_query.exists()).scalar() if nodegroup_exists: raise errors.NotAllowed("Node group '{0}' already exists " "in environment {1}.".format( data['name'], data['cluster_id']))