def test_raise_exception_when_plugin_overlap_another_plugin_volumes(self):
        plugin_name = 'test_plugin_4'
        volumes_metadata = {
            'volumes_roles_mapping': {
                plugin_name: [
                    {'allocate_size': 'min', 'id': plugin_name}
                ]
            },
            'volumes': [
                {'id': 'test_plugin_2', 'type': 'vg'},
                {'id': plugin_name, 'type': 'vg'}
            ]
        }
        self.env.create_plugin(
            cluster=self.cluster,
            name=plugin_name,
            package_version='3.0.0',
            fuel_version=['7.0'],
            volumes_metadata=volumes_metadata
        )

        expected_message = (
            'Plugin test_plugin_4-0.1.0 is overlapping with plugin '
            'test_plugin_2-0.1.0 by introducing the same volume '
            'with id "test_plugin_2"')

        with self.assertRaisesRegexp(errors.AlreadyExists,
                                     expected_message):
            PluginManager.get_volumes_metadata(self.cluster)
Exemple #2
0
 def patch_attributes(cls, instance, data):
     PluginManager.process_cluster_attributes(instance, data['editable'])
     instance.attributes.editable = dict_merge(
         instance.attributes.editable, data['editable'])
     cls.add_pending_changes(instance, "attributes")
     cls.get_network_manager(instance).update_restricted_networks(instance)
     db().flush()
    def test_raise_exception_when_plugin_overlap_release_volumes(self):
        cluster = self.env.create_cluster(api=False)
        plugin_name = 'test_plugin_3'
        volumes_metadata = {
            'volumes_roles_mapping': {
                plugin_name: [
                    {'allocate_size': 'min', 'id': plugin_name}
                ]
            },
            'volumes': [
                {'id': 'os', 'type': 'vg'},
                {'id': plugin_name, 'type': 'vg'}
            ]
        }
        self.env.create_plugin(
            cluster=cluster,
            name=plugin_name,
            package_version='3.0.0',
            fuel_version=['7.0'],
            volumes_metadata=volumes_metadata
        )

        expected_message = (
            'Plugin test_plugin_3-0.1.0 is overlapping with release '
            'by introducing the same volume with id "os"')

        with self.assertRaisesRegexp(errors.AlreadyExists,
                                     expected_message):
            PluginManager.get_volumes_metadata(cluster)
    def test_update_plugin_node_attributes(self):
        self.env.create_plugin(
            name='plugin_b',
            cluster=self.cluster,
            enabled=True,
            package_version='5.0.0',
            node_attributes_metadata={
                'section_plugin_b': {
                    'attr_b': {'value': 'test_b'}
                }
            })
        new_attrs = PluginManager.get_plugin_node_attributes(self.node)
        new_attrs['plugin_a_section_1']['attr_1']['value'] = 'new_test_1'
        new_attrs['section_plugin_b']['attr_b']['value'] = 'new_test_b'
        PluginManager.update_plugin_node_attributes(new_attrs)
        attributes = PluginManager.get_plugin_node_attributes(self.node)
        for attribute in attributes:
            del attributes[attribute]['metadata']['node_plugin_id']
        self.assertDictEqual(
            {
                'plugin_a_section_1': {
                    'metadata': {'label': 'Section 1 of Plugin A',
                                 'class': 'plugin'},
                    'attr_1': {'value': 'new_test_1'}},
                'plugin_a_section_2': {
                    'metadata': {'class': 'plugin'},
                    'attr_2': {'value': 'test_2'}},
                'section_plugin_b': {
                    'metadata': {'class': 'plugin'},

                    'attr_b': {'value': 'new_test_b'}}
            },
            attributes
        )
Exemple #5
0
 def patch_attributes(cls, instance, data):
     PluginManager.process_cluster_attributes(instance, data['editable'])
     instance.attributes.editable = dict_merge(
         instance.attributes.editable, data['editable'])
     cls.add_pending_changes(instance, "attributes")
     cls.get_network_manager(instance).update_restricted_networks(instance)
     db().flush()
    def test_raise_exception_when_plugin_overlap_release_component(self):
        release = self.env.create_release(
            version='2015.1-8.1',
            operating_system='Ubuntu',
            modes=[consts.CLUSTER_MODES.ha_compact],
            components_metadata=self.env.get_default_components())

        self.env.create_plugin(
            name='plugin_with_components',
            package_version='4.0.0',
            fuel_version=['8.0'],
            releases=[{
                'repository_path': 'repositories/ubuntu',
                'version': '2015.1-8.1', 'os': 'ubuntu',
                'mode': ['ha'],
                'deployment_scripts_path': 'deployment_scripts/'}],
            components_metadata=self.env.get_default_components())

        expected_message = (
            'Plugin plugin_with_components is overlapping with release '
            'by introducing the same component with name '
            '"hypervisor:test_hypervisor"')

        with self.assertRaisesRegexp(errors.AlreadyExists,
                                     expected_message):
            PluginManager.get_components_metadata(release)
