Resolve tasks by role tags

This commit switching tasks resolution approach to the tags based one.
Tag - minimal unit what's necessary only for task resolution and can be
mapped to the node through the role interface only. Each role provides set
of tags in its 'tags' field and may be modified via role API. Tag may be
created separately via tag API, but, this tag can not be used unless it's
stuck to the role.

Change-Id: Icd78fd124997c8aafb07964eeb8e0f7dbb1b1cd2
Implements: blueprint role-decomposition
This commit is contained in:
Ryan Moe 2016-09-06 10:44:10 -07:00 committed by Viacheslav Valyavskiy
parent f1550ad2a2
commit 2b0242f645
41 changed files with 647 additions and 247 deletions

View File

@ -103,7 +103,8 @@ ROLE_META_INFO = {
"description": ("Name of a role group which reflects the role" "description": ("Name of a role group which reflects the role"
" purpose in cloud or deployment process")}, " purpose in cloud or deployment process")},
"limits": LIMITS, "limits": LIMITS,
"restrictions": base_types.RESTRICTIONS}} "restrictions": base_types.RESTRICTIONS,
"tags": base_types.STRINGS_ARRAY}}
SCHEMA = { SCHEMA = {

View File

@ -21,6 +21,8 @@ Create Date: 2016-10-22 02:11:47.708895
""" """
from alembic import op from alembic import op
from oslo_serialization import jsonutils
import six
import sqlalchemy as sa import sqlalchemy as sa
@ -34,9 +36,13 @@ down_revision = 'c6edea552f1e'
def upgrade(): def upgrade():
upgrade_cluster_roles() upgrade_cluster_roles()
upgrade_tags_meta()
upgrade_primary_unit()
def downgrade(): def downgrade():
downgrade_primary_unit()
downgrade_tags_meta()
downgrade_cluster_roles() downgrade_cluster_roles()
@ -60,3 +66,81 @@ def upgrade_cluster_roles():
def downgrade_cluster_roles(): def downgrade_cluster_roles():
op.drop_column('clusters', 'roles_metadata') op.drop_column('clusters', 'roles_metadata')
op.drop_column('clusters', 'volumes_metadata') op.drop_column('clusters', 'volumes_metadata')
def upgrade_tags_meta():
connection = op.get_bind()
op.add_column(
'releases',
sa.Column('tags_metadata',
fields.JSON(),
server_default='{}',
nullable=False),
)
op.add_column(
'clusters',
sa.Column('tags_metadata',
fields.JSON(),
server_default='{}',
nullable=False),
)
op.add_column(
'plugins',
sa.Column('tags_metadata',
fields.JSON(),
server_default='{}',
nullable=False),
)
q_get_role_meta = "SELECT id, roles_metadata FROM {}"
q_update_tags_meta = ("UPDATE {} SET tags_metadata = :tags_meta "
"WHERE id = :obj_id")
q_update_roles_meta = ("UPDATE {} SET roles_metadata = :roles_meta "
"WHERE id = :obj_id")
for table in ['releases', 'plugins']:
for obj_id, roles_meta in connection.execute(
sa.text(q_get_role_meta.format(table))):
tags_meta = {}
roles_meta = jsonutils.loads(roles_meta or '{}')
for role_name, meta in six.iteritems(roles_meta):
meta['tags'] = [role_name]
tags_meta[role_name] = {'has_primary': meta.get('has_primary',
False)}
connection.execute(sa.text(q_update_roles_meta.format(table)),
roles_meta=jsonutils.dumps(roles_meta),
obj_id=obj_id)
connection.execute(sa.text(q_update_tags_meta.format(table)),
tags_meta=jsonutils.dumps(tags_meta),
obj_id=obj_id)
def downgrade_tags_meta():
op.drop_column('plugins', 'tags_metadata')
op.drop_column('clusters', 'tags_metadata')
op.drop_column('releases', 'tags_metadata')
def upgrade_primary_unit():
op.alter_column('nodes', 'primary_roles', new_column_name='primary_tags')
def downgrade_primary_unit():
connection = op.get_bind()
q_get_roles = sa.text('''
SELECT id, roles, pending_roles, primary_tags
FROM nodes
''')
q_update_primary_tags = sa.text('''
UPDATE nodes
SET primary_tags = :primary_tags
WHERE id = :node_id
''')
for node_id, roles, p_roles, pr_tags in connection.execute(q_get_roles):
primary_tags = list(set(roles + p_roles) & set(pr_tags))
connection.execute(
q_update_primary_tags,
node_id=node_id,
primary_tags=primary_tags
)
op.alter_column('nodes', 'primary_tags', new_column_name='primary_roles')

View File

@ -127,6 +127,9 @@ class Cluster(Base):
roles_metadata = Column(MutableDict.as_mutable(JSON), roles_metadata = Column(MutableDict.as_mutable(JSON),
default={}, default={},
server_default='{}') server_default='{}')
tags_metadata = Column(MutableDict.as_mutable(JSON),
server_default='{}',
nullable=False)
@property @property
def changes(self): def changes(self):

View File

@ -99,7 +99,7 @@ class Node(Base):
default=[], nullable=False, server_default='{}') default=[], nullable=False, server_default='{}')
pending_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)), pending_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
default=[], nullable=False, server_default='{}') default=[], nullable=False, server_default='{}')
primary_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)), primary_tags = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
default=[], nullable=False, server_default='{}') default=[], nullable=False, server_default='{}')
nic_interfaces = relationship("NodeNICInterface", backref="node", nic_interfaces = relationship("NodeNICInterface", backref="node",

View File

@ -180,6 +180,8 @@ class Plugin(Base):
MutableDict.as_mutable(JSON), server_default='{}', nullable=False) MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
roles_metadata = Column( roles_metadata = Column(
MutableDict.as_mutable(JSON), server_default='{}', nullable=False) MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
tags_metadata = Column(
MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
network_roles_metadata = Column( network_roles_metadata = Column(
MutableList.as_mutable(JSON), server_default='[]', nullable=False) MutableList.as_mutable(JSON), server_default='[]', nullable=False)
nic_attributes_metadata = Column( nic_attributes_metadata = Column(

View File

@ -54,6 +54,8 @@ class Release(Base):
volumes_metadata = Column(MutableDict.as_mutable(JSON), default={}) volumes_metadata = Column(MutableDict.as_mutable(JSON), default={})
modes_metadata = Column(MutableDict.as_mutable(JSON), default={}) modes_metadata = Column(MutableDict.as_mutable(JSON), default={})
roles_metadata = Column(MutableDict.as_mutable(JSON), default={}) roles_metadata = Column(MutableDict.as_mutable(JSON), default={})
tags_metadata = Column(
MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
network_roles_metadata = Column( network_roles_metadata = Column(
MutableList.as_mutable(JSON), default=[], server_default='[]') MutableList.as_mutable(JSON), default=[], server_default='[]')
vmware_attributes_metadata = Column( vmware_attributes_metadata = Column(

View File

@ -1074,7 +1074,7 @@ class NeutronNetworkDeploymentSerializer70(
for node in objects.Cluster.get_nodes_not_for_deletion(cluster): for node in objects.Cluster.get_nodes_not_for_deletion(cluster):
name = objects.Node.get_slave_name(node) name = objects.Node.get_slave_name(node)
node_roles = objects.Node.all_roles(node) node_roles = objects.Node.all_tags(node)
network_roles = cls.get_network_role_mapping_to_ip(node) network_roles = cls.get_network_role_mapping_to_ip(node)
# Use permanent identifier as a node key # Use permanent identifier as a node key
key = objects.Node.permanent_id(node) key = objects.Node.permanent_id(node)

View File

@ -365,7 +365,7 @@ class NovaNetworkDeploymentSerializer70(NovaNetworkDeploymentSerializer61):
for n in Cluster.get_nodes_not_for_deletion(cluster): for n in Cluster.get_nodes_not_for_deletion(cluster):
name = Node.get_slave_name(n) name = Node.get_slave_name(n)
node_roles = Node.all_roles(n) node_roles = Node.all_tags(n)
# Use permanent identifier as a node key # Use permanent identifier as a node key
key = Node.permanent_id(n) key = Node.permanent_id(n)

View File

@ -16,7 +16,6 @@
update_required: update_required:
- compute - compute
- cinder - cinder
has_primary: true
public_ip_required: true public_ip_required: true
public_for_dvr_required: true public_for_dvr_required: true
group: "base" group: "base"
@ -27,6 +26,8 @@
- condition: "settings:neutron_advanced_configuration.neutron_l3_ha.value == true" - condition: "settings:neutron_advanced_configuration.neutron_l3_ha.value == true"
min: 2 min: 2
message: "Neutron L3 HA requires at least 2 Controller nodes to function properly." message: "Neutron L3 HA requires at least 2 Controller nodes to function properly."
tags:
- controller
compute: compute:
name: "Compute" name: "Compute"
description: "A Compute node creates, manages, and terminates virtual machine instances." description: "A Compute node creates, manages, and terminates virtual machine instances."
@ -36,6 +37,8 @@
limits: limits:
recommended: 1 recommended: 1
fault_tolerance: "2%" fault_tolerance: "2%"
tags:
- compute
cinder: cinder:
# NOTE: naming, see https://bugs.launchpad.net/fuel/+bug/1383224 # NOTE: naming, see https://bugs.launchpad.net/fuel/+bug/1383224
name: "Cinder" name: "Cinder"
@ -50,10 +53,11 @@
# NOTE: https://bugs.launchpad.net/fuel/+bug/1372914 - Prohibit possibility of adding cinder nodes to an environment with Ceph RBD # NOTE: https://bugs.launchpad.net/fuel/+bug/1372914 - Prohibit possibility of adding cinder nodes to an environment with Ceph RBD
- condition: "settings:storage.volumes_ceph.value == true" - condition: "settings:storage.volumes_ceph.value == true"
message: "Ceph RBD cannot be used with Cinder" message: "Ceph RBD cannot be used with Cinder"
tags:
- cinder
cinder-block-device: cinder-block-device:
name: 'Cinder Block Device' name: 'Cinder Block Device'
description: 'Host node for Cinder Block Devices.' description: 'Host node for Cinder Block Devices.'
has_primary: false
public_ip_required: false public_ip_required: false
weight: 35 weight: 35
group: "storage" group: "storage"
@ -67,6 +71,8 @@
message: "Cinder Block Device driver should be enabled in the environment settings." message: "Cinder Block Device driver should be enabled in the environment settings."
- condition: "settings:storage.volumes_ceph.value == true" - condition: "settings:storage.volumes_ceph.value == true"
message: "Ceph RBD cannot be used with Cinder Block Device" message: "Ceph RBD cannot be used with Cinder Block Device"
tags:
- cinder-block-device
cinder-vmware: cinder-vmware:
name: "Cinder Proxy to VMware Datastore" name: "Cinder Proxy to VMware Datastore"
description: "Cinder-VMware provides scheduling of block storage resources delivered over VMware vCenter. Block storage can be used for database storage, expandable file systems, or providing a server with access to raw block level devices." description: "Cinder-VMware provides scheduling of block storage resources delivered over VMware vCenter. Block storage can be used for database storage, expandable file systems, or providing a server with access to raw block level devices."
@ -78,6 +84,8 @@
- condition: "settings:common.use_vcenter.value == false" - condition: "settings:common.use_vcenter.value == false"
action: "hide" action: "hide"
message: "VMware vCenter not enabled for cluster" message: "VMware vCenter not enabled for cluster"
tags:
- cinder-vmware
ceph-osd: ceph-osd:
name: "Ceph OSD" name: "Ceph OSD"
description: "Ceph storage can be configured to provide storage for block volumes (Cinder), images (Glance) and ephemeral instance storage (Nova). It can also provide object storage through the S3 and Swift API (See settings to enable each)." description: "Ceph storage can be configured to provide storage for block volumes (Cinder), images (Glance) and ephemeral instance storage (Nova). It can also provide object storage through the S3 and Swift API (See settings to enable each)."
@ -90,6 +98,8 @@
message: "Ceph should be enabled in the environment settings." message: "Ceph should be enabled in the environment settings."
update_once: update_once:
- controller - controller
tags:
- ceph-osd
mongo: mongo:
name: "Telemetry - MongoDB" name: "Telemetry - MongoDB"
description: "A feature-complete and recommended database for storage of metering data from OpenStack Telemetry (Ceilometer)." description: "A feature-complete and recommended database for storage of metering data from OpenStack Telemetry (Ceilometer)."
@ -98,7 +108,6 @@
conflicts: conflicts:
- compute - compute
- ceph-osd - ceph-osd
has_primary: true
limits: limits:
min: 1 min: 1
overrides: overrides:
@ -113,11 +122,15 @@
message: "Ceilometer should be enabled in the environment settings." message: "Ceilometer should be enabled in the environment settings."
- condition: "settings:additional_components.mongo.value == true" - condition: "settings:additional_components.mongo.value == true"
message: "You are already using external MongoDB." message: "You are already using external MongoDB."
tags:
- mongo
base-os: base-os:
name: "Operating System" name: "Operating System"
description: "Install base Operating System without additional packages and configuration." description: "Install base Operating System without additional packages and configuration."
weight: 70 weight: 70
group: "other" group: "other"
tags:
- base-os
virt: virt:
name: "Virtual" name: "Virtual"
description: "ADVANCED: Make available possibilities to spawn vms on this node that can be assign as a normal nodes." description: "ADVANCED: Make available possibilities to spawn vms on this node that can be assign as a normal nodes."
@ -131,6 +144,8 @@
- condition: "not ('advanced' in version:feature_groups)" - condition: "not ('advanced' in version:feature_groups)"
action: "hide" action: "hide"
message: "Advanced feature should be enabled in feature groups" message: "Advanced feature should be enabled in feature groups"
tags:
- virt
compute-vmware: compute-vmware:
name: "Compute VMware" name: "Compute VMware"
description: "A node that runs nova-compute with VCDriver, that manages ESXi computing resources via VMware vCenter." description: "A node that runs nova-compute with VCDriver, that manages ESXi computing resources via VMware vCenter."
@ -150,6 +165,8 @@
- condition: "settings:common.use_vcenter.value == false" - condition: "settings:common.use_vcenter.value == false"
action: "hide" action: "hide"
message: "VMware vCenter not enabled for cluster" message: "VMware vCenter not enabled for cluster"
tags:
- compute-vmware
ironic: ironic:
name: "Ironic" name: "Ironic"
description: "Ironic conductor." description: "Ironic conductor."
@ -163,6 +180,31 @@
restrictions: restrictions:
- condition: "settings:additional_components.ironic.value == false" - condition: "settings:additional_components.ironic.value == false"
message: "Ironic should be enabled in the environment settings." message: "Ironic should be enabled in the environment settings."
tags:
- ironic
tags_metadata:
controller:
has_primary: true
compute:
has_primary: false
cinder:
has_primary: false
cinder-block-device:
has_primary: false
cinder-vmware:
has_primary: false
ceph-osd:
has_primary: false
mongo:
has_primary: true
base-os:
has_primary: false
virt:
has_primary: false
compute-vmware:
has_primary: false
ironic:
has_primary: false
network_roles_metadata: network_roles_metadata:
- -

View File

@ -24,7 +24,7 @@ from nailgun import errors
from nailgun.lcm.task_serializer import TasksSerializersFactory from nailgun.lcm.task_serializer import TasksSerializersFactory
from nailgun.logger import logger from nailgun.logger import logger
from nailgun.settings import settings from nailgun.settings import settings
from nailgun.utils.role_resolver import NameMatchingPolicy from nailgun.utils.resolvers import NameMatchingPolicy
# This class has similar functional with TasksSerializer from task deploy # This class has similar functional with TasksSerializer from task deploy
@ -153,8 +153,8 @@ class TransactionSerializer(object):
consts.ORCHESTRATOR_TASK_TYPES.skipped consts.ORCHESTRATOR_TASK_TYPES.skipped
) )
def __init__(self, context, role_resolver): def __init__(self, context, resolver):
self.role_resolver = role_resolver self.resolver = resolver
self.context = context self.context = context
self.tasks_graph = {} self.tasks_graph = {}
self.tasks_dictionary = {} self.tasks_dictionary = {}
@ -165,15 +165,15 @@ class TransactionSerializer(object):
self.concurrency_policy = get_concurrency_policy() self.concurrency_policy = get_concurrency_policy()
@classmethod @classmethod
def serialize(cls, context, tasks, role_resolver): def serialize(cls, context, tasks, resolver):
"""Resolves roles and dependencies for tasks. """Resolves roles and dependencies for tasks.
:param context: the deployment context :param context: the deployment context
:param tasks: the deployment tasks :param tasks: the deployment tasks
:param role_resolver: the nodes role resolver :param resolver: the nodes tag resolver
:return: the list of serialized task per node :return: the list of serialized task per node
""" """
serializer = cls(context, role_resolver) serializer = cls(context, resolver)
serializer.process_tasks(tasks) serializer.process_tasks(tasks)
serializer.resolve_dependencies() serializer.resolve_dependencies()
tasks_graph = serializer.tasks_graph tasks_graph = serializer.tasks_graph
@ -248,8 +248,8 @@ class TransactionSerializer(object):
yield node_id, task yield node_id, task
for task in groups: for task in groups:
node_ids = self.role_resolver.resolve( node_ids = self.resolver.resolve(
task.get('roles', task.get('groups')) task.get('tags', task.get('roles', task.get('groups')))
) )
if not node_ids: if not node_ids:
continue continue
@ -279,8 +279,8 @@ class TransactionSerializer(object):
# all synchronisation tasks will run on sync node # all synchronisation tasks will run on sync node
return [None] return [None]
# TODO(bgaifullin) remove deprecated groups # TODO(bgaifullin) remove deprecated groups
return self.role_resolver.resolve( return self.resolver.resolve(
task.get('roles', task.get('groups')) task.get('tags', task.get('roles', task.get('groups')))
) )
def resolve_dependencies(self): def resolve_dependencies(self):
@ -338,7 +338,7 @@ class TransactionSerializer(object):
return return
for dep in six.moves.filter(None, dependencies): for dep in six.moves.filter(None, dependencies):
roles = dep.get('role', consts.TASK_ROLES.all) roles = dep.get('tags', dep.get('role', consts.TASK_ROLES.all))
if roles == consts.TASK_ROLES.self: if roles == consts.TASK_ROLES.self:
node_ids = [node_id] node_ids = [node_id]
@ -347,7 +347,7 @@ class TransactionSerializer(object):
node_ids = [None] node_ids = [None]
excludes = [] excludes = []
else: else:
node_ids = self.role_resolver.resolve( node_ids = self.resolver.resolve(
roles, dep.get('policy', consts.NODE_RESOLVE_POLICY.all) roles, dep.get('policy', consts.NODE_RESOLVE_POLICY.all)
) )
excludes = [(task_id, node_id)] excludes = [(task_id, node_id)]

View File

@ -825,36 +825,22 @@ class Cluster(NailgunObject):
return instance.roles_metadata return instance.roles_metadata
@classmethod @classmethod
def set_primary_role(cls, instance, nodes, role_name): def set_primary_tag(cls, instance, nodes, tag):
"""Method for assigning primary attribute for specific role. """Method for assigning primary attribute for specific tag.
- verify that there is no primary attribute of specific role
assigned to cluster nodes with this role in role list
or pending role list, and this node is not marked for deletion
- if there is no primary role assigned, filter nodes which have current
role in roles or pending_roles
- if there is nodes with ready state - they should have higher priority
- if role was in primary_role_list - change primary attribute
for that association, same for role_list, this is required
because deployment_serializer used by cli to generate deployment info
:param instance: Cluster db objects :param instance: Cluster db objects
:param nodes: list of Node db objects :param nodes: list of Node db objects
:param role_name: string with known role name :param tag: string with known tag name
""" """
if role_name not in cls.get_roles(instance): from objects import Node
logger.warning( node = cls.get_primary_node(instance, tag)
'Trying to assign primary for non-existing role %s', role_name)
return
node = cls.get_primary_node(instance, role_name)
if not node: if not node:
# get nodes with a given role name which are not going to be # get nodes with a given role name which are not going to be
# removed # removed
filtered_nodes = [] filtered_nodes = []
for node in nodes: for node in nodes:
if (not node.pending_deletion and ( if (not node.pending_deletion and (
role_name in set(node.roles + node.pending_roles))): tag in Node.get_tags(node))):
filtered_nodes.append(node) filtered_nodes.append(node)
filtered_nodes = sorted(filtered_nodes, key=lambda node: node.id) filtered_nodes = sorted(filtered_nodes, key=lambda node: node.id)
@ -864,27 +850,29 @@ class Cluster(NailgunObject):
if node.status == consts.NODE_STATUSES.ready), if node.status == consts.NODE_STATUSES.ready),
filtered_nodes[0]) filtered_nodes[0])
primary_node.primary_roles = list(primary_node.primary_roles) primary_node.primary_tags = list(primary_node.primary_tags)
primary_node.primary_roles.append(role_name) primary_node.primary_tags.append(tag)
db().flush() db().flush()
@classmethod @classmethod
def set_primary_roles(cls, instance, nodes): def set_primary_tags(cls, instance, nodes):
"""Assignment of all primary attribute for all roles that requires it. """Assignment of all primary attribute for all tags that requires it.
This method is idempotent This method is idempotent
To mark role as primary add has_primary: true attribute to release To mark tag as primary add "has_primary: true" attribute to tag meta
:param instance: Cluster db object :param instance: Cluster db object
:param nodes: list of Node db objects :param nodes: list of Node db objects
""" """
if not instance.is_ha_mode: if not instance.is_ha_mode:
return return
roles_metadata = cls.get_roles(instance)
for role, meta in six.iteritems(roles_metadata): tags_meta = cls.get_tags_metadata(instance)
if meta.get('has_primary'): for role, meta in six.iteritems(cls.get_roles(instance)):
cls.set_primary_role(instance, nodes, role) for tag in meta.get('tags', []):
if tags_meta[tag].get('has_primary'):
cls.set_primary_tag(instance, nodes, tag)
@classmethod @classmethod
def get_nodes_by_role(cls, instance, role_name): def get_nodes_by_role(cls, instance, role_name):
@ -925,36 +913,31 @@ class Cluster(NailgunObject):
return query return query
@classmethod @classmethod
def get_primary_node(cls, instance, role_name): def get_primary_node(cls, instance, tag):
"""Get primary node for role_name """Get primary node for tag
If primary node is not found None will be returned If primary node is not found None will be returned
Pending roles and roles are used in search
:param instance: cluster db object :param instance: cluster db object
:type: python object :type: python object
:param role_name: node role name :param tag: node tag name
:type: string :type: string
:returns: node db object or None :returns: node db object or None
""" """
logger.debug("Getting primary node for role: %s", role_name) logger.debug("Getting primary node for tag: %s", tag)
if role_name not in cls.get_roles(instance):
logger.debug("Role not found: %s", role_name)
return None
primary_node = db().query(models.Node).filter_by( primary_node = db().query(models.Node).filter_by(
pending_deletion=False, pending_deletion=False,
cluster_id=instance.id cluster_id=instance.id
).filter( ).filter(
models.Node.primary_roles.any(role_name) models.Node.primary_tags.any(tag)
).first() ).first()
if primary_node is None: if primary_node is None:
logger.debug("Not found primary node for role: %s", role_name) logger.debug("Not found primary node for tag: %s", tag)
else: else:
logger.debug("Found primary node: %s for role: %s", logger.debug("Found primary node: %s for tag: %s",
primary_node.id, role_name) primary_node.id, tag)
return primary_node return primary_node
@classmethod @classmethod
@ -1234,6 +1217,26 @@ class Cluster(NailgunObject):
tasks.append(task) tasks.append(task)
return tasks return tasks
@classmethod
def get_tags_metadata(cls, instance):
"""Return proper tags metadata for cluster
Metadata consists of general tags metadata from release,
tags metadata from cluster and tags metadata from
plugins which are enabled for this cluster.
:param instance: Cluster DB instance
:returns: dict -- object with merged tags metadata
"""
tags_meta = dict(instance.release.tags_metadata)
cluster_tags_meta = instance.tags_metadata
tags_meta.update(cluster_tags_meta)
plugins_tags_meta = PluginManager.get_tags_metadata(instance)
tags_meta.update(plugins_tags_meta)
return tags_meta
@classmethod @classmethod
def get_volumes_metadata(cls, instance): def get_volumes_metadata(cls, instance):
"""Return proper volumes metadata for cluster """Return proper volumes metadata for cluster

View File

@ -329,7 +329,7 @@ class Node(NailgunObject):
roles = data.pop("roles", None) roles = data.pop("roles", None)
pending_roles = data.pop("pending_roles", None) pending_roles = data.pop("pending_roles", None)
primary_roles = data.pop("primary_roles", None) primary_tags = data.pop("primary_tags", None)
new_node_meta = data.pop("meta", {}) new_node_meta = data.pop("meta", {})
new_node_cluster_id = data.pop("cluster_id", None) new_node_cluster_id = data.pop("cluster_id", None)
@ -354,8 +354,8 @@ class Node(NailgunObject):
cls.update_roles(new_node, roles) cls.update_roles(new_node, roles)
if pending_roles is not None: if pending_roles is not None:
cls.update_pending_roles(new_node, pending_roles) cls.update_pending_roles(new_node, pending_roles)
if primary_roles is not None: if primary_tags is not None:
cls.update_primary_roles(new_node, primary_roles) cls.update_primary_tags(new_node, primary_tags)
# adding node into cluster # adding node into cluster
if new_node_cluster_id: if new_node_cluster_id:
@ -759,7 +759,7 @@ class Node(NailgunObject):
instance.group_id = None instance.group_id = None
instance.kernel_params = None instance.kernel_params = None
cls.update_roles(instance, roles) cls.update_roles(instance, roles)
cls.update_primary_roles(instance, []) cls.update_primary_tags(instance, [])
cls.update_pending_roles(instance, pending_roles) cls.update_pending_roles(instance, pending_roles)
cls.remove_replaced_params(instance) cls.remove_replaced_params(instance)
cls.assign_group(instance) cls.assign_group(instance)
@ -911,38 +911,38 @@ class Node(NailgunObject):
db().flush() db().flush()
@classmethod @classmethod
def update_primary_roles(cls, instance, new_primary_roles): def update_primary_tags(cls, instance, new_primary_tags):
"""Update primary_roles for Node instance. """Update primary_tags for Node instance.
Logs an error if node doesn't belong to Cluster Logs an error if node doesn't belong to Cluster
:param instance: Node instance :param instance: Node instance
:param new_primary_roles: list of new pending role names :param new_primary_tags: list of new primary tag names
:returns: None :returns: None
""" """
if not instance.cluster_id: if not instance.cluster_id:
logger.warning( logger.warning(
u"Attempting to assign pending roles to node " u"Attempting to assign peimary tags to node "
u"'{0}' which isn't added to cluster".format( u"'{0}' which isn't added to cluster".format(
instance.full_name)) instance.full_name))
return return
assigned_roles = set(instance.roles + instance.pending_roles) assigned_tags = set(cls.get_tags(instance))
for role in new_primary_roles: missing_tags = set(new_primary_tags) - set(assigned_tags)
if role not in assigned_roles: if missing_tags:
logger.warning( logger.warning(
u"Could not mark node {0} as primary for {1} role, " u"Could not mark node {0} as primary for {1} tags, "
u"because there's no assigned {1} role.".format( u"because corresponding roles are not assigned.".format(
instance.full_name, role) instance.full_name, missing_tags)
) )
return return
logger.debug( logger.debug(
u"Updating primary roles for node {0}: {1}".format( u"Updating primary tags for node {0}: {1}".format(
instance.full_name, instance.full_name,
new_primary_roles)) new_primary_tags))
instance.primary_roles = new_primary_roles instance.primary_tags = new_primary_tags
db().flush() db().flush()
@classmethod @classmethod
@ -1029,7 +1029,7 @@ class Node(NailgunObject):
instance.cluster_id = None instance.cluster_id = None
instance.group_id = None instance.group_id = None
instance.kernel_params = None instance.kernel_params = None
instance.primary_roles = [] instance.primary_tags = []
instance.hostname = cls.default_slave_name(instance) instance.hostname = cls.default_slave_name(instance)
instance.attributes = {} instance.attributes = {}
@ -1044,7 +1044,7 @@ class Node(NailgunObject):
"""Move roles to pending_roles""" """Move roles to pending_roles"""
instance.pending_roles = instance.pending_roles + instance.roles instance.pending_roles = instance.pending_roles + instance.roles
instance.roles = [] instance.roles = []
instance.primary_roles = [] instance.primary_tags = []
db().flush() db().flush()
@classmethod @classmethod
@ -1113,14 +1113,35 @@ class Node(NailgunObject):
instance.network_template = None instance.network_template = None
@classmethod @classmethod
def all_roles(cls, instance): def get_tags(cls, instance):
"""Get node tags
Returns list of nodes tags based on roles assigned to it.
Primary tags are included into result as it is.
"""
roles = set(instance.roles + instance.pending_roles) roles = set(instance.roles + instance.pending_roles)
roles -= set(instance.primary_roles) roles_meta = Cluster.get_roles(instance.cluster)
tags = ()
for role in roles:
tags = itertools.chain(tags, roles_meta[role].get('tags', [role]))
return tags
primary_roles = set([ @classmethod
'primary-{0}'.format(role) for role in instance.primary_roles]) def all_tags(cls, instance):
"""Get node tags including primary-tags with prefix
return sorted(roles | primary_roles) Returns list of nodes tags based on roles assigned to it.
Primary tags are included into result with 'primary-' prefix.
This method is mostly used for node's tasks resolution.
"""
tags = set(cls.get_tags(instance))
tags -= set(instance.primary_tags)
primary_tags = set([
'primary-{0}'.format(tag) for tag in instance.primary_tags])
return sorted(tags | primary_tags)
@classmethod @classmethod
def apply_network_template(cls, instance, template): def apply_network_template(cls, instance, template):

View File

@ -74,6 +74,7 @@ class Release(NailgunObject):
for graph_type, graph_data in six.iteritems(graphs): for graph_type, graph_data in six.iteritems(graphs):
DeploymentGraph.create_for_model( DeploymentGraph.create_for_model(
graph_data, release_obj, graph_type) graph_data, release_obj, graph_type)
return release_obj return release_obj
@classmethod @classmethod

View File

@ -28,8 +28,8 @@ from nailgun import objects
from nailgun import plugins from nailgun import plugins
from nailgun.settings import settings from nailgun.settings import settings
from nailgun import utils from nailgun import utils
from nailgun.utils.role_resolver import NameMatchingPolicy from nailgun.utils.resolvers import NameMatchingPolicy
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
from nailgun.orchestrator.base_serializers import MuranoMetadataSerializerMixin from nailgun.orchestrator.base_serializers import MuranoMetadataSerializerMixin
from nailgun.orchestrator.base_serializers import \ from nailgun.orchestrator.base_serializers import \
@ -51,17 +51,17 @@ class DeploymentMultinodeSerializer(object):
def __init__(self, tasks_graph=None): def __init__(self, tasks_graph=None):
self.task_graph = tasks_graph self.task_graph = tasks_graph
self.all_nodes = None self.all_nodes = None
self.role_resolver = None self.resolver = None
self.initialized = None self.initialized = None
def initialize(self, cluster): def initialize(self, cluster):
self.all_nodes = objects.Cluster.get_nodes_not_for_deletion(cluster) self.all_nodes = objects.Cluster.get_nodes_not_for_deletion(cluster)
self.role_resolver = RoleResolver(self.all_nodes) self.resolver = TagResolver(self.all_nodes)
self.initialized = cluster.id self.initialized = cluster.id
def finalize(self): def finalize(self):
self.all_nodes = None self.all_nodes = None
self.role_resolver = None self.resolver = None
self.initialized = None self.initialized = None
def _ensure_initialized_for(self, cluster): def _ensure_initialized_for(self, cluster):
@ -162,7 +162,7 @@ class DeploymentMultinodeSerializer(object):
username = attrs['workloads_collector'].pop('user', None) username = attrs['workloads_collector'].pop('user', None)
attrs['workloads_collector']['username'] = username attrs['workloads_collector']['username'] = username
if self.role_resolver.resolve(['cinder']): if self.resolver.resolve(['cinder']):
attrs['use_cinder'] = True attrs['use_cinder'] = True
net_serializer = self.get_net_provider_serializer(cluster) net_serializer = self.get_net_provider_serializer(cluster)
@ -178,7 +178,7 @@ class DeploymentMultinodeSerializer(object):
node_list = [] node_list = []
for node in nodes: for node in nodes:
for role in objects.Node.all_roles(node): for role in objects.Node.all_tags(node):
node_list.append(cls.serialize_node_for_node_list(node, role)) node_list.append(cls.serialize_node_for_node_list(node, role))
return node_list return node_list
@ -207,7 +207,7 @@ class DeploymentMultinodeSerializer(object):
""" """
serialized_nodes = [] serialized_nodes = []
for node in nodes: for node in nodes:
for role in objects.Node.all_roles(node): for role in objects.Node.all_tags(node):
serialized_nodes.append( serialized_nodes.append(
self.serialize_node(node, role) self.serialize_node(node, role)
) )
@ -728,7 +728,7 @@ class DeploymentLCMSerializer(DeploymentHASerializer90):
def serialize_nodes(self, nodes): def serialize_nodes(self, nodes):
serialized_nodes = [] serialized_nodes = []
for node in nodes: for node in nodes:
roles = objects.Node.all_roles(node) roles = objects.Node.all_tags(node)
if roles: if roles:
serialized_nodes.append( serialized_nodes.append(
self.serialize_node(node, roles) self.serialize_node(node, roles)
@ -893,7 +893,7 @@ def _invoke_serializer(serializer, cluster, nodes,
cluster, cluster.nodes, ignore_customized cluster, cluster.nodes, ignore_customized
) )
objects.Cluster.set_primary_roles(cluster, nodes) objects.Cluster.set_primary_tags(cluster, nodes)
return serializer.serialize( return serializer.serialize(
cluster, nodes, cluster, nodes,
ignore_customized=ignore_customized, skip_extensions=skip_extensions ignore_customized=ignore_customized, skip_extensions=skip_extensions

View File

@ -30,7 +30,7 @@ from nailgun import objects
from nailgun.orchestrator import priority_serializers as ps from nailgun.orchestrator import priority_serializers as ps
from nailgun.orchestrator.tasks_serializer import TaskSerializers from nailgun.orchestrator.tasks_serializer import TaskSerializers
from nailgun.policy.name_match import NameMatchingPolicy from nailgun.policy.name_match import NameMatchingPolicy
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
class GraphSolver(nx.DiGraph): class GraphSolver(nx.DiGraph):
@ -432,7 +432,7 @@ class AstuteGraph(object):
:param nodes: list of node db objects :param nodes: list of node db objects
""" """
serialized = [] serialized = []
role_resolver = RoleResolver(nodes) resolver = TagResolver(nodes)
for task in tasks: for task in tasks:
@ -440,7 +440,7 @@ class AstuteGraph(object):
continue continue
serializer = self.serializers.get_stage_serializer(task)( serializer = self.serializers.get_stage_serializer(task)(
task, self.cluster, nodes, role_resolver=role_resolver) task, self.cluster, nodes, resolver=resolver)
if not serializer.should_execute(): if not serializer.should_execute():
continue continue

View File

@ -25,7 +25,7 @@ from nailgun import errors
from nailgun.logger import logger from nailgun.logger import logger
import nailgun.orchestrator.tasks_templates as templates import nailgun.orchestrator.tasks_templates as templates
from nailgun.settings import settings from nailgun.settings import settings
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
# TODO(bgaifullin) HUCK to prevent cycle imports # TODO(bgaifullin) HUCK to prevent cycle imports
from nailgun.plugins.manager import PluginManager from nailgun.plugins.manager import PluginManager
@ -34,17 +34,17 @@ from nailgun.plugins.manager import PluginManager
class BasePluginDeploymentHooksSerializer(object): class BasePluginDeploymentHooksSerializer(object):
# TODO(dshulyak) refactor it to be consistent with task_serializer # TODO(dshulyak) refactor it to be consistent with task_serializer
def __init__(self, cluster, nodes, role_resolver=None): def __init__(self, cluster, nodes, resolver=None):
"""Initialises. """Initialises.
:param cluster: the cluster object instance :param cluster: the cluster object instance
:param nodes: the list of nodes for deployment :param nodes: the list of nodes for deployment
:param role_resolver: the instance of BaseRoleResolver :param resolver: the instance of BaseRoleResolver
""" """
self.cluster = cluster self.cluster = cluster
self.nodes = nodes self.nodes = nodes
self.role_resolver = role_resolver or RoleResolver(nodes) self.resolver = resolver or TagResolver(nodes)
def deployment_tasks(self, plugins, stage): def deployment_tasks(self, plugins, stage):
plugin_tasks = [] plugin_tasks = []
@ -58,7 +58,7 @@ class BasePluginDeploymentHooksSerializer(object):
sorted_tasks = self._sort_by_stage_postfix(plugin_tasks) sorted_tasks = self._sort_by_stage_postfix(plugin_tasks)
for task in sorted_tasks: for task in sorted_tasks:
make_task = None make_task = None
uids = self.role_resolver.resolve(task['role']) uids = self.resolver.resolve(task.get('tags', task['role']))
if not uids: if not uids:
continue continue
@ -163,10 +163,10 @@ class PluginsPreDeploymentHooksSerializer(BasePluginDeploymentHooksSerializer):
for task in tasks_to_process: for task in tasks_to_process:
# plugin tasks may store information about node # plugin tasks may store information about node
# role not only in `role` key but also in `groups` # role not only in `role` key but also in `groups`
task_role = task.get('role', task.get('groups')) task_role = task.get('tags', task.get('role', task.get('groups')))
if task_role == consts.TASK_ROLES.all: if task_role == consts.TASK_ROLES.all:
# just return all nodes # just return all nodes
return self.role_resolver.resolve(consts.TASK_ROLES.all) return self.resolver.resolve(consts.TASK_ROLES.all)
elif isinstance(task_role, six.string_types): elif isinstance(task_role, six.string_types):
roles.add(task_role) roles.add(task_role)
elif isinstance(task_role, (list, tuple)): elif isinstance(task_role, (list, tuple)):
@ -187,7 +187,7 @@ class PluginsPreDeploymentHooksSerializer(BasePluginDeploymentHooksSerializer):
# executes `apt-get update` which fails on CentOS # executes `apt-get update` which fails on CentOS
roles.discard(consts.TASK_ROLES.master) roles.discard(consts.TASK_ROLES.master)
return list(self.role_resolver.resolve(roles)) return list(self.resolver.resolve(roles))
def create_repositories(self, plugins): def create_repositories(self, plugins):
operating_system = self.cluster.release.operating_system operating_system = self.cluster.release.operating_system

View File

@ -36,16 +36,16 @@ def stage_serialize(serializer, graph_tasks):
def pre_deployment_serialize(orchestrator_graph, cluster, nodes, def pre_deployment_serialize(orchestrator_graph, cluster, nodes,
role_resolver=None): resolver=None):
graph_tasks = orchestrator_graph.pre_tasks_serialize(nodes) graph_tasks = orchestrator_graph.pre_tasks_serialize(nodes)
return stage_serialize( return stage_serialize(
plugins_serializers.PluginsPreDeploymentHooksSerializer( plugins_serializers.PluginsPreDeploymentHooksSerializer(
cluster, nodes, role_resolver=role_resolver), graph_tasks) cluster, nodes, resolver=resolver), graph_tasks)
def post_deployment_serialize(orchestrator_graph, cluster, nodes, def post_deployment_serialize(orchestrator_graph, cluster, nodes,
role_resolver=None): resolver=None):
graph_tasks = orchestrator_graph.post_tasks_serialize(nodes) graph_tasks = orchestrator_graph.post_tasks_serialize(nodes)
return stage_serialize( return stage_serialize(
plugins_serializers.PluginsPostDeploymentHooksSerializer( plugins_serializers.PluginsPostDeploymentHooksSerializer(
cluster, nodes, role_resolver=role_resolver), graph_tasks) cluster, nodes, resolver=resolver), graph_tasks)

View File

@ -29,9 +29,9 @@ from nailgun.orchestrator.tasks_serializer import CreateVMsOnCompute
from nailgun.orchestrator.tasks_serializer import StandardConfigRolesHook from nailgun.orchestrator.tasks_serializer import StandardConfigRolesHook
from nailgun.orchestrator.tasks_serializer import TaskSerializers from nailgun.orchestrator.tasks_serializer import TaskSerializers
from nailgun.orchestrator.tasks_templates import make_noop_task from nailgun.orchestrator.tasks_templates import make_noop_task
from nailgun.utils.role_resolver import NameMatchingPolicy from nailgun.utils.resolvers import NameMatchingPolicy
from nailgun.utils.role_resolver import NullResolver from nailgun.utils.resolvers import NullResolver
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
class NoopSerializer(StandardConfigRolesHook): class NoopSerializer(StandardConfigRolesHook):
@ -40,11 +40,12 @@ class NoopSerializer(StandardConfigRolesHook):
return True return True
def get_uids(self): def get_uids(self):
roles = self.task.get('groups', self.task.get('role')) tags = self.task.get('tags', self.task.get('groups',
if roles is None: self.task.get('role')))
if tags is None:
# it means that task is not associated with any node # it means that task is not associated with any node
return [None] return [None]
return self.role_resolver.resolve(roles) return self.resolver.resolve(tags)
def serialize(self): def serialize(self):
uids = self.get_uids() uids = self.get_uids()
@ -60,7 +61,7 @@ class PluginTaskSerializer(StandardConfigRolesHook):
def serialize(self): def serialize(self):
serializer = self.serializer_class( serializer = self.serializer_class(
self.cluster, self.nodes, role_resolver=self.role_resolver self.cluster, self.nodes, resolver=self.resolver
) )
return itertools.chain( return itertools.chain(
serializer.serialize_begin_tasks(), serializer.serialize_begin_tasks(),
@ -417,7 +418,7 @@ class TasksSerializer(object):
self.deployment_nodes = nodes self.deployment_nodes = nodes
self.affected_node_ids = frozenset() self.affected_node_ids = frozenset()
self.cluster = cluster self.cluster = cluster
self.role_resolver = RoleResolver(self.deployment_nodes) self.resolver = TagResolver(self.deployment_nodes)
self.task_serializer = DeployTaskSerializer() self.task_serializer = DeployTaskSerializer()
self.task_processor = TaskProcessor() self.task_processor = TaskProcessor()
self.tasks_connections = collections.defaultdict(dict) self.tasks_connections = collections.defaultdict(dict)
@ -466,17 +467,17 @@ class TasksSerializer(object):
else: else:
tasks_mapping[task['id']] = task tasks_mapping[task['id']] = task
skip = not self.task_filter(task['id']) skip = not self.task_filter(task['id'])
self.process_task(task, self.role_resolver, skip) self.process_task(task, self.resolver, skip)
self.expand_task_groups(groups, tasks_mapping) self.expand_task_groups(groups, tasks_mapping)
# make sure that null node is present # make sure that null node is present
self.tasks_connections.setdefault(None, dict()) self.tasks_connections.setdefault(None, dict())
def process_task(self, task, role_resolver, skip=False): def process_task(self, task, resolver, skip=False):
"""Processes one task one nodes of cluster. """Processes one task one nodes of cluster.
:param task: the task instance :param task: the task instance
:param role_resolver: the role resolver :param resolver: the role resolver
:param skip: make the task as skipped :param skip: make the task as skipped
""" """
@ -485,7 +486,7 @@ class TasksSerializer(object):
) )
task_serializer = serializer_factory( task_serializer = serializer_factory(
task, self.cluster, self.deployment_nodes, task, self.cluster, self.deployment_nodes,
role_resolver=role_resolver resolver=resolver
) )
skipped = skip or not task_serializer.should_execute() skipped = skip or not task_serializer.should_execute()
force = self.events and self.events.check_subscription(task) force = self.events and self.events.check_subscription(task)
@ -493,12 +494,12 @@ class TasksSerializer(object):
# Do not call real serializer if it should be skipped # Do not call real serializer if it should be skipped
task_serializer = NoopSerializer( task_serializer = NoopSerializer(
task, self.cluster, self.deployment_nodes, task, self.cluster, self.deployment_nodes,
role_resolver=role_resolver resolver=resolver
) )
serialised_tasks = self.task_processor.process_tasks( serialised_tasks = self.task_processor.process_tasks(
task, task_serializer.serialize() task, task_serializer.serialize()
) )
for serialized in serialised_tasks: for serialized in serialised_tasks:
# all skipped task shall have type skipped # all skipped task shall have type skipped
# do not exclude them from graph to keep connections between nodes # do not exclude them from graph to keep connections between nodes
@ -576,7 +577,8 @@ class TasksSerializer(object):
""" """
for task in groups: for task in groups:
skipped = not self.task_filter(task['id']) skipped = not self.task_filter(task['id'])
node_ids = self.role_resolver.resolve(task.get('role', ())) node_ids = self.resolver.resolve(task.get('tags',
task.get('role', ())))
for sub_task_id in task.get('tasks', ()): for sub_task_id in task.get('tasks', ()):
try: try:
sub_task = task_mapping[sub_task_id] sub_task = task_mapping[sub_task_id]
@ -624,13 +626,13 @@ class TasksSerializer(object):
return return
for dep in dependencies: for dep in dependencies:
roles = dep.get('role', consts.TASK_ROLES.all) roles = dep.get('tags', dep.get('role', consts.TASK_ROLES.all))
if roles == consts.TASK_ROLES.self: if roles == consts.TASK_ROLES.self:
node_ids = [node_id] node_ids = [node_id]
excludes = [] excludes = []
else: else:
node_ids = self.role_resolver.resolve( node_ids = self.resolver.resolve(
roles, dep.get('policy', consts.NODE_RESOLVE_POLICY.all) roles, dep.get('policy', consts.NODE_RESOLVE_POLICY.all)
) )
excludes = [(node_id, task_id)] excludes = [(node_id, task_id)]

View File

@ -28,7 +28,7 @@ from nailgun.orchestrator import deployment_serializers
from nailgun.orchestrator import tasks_templates as templates from nailgun.orchestrator import tasks_templates as templates
from nailgun.settings import settings from nailgun.settings import settings
from nailgun import utils from nailgun import utils
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
@ -89,14 +89,15 @@ class PuppetHook(GenericNodeHook):
class StandardConfigRolesHook(ExpressionBasedTask): class StandardConfigRolesHook(ExpressionBasedTask):
"""Role hooks that serializes task based on config file only.""" """Role hooks that serializes task based on config file only."""
def __init__(self, task, cluster, nodes, role_resolver=None): def __init__(self, task, cluster, nodes, resolver=None):
super(StandardConfigRolesHook, self).__init__(task, cluster) super(StandardConfigRolesHook, self).__init__(task, cluster)
self.nodes = nodes self.nodes = nodes
self.role_resolver = role_resolver or RoleResolver(nodes) self.resolver = resolver or TagResolver(nodes)
def get_uids(self): def get_uids(self):
return list(self.role_resolver.resolve( return list(self.resolver.resolve(
self.task.get('role', self.task.get('groups')) self.task.get('tags', self.task.get('role',
self.task.get('groups')))
)) ))
def serialize(self): def serialize(self):
@ -115,7 +116,7 @@ class UploadMOSRepo(GenericRolesHook):
identity = 'upload_core_repos' identity = 'upload_core_repos'
def get_uids(self): def get_uids(self):
return list(self.role_resolver.resolve(consts.TASK_ROLES.all)) return list(self.resolver.resolve(consts.TASK_ROLES.all))
def serialize(self): def serialize(self):
uids = self.get_uids() uids = self.get_uids()
@ -159,7 +160,7 @@ class RsyncPuppet(GenericRolesHook):
identity = 'rsync_core_puppet' identity = 'rsync_core_puppet'
def get_uids(self): def get_uids(self):
return list(self.role_resolver.resolve(consts.TASK_ROLES.all)) return list(self.resolver.resolve(consts.TASK_ROLES.all))
def serialize(self): def serialize(self):
src_path = self.task['parameters']['src'].format( src_path = self.task['parameters']['src'].format(
@ -238,7 +239,7 @@ class IronicCopyBootstrapKey(CopyKeys):
identity = 'ironic_copy_bootstrap_key' identity = 'ironic_copy_bootstrap_key'
def should_execute(self): def should_execute(self):
return len(self.role_resolver.resolve(['ironic'])) > 0 return len(self.resolver.resolve(['ironic'])) > 0
class RestartRadosGW(GenericRolesHook): class RestartRadosGW(GenericRolesHook):
@ -258,9 +259,9 @@ class CreateVMsOnCompute(GenericRolesHook):
identity = 'generate_vms' identity = 'generate_vms'
hook_type = 'puppet' hook_type = 'puppet'
def __init__(self, task, cluster, nodes, role_resolver=None): def __init__(self, task, cluster, nodes, resolver=None):
super(CreateVMsOnCompute, self).__init__( super(CreateVMsOnCompute, self).__init__(
task, cluster, [], role_resolver task, cluster, [], resolver
) )
self.vm_nodes = objects.Cluster.get_nodes_to_spawn_vms(self.cluster) self.vm_nodes = objects.Cluster.get_nodes_to_spawn_vms(self.cluster)
@ -336,9 +337,9 @@ class UploadConfiguration(GenericRolesHook):
identity = 'upload_configuration' identity = 'upload_configuration'
def __init__(self, task, cluster, nodes, configs=None, role_resolver=None): def __init__(self, task, cluster, nodes, configs=None, resolver=None):
super(UploadConfiguration, self).__init__( super(UploadConfiguration, self).__init__(
task, cluster, nodes, role_resolver=role_resolver task, cluster, nodes, resolver=resolver
) )
self.configs = configs self.configs = configs

View File

@ -328,9 +328,23 @@ class PluginManager(object):
return result return result
@classmethod
def get_tags_metadata(cls, cluster):
"""Get tags metadata for all plugins enabled for the cluster
:param cluster: A cluster instance
:type cluster: Cluster model
:return: dict -- Object with merged tags data from plugins
"""
tags_metadata = {}
enabled_plugins = ClusterPlugin.get_enabled(cluster.id)
for plugin in enabled_plugins:
tags_metadata.update(plugin.tags_metadata)
return tags_metadata
@classmethod @classmethod
def get_volumes_metadata(cls, cluster): def get_volumes_metadata(cls, cluster):
"""Get volumes metadata for cluster from all plugins which enabled it. """Get volumes metadata for all plugins enabled for the cluster
:param cluster: A cluster instance :param cluster: A cluster instance
:type cluster: Cluster model :type cluster: Cluster model

View File

@ -191,6 +191,7 @@ class InstallationInfo(object):
WhiteListRule(('attributes_metadata',), 'attributes_metadata', None), WhiteListRule(('attributes_metadata',), 'attributes_metadata', None),
WhiteListRule(('volumes_metadata',), 'volumes_metadata', None), WhiteListRule(('volumes_metadata',), 'volumes_metadata', None),
WhiteListRule(('roles_metadata',), 'roles_metadata', None), WhiteListRule(('roles_metadata',), 'roles_metadata', None),
WhiteListRule(('tags_metadata',), 'tags_metadata', None),
WhiteListRule(('network_roles_metadata',), WhiteListRule(('network_roles_metadata',),
'network_roles_metadata', None), 'network_roles_metadata', None),
WhiteListRule(('components_metadata',), 'components_metadata', None), WhiteListRule(('components_metadata',), 'components_metadata', None),
@ -213,7 +214,7 @@ class InstallationInfo(object):
WhiteListRule(('name',), 'name', None), WhiteListRule(('name',), 'name', None),
WhiteListRule(('labels',), 'labels', None), WhiteListRule(('labels',), 'labels', None),
WhiteListRule(('roles',), 'roles', None), WhiteListRule(('roles',), 'roles', None),
WhiteListRule(('primary_roles',), 'primary_roles', None), WhiteListRule(('primary_tags',), 'primary_tags', None),
WhiteListRule(('os_platform',), 'os', None), WhiteListRule(('os_platform',), 'os', None),
WhiteListRule(('manufacturer',), 'manufacturer', None), WhiteListRule(('manufacturer',), 'manufacturer', None),
WhiteListRule(('platform_name',), 'platform_name', None), WhiteListRule(('platform_name',), 'platform_name', None),
@ -310,6 +311,7 @@ class InstallationInfo(object):
'components': cluster.components, 'components': cluster.components,
'cluster_plugins': cluster.cluster_plugins, 'cluster_plugins': cluster.cluster_plugins,
'roles_metadata': cluster.roles_metadata, 'roles_metadata': cluster.roles_metadata,
'tags_metadata': cluster.tags_metadata,
'volumes_metadata': cluster.volumes_metadata, 'volumes_metadata': cluster.volumes_metadata,
} }
clusters_info.append(cluster_info) clusters_info.append(cluster_info)

View File

@ -93,12 +93,12 @@ def _add_cross_depends(task, depends):
return task return task
def adapt_legacy_tasks(deployment_tasks, legacy_plugin_tasks, role_resolver): def adapt_legacy_tasks(deployment_tasks, legacy_plugin_tasks, resolver):
"""Adapt the legacy tasks to execute with Task Based Engine. """Adapt the legacy tasks to execute with Task Based Engine.
:param deployment_tasks: the list of deployment tasks :param deployment_tasks: the list of deployment tasks
:param legacy_plugin_tasks: the pre/post tasks from tasks.yaml :param legacy_plugin_tasks: the pre/post tasks from tasks.yaml
:param role_resolver: the RoleResolver instance :param resolver: the TagResolver instance
""" """
min_task_version = StrictVersion(consts.TASK_CROSS_DEPENDENCY) min_task_version = StrictVersion(consts.TASK_CROSS_DEPENDENCY)
@ -134,7 +134,7 @@ def adapt_legacy_tasks(deployment_tasks, legacy_plugin_tasks, role_resolver):
elif task['id'] in post_deployment_graph.node: elif task['id'] in post_deployment_graph.node:
required_for.add(TASK_END_TEMPLATE.format('post_deployment')) required_for.add(TASK_END_TEMPLATE.format('post_deployment'))
else: else:
for role in role_resolver.get_all_roles(_get_role(task)): for role in resolver.get_all_roles(_get_role(task)):
required_for.add(TASK_END_TEMPLATE.format(role)) required_for.add(TASK_END_TEMPLATE.format(role))
task['required_for'] = list(required_for) task['required_for'] = list(required_for)
if task_version < min_task_version: if task_version < min_task_version:
@ -167,7 +167,7 @@ def adapt_legacy_tasks(deployment_tasks, legacy_plugin_tasks, role_resolver):
logger.info("Added cross_depends for legacy task: %s", task['id']) logger.info("Added cross_depends for legacy task: %s", task['id'])
task_depends = [ task_depends = [
{'name': TASK_START_TEMPLATE.format(g), 'role': 'self'} {'name': TASK_START_TEMPLATE.format(g), 'role': 'self'}
for g in role_resolver.get_all_roles(_get_role(task)) for g in resolver.get_all_roles(_get_role(task))
] ]
yield _add_cross_depends(task, task_depends) yield _add_cross_depends(task, task_depends)

View File

@ -56,8 +56,8 @@ from nailgun.task.fake import FAKE_THREADS
from nailgun.task.helpers import TaskHelper from nailgun.task.helpers import TaskHelper
from nailgun.task.legacy_tasks_adapter import adapt_legacy_tasks from nailgun.task.legacy_tasks_adapter import adapt_legacy_tasks
from nailgun.utils import logs as logs_utils from nailgun.utils import logs as logs_utils
from nailgun.utils.resolvers import TagResolver
from nailgun.utils.restrictions import VmwareAttributesRestriction from nailgun.utils.restrictions import VmwareAttributesRestriction
from nailgun.utils.role_resolver import RoleResolver
def make_astute_message(task, method, respond_to, args): def make_astute_message(task, method, respond_to, args):
@ -337,7 +337,7 @@ class DeploymentTask(BaseDeploymentTask):
# NOTE(dshulyak) At this point parts of the orchestration can be empty, # NOTE(dshulyak) At this point parts of the orchestration can be empty,
# it should not cause any issues with deployment/progress and was # it should not cause any issues with deployment/progress and was
# done by design # done by design
role_resolver = RoleResolver(nodes) resolver = TagResolver(nodes)
serialized_cluster = deployment_serializers.serialize( serialized_cluster = deployment_serializers.serialize(
graph, transaction.cluster, nodes) graph, transaction.cluster, nodes)
@ -346,10 +346,10 @@ class DeploymentTask(BaseDeploymentTask):
pre_deployment = stages.pre_deployment_serialize( pre_deployment = stages.pre_deployment_serialize(
graph, transaction.cluster, nodes, graph, transaction.cluster, nodes,
role_resolver=role_resolver) resolver=resolver)
post_deployment = stages.post_deployment_serialize( post_deployment = stages.post_deployment_serialize(
graph, transaction.cluster, nodes, graph, transaction.cluster, nodes,
role_resolver=role_resolver) resolver=resolver)
if affected_nodes: if affected_nodes:
graph.reexecutable_tasks(events) graph.reexecutable_tasks(events)
@ -362,10 +362,10 @@ class DeploymentTask(BaseDeploymentTask):
pre_deployment_affected = stages.pre_deployment_serialize( pre_deployment_affected = stages.pre_deployment_serialize(
graph, transaction.cluster, affected_nodes, graph, transaction.cluster, affected_nodes,
role_resolver=role_resolver) resolver=resolver)
post_deployment_affected = stages.post_deployment_serialize( post_deployment_affected = stages.post_deployment_serialize(
graph, transaction.cluster, affected_nodes, graph, transaction.cluster, affected_nodes,
role_resolver=role_resolver) resolver=resolver)
cls._extend_tasks_list(pre_deployment, pre_deployment_affected) cls._extend_tasks_list(pre_deployment, pre_deployment_affected)
cls._extend_tasks_list(post_deployment, post_deployment_affected) cls._extend_tasks_list(post_deployment, post_deployment_affected)
@ -555,7 +555,7 @@ class ClusterTransaction(DeploymentTask):
# TODO(bgaifullin) Primary roles applied in deployment_serializers # TODO(bgaifullin) Primary roles applied in deployment_serializers
# need to move this code from deployment serializer # need to move this code from deployment serializer
# also role resolver should be created after serialization completed # also role resolver should be created after serialization completed
role_resolver = RoleResolver(nodes) resolver = TagResolver(nodes)
cluster = transaction.cluster cluster = transaction.cluster
if objects.Cluster.is_propagate_task_deploy_enabled(cluster): if objects.Cluster.is_propagate_task_deploy_enabled(cluster):
@ -566,12 +566,12 @@ class ClusterTransaction(DeploymentTask):
) )
else: else:
plugin_tasks = None plugin_tasks = None
tasks = adapt_legacy_tasks(tasks, plugin_tasks, role_resolver) tasks = adapt_legacy_tasks(tasks, plugin_tasks, resolver)
directory, graph, metadata = lcm.TransactionSerializer.serialize( directory, graph, metadata = lcm.TransactionSerializer.serialize(
context, context,
tasks, tasks,
role_resolver, resolver,
) )
logger.info("tasks serialization is finished.") logger.info("tasks serialization is finished.")

View File

@ -155,7 +155,7 @@ class TestReplacedDeploymentInfoSerialization(OrchestratorSerializerTestBase):
self.cluster = self.env.create( self.cluster = self.env.create(
release_kwargs={'version': self.env_version}, release_kwargs={'version': self.env_version},
cluster_kwargs={'api': False}) cluster_kwargs={'api': False})
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def test_replaced_tasks_is_not_preserved(self): def test_replaced_tasks_is_not_preserved(self):
node = self.env.create_node( node = self.env.create_node(
@ -184,7 +184,7 @@ class TestNovaOrchestratorSerializer(OrchestratorSerializerTestBase):
def setUp(self): def setUp(self):
super(TestNovaOrchestratorSerializer, self).setUp() super(TestNovaOrchestratorSerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact) self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode, network_manager='FlatDHCPManager'): def create_env(self, mode, network_manager='FlatDHCPManager'):
node_args = [ node_args = [
@ -488,7 +488,7 @@ class TestNovaNetworkOrchestratorSerializer61(OrchestratorSerializerTestBase):
cluster_db = self.db.query(Cluster).get(cluster['id']) cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db) objects.Cluster.prepare_for_deployment(cluster_db)
objects.Cluster.set_primary_roles(cluster_db, cluster_db.nodes) objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
self.db.flush() self.db.flush()
return cluster_db return cluster_db
@ -743,7 +743,7 @@ class TestNeutronOrchestratorSerializer61(OrchestratorSerializerTestBase):
cluster_db = self.db.query(Cluster).get(cluster['id']) cluster_db = self.db.query(Cluster).get(cluster['id'])
objects.Cluster.prepare_for_deployment(cluster_db) objects.Cluster.prepare_for_deployment(cluster_db)
objects.Cluster.set_primary_roles(cluster_db, cluster_db.nodes) objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
self.db.flush() self.db.flush()
return cluster_db return cluster_db
@ -1227,7 +1227,7 @@ class TestNovaOrchestratorHASerializer(OrchestratorSerializerTestBase):
def setUp(self): def setUp(self):
super(TestNovaOrchestratorHASerializer, self).setUp() super(TestNovaOrchestratorHASerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact) self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode): def create_env(self, mode):
cluster = self.env.create( cluster = self.env.create(
@ -1454,7 +1454,7 @@ class TestNeutronOrchestratorSerializer(OrchestratorSerializerTestBase):
def setUp(self): def setUp(self):
super(TestNeutronOrchestratorSerializer, self).setUp() super(TestNeutronOrchestratorSerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact) self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode, segment_type='vlan'): def create_env(self, mode, segment_type='vlan'):
release_kwargs = {} release_kwargs = {}
@ -2128,10 +2128,11 @@ class TestNeutronOrchestratorHASerializer(OrchestratorSerializerTestBase):
def setUp(self): def setUp(self):
super(TestNeutronOrchestratorHASerializer, self).setUp() super(TestNeutronOrchestratorHASerializer, self).setUp()
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact) self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
def create_env(self, mode): def create_env(self, mode):
cluster = self.env.create( cluster = self.env.create(
api=True,
release_kwargs={'version': self.env_version}, release_kwargs={'version': self.env_version},
cluster_kwargs={ cluster_kwargs={
'mode': mode, 'mode': mode,
@ -2857,7 +2858,7 @@ class TestDeploymentGraphlessSerializers(OrchestratorSerializerTestBase):
{'roles': [], 'pending_roles': ['cinder'], {'roles': [], 'pending_roles': ['cinder'],
'pending_addition': True}] 'pending_addition': True}]
) )
objects.Cluster.set_primary_roles(self.cluster, self.cluster.nodes) objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
@property @property
def serializer(self): def serializer(self):

View File

@ -766,11 +766,12 @@ class TestPluginDeploymentTasksInjection70(base.BaseIntegrationTest):
'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.vlan, 'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.vlan,
}, },
nodes_kwargs=[ nodes_kwargs=[
{'roles': ['controller'], 'primary_roles': ['controller'], {'roles': ['controller'], 'primary_tags': ['controller'],
'pending_addition': True} 'pending_addition': True}
] ]
) )
objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
self.plugin_data = { self.plugin_data = {
'package_version': '3.0.0', 'package_version': '3.0.0',
'releases': [ 'releases': [
@ -1128,6 +1129,8 @@ class TestRolesSerializationWithPlugins(BaseDeploymentSerializer,
objects.Cluster.prepare_for_deployment(self.cluster) objects.Cluster.prepare_for_deployment(self.cluster)
serializer = self._get_serializer(self.cluster) serializer = self._get_serializer(self.cluster)
with mock.patch('nailgun.objects.node.Node.all_tags',
mock.Mock(return_value=['test_role'])):
serialized_data = serializer.serialize( serialized_data = serializer.serialize(
self.cluster, self.cluster.nodes) self.cluster, self.cluster.nodes)
serialized_data = deployment_info_to_legacy(serialized_data) serialized_data = deployment_info_to_legacy(serialized_data)
@ -1868,7 +1871,7 @@ class TestNetworkTemplateSerializer70(BaseDeploymentSerializer,
def check_vendor_specific_is_not_set(self, use_net_template=False): def check_vendor_specific_is_not_set(self, use_net_template=False):
node = self.env.create_node( node = self.env.create_node(
cluster_id=self.cluster.id, cluster_id=self.cluster.id,
roles=['controller'], primary_roles=['controller'] roles=['controller'], primary_tags=['controller']
) )
objects.Cluster.set_network_template( objects.Cluster.set_network_template(
self.cluster, self.cluster,

View File

@ -316,7 +316,7 @@ class TestDeploymentAttributesSerialization80(
def test_neutron_attrs(self): def test_neutron_attrs(self):
self.env.create_node( self.env.create_node(
cluster_id=self.cluster_db.id, cluster_id=self.cluster_db.id,
roles=['controller'], primary_roles=['controller'] roles=['controller'], primary_tags=['controller']
) )
objects.Cluster.prepare_for_deployment(self.cluster_db) objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized_for_astute = self.serializer.serialize( serialized_for_astute = self.serializer.serialize(
@ -340,7 +340,7 @@ class TestDeploymentAttributesSerialization80(
def test_baremetal_transformations(self): def test_baremetal_transformations(self):
self.env._set_additional_component(self.cluster_db, 'ironic', True) self.env._set_additional_component(self.cluster_db, 'ironic', True)
self.env.create_node(cluster_id=self.cluster_db.id, self.env.create_node(cluster_id=self.cluster_db.id,
roles=['primary-controller']) roles=['controller'])
objects.Cluster.prepare_for_deployment(self.cluster_db) objects.Cluster.prepare_for_deployment(self.cluster_db)
serialized_for_astute = self.serializer.serialize( serialized_for_astute = self.serializer.serialize(
self.cluster_db, self.cluster_db.nodes) self.cluster_db, self.cluster_db.nodes)

View File

@ -802,7 +802,7 @@ class TestNetworkTemplateSerializer90CompatibleWith80(
def check_vendor_specific_is_not_set(self, use_net_template=False): def check_vendor_specific_is_not_set(self, use_net_template=False):
node = self.env.create_node( node = self.env.create_node(
cluster_id=self.cluster.id, cluster_id=self.cluster.id,
roles=['controller'], primary_roles=['controller'] roles=['controller'], primary_tags=['controller']
) )
objects.Cluster.set_network_template( objects.Cluster.set_network_template(
self.cluster, self.cluster,
@ -863,7 +863,7 @@ class TestNetworkTemplateSerializer90(
def check_selective_gateway(self, use_net_template=False): def check_selective_gateway(self, use_net_template=False):
node = self.env.create_node( node = self.env.create_node(
cluster_id=self.cluster.id, cluster_id=self.cluster.id,
roles=['controller'], primary_roles=['controller'] roles=['controller'], primary_tags=['controller']
) )
objects.Cluster.set_network_template( objects.Cluster.set_network_template(
self.cluster, self.cluster,

View File

@ -193,7 +193,7 @@ class TestTaskManagers(BaseIntegrationTest):
@mock.patch('nailgun.task.task.rpc.cast') @mock.patch('nailgun.task.task.rpc.cast')
@mock.patch('objects.Cluster.get_deployment_tasks') @mock.patch('objects.Cluster.get_deployment_tasks')
def test_deployment_tasks_assigned_for_primary_roles( def test_deployment_tasks_assigned_for_primary_tags(
self, tasks_mock, rpc_mock self, tasks_mock, rpc_mock
): ):
tasks_mock.return_value = [ tasks_mock.return_value = [
@ -1187,16 +1187,16 @@ class TestTaskManagers(BaseIntegrationTest):
nodes_kwargs=[{'roles': ['controller'], nodes_kwargs=[{'roles': ['controller'],
'status': consts.NODE_STATUSES.ready}] * 3) 'status': consts.NODE_STATUSES.ready}] * 3)
task_manager = manager.NodeDeletionTaskManager(cluster_id=cluster.id) task_manager = manager.NodeDeletionTaskManager(cluster_id=cluster.id)
objects.Cluster.set_primary_roles(cluster, self.env.nodes) objects.Cluster.set_primary_tags(cluster, self.env.nodes)
primary_node = filter( primary_node = filter(
lambda n: 'controller' in n.primary_roles, lambda n: 'controller' in n.primary_tags,
self.env.nodes)[0] self.env.nodes)[0]
task_manager.execute([primary_node]) task_manager.execute([primary_node])
self.env.refresh_nodes() self.env.refresh_nodes()
new_primary = filter( new_primary = filter(
lambda n: ('controller' in n.primary_roles and lambda n: ('primary-controller' in objects.Node.all_tags(n) and
n.pending_deletion is False), n.pending_deletion is False),
self.env.nodes)[0] self.env.nodes)[0]

View File

@ -578,7 +578,7 @@ class TestTransactionManager(base.BaseIntegrationTest):
self.assertEqual(task.status, consts.TASK_STATUSES.ready) self.assertEqual(task.status, consts.TASK_STATUSES.ready)
@mock.patch('nailgun.transactions.manager.rpc') @mock.patch('nailgun.transactions.manager.rpc')
def test_execute_for_primary_roles(self, rpc_mock): def test_execute_for_primary_tags(self, rpc_mock):
self.graph.tasks.append(objects.DeploymentGraphTask.create( self.graph.tasks.append(objects.DeploymentGraphTask.create(
{ {
'id': 'test_task_2', 'id': 'test_task_2',

View File

@ -0,0 +1,101 @@
# coding: utf-8
# Copyright 2016 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import alembic
from oslo_serialization import jsonutils
import sqlalchemy as sa
from nailgun.db import db
from nailgun.db import dropdb
from nailgun.db.migration import ALEMBIC_CONFIG
from nailgun.test import base
_prepare_revision = 'dc8bc8751c42'
_test_revision = 'c6edea552f1e'
def setup_module():
dropdb()
alembic.command.upgrade(ALEMBIC_CONFIG, _prepare_revision)
prepare()
alembic.command.downgrade(ALEMBIC_CONFIG, _test_revision)
def prepare():
meta = base.reflect_db_metadata()
result = db.execute(
meta.tables['releases'].insert(),
[{
'name': 'test_name',
'version': '2016.1-11.0',
'operating_system': 'ubuntu',
'state': 'available',
'roles': jsonutils.dumps([
'controller',
]),
'roles_metadata': jsonutils.dumps({
'controller': {
'name': 'Controller',
},
}),
'is_deployable': True
}])
release_id = result.inserted_primary_key[0]
result = db.execute(
meta.tables['clusters'].insert(),
[{
'name': 'test_env1',
'release_id': release_id,
'mode': 'ha_compact',
'status': 'operational',
'net_provider': 'neutron',
'grouping': 'roles',
'fuel_version': '10.0',
}])
cluster_id = result.inserted_primary_key[0]
result = db.execute(
meta.tables['nodes'].insert(),
[{
'uuid': 'fcd49872-3917-4a18-98f9-3f5acfe3fdec',
'cluster_id': cluster_id,
'group_id': None,
'status': 'ready',
'roles': ['role_x', 'role_y'],
'primary_tags': ['role_y', 'test'],
'meta': '{}',
'mac': 'bb:aa:aa:aa:aa:aa',
'timestamp': datetime.datetime.utcnow(),
}]
)
db.commit()
class TestPluginTags(base.BaseAlembicMigrationTest):
def test_primary_tags_downgrade(self):
nodes = self.meta.tables['nodes']
query = sa.select([nodes.c.primary_roles]).where(
nodes.c.uuid == 'fcd49872-3917-4a18-98f9-3f5acfe3fdec')
primary_roles = db.execute(query).fetchone()[0]
self.assertItemsEqual(primary_roles, ['role_y'])

View File

@ -20,7 +20,7 @@ import multiprocessing.dummy
from nailgun import consts from nailgun import consts
from nailgun import errors from nailgun import errors
from nailgun import lcm from nailgun import lcm
from nailgun.utils.role_resolver import RoleResolver from nailgun.utils.resolvers import TagResolver
from nailgun.test.base import BaseUnitTest from nailgun.test.base import BaseUnitTest
@ -108,13 +108,13 @@ class TestTransactionSerializer(BaseUnitTest):
} }
}) })
with mock.patch('nailgun.utils.role_resolver.objects') as m_objects: with mock.patch('nailgun.utils.resolvers.objects') as m_objects:
m_objects.Node.all_roles = lambda x: x.roles m_objects.Node.all_tags = lambda x: x.roles
cls.role_resolver = RoleResolver(cls.nodes) cls.resolver = TagResolver(cls.nodes)
def test_serialize_integration(self): def test_serialize_integration(self):
serialized = lcm.TransactionSerializer.serialize( serialized = lcm.TransactionSerializer.serialize(
self.context, self.tasks, self.role_resolver self.context, self.tasks, self.resolver
)[1] )[1]
# controller # controller
self.datadiff( self.datadiff(
@ -191,7 +191,7 @@ class TestTransactionSerializer(BaseUnitTest):
def test_resolve_nodes(self): def test_resolve_nodes(self):
serializer = lcm.TransactionSerializer( serializer = lcm.TransactionSerializer(
self.context, self.role_resolver self.context, self.resolver
) )
self.assertEqual( self.assertEqual(
[None], [None],
@ -219,7 +219,7 @@ class TestTransactionSerializer(BaseUnitTest):
def test_dependencies_de_duplication(self): def test_dependencies_de_duplication(self):
serializer = lcm.TransactionSerializer( serializer = lcm.TransactionSerializer(
self.context, self.role_resolver self.context, self.resolver
) )
serializer.tasks_graph = { serializer.tasks_graph = {
None: {}, None: {},
@ -277,7 +277,7 @@ class TestTransactionSerializer(BaseUnitTest):
'tasks': ['task4', 'task2'] 'tasks': ['task4', 'task2']
}) })
serialized = lcm.TransactionSerializer.serialize( serialized = lcm.TransactionSerializer.serialize(
self.context, tasks, self.role_resolver self.context, tasks, self.resolver
) )
tasks_per_node = serialized[1] tasks_per_node = serialized[1]
self.datadiff( self.datadiff(
@ -326,7 +326,7 @@ class TestTransactionSerializer(BaseUnitTest):
def test_expand_dependencies(self): def test_expand_dependencies(self):
serializer = lcm.TransactionSerializer( serializer = lcm.TransactionSerializer(
self.context, self.role_resolver self.context, self.resolver
) )
serializer.tasks_graph = { serializer.tasks_graph = {
'1': {'task1': {}}, '1': {'task1': {}},
@ -342,7 +342,7 @@ class TestTransactionSerializer(BaseUnitTest):
def test_expand_cross_dependencies(self): def test_expand_cross_dependencies(self):
serializer = lcm.TransactionSerializer( serializer = lcm.TransactionSerializer(
self.context, self.role_resolver self.context, self.resolver
) )
serializer.tasks_graph = { serializer.tasks_graph = {
'1': {'task1': {}, 'task2': {}}, '1': {'task1': {}, 'task2': {}},
@ -380,7 +380,7 @@ class TestTransactionSerializer(BaseUnitTest):
def test_need_update_task(self): def test_need_update_task(self):
serializer = lcm.TransactionSerializer( serializer = lcm.TransactionSerializer(
self.context, self.role_resolver self.context, self.resolver
) )
self.assertTrue(serializer.need_update_task( self.assertTrue(serializer.need_update_task(
{}, {"id": "task1", "type": "puppet"} {}, {"id": "task1", "type": "puppet"}

View File

@ -59,9 +59,9 @@ class TestLegacyTasksAdapter(BaseTestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestLegacyTasksAdapter, cls).setUpClass() super(TestLegacyTasksAdapter, cls).setUpClass()
cls.role_resolver = mock.MagicMock() cls.resolver = mock.MagicMock()
cls.role_resolver.get_all_roles.side_effect = \ cls.resolver.get_all_roles.side_effect = \
cls.role_resolver_side_effect cls.resolver_side_effect
def test_returns_same_task_if_no_legacy(self): def test_returns_same_task_if_no_legacy(self):
tasks = [ tasks = [
@ -71,7 +71,7 @@ class TestLegacyTasksAdapter(BaseTestCase):
{'id': 'group1', 'type': consts.ORCHESTRATOR_TASK_TYPES.group}, {'id': 'group1', 'type': consts.ORCHESTRATOR_TASK_TYPES.group},
{'id': 'stage1', 'type': consts.ORCHESTRATOR_TASK_TYPES.stage} {'id': 'stage1', 'type': consts.ORCHESTRATOR_TASK_TYPES.stage}
] ]
new_tasks = list(adapt_legacy_tasks(tasks, None, self.role_resolver)) new_tasks = list(adapt_legacy_tasks(tasks, None, self.resolver))
self.datadiff(tasks, new_tasks, ignore_keys='required_for') self.datadiff(tasks, new_tasks, ignore_keys='required_for')
self.assertEqual([], tasks[0].get('required_for', [])) self.assertEqual([], tasks[0].get('required_for', []))
self.assertEqual( self.assertEqual(
@ -79,7 +79,7 @@ class TestLegacyTasksAdapter(BaseTestCase):
) )
@staticmethod @staticmethod
def role_resolver_side_effect(roles): def resolver_side_effect(roles):
if isinstance(roles, six.string_types): if isinstance(roles, six.string_types):
roles = [roles] roles = [roles]
return set(roles) return set(roles)
@ -118,7 +118,7 @@ class TestLegacyTasksAdapter(BaseTestCase):
] ]
tasks.extend(stages) tasks.extend(stages)
new_tasks = list(adapt_legacy_tasks(tasks, [], self.role_resolver)) new_tasks = list(adapt_legacy_tasks(tasks, [], self.resolver))
self.assertEqual( self.assertEqual(
{ {
@ -297,7 +297,7 @@ class TestLegacyTasksAdapter(BaseTestCase):
} }
] ]
new_tasks = list(adapt_legacy_tasks( new_tasks = list(adapt_legacy_tasks(
tasks, legacy_plugin_tasks, self.role_resolver tasks, legacy_plugin_tasks, self.resolver
)) ))
stage1_tasks = new_tasks[-5:-2] stage1_tasks = new_tasks[-5:-2]
depends = [{'role': None, 'name': 'stage1_end'}] depends = [{'role': None, 'name': 'stage1_end'}]

View File

@ -0,0 +1,115 @@
# Copyright 2016 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import alembic
from oslo_serialization import jsonutils
import six
import sqlalchemy as sa
from nailgun.db import db
from nailgun.db import dropdb
from nailgun.db.migration import ALEMBIC_CONFIG
from nailgun.test import base
_prepare_revision = 'c6edea552f1e'
_test_revision = 'dc8bc8751c42'
def setup_module():
dropdb()
alembic.command.upgrade(ALEMBIC_CONFIG, _prepare_revision)
prepare()
alembic.command.upgrade(ALEMBIC_CONFIG, _test_revision)
def prepare():
meta = base.reflect_db_metadata()
result = db.execute(
meta.tables['releases'].insert(),
[{
'name': 'test_name',
'version': '2016.1-11.0',
'operating_system': 'ubuntu',
'state': 'available',
'roles': jsonutils.dumps([
'controller',
]),
'roles_metadata': jsonutils.dumps({
'controller': {
'name': 'Controller',
'has_primary': True
},
'compute': {
'name': 'Compute'
},
}),
'is_deployable': True
}])
release_id = result.inserted_primary_key[0]
result = db.execute(
meta.tables['clusters'].insert(),
[{
'name': 'test_env1',
'release_id': release_id,
'mode': 'ha_compact',
'status': 'operational',
'net_provider': 'neutron',
'grouping': 'roles',
'fuel_version': '10.0',
}])
cluster_id = result.inserted_primary_key[0]
result = db.execute(
meta.tables['nodes'].insert(),
[{
'uuid': 'fcd49872-3917-4a18-98f9-3f5acfe3fdec',
'cluster_id': cluster_id,
'group_id': None,
'status': 'ready',
'roles': ['role_x', 'role_y'],
'primary_roles': ['role_y'],
'meta': '{}',
'mac': 'bb:aa:aa:aa:aa:aa',
'timestamp': datetime.datetime.utcnow(),
}]
)
db.commit()
class TestTags(base.BaseAlembicMigrationTest):
def test_primary_tags_migration(self):
nodes = self.meta.tables['nodes']
query = sa.select([nodes.c.primary_tags]).where(
nodes.c.uuid == 'fcd49872-3917-4a18-98f9-3f5acfe3fdec')
primary_tags = db.execute(query).fetchone()[0]
self.assertItemsEqual(primary_tags, ['role_y'])
def test_tags_meta_migration(self):
releases = self.meta.tables['releases']
query = sa.select([releases.c.roles_metadata,
releases.c.tags_metadata])
for roles_meta, tags_meta in db.execute(query):
tags_meta = jsonutils.loads(tags_meta)
for role_name, role_meta in six.iteritems(
jsonutils.loads(roles_meta)):
self.assertEqual(
tags_meta[role_name].get('has_primary', False),
role_meta.get('has_primary', False)
)

View File

@ -209,7 +209,7 @@ class TestNodeObject(BaseIntegrationTest):
self.assertEqual(new_cluster.id, node.cluster_id) self.assertEqual(new_cluster.id, node.cluster_id)
self.assertEqual(new_group.id, node.group_id) self.assertEqual(new_group.id, node.group_id)
self.assertEqual([], node.roles) self.assertEqual([], node.roles)
self.assertEqual([], node.primary_roles) self.assertEqual([], node.primary_tags)
self.assertItemsEqual(roles, node.pending_roles) self.assertItemsEqual(roles, node.pending_roles)
self.assertEqual(node.attributes, cluster.release.node_attributes) self.assertEqual(node.attributes, cluster.release.node_attributes)
@ -257,7 +257,7 @@ class TestNodeObject(BaseIntegrationTest):
self.assertEqual(new_cluster.id, node.cluster_id) self.assertEqual(new_cluster.id, node.cluster_id)
self.assertEqual(new_group.id, node.group_id) self.assertEqual(new_group.id, node.group_id)
self.assertEqual([], node.roles) self.assertEqual([], node.roles)
self.assertEqual([], node.primary_roles) self.assertEqual([], node.primary_tags)
self.assertItemsEqual(roles, node.pending_roles) self.assertItemsEqual(roles, node.pending_roles)
self.assertIsNotNone(node.network_template) self.assertIsNotNone(node.network_template)
endpoints = node.network_template['templates']['common']['endpoints'] endpoints = node.network_template['templates']['common']['endpoints']

View File

@ -26,7 +26,7 @@ from nailgun.orchestrator.plugins_serializers import \
from nailgun.orchestrator.plugins_serializers import \ from nailgun.orchestrator.plugins_serializers import \
PluginsPreDeploymentHooksSerializer PluginsPreDeploymentHooksSerializer
from nailgun.test import base from nailgun.test import base
from nailgun.utils.role_resolver import NullResolver from nailgun.utils.resolvers import NullResolver
class TestBasePluginDeploymentHooksSerializer(base.BaseTestCase): class TestBasePluginDeploymentHooksSerializer(base.BaseTestCase):
@ -42,7 +42,7 @@ class TestBasePluginDeploymentHooksSerializer(base.BaseTestCase):
self.hook = BasePluginDeploymentHooksSerializer( self.hook = BasePluginDeploymentHooksSerializer(
self.nodes, self.nodes,
self.cluster, self.cluster,
role_resolver=NullResolver({x['id'] for x in self.nodes}) resolver=NullResolver([x['id'] for x in self.nodes])
) )
def test_tasks_are_serializable(self): def test_tasks_are_serializable(self):
@ -161,7 +161,7 @@ class TestTasksDeploymentOrder(base.BaseTestCase):
self.hook = BasePluginDeploymentHooksSerializer( self.hook = BasePluginDeploymentHooksSerializer(
self.nodes, self.nodes,
self.cluster, self.cluster,
role_resolver=NullResolver([x['id'] for x in self.nodes]) resolver=NullResolver([x['id'] for x in self.nodes])
) )
def make_plugin_mock_with_stages(self, plugin_name, stages): def make_plugin_mock_with_stages(self, plugin_name, stages):
@ -238,7 +238,7 @@ class TestPluginsPreDeploymentHooksSerializer(
self.hook = PluginsPreDeploymentHooksSerializer( self.hook = PluginsPreDeploymentHooksSerializer(
self.cluster, self.cluster,
self.nodes, self.nodes,
role_resolver=NullResolver([x['id'] for x in self.nodes])) resolver=NullResolver([x['id'] for x in self.nodes]))
@mock.patch( @mock.patch(
'nailgun.orchestrator.plugins_serializers.' 'nailgun.orchestrator.plugins_serializers.'
@ -298,7 +298,7 @@ class TestPluginsPostDeploymentHooksSerializer(
self.hook = PluginsPostDeploymentHooksSerializer( self.hook = PluginsPostDeploymentHooksSerializer(
self.cluster, self.cluster,
self.nodes, self.nodes,
role_resolver=NullResolver([x['id'] for x in self.nodes])) resolver=NullResolver([x['id'] for x in self.nodes]))
def test_serialize_begin_tasks(self): def test_serialize_begin_tasks(self):
self.assertItemsEqual(self.hook.serialize_begin_tasks(), list()) self.assertItemsEqual(self.hook.serialize_begin_tasks(), list())

View File

@ -18,6 +18,7 @@ from contextlib import contextmanager
import six import six
from nailgun import consts from nailgun import consts
from nailgun.db import db
from nailgun import objects from nailgun import objects
from nailgun.test import base from nailgun.test import base
@ -49,13 +50,13 @@ class BasePrimaryRolesAssignmentTestCase(base.BaseTestCase):
{'pending_roles': [self.role_name], {'pending_roles': [self.role_name],
'status': consts.NODE_STATUSES.discover, 'status': consts.NODE_STATUSES.discover,
'pending_addition': True}]) 'pending_addition': True}])
objects.Cluster.set_primary_roles(cluster, cluster.nodes) objects.Cluster.set_primary_tags(cluster, cluster.nodes)
nodes = sorted(cluster.nodes, key=lambda node: node.id) nodes = sorted(cluster.nodes, key=lambda node: node.id)
# with lowest uid is assigned as primary # with lowest uid is assigned as primary
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[0]), [self.primary_role_name]) objects.Node.all_tags(nodes[0]), [self.primary_role_name])
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[1]), [self.role_name]) objects.Node.all_tags(nodes[1]), [self.role_name])
def test_primary_controller_assigned_for_ready_node(self): def test_primary_controller_assigned_for_ready_node(self):
cluster = self.env.create( cluster = self.env.create(
@ -69,16 +70,16 @@ class BasePrimaryRolesAssignmentTestCase(base.BaseTestCase):
{'roles': [self.role_name], {'roles': [self.role_name],
'status': consts.NODE_STATUSES.ready, 'status': consts.NODE_STATUSES.ready,
'pending_addition': True}]) 'pending_addition': True}])
objects.Cluster.set_primary_roles(cluster, cluster.nodes) objects.Cluster.set_primary_tags(cluster, cluster.nodes)
# primary assigned to node with ready status # primary assigned to node with ready status
nodes = sorted(cluster.nodes, key=lambda node: node.id) nodes = sorted(cluster.nodes, key=lambda node: node.id)
ready_node = next(n for n in cluster.nodes ready_node = next(n for n in cluster.nodes
if n.status == consts.NODE_STATUSES.ready) if n.status == consts.NODE_STATUSES.ready)
self.assertEqual(nodes[1], ready_node) self.assertEqual(nodes[1], ready_node)
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[1]), [self.primary_role_name]) objects.Node.all_tags(nodes[1]), [self.primary_role_name])
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[0]), [self.role_name]) objects.Node.all_tags(nodes[0]), [self.role_name])
def test_primary_assignment_multinode(self): def test_primary_assignment_multinode(self):
"""Primary should not be assigned in multinode env.""" """Primary should not be assigned in multinode env."""
@ -95,11 +96,11 @@ class BasePrimaryRolesAssignmentTestCase(base.BaseTestCase):
{'roles': [self.role_name], {'roles': [self.role_name],
'status': consts.NODE_STATUSES.ready, 'status': consts.NODE_STATUSES.ready,
'pending_addition': True}]) 'pending_addition': True}])
objects.Cluster.set_primary_roles(cluster, cluster.nodes) objects.Cluster.set_primary_tags(cluster, cluster.nodes)
self.assertEqual( self.assertEqual(
objects.Node.all_roles(cluster.nodes[0]), [self.role_name]) objects.Node.all_tags(cluster.nodes[0]), [self.role_name])
self.assertEqual( self.assertEqual(
objects.Node.all_roles(cluster.nodes[1]), [self.role_name]) objects.Node.all_tags(cluster.nodes[1]), [self.role_name])
def test_primary_not_assigned_to_pending_deletion(self): def test_primary_not_assigned_to_pending_deletion(self):
cluster = self.env.create( cluster = self.env.create(
@ -110,9 +111,9 @@ class BasePrimaryRolesAssignmentTestCase(base.BaseTestCase):
{'roles': [self.role_name], {'roles': [self.role_name],
'status': consts.NODE_STATUSES.ready, 'status': consts.NODE_STATUSES.ready,
'pending_deletion': True}]) 'pending_deletion': True}])
objects.Cluster.set_primary_roles(cluster, cluster.nodes) objects.Cluster.set_primary_tags(cluster, cluster.nodes)
self.assertEqual( self.assertEqual(
objects.Node.all_roles(cluster.nodes[0]), [self.role_name]) objects.Node.all_tags(cluster.nodes[0]), [self.role_name])
@contextmanager @contextmanager
def assert_node_reassigned(self): def assert_node_reassigned(self):
@ -127,16 +128,17 @@ class BasePrimaryRolesAssignmentTestCase(base.BaseTestCase):
{'roles': [self.role_name], {'roles': [self.role_name],
'status': consts.NODE_STATUSES.ready, 'status': consts.NODE_STATUSES.ready,
'pending_addition': True}]) 'pending_addition': True}])
objects.Cluster.set_primary_roles(cluster, cluster.nodes) objects.Cluster.set_primary_tags(cluster, cluster.nodes)
nodes = sorted(cluster.nodes, key=lambda node: node.id) nodes = sorted(cluster.nodes, key=lambda node: node.id)
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[1]), [self.primary_role_name]) objects.Node.all_tags(nodes[1]), [self.primary_role_name])
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[0]), [self.role_name]) objects.Node.all_tags(nodes[0]), [self.role_name])
yield nodes[1] yield nodes[1]
objects.Cluster.set_primary_roles(cluster, cluster.nodes) db().refresh(cluster)
objects.Cluster.set_primary_tags(cluster, cluster.nodes)
self.assertEqual( self.assertEqual(
objects.Node.all_roles(nodes[0]), [self.primary_role_name]) objects.Node.all_tags(nodes[0]), [self.primary_role_name])
def test_primary_assign_after_reset_to_discovery(self): def test_primary_assign_after_reset_to_discovery(self):
"""Removing primary roles after resetting node to discovery""" """Removing primary roles after resetting node to discovery"""

