mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-06 13:22:48 +00:00
Merge pull request #10183 from bcoca/tag_control
adds complex tag management
This commit is contained in:
@@ -36,6 +36,7 @@ import pipes
|
||||
# holds all other variables about a host
|
||||
SETUP_CACHE = ansible.cache.FactCache()
|
||||
VARS_CACHE = collections.defaultdict(dict)
|
||||
RESERVED_TAGS = ['all','tagged','untagged','always']
|
||||
|
||||
|
||||
class PlayBook(object):
|
||||
@@ -314,6 +315,7 @@ class PlayBook(object):
|
||||
assert play is not None
|
||||
|
||||
matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
|
||||
|
||||
matched_tags_all = matched_tags_all | matched_tags
|
||||
unmatched_tags_all = unmatched_tags_all | unmatched_tags
|
||||
|
||||
@@ -332,10 +334,13 @@ class PlayBook(object):
|
||||
# the user can correct the arguments.
|
||||
unknown_tags = ((set(self.only_tags) | set(self.skip_tags)) -
|
||||
(matched_tags_all | unmatched_tags_all))
|
||||
unknown_tags.discard('all')
|
||||
|
||||
for t in RESERVED_TAGS:
|
||||
unknown_tags.discard(t)
|
||||
|
||||
if len(unknown_tags) > 0:
|
||||
unmatched_tags_all.discard('all')
|
||||
for t in RESERVED_TAGS:
|
||||
unmatched_tags_all.discard(t)
|
||||
msg = 'tag(s) not found in playbook: %s. possible values: %s'
|
||||
unknown = ','.join(sorted(unknown_tags))
|
||||
unmatched = ','.join(sorted(unmatched_tags_all))
|
||||
@@ -667,7 +672,53 @@ class PlayBook(object):
|
||||
return filename
|
||||
|
||||
# *****************************************************
|
||||
def tasks_to_run_in_play(self, play):
|
||||
|
||||
tasks = []
|
||||
|
||||
for task in play.tasks():
|
||||
# only run the task if the requested tags match or has 'always' tag
|
||||
u = set(['untagged'])
|
||||
task_set = set(task.tags)
|
||||
|
||||
if 'always' in task.tags:
|
||||
should_run = True
|
||||
else:
|
||||
if 'all' in self.only_tags:
|
||||
should_run = True
|
||||
else:
|
||||
should_run = False
|
||||
if 'tagged' in self.only_tags:
|
||||
if task_set != u:
|
||||
should_run = True
|
||||
elif 'untagged' in self.only_tags:
|
||||
if task_set == u:
|
||||
should_run = True
|
||||
else:
|
||||
if task_set.intersection(self.only_tags):
|
||||
should_run = True
|
||||
|
||||
# Check for tags that we need to skip
|
||||
if 'all' in self.skip_tags:
|
||||
should_run = False
|
||||
else:
|
||||
if 'tagged' in self.skip_tags:
|
||||
if task_set != u:
|
||||
should_run = False
|
||||
elif 'untagged' in self.skip_tags:
|
||||
if task_set == u:
|
||||
should_run = False
|
||||
else:
|
||||
if should_run:
|
||||
if task_set.intersection(self.skip_tags):
|
||||
should_run = False
|
||||
|
||||
if should_run:
|
||||
tasks.append(task)
|
||||
|
||||
return tasks
|
||||
|
||||
# *****************************************************
|
||||
def _run_play(self, play):
|
||||
''' run a list of tasks for a given pattern, in order '''
|
||||
|
||||
@@ -720,7 +771,7 @@ class PlayBook(object):
|
||||
play._play_hosts = self._trim_unavailable_hosts(on_hosts)
|
||||
self.inventory.also_restrict_to(on_hosts)
|
||||
|
||||
for task in play.tasks():
|
||||
for task in self.tasks_to_run_in_play(play):
|
||||
|
||||
if task.meta is not None:
|
||||
# meta tasks can force handlers to run mid-play
|
||||
@@ -730,27 +781,11 @@ class PlayBook(object):
|
||||
# skip calling the handler till the play is finished
|
||||
continue
|
||||
|
||||
# only run the task if the requested tags match
|
||||
should_run = False
|
||||
for x in self.only_tags:
|
||||
|
||||
for y in task.tags:
|
||||
if x == y:
|
||||
should_run = True
|
||||
break
|
||||
|
||||
# Check for tags that we need to skip
|
||||
if should_run:
|
||||
if any(x in task.tags for x in self.skip_tags):
|
||||
should_run = False
|
||||
|
||||
if should_run:
|
||||
|
||||
if not self._run_task(play, task, False):
|
||||
# whether no hosts matched is fatal or not depends if it was on the initial step.
|
||||
# if we got exactly no hosts on the first step (setup!) then the host group
|
||||
# just didn't match anything and that's ok
|
||||
return False
|
||||
if not self._run_task(play, task, False):
|
||||
# whether no hosts matched is fatal or not depends if it was on the initial step.
|
||||
# if we got exactly no hosts on the first step (setup!) then the host group
|
||||
# just didn't match anything and that's ok
|
||||
return False
|
||||
|
||||
# Get a new list of what hosts are left as available, the ones that
|
||||
# did not go fail/dark during the task
|
||||
|
||||
@@ -669,20 +669,6 @@ class Play(object):
|
||||
|
||||
# *************************************************
|
||||
|
||||
def _is_valid_tag(self, tag_list):
|
||||
"""
|
||||
Check to see if the list of tags passed in is in the list of tags
|
||||
we only want (playbook.only_tags), or if it is not in the list of
|
||||
tags we don't want (playbook.skip_tags).
|
||||
"""
|
||||
matched_skip_tags = set(tag_list) & set(self.playbook.skip_tags)
|
||||
matched_only_tags = set(tag_list) & set(self.playbook.only_tags)
|
||||
if len(matched_skip_tags) > 0 or (self.playbook.only_tags != ['all'] and len(matched_only_tags) == 0):
|
||||
return False
|
||||
return True
|
||||
|
||||
# *************************************************
|
||||
|
||||
def tasks(self):
|
||||
''' return task objects for this play '''
|
||||
return self._tasks
|
||||
@@ -783,8 +769,27 @@ class Play(object):
|
||||
# compare the lists of tags using sets and return the matched and unmatched
|
||||
all_tags_set = set(all_tags)
|
||||
tags_set = set(tags)
|
||||
matched_tags = all_tags_set & tags_set
|
||||
unmatched_tags = all_tags_set - tags_set
|
||||
|
||||
matched_tags = all_tags_set.intersection(tags_set)
|
||||
unmatched_tags = all_tags_set.difference(tags_set)
|
||||
|
||||
a = set(['always'])
|
||||
u = set(['untagged'])
|
||||
if 'always' in all_tags_set:
|
||||
matched_tags = matched_tags.union(a)
|
||||
unmatched_tags = all_tags_set.difference(a)
|
||||
|
||||
if 'all' in tags_set:
|
||||
matched_tags = matched_tags.union(all_tags_set)
|
||||
unmatched_tags = set()
|
||||
|
||||
if 'tagged' in tags_set:
|
||||
matched_tags = all_tags_set.difference(u)
|
||||
unmatched_tags = u
|
||||
|
||||
if 'untagged' in tags_set and 'untagged' in all_tags_set:
|
||||
matched_tags = matched_tags.union(u)
|
||||
unmatched_tags = unmatched_tags.difference(u)
|
||||
|
||||
return matched_tags, unmatched_tags
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class Task(object):
|
||||
|
||||
# load various attributes
|
||||
self.name = ds.get('name', None)
|
||||
self.tags = [ 'all' ]
|
||||
self.tags = [ 'untagged' ]
|
||||
self.register = ds.get('register', None)
|
||||
self.sudo = utils.boolean(ds.get('sudo', play.sudo))
|
||||
self.su = utils.boolean(ds.get('su', play.su))
|
||||
@@ -316,6 +316,9 @@ class Task(object):
|
||||
self.tags.extend(apply_tags)
|
||||
self.tags.extend(import_tags)
|
||||
|
||||
if len(self.tags) > 1:
|
||||
self.tags.remove('untagged')
|
||||
|
||||
if additional_conditions:
|
||||
new_conditions = additional_conditions[:]
|
||||
if self.when:
|
||||
|
||||
Reference in New Issue
Block a user