Exemple #7
0
    def test_raise_exception_when_plugin_overlap_another_plugin_volumes(self):
        plugin_name = 'test_plugin_4'
        volumes_metadata = {
            'volumes_roles_mapping': {
                plugin_name: [{
                    'allocate_size': 'min',
                    'id': plugin_name
                }]
            },
            'volumes': [{
                'id': 'test_plugin_2',
                'type': 'vg'
            }, {
                'id': plugin_name,
                'type': 'vg'
            }]
        }
        self.env.create_plugin(api=True,
                               cluster=self.cluster,
                               name=plugin_name,
                               package_version='3.0.0',
                               fuel_version=['7.0'],
                               volumes_metadata=volumes_metadata)

        expected_message = (
            'Plugin test_plugin_4-0.1.0 is overlapping with plugin '
            'test_plugin_2-0.1.0 by introducing the same volume '
            'with id "test_plugin_2"')

        with self.assertRaisesRegexp(errors.AlreadyExists, expected_message):
            PluginManager.get_volumes_metadata(self.cluster)
Exemple #8
0
    def test_raise_exception_when_plugin_overlap_release_component(self):
        release = self.env.create_release(
            version='2015.1-8.1',
            operating_system='Ubuntu',
            modes=[consts.CLUSTER_MODES.ha_compact],
            components_metadata=self.env.get_default_components())

        self.env.create_plugin(
            name='plugin_with_components',
            package_version='4.0.0',
            fuel_version=['8.0'],
            releases=[{
                'repository_path': 'repositories/ubuntu',
                'version': '2015.1-8.1',
                'os': 'ubuntu',
                'mode': ['ha'],
                'deployment_scripts_path': 'deployment_scripts/'
            }],
            components_metadata=self.env.get_default_components())

        expected_message = (
            'Plugin plugin_with_components is overlapping with release '
            'by introducing the same component with name '
            '"hypervisor:test_hypervisor"')

        with self.assertRaisesRegexp(errors.AlreadyExists, expected_message):
            PluginManager.get_components_metadata(release)
Exemple #9
0
    def update_attributes(cls, instance, data):
        PluginManager.process_cluster_attributes(instance, data['editable'])

        for key, value in data.iteritems():
            setattr(instance.attributes, key, value)
        cls.add_pending_changes(instance, "attributes")
        db().flush()
    def test_raise_exception_when_plugin_overlap_release_volumes(self):
        cluster = self.env.create_cluster(api=False)
        plugin_name = 'test_plugin_3'
        volumes_metadata = {
            'volumes_roles_mapping': {
                plugin_name: [
                    {'allocate_size': 'min', 'id': plugin_name}
                ]
            },
            'volumes': [
                {'id': 'os', 'type': 'vg'},
                {'id': plugin_name, 'type': 'vg'}
            ]
        }
        self.env.create_plugin(
            api=True,
            cluster=cluster,
            name=plugin_name,
            package_version='3.0.0',
            fuel_version=['7.0'],
            volumes_metadata=volumes_metadata
        )

        expected_message = (
            'Plugin test_plugin_3-0.1.0 is overlapping with release '
            'by introducing the same volume with id "os"')

        with self.assertRaisesRegexp(errors.AlreadyExists,
                                     expected_message):
            PluginManager.get_volumes_metadata(cluster)
Exemple #11
0
    def update_attributes(cls, instance, data):
        PluginManager.process_cluster_attributes(instance, data['editable'])

        for key, value in data.iteritems():
            setattr(instance.attributes, key, value)
        cls.add_pending_changes(instance, "attributes")
        db().flush()
