Beispiel #1
0
    def validate_allowed_attributes(cls, cluster, data, force):
        """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
        :param force: Allow forcefully update cluster attributes
        :type force: bool
        :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 or force:
            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
                )
Beispiel #2
0
    def validate_hostname(cls, hostname, instance):
        if not cls.HostnameRegex.match(hostname):
            raise errors.InvalidData(
                'Hostname must consist of english characters, '
                'digits, minus signs and periods. '
                '(The following pattern must apply {})'.format(
                    base_types.FQDN['pattern']))

        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))
Beispiel #3
0
    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)
            )
Beispiel #4
0
    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
Beispiel #5
0
    def validate(cls, data):
        data = cls.validate_json(data)
        cluster = objects.Cluster.get_by_uid(data['cluster_id'],
                                             fail_if_not_found=True)

        cls._check_for_deployed_nodes(cluster)

        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
Beispiel #6
0
 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.")
Beispiel #7
0
    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")
Beispiel #8
0
    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)

        return d
Beispiel #9
0
    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
Beispiel #10
0
    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)))
Beispiel #11
0
    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']))