View File

@ -19,10 +19,10 @@ import six
from nailgun import consts from nailgun import consts
from nailgun.test.base import BaseUnitTest from nailgun.test.base import BaseUnitTest
from nailgun.utils import role_resolver from nailgun.utils import resolvers
class TestPatternBasedRoleResolver(BaseUnitTest): class TestPatternBasedTagResolver(BaseUnitTest):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.roles_of_nodes = [ cls.roles_of_nodes = [
@ -38,12 +38,12 @@ class TestPatternBasedRoleResolver(BaseUnitTest):
] ]
def setUp(self): def setUp(self):
objs_mock = mock.patch('nailgun.utils.role_resolver.objects') objs_mock = mock.patch('nailgun.utils.resolvers.objects')
self.addCleanup(objs_mock.stop) self.addCleanup(objs_mock.stop)
objs_mock.start().Node.all_roles.side_effect = self.roles_of_nodes objs_mock.start().Node.all_tags.side_effect = self.roles_of_nodes
def test_resolve_by_pattern(self): def test_resolve_by_pattern(self):
resolver = role_resolver.RoleResolver(self.nodes) resolver = resolvers.TagResolver(self.nodes)
self.assertItemsEqual( self.assertItemsEqual(
["0", "2", "3"], ["0", "2", "3"],
resolver.resolve(["/.*controller/"]) resolver.resolve(["/.*controller/"])
@ -58,14 +58,14 @@ class TestPatternBasedRoleResolver(BaseUnitTest):
) )
def test_resolve_all(self): def test_resolve_all(self):
resolver = role_resolver.RoleResolver(self.nodes) resolver = resolvers.TagResolver(self.nodes)
self.assertItemsEqual( self.assertItemsEqual(
(x.uid for x in self.nodes), (x.uid for x in self.nodes),
resolver.resolve("*") resolver.resolve("*")
) )
def test_resolve_master(self): def test_resolve_master(self):
resolver = role_resolver.RoleResolver(self.nodes) resolver = resolvers.TagResolver(self.nodes)
self.assertItemsEqual( self.assertItemsEqual(
[consts.MASTER_NODE_UID], [consts.MASTER_NODE_UID],
resolver.resolve(consts.TASK_ROLES.master) resolver.resolve(consts.TASK_ROLES.master)
@ -76,7 +76,7 @@ class TestPatternBasedRoleResolver(BaseUnitTest):
) )
def test_resolve_any(self): def test_resolve_any(self):
resolver = role_resolver.RoleResolver(self.nodes) resolver = resolvers.TagResolver(self.nodes)
all_nodes = resolver.resolve("*", consts.NODE_RESOLVE_POLICY.all) all_nodes = resolver.resolve("*", consts.NODE_RESOLVE_POLICY.all)
self.assertItemsEqual( self.assertItemsEqual(
all_nodes, all_nodes,
@ -87,7 +87,7 @@ class TestPatternBasedRoleResolver(BaseUnitTest):
self.assertTrue(any_node.issubset(all_nodes)) self.assertTrue(any_node.issubset(all_nodes))
def test_get_all_roles(self): def test_get_all_roles(self):
resolver = role_resolver.RoleResolver(self.nodes) resolver = resolvers.TagResolver(self.nodes)
all_roles = {r for roles in self.roles_of_nodes for r in roles} all_roles = {r for roles in self.roles_of_nodes for r in roles}
self.assertEqual(all_roles, resolver.get_all_roles()) self.assertEqual(all_roles, resolver.get_all_roles())
self.assertEqual(all_roles, resolver.get_all_roles( self.assertEqual(all_roles, resolver.get_all_roles(
@ -108,5 +108,5 @@ class TestNullResolver(BaseUnitTest):
node_ids = ['1', '2', '3'] node_ids = ['1', '2', '3']
self.assertIs( self.assertIs(
node_ids, node_ids,
role_resolver.NullResolver(node_ids).resolve("controller") resolvers.NullResolver(node_ids).resolve("controller")
) )

View File

@ -45,7 +45,7 @@ class BaseTaskSerializationTest(base.BaseTestCase):
self.env.create_node( self.env.create_node(
roles=['controller'], cluster_id=self.cluster.id), roles=['controller'], cluster_id=self.cluster.id),
self.env.create_node( self.env.create_node(
roles=['controller'], primary_roles=['controller'], roles=['controller'], primary_tags=['controller'],
cluster_id=self.cluster.id), cluster_id=self.cluster.id),
self.env.create_node( self.env.create_node(
roles=['cinder', 'compute'], cluster_id=self.cluster.id)] roles=['cinder', 'compute'], cluster_id=self.cluster.id)]
@ -80,7 +80,7 @@ class BaseTaskSerializationTestUbuntu(base.BaseTestCase):
self.env.create_node( self.env.create_node(
roles=['controller'], cluster_id=self.cluster.id), roles=['controller'], cluster_id=self.cluster.id),
self.env.create_node( self.env.create_node(
roles=['primary-controller'], cluster_id=self.cluster.id), roles=['controller'], cluster_id=self.cluster.id),
self.env.create_node( self.env.create_node(
roles=['cinder', 'compute'], cluster_id=self.cluster.id)] roles=['cinder', 'compute'], cluster_id=self.cluster.id)]
self.all_uids = [n.uid for n in self.nodes] self.all_uids = [n.uid for n in self.nodes]
@ -187,7 +187,7 @@ class TestHooksSerializers(BaseTaskSerializationTest):
self.assertFalse(task.should_execute()) self.assertFalse(task.should_execute())
@mock.patch.object(NetworkDeploymentSerializer, 'update_nodes_net_info') @mock.patch.object(NetworkDeploymentSerializer, 'update_nodes_net_info')
@mock.patch.object(objects.Node, 'all_roles') @mock.patch.object(objects.Node, 'all_tags')
def test_upload_nodes_info(self, m_roles, m_update_nodes): def test_upload_nodes_info(self, m_roles, m_update_nodes):
# mark one node as ready so we can test for duplicates # mark one node as ready so we can test for duplicates
self.env.nodes[0].status = consts.NODE_STATUSES.ready self.env.nodes[0].status = consts.NODE_STATUSES.ready

View File

@ -360,7 +360,7 @@ class TestTaskSerializers(BaseTestCase):
def test_expand_task_groups(self): def test_expand_task_groups(self):
node_ids = ['1', '2'] node_ids = ['1', '2']
with mock.patch.object(self.serializer, 'role_resolver') as m_resolve: with mock.patch.object(self.serializer, 'resolver') as m_resolve:
m_resolve.resolve.return_value = node_ids m_resolve.resolve.return_value = node_ids
self.serializer.expand_task_groups( self.serializer.expand_task_groups(
[ [
@ -433,7 +433,7 @@ class TestTaskSerializers(BaseTestCase):
} }
} }
with mock.patch.object(self.serializer, 'role_resolver') as m_resolve: with mock.patch.object(self.serializer, 'resolver') as m_resolve:
m_resolve.resolve.return_value = node_ids m_resolve.resolve.return_value = node_ids
# the default role and policy # the default role and policy
self.assertItemsEqual( self.assertItemsEqual(
@ -536,7 +536,7 @@ class TestTaskSerializers(BaseTestCase):
self.serializer.task_processor.origin_task_ids = { self.serializer.task_processor.origin_task_ids = {
'task_1': 'task' 'task_1': 'task'
} }
self.serializer.role_resolver = task_based_deployment.NullResolver( self.serializer.resolver = task_based_deployment.NullResolver(
node_ids node_ids
) )
self.serializer.resolve_dependencies() self.serializer.resolve_dependencies()
@ -592,11 +592,11 @@ class TestTaskSerializers(BaseTestCase):
def test_deploy_only_selected_nodes(self): def test_deploy_only_selected_nodes(self):
tasks = [ tasks = [
{ {
"id": "test1", "role": ["controller"], "id": "test1", "role": ["controller"], "tags": ["controller"],
"type": "puppet", "version": "2.0.0", "parameters": {} "type": "puppet", "version": "2.0.0", "parameters": {}
}, },
{ {
"id": "test2", "role": ["compute"], "id": "test2", "role": ["compute"], "tags": ["compute"],
"type": "puppet", "version": "2.0.0", "parameters": {} "type": "puppet", "version": "2.0.0", "parameters": {}
} }
] ]
@ -619,20 +619,20 @@ class TestTaskSerializers(BaseTestCase):
def test_serialise_with_events(self): def test_serialise_with_events(self):
tasks = [ tasks = [
{ {
"id": "test1", "role": ["controller"], "id": "test1", "role": ["controller"], "tags": ["controller"],
"type": "puppet", "version": "2.0.0", "parameters": {} "type": "puppet", "version": "2.0.0", "parameters": {}
}, },
{ {
"id": "test2", "role": ["compute"], "id": "test2", "role": ["compute"], "tags": ["compute"],
"type": "puppet", "version": "2.0.0", "parameters": {}, "type": "puppet", "version": "2.0.0", "parameters": {},
"reexecute_on": ["deploy"] "reexecute_on": ["deploy"]
}, },
{ {
"id": "test3", "role": ["compute"], "id": "test3", "role": ["compute"], "tags": ["compute"],
"type": "puppet", "version": "2.0.0", "parameters": {} "type": "puppet", "version": "2.0.0", "parameters": {}
}, },
{ {
"id": "test4", "role": ["cinder"], "id": "test4", "role": ["cinder"], "tags": ["cinder"],
"type": "puppet", "version": "2.0.0", "parameters": {} "type": "puppet", "version": "2.0.0", "parameters": {}
} }
] ]

View File

@ -34,7 +34,7 @@ from nailgun.task import legacy_tasks_adapter
from nailgun.utils import dict_update from nailgun.utils import dict_update
from nailgun.utils import get_in from nailgun.utils import get_in
from nailgun.utils import mule from nailgun.utils import mule
from nailgun.utils import role_resolver from nailgun.utils import resolvers
from nailgun import yaql_ext from nailgun import yaql_ext
@ -359,8 +359,8 @@ class TransactionsManager(object):
# we should initialize primary roles for cluster before # we should initialize primary roles for cluster before
# role resolve has been created # role resolve has been created
objects.Cluster.set_primary_roles(cluster, nodes) objects.Cluster.set_primary_tags(cluster, nodes)
resolver = role_resolver.RoleResolver(nodes) resolver = resolvers.TagResolver(nodes)
_adjust_graph_tasks( _adjust_graph_tasks(
graph, graph,
cluster, cluster,

View File

@ -67,7 +67,7 @@ class NullResolver(BaseRoleResolver):
return [] return []
class RoleResolver(BaseRoleResolver): class TagResolver(BaseRoleResolver):
"""The general role resolver. """The general role resolver.
Allows to use patterns in name of role Allows to use patterns in name of role
@ -86,7 +86,7 @@ class RoleResolver(BaseRoleResolver):
""" """
self.__mapping = defaultdict(set) self.__mapping = defaultdict(set)
for node in nodes: for node in nodes:
for r in objects.Node.all_roles(node): for r in objects.Node.all_tags(node):
self.__mapping[r].add(node.uid) self.__mapping[r].add(node.uid)
def resolve(self, roles, policy=None): def resolve(self, roles, policy=None):