Exemple #12
0
    def create(cls, data):
        """Create Cluster instance with specified parameters in DB.

        This includes:
        * creating Cluster attributes and generating default values \
        (see :func:`create_attributes`)
        * creating NetworkGroups for Cluster
        * adding default pending changes (see :func:`add_pending_changes`)
        * if "nodes" are specified in data then they are added to Cluster \
        (see :func:`update_nodes`)

        :param data: dictionary of key-value pairs as object fields
        :returns: Cluster instance
        """

        # TODO(enchantner): fix this temporary hack in clients
        if "release_id" not in data:
            release_id = data.pop("release", None)
            data["release_id"] = release_id

        # remove read-only attribute
        data.pop("is_locked", None)
        assign_nodes = data.pop("nodes", [])
        enabled_editable_attributes = None

        if 'components' in data:
            enabled_core_attributes = cls.get_cluster_attributes_by_components(
                data['components'], data["release_id"])
            data = dict_merge(data, enabled_core_attributes['cluster'])
            enabled_editable_attributes = enabled_core_attributes['editable']

        data["fuel_version"] = settings.VERSION["release"]
        cluster = super(Cluster, cls).create(data)
        cls.create_default_group(cluster)

        cls.create_attributes(cluster, enabled_editable_attributes)
        cls.create_vmware_attributes(cluster)
        cls.create_default_extensions(cluster)

        try:
            cls.get_network_manager(cluster).\
                create_network_groups_and_config(cluster, data)
            cls.add_pending_changes(cluster, consts.CLUSTER_CHANGES.attributes)
            cls.add_pending_changes(cluster, consts.CLUSTER_CHANGES.networks)
            cls.add_pending_changes(cluster,
                                    consts.CLUSTER_CHANGES.vmware_attributes)

            if assign_nodes:
                cls.update_nodes(cluster, assign_nodes)
        except (errors.OutOfVLANs, errors.OutOfIPs,
                errors.NoSuitableCIDR) as exc:
            raise errors.CannotCreate(exc.message)

        db().flush()

        ClusterPlugins.add_compatible_plugins(cluster)
        PluginManager.enable_plugins_by_components(cluster)

        return cluster
Exemple #13
0
    def create_attributes(cls, instance):
        """Create attributes for interface with default values.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :returns: None
        """
        instance.attributes = cls._get_default_attributes(instance)
        PluginManager.add_plugin_attributes_for_interface(instance)

        db().flush()
Exemple #14
0
    def create_attributes(cls, instance):
        """Create attributes for interface with default values.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :returns: None
        """
        instance.attributes = cls._get_default_attributes(instance)
        PluginManager.add_plugin_attributes_for_interface(instance)

        db().flush()
    def test_get_specific_version(self):
        versions = [
            {'metadata': {'plugin_id': '1'}},
            {'metadata': {'plugin_id': '2'}}
        ]

        plugin_version_attrs = PluginManager._get_specific_version(
            versions, '1')
        self.assertEqual(versions[0], plugin_version_attrs)
        not_existed_plugin_version_attrs = PluginManager._get_specific_version(
            versions, '3')
        self.assertEqual({}, not_existed_plugin_version_attrs)
    def test_get_specific_version(self):
        versions = [
            {'metadata': {'plugin_id': '1'}},
            {'metadata': {'plugin_id': '2'}}
        ]

        plugin_version_attrs = PluginManager._get_specific_version(
            versions, '1')
        self.assertEqual(versions[0], plugin_version_attrs)
        not_existed_plugin_version_attrs = PluginManager._get_specific_version(
            versions, '3')
        self.assertEqual({}, not_existed_plugin_version_attrs)
 def test_update_nic_attributes(self):
     new_attrs = PluginManager.get_nic_attributes(self.interface)
     new_attrs['plugin_a']['attr_a']['value'] = {}
     PluginManager.update_nic_attributes(new_attrs)
     attributes = PluginManager.get_nic_attributes(self.interface)
     del attributes['plugin_a']['metadata']['nic_plugin_id']
     self.assertDictEqual(
         {'plugin_a': {
             'attr_a': {'value': {}},
             'metadata': {
                 'class': 'plugin',
                 'label': 'Test plugin'}}}, attributes)
Exemple #18
0
    def POST(self):
        """:returns: JSONized REST object.
        :http: * 200 (plugins successfully synced)
               * 404 (plugin not found in db)
               * 400 (problem with parsing metadata file)
        """
        data = self.checked_data()
        ids = data.get("ids", None)

        try:
            PluginManager.sync_plugins_metadata(plugin_ids=ids)
        except errors.ParseError as exc:
            raise self.http(400, msg=six.text_type(exc))

        raise self.http(200)
Exemple #19
0
    def POST(self):
        """:returns: JSONized REST object.
        :http: * 200 (plugins successfully synced)
               * 404 (plugin not found in db)
               * 400 (problem with parsing metadata file)
        """
        data = self.checked_data()
        ids = data.get('ids', None)

        try:
            PluginManager.sync_plugins_metadata(plugin_ids=ids)
        except errors.ParseError as exc:
            raise self.http(400, msg=six.text_type(exc))

        raise self.http(200)
Exemple #20
0
    def get_default_attributes(cls, instance):
        """Get default attributes for interface.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :returns: dict -- Dict object of NIC attributes
        """
        attributes = cls._get_default_attributes(instance)
        attributes = utils.dict_merge(
            attributes, PluginManager.get_nic_attributes(instance))
        attributes = utils.dict_merge(
            attributes,
            PluginManager.get_nic_default_attributes(instance.node.cluster))

        return attributes
Exemple #21
0
    def get_network_roles(cls, instance):
        """Method for receiving network roles for particular cluster

        :param instance: nailgun.db.sqlalchemy.models.Cluster instance
        :returns: List of network roles' descriptions
        """
        return instance.release.network_roles_metadata + PluginManager.get_network_roles(instance)
 def serialize(self):
     plugins = PluginManager.get_cluster_plugins_with_tasks(self.cluster)
     return itertools.chain(
         self.create_repositories(plugins),
         self.sync_scripts(plugins),
         self.deployment_tasks(plugins)
     )
Exemple #23
0
    def get_all_components(cls, instance):
        """Get all components related to release

        Due to components architecture compatible/incompatible are duplex
        relations. So if some component is compatible/incompatible with another
        the last one also should have such relation.

        :param instance: Release instance
        :type instance: Release DB instance
        :returns: list -- list of all components
        """
        plugin_components = PluginManager.get_components_metadata(instance)
        components = copy.deepcopy(instance.components_metadata +
                                   plugin_components)
        # we should provide commutative property for compatible/incompatible
        # relations between components
        for comp_i, comp_j in itertools.permutations(components, 2):
            if cls._check_relation(comp_j, comp_i, 'incompatible'):
                comp_i.setdefault('incompatible', []).append({
                    'name':
                    comp_j['name'],
                    'message':
                    "Not compatible with {0}".format(
                        comp_j.get('label') or comp_j.get('name'))
                })
            if cls._check_relation(comp_j, comp_i, 'compatible'):
                comp_i.setdefault('compatible',
                                  []).append({'name': comp_j['name']})

        return components
Exemple #24
0
    def update(cls, instance, data):
        """Update data of native and plugin attributes for interface.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :param data: Data to update
        :type data: dict
        :returns: instance of an object (model)
        """
        attributes = data.pop('attributes', None)
        if attributes:
            PluginManager.update_nic_attributes(attributes)
            instance.attributes = utils.dict_merge(
                instance.attributes, attributes)

        return super(NIC, cls).update(instance, data)
Exemple #25
0
    def update(cls, instance, data):
        """Update data of native and plugin attributes for interface.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :param data: Data to update
        :type data: dict
        :returns: instance of an object (model)
        """
        attributes = data.pop('attributes', None)
        if attributes:
            PluginManager.update_nic_attributes(attributes)
            instance.attributes = utils.dict_merge(instance.attributes,
                                                   attributes)

        return super(NIC, cls).update(instance, data)
    def get_all_components(cls, instance):
        """Get all components related to release

        Due to components architecture compatible/incompatible are duplex
        relations. So if some component is compatible/incompatible with another
        the last one also should have such relation.

        :param instance: Release instance
        :type instance: Release DB instance
        :returns: list -- list of all components
        """
        plugin_components = PluginManager.get_components_metadata(instance)
        components = copy.deepcopy(
            instance.components_metadata + plugin_components)
        # we should provide commutative property for compatible/incompatible
        # relations between components
        for comp_i, comp_j in itertools.permutations(components, 2):
            if cls._check_relation(comp_j, comp_i, 'incompatible'):
                comp_i.setdefault('incompatible', []).append({
                    'name': comp_j['name'],
                    'message': "Not compatible with {0}".format(
                        comp_j.get('label') or comp_j.get('name'))})
            if cls._check_relation(comp_j, comp_i, 'compatible'):
                comp_i.setdefault('compatible', []).append({
                    'name': comp_j['name']})

        return components
