Merge "Allow using role 'master' in conjunction with other"

This commit is contained in:
Jenkins 2016-03-23 12:40:21 +00:00 committed by Gerrit Code Review
commit c4b2864014
4 changed files with 56 additions and 39 deletions

View File

@ -18,6 +18,8 @@
import itertools
import six
from nailgun import consts
from nailgun.errors import errors
from nailgun.logger import logger
@ -148,7 +150,7 @@ class PluginsPreDeploymentHooksSerializer(BasePluginDeploymentHooksSerializer):
# plugin tasks
tasks_to_process = plugin.tasks + plugin.deployment_tasks
roles = []
roles = set()
for task in tasks_to_process:
# plugin tasks may store information about node
# role not only in `role` key but also in `groups`
@ -156,15 +158,10 @@ class PluginsPreDeploymentHooksSerializer(BasePluginDeploymentHooksSerializer):
if task_role == consts.TASK_ROLES.all:
# just return all nodes
return self.role_resolver.resolve(consts.TASK_ROLES.all)
elif task_role == consts.TASK_ROLES.master:
# NOTE(aroma): pre-deployment tasks should not be executed on
# master node because in some cases it leads to errors due to
# commands need to be run are not compatible with master node
# OS (CentOS). E.g. of such situation - create repository
# executes `apt-get update` which fails on CentOS
continue
elif isinstance(task_role, list):
roles.extend(task_role)
elif isinstance(task_role, six.string_types):
roles.add(task_role)
elif isinstance(task_role, (list, tuple)):
roles.update(task_role)
# if task has 'skipped' status it is allowed that 'roles' and
# 'groups' are not be specified
elif task['type'] != consts.ORCHESTRATOR_TASK_TYPES.skipped:
@ -174,7 +171,14 @@ class PluginsPreDeploymentHooksSerializer(BasePluginDeploymentHooksSerializer):
'a list of roles or "*"',
task)
return self.role_resolver.resolve(roles)
# NOTE(aroma): pre-deployment tasks should not be executed on
# master node because in some cases it leads to errors due to
# commands need to be run are not compatible with master node
# OS (CentOS). E.g. of such situation - create repository
# executes `apt-get update` which fails on CentOS
roles.discard(consts.TASK_ROLES.master)
return list(self.role_resolver.resolve(roles))
def create_repositories(self, plugins):
operating_system = self.cluster.release.operating_system

View File

@ -93,9 +93,9 @@ class StandardConfigRolesHook(ExpressionBasedTask):
self.role_resolver = role_resolver or RoleResolver(nodes)
def get_uids(self):
return self.role_resolver.resolve(
return list(self.role_resolver.resolve(
self.task.get('role', self.task.get('groups'))
)
))
def serialize(self):
uids = self.get_uids()
@ -113,7 +113,7 @@ class UploadMOSRepo(GenericRolesHook):
identity = 'upload_core_repos'
def get_uids(self):
return self.role_resolver.resolve(consts.TASK_ROLES.all)
return list(self.role_resolver.resolve(consts.TASK_ROLES.all))
def serialize(self):
uids = self.get_uids()
@ -157,7 +157,7 @@ class RsyncPuppet(GenericRolesHook):
identity = 'rsync_core_puppet'
def get_uids(self):
return self.role_resolver.resolve(consts.TASK_ROLES.all)
return list(self.role_resolver.resolve(consts.TASK_ROLES.all))
def serialize(self):
src_path = self.task['parameters']['src'].format(

View File

@ -66,17 +66,25 @@ class TestPatternBasedRoleResolver(BaseUnitTest):
def test_resolve_master(self):
resolver = role_resolver.RoleResolver(self.nodes)
self.assertEqual(
self.assertItemsEqual(
[consts.MASTER_NODE_UID],
resolver.resolve(consts.TASK_ROLES.master)
)
self.assertItemsEqual(
[consts.MASTER_NODE_UID, '2', '3'],
resolver.resolve([consts.TASK_ROLES.master, 'controller'])
)
def test_resolve_any(self):
resolver = role_resolver.RoleResolver(self.nodes)
all_nodes = resolver.resolve("*", consts.NODE_RESOLVE_POLICY.all)
self.assertItemsEqual(
all_nodes,
(n.uid for n in self.nodes)
)
any_node = resolver.resolve("*", consts.NODE_RESOLVE_POLICY.any)
self.assertEqual(1, len(any_node))
self.assertIn(any_node[0], all_nodes)
self.assertTrue(any_node.issubset(all_nodes))
class TestNullResolver(BaseUnitTest):

View File

@ -40,7 +40,7 @@ class BaseRoleResolver(object):
any means need to return any node from resolved
all means need to return all resolved nodes
:type policy: str
:return: the list of nodes
:return: the unique set of nodes
"""
@ -79,35 +79,40 @@ class RoleResolver(BaseRoleResolver):
self.__mapping[r].add(node.uid)
def resolve(self, roles, policy=None):
if isinstance(roles, six.string_types) and roles in self.SPECIAL_ROLES:
result = self.SPECIAL_ROLES[roles]
elif roles == consts.TASK_ROLES.all:
result = list(set(
result = set()
if roles == consts.TASK_ROLES.all:
# optimization
result = {
uid for nodes in six.itervalues(self.__mapping)
for uid in nodes
))
elif isinstance(roles, (list, tuple)):
result = set()
for role in roles:
pattern = NameMatchingPolicy.create(role)
for node_role, nodes_ids in six.iteritems(self.__mapping):
if pattern.match(node_role):
result.update(nodes_ids)
result = list(result)
}
else:
# TODO(fix using wrong format for roles in tasks.yaml)
# After it will be allowed to raise exception here
logger.warn(
'Wrong roles format, `roles` should be a list or "*": %s',
roles
)
return []
if isinstance(roles, six.string_types):
roles = [roles]
if not isinstance(roles, (list, tuple, set)):
# TODO(bgaifullin) fix wrong format for roles in tasks.yaml
# After it will be allowed to raise exception here
logger.warn(
'Wrong roles format, `roles` should be a list or "*": %s',
roles
)
return result
for role in roles:
if role in self.SPECIAL_ROLES:
result.update(self.SPECIAL_ROLES[role])
else:
pattern = NameMatchingPolicy.create(role)
for node_role, nodes_ids in six.iteritems(self.__mapping):
if pattern.match(node_role):
result.update(nodes_ids)
# in some cases need only one any node from pool
# for example if need only one any controller.
# to distribute load select first node from pool
if result and policy == consts.NODE_RESOLVE_POLICY.any:
result = result[0:1]
result = {next(iter(result))}
logger.debug(
"Role '%s' and policy '%s' was resolved to: %s",