Exemple #27
0
    def get_attributes(cls, instance, all_plugins_versions=False):
        """Get attributes for current Cluster instance.

        :param instance: Cluster instance
        :param all_plugins_versions: Get attributes of all versions of plugins
        :returns: dict
        """
        try:
            attrs = db().query(models.Attributes).filter(
                models.Attributes.cluster_id == instance.id
            ).one()
        except MultipleResultsFound:
            raise errors.InvalidData(
                u"Multiple rows with attributes were found for cluster '{0}'"
                .format(instance.name)
            )
        except NoResultFound:
            raise errors.InvalidData(
                u"No attributes were found for cluster '{0}'"
                .format(instance.name)
            )
        attrs = dict(attrs)

        # Merge plugins attributes into editable ones
        plugin_attrs = PluginManager.get_plugins_attributes(
            instance, all_versions=all_plugins_versions)
        plugin_attrs = traverse(plugin_attrs, AttributesGenerator, {
            'cluster': instance,
            'settings': settings,
        })
        attrs['editable'].update(plugin_attrs)

        return attrs
Exemple #28
0
    def get_attributes(cls, instance, all_plugins_versions=False):
        """Get attributes for current Cluster instance.

        :param instance: Cluster instance
        :param all_plugins_versions: Get attributes of all versions of plugins
        :returns: dict
        """
        try:
            attrs = db().query(models.Attributes).filter(
                models.Attributes.cluster_id == instance.id
            ).one()
        except MultipleResultsFound:
            raise errors.InvalidData(
                u"Multiple rows with attributes were found for cluster '{0}'"
                .format(instance.name)
            )
        except NoResultFound:
            raise errors.InvalidData(
                u"No attributes were found for cluster '{0}'"
                .format(instance.name)
            )
        attrs = dict(attrs)

        # Merge plugins attributes into editable ones
        plugin_attrs = PluginManager.get_plugins_attributes(
            instance, all_versions=all_plugins_versions)
        plugin_attrs = traverse(plugin_attrs, AttributesGenerator, {
            'cluster': instance,
            'settings': settings,
        })
        attrs['editable'].update(plugin_attrs)

        return attrs
    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
                )
Exemple #30
0
 def serialize(self):
     tasks = []
     plugins = PluginManager.get_cluster_plugins_with_tasks(self.cluster)
     tasks.extend(self.create_repositories(plugins))
     tasks.extend(self.sync_scripts(plugins))
     tasks.extend(self.deployment_tasks(plugins))
     return tasks
Exemple #31
0
    def test_get_plugin_volumes_metadata_for_cluster(self):
        volumes_metadata = PluginManager.get_volumes_metadata(self.cluster)
        expected_volumes_metadata = {
            'volumes_roles_mapping': {
                'test_plugin_1': [{
                    'allocate_size': 'min',
                    'id': 'test_plugin_1'
                }],
                'test_plugin_2': [{
                    'allocate_size': 'min',
                    'id': 'test_plugin_2'
                }],
            },
            'volumes': [{
                'id': 'test_plugin_1',
                'type': 'vg'
            }, {
                'id': 'test_plugin_2',
                'type': 'vg'
            }]
        }

        self.assertEqual(volumes_metadata['volumes_roles_mapping'],
                         expected_volumes_metadata['volumes_roles_mapping'])
        self.assertItemsEqual(volumes_metadata['volumes'],
                              expected_volumes_metadata['volumes'])
Exemple #32
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
                )
 def serialize(self):
     tasks = []
     plugins = PluginManager.get_cluster_plugins_with_tasks(self.cluster)
     tasks.extend(self.create_repositories(plugins))
     tasks.extend(self.sync_scripts(plugins))
     tasks.extend(self.deployment_tasks(plugins))
     return tasks
Exemple #34
0
    def test_merge_plugin_values(self):
        attributes = {
            'test_plugin': {
                'metadata': {
                    'class':
                    'plugin',
                    'chosen_id':
                    1,
                    'enabled':
                    True,
                    'versions': [{
                        'metadata': {
                            'plugin_id': 1
                        },
                        'attribute_a': {
                            'value': 'test_a'
                        },
                        'attribute_b': {
                            'value': 'test_b'
                        }
                    }, {
                        'metadata': {
                            'plugin_id': 2
                        },
                        'attribute_a': {
                            'value': 'test_a'
                        },
                        'attribute_c': {
                            'value': 'test_c'
                        }
                    }]
                },
                'attribute_a': {
                    'value': ''
                },
                'attribute_b': {
                    'value': ''
                }
            }
        }

        PluginManager.inject_plugin_attribute_values(attributes)

        self.assertEqual('test_a',
                         attributes['test_plugin']['attribute_a']['value'])
        self.assertEqual('test_b',
                         attributes['test_plugin']['attribute_b']['value'])
Exemple #35
0
    def update(cls, instance, data):
        """Update existing Bond with specified parameters.

        :param instance: object (model) instance
        :param data: dictionary of key-value pairs as object fields
        :returns: instance of an object (model)
        """
        attributes = data.pop('attributes', None)
        if attributes:
            PluginManager.update_bond_attributes(attributes)
            instance.attributes = utils.dict_merge(
                instance.attributes, attributes)

        instance = super(Bond, cls).update(instance, data)
        instance.offloading_modes = data.get('offloading_modes', {})

        return instance
Exemple #36
0
    def get_network_roles(cls, instance):
        """Method for receiving network roles for particular cluster

        :param instance: nailgun.db.sqlalchemy.models.Cluster instance
        :returns: List of network roles' descriptions
        """
        return (instance.release.network_roles_metadata +
                PluginManager.get_network_roles(instance))
Exemple #37
0
    def get_default_attributes(cls, instance):
        """Get default attributes for interface.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :returns: dict -- Dict object of NIC attributes
        """
        attributes = cls._get_default_attributes(instance)
        attributes = utils.dict_merge(
            attributes,
            PluginManager.get_nic_attributes(instance))
        attributes = utils.dict_merge(
            attributes,
            PluginManager.get_nic_default_attributes(
                instance.node.cluster))

        return attributes
Exemple #38
0
    def update(cls, instance, data):
        """Update existing Bond with specified parameters.

        :param instance: object (model) instance
        :param data: dictionary of key-value pairs as object fields
        :returns: instance of an object (model)
        """
        attributes = data.pop('attributes', None)
        if attributes:
            PluginManager.update_bond_attributes(attributes)
            instance.attributes = utils.dict_merge(instance.attributes,
                                                   attributes)

        instance = super(Bond, cls).update(instance, data)
        instance.offloading_modes = data.get('offloading_modes', {})

        return instance
Exemple #39
0
    def test_get_plugins_attributes_when_cluster_is_not_locked(self):
        self.env.create(api=False)
        cluster = self.env.clusters[-1]
        plugin_a1 = self.env.create_plugin(name='plugin_a',
                                           version='1.0.1',
                                           cluster=cluster,
                                           enabled=False)
        plugin_a2 = self.env.create_plugin(name='plugin_a',
                                           version='1.0.2',
                                           is_hotpluggable=True,
                                           cluster=cluster,
                                           enabled=True)
        plugin_b = self.env.create_plugin(name='plugin_b',
                                          title='plugin_a_title',
                                          cluster=cluster)
        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'])

        self.assertEqual(str(plugin_b.id),
                         attributes['plugin_b']['plugin_versions']['value'])
Exemple #40
0
    def get_roles(cls, instance):
        """Returns a dictionary of node roles available for deployment.

        :param instance: cluster instance
        :returns: a dictionary of roles metadata
        """
        available_roles = copy.deepcopy(instance.release.roles_metadata)
        available_roles.update(PluginManager.get_plugins_node_roles(instance))
        return available_roles
Exemple #41
0
    def get_roles(cls, instance):
        """Returns a dictionary of node roles available for deployment.

        :param instance: cluster instance
        :returns: a dictionary of roles metadata
        """
        available_roles = copy.deepcopy(instance.release.roles_metadata)
        available_roles.update(PluginManager.get_plugins_node_roles(instance))
        return available_roles
Exemple #42
0
    def get_all_components(cls, instance):
        """Get all components related to release

        :param instance: Release instance
        :type instance: Release DB instance
        :returns: list -- list of all components
        """
        plugin_components = PluginManager.get_components_metadata(instance)
        return instance.components_metadata + plugin_components
Exemple #43
0
    def get_network_roles(
            cls, instance, merge_policy=NetworkRoleMergePolicy()):
        """Method for receiving network roles for particular cluster

        :param instance: nailgun.db.sqlalchemy.models.Cluster instance
        :param merge_policy: the policy to merge same roles
        :returns: List of network roles' descriptions
        """
        return PluginManager.get_network_roles(instance, merge_policy)
Exemple #44
0
    def get_network_roles(
            cls, instance, merge_policy=NetworkRoleMergePolicy()):
        """Method for receiving network roles for particular cluster

        :param instance: nailgun.db.sqlalchemy.models.Cluster instance
        :param merge_policy: the policy to merge same roles
        :returns: List of network roles' descriptions
        """
        return PluginManager.get_network_roles(instance, merge_policy)
Exemple #45
0
    def get_all_components(cls, instance):
        """Get all components related to release

        :param instance: Release instance
        :type instance: Release DB instance
        :returns: list -- list of all components
        """
        plugin_components = PluginManager.get_components_metadata(instance)
        return instance.components_metadata + plugin_components
 def test_get_nic_plugin_atributes(self):
     attributes = PluginManager.get_nic_attributes(self.interface)
     del attributes['plugin_a']['metadata']['nic_plugin_id']
     self.assertDictEqual(
         {'plugin_a': {
             'attr_a': {'value': 'test_a'},
             'metadata': {
                 'class': 'plugin',
                 'label': 'Test plugin'}}}, attributes)
 def test_add_plugin_attributes_for_node(self):
     new_cluster_node = self.env.create_node(
         cluster_id=self.cluster.id,
         roles=['controller']
     )
     PluginManager.add_plugin_attributes_for_node(new_cluster_node)
     node_cluster_plugins = new_cluster_node.node_cluster_plugins
     self.assertEqual(len(node_cluster_plugins), 1)
     attributes = node_cluster_plugins[0].attributes
     self.assertDictEqual(
         {
             'plugin_a_section_1': {
                 'metadata': {'label': 'Section 1 of Plugin A'},
                 'attr_1': {'value': 'test_1'}},
             'plugin_a_section_2': {
                 'attr_2': {'value': 'test_2'}}
         },
         attributes
     )
Exemple #48
0
    def test_get_empty_plugin_volumes_metadata_for_cluster(self):
        cluster = self.env.create_cluster(api=False)
        self.env.create_plugin(cluster=cluster, package_version='3.0.0')
        volumes_metadata = PluginManager.get_volumes_metadata(cluster)
        expected_volumes_metadata = {
            'volumes_roles_mapping': {},
            'volumes': []
        }

        self.assertEqual(volumes_metadata, expected_volumes_metadata)
    def test_merge_plugin_values(self):
        attributes = {
            'test_plugin': {
                'metadata': {
                    'class': 'plugin',
                    'chosen_id': 1,
                    'enabled': True,
                    'versions': [
                        {
                            'metadata': {
                                'plugin_id': 1
                            },
                            'attribute_a': {
                                'value': 'test_a'
                            },
                            'attribute_b': {
                                'value': 'test_b'
                            }
                        },
                        {
                            'metadata': {
                                'plugin_id': 2
                            },
                            'attribute_a': {
                                'value': 'test_a'
                            },
                            'attribute_c': {
                                'value': 'test_c'
                            }
                        }
                    ]
                },
                'attribute_a': {'value': ''},
                'attribute_b': {'value': ''}
            }
        }

        PluginManager.inject_plugin_attribute_values(attributes)

        self.assertEqual(
            'test_a', attributes['test_plugin']['attribute_a']['value'])
        self.assertEqual(
            'test_b', attributes['test_plugin']['attribute_b']['value'])
    def test_get_components(self):
        self.env.create_plugin(
            name='plugin_with_components',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        components_metadata = PluginManager.get_components_metadata(
            self.release)
        self.assertEqual(
            components_metadata, self.env.get_default_components())
Exemple #51
0
    def test_raise_exception_when_plugin_overlap_another_component(self):
        self.env.create_plugin(
            name='plugin_with_components_1',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        self.env.create_plugin(
            name='plugin_with_components_2',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        expected_message = (
            'Plugin plugin_with_components_2 is overlapping with '
            'plugin_with_components_1 by introducing the same component '
            'with name "hypervisor:test_hypervisor"')

        with self.assertRaisesRegexp(errors.AlreadyExists, expected_message):
            PluginManager.get_components_metadata(self.release)
Exemple #52
0
    def test_get_components(self):
        self.env.create_plugin(
            name='plugin_with_components',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        components_metadata = PluginManager.get_components_metadata(
            self.release)
        self.assertEqual(components_metadata,
                         self.env.get_default_components())
    def test_raise_exception_when_plugin_overlap_another_component(self):
        self.env.create_plugin(
            name='plugin_with_components_1',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        self.env.create_plugin(
            name='plugin_with_components_2',
            package_version='4.0.0',
            fuel_version=['8.0'],
            components_metadata=self.env.get_default_components())

        expected_message = (
            'Plugin plugin_with_components_2 is overlapping with '
            'plugin_with_components_1 by introducing the same component '
            'with name "hypervisor:test_hypervisor"')

        with self.assertRaisesRegexp(errors.AlreadyExists,
                                     expected_message):
            PluginManager.get_components_metadata(self.release)
    def test_get_empty_plugin_volumes_metadata_for_cluster(self):
        cluster = self.env.create_cluster(api=False)
        self.env.create_plugin(
            cluster=cluster,
            package_version='3.0.0'
        )
        volumes_metadata = PluginManager.get_volumes_metadata(cluster)
        expected_volumes_metadata = {
            'volumes_roles_mapping': {}, 'volumes': []}

        self.assertEqual(
            volumes_metadata, expected_volumes_metadata)
Exemple #55
0
    def get_default_attributes(cls, cluster):
        """Get native and plugin default attributes for bond.

        :param cluster: A cluster instance
        :type cluster: Cluster model
        :returns: dict -- Object of bond default attributes
        """
        default_attributes = cluster.release.bond_attributes
        default_attributes = utils.dict_merge(
            default_attributes,
            PluginManager.get_bond_default_attributes(cluster))

        return default_attributes
Exemple #56
0
    def get_attributes(cls, instance):
        """Get native and plugin attributes for bond.

        :param instance: NodeBondInterface instance
        :type instance: NodeBondInterface model
        :returns: dict -- Object of bond attributes
        """
        attributes = copy.deepcopy(instance.attributes)
        attributes = utils.dict_merge(
            attributes,
            PluginManager.get_bond_attributes(instance))

        return attributes
Exemple #57
0
    def get_attributes(cls, instance):
        """Get all attributes for interface.

        :param instance: NodeNICInterface instance
        :type instance: NodeNICInterface model
        :returns: dict -- Object of interface attributes
        """
        attributes = copy.deepcopy(instance.attributes)
        attributes = utils.dict_merge(
            attributes,
            PluginManager.get_nic_attributes(instance))

        return attributes
Exemple #58
0
    def get_default_editable_attributes(cls, instance):
        """Get editable attributes from release metadata

        :param instance: Cluster instance
        :returns: Dict object
        """
        editable = instance.release.attributes_metadata.get("editable")
        generate_editables(editable, AttributesGenerator)
        # when attributes created we need to understand whether should plugin
        # be applied for created cluster
        plugin_attrs = PluginManager.get_plugin_attributes(instance)
        editable = dict(plugin_attrs, **editable)
        return editable
    def test_removes_tasks_from_db_if_removed_from_new_plugin(self):
        plugin = self.env.create_plugin(
            tasks=self.env.get_default_plugin_tasks())
        mocked_metadata = {
            'metadata.yaml': {},
            'environment_config.yaml': {},
        }
        self.assertNotEqual(plugin.tasks, [])

        with mock.patch(
            'nailgun.plugins.loaders.files_manager.FilesManager.load'
        ) as load:

            def se(key):
                # Simulate that tasks.yaml was removed
                if key.endswith('tasks.yaml'):
                    raise errors.NoPluginFileFound()
                return copy.deepcopy(
                    mocked_metadata.get(os.path.basename(key)))

            load.side_effect = se
            PluginManager.sync_plugins_metadata(plugin_ids=[plugin.id])

        self.assertEqual(plugin.tasks, [])
Exemple #60
0
    def get_volumes_metadata(cls, instance):
        """Return proper volumes metadata for cluster and consists
        with general volumes metadata from release and volumes
        metadata from plugins which releated to this cluster

        :param instance: Cluster DB instance
        :returns: dict -- object with merged volumes metadata
        """
        volumes_metadata = copy.deepcopy(instance.release.volumes_metadata)
        plugin_volumes = PluginManager.get_volumes_metadata(instance)

        volumes_metadata["volumes_roles_mapping"].update(plugin_volumes["volumes_roles_mapping"])

        volumes_metadata["volumes"].extend(plugin_volumes["volumes"])

        return volumes_metadata