mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-26 04:11:25 -07:00
Merge branch 'playbook-skip-tags' of git://github.com/dekked/ansible into skip_tags
This commit is contained in:
commit
f592340f7f
2 changed files with 51 additions and 23 deletions
|
@ -23,7 +23,7 @@ import os
|
||||||
|
|
||||||
import ansible.playbook
|
import ansible.playbook
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
import ansible.utils.template
|
import ansible.utils.template
|
||||||
from ansible import errors
|
from ansible import errors
|
||||||
from ansible import callbacks
|
from ansible import callbacks
|
||||||
from ansible import utils
|
from ansible import utils
|
||||||
|
@ -53,11 +53,11 @@ def main(args):
|
||||||
|
|
||||||
# create parser for CLI options
|
# create parser for CLI options
|
||||||
parser = utils.base_parser(
|
parser = utils.base_parser(
|
||||||
constants=C,
|
constants=C,
|
||||||
usage = "%prog playbook.yml",
|
usage = "%prog playbook.yml",
|
||||||
connect_opts=True,
|
connect_opts=True,
|
||||||
runas_opts=True,
|
runas_opts=True,
|
||||||
subset_opts=True,
|
subset_opts=True,
|
||||||
check_opts=True,
|
check_opts=True,
|
||||||
diff_opts=True
|
diff_opts=True
|
||||||
)
|
)
|
||||||
|
@ -65,13 +65,15 @@ def main(args):
|
||||||
help="set additional key=value variables from the CLI")
|
help="set additional key=value variables from the CLI")
|
||||||
parser.add_option('-t', '--tags', dest='tags', default='all',
|
parser.add_option('-t', '--tags', dest='tags', default='all',
|
||||||
help="only run plays and tasks tagged with these values")
|
help="only run plays and tasks tagged with these values")
|
||||||
|
parser.add_option('--skip-tags', dest='skip_tags',
|
||||||
|
help="only run plays and tasks whose tags do not match these values")
|
||||||
parser.add_option('--syntax-check', dest='syntax', action='store_true',
|
parser.add_option('--syntax-check', dest='syntax', action='store_true',
|
||||||
help="perform a syntax check on the playbook, but do not execute it")
|
help="perform a syntax check on the playbook, but do not execute it")
|
||||||
parser.add_option('--list-tasks', dest='listtasks', action='store_true',
|
parser.add_option('--list-tasks', dest='listtasks', action='store_true',
|
||||||
help="list all tasks that would be executed")
|
help="list all tasks that would be executed")
|
||||||
parser.add_option('--step', dest='step', action='store_true',
|
parser.add_option('--step', dest='step', action='store_true',
|
||||||
help="one-step-at-a-time: confirm each task before running")
|
help="one-step-at-a-time: confirm each task before running")
|
||||||
parser.add_option('--start-at-task', dest='start_at',
|
parser.add_option('--start-at-task', dest='start_at',
|
||||||
help="start the playbook at the task matching this name")
|
help="start the playbook at the task matching this name")
|
||||||
|
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
|
@ -97,6 +99,9 @@ def main(args):
|
||||||
else:
|
else:
|
||||||
extra_vars = utils.parse_kv(options.extra_vars)
|
extra_vars = utils.parse_kv(options.extra_vars)
|
||||||
only_tags = options.tags.split(",")
|
only_tags = options.tags.split(",")
|
||||||
|
skip_tags = options.skip_tags
|
||||||
|
if options.skip_tags is not None:
|
||||||
|
skip_tags = options.skip_tags.split(",")
|
||||||
|
|
||||||
for playbook in args:
|
for playbook in args:
|
||||||
if not os.path.exists(playbook):
|
if not os.path.exists(playbook):
|
||||||
|
@ -136,6 +141,7 @@ def main(args):
|
||||||
extra_vars=extra_vars,
|
extra_vars=extra_vars,
|
||||||
private_key_file=options.private_key_file,
|
private_key_file=options.private_key_file,
|
||||||
only_tags=only_tags,
|
only_tags=only_tags,
|
||||||
|
skip_tags=skip_tags,
|
||||||
check=options.check,
|
check=options.check,
|
||||||
diff=options.diff
|
diff=options.diff
|
||||||
)
|
)
|
||||||
|
@ -156,13 +162,20 @@ def main(args):
|
||||||
print ' %s' % host
|
print ' %s' % host
|
||||||
if options.listtasks:
|
if options.listtasks:
|
||||||
matched_tags, unmatched_tags = play.compare_tags(pb.only_tags)
|
matched_tags, unmatched_tags = play.compare_tags(pb.only_tags)
|
||||||
|
|
||||||
|
# Remove skipped tasks
|
||||||
|
matched_tags = matched_tags - set(pb.skip_tags)
|
||||||
|
|
||||||
unmatched_tags.discard('all')
|
unmatched_tags.discard('all')
|
||||||
unknown_tags = set(pb.only_tags) - (matched_tags | unmatched_tags)
|
unknown_tags = ((set(pb.only_tags) | set(pb.skip_tags)) -
|
||||||
|
(matched_tags | unmatched_tags))
|
||||||
|
|
||||||
if unknown_tags:
|
if unknown_tags:
|
||||||
continue
|
continue
|
||||||
print ' play #%d (%s): task count=%d' % (playnum, label, len(play.tasks()))
|
print ' play #%d (%s): task count=%d' % (playnum, label, len(play.tasks()))
|
||||||
for task in play.tasks():
|
for task in play.tasks():
|
||||||
if set(task.tags).intersection(pb.only_tags):
|
if (set(task.tags).intersection(pb.only_tags) and not
|
||||||
|
set(task.tags).intersection(pb.skip_tags)):
|
||||||
if getattr(task, 'name', None) is not None:
|
if getattr(task, 'name', None) is not None:
|
||||||
# meta tasks have no names
|
# meta tasks have no names
|
||||||
print ' %s' % task.name
|
print ' %s' % task.name
|
||||||
|
@ -173,7 +186,7 @@ def main(args):
|
||||||
# if we've not exited by now then we are fine.
|
# if we've not exited by now then we are fine.
|
||||||
print 'Playbook Syntax is fine'
|
print 'Playbook Syntax is fine'
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
failed_hosts = []
|
failed_hosts = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -202,7 +215,7 @@ def main(args):
|
||||||
colorize('ok', t['ok'], 'green'),
|
colorize('ok', t['ok'], 'green'),
|
||||||
colorize('changed', t['changed'], 'yellow'),
|
colorize('changed', t['changed'], 'yellow'),
|
||||||
colorize('unreachable', t['unreachable'], 'red'),
|
colorize('unreachable', t['unreachable'], 'red'),
|
||||||
colorize('failed', t['failures'], 'red')),
|
colorize('failed', t['failures'], 'red')),
|
||||||
screen_only=True
|
screen_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -211,11 +224,11 @@ def main(args):
|
||||||
colorize('ok', t['ok'], None),
|
colorize('ok', t['ok'], None),
|
||||||
colorize('changed', t['changed'], None),
|
colorize('changed', t['changed'], None),
|
||||||
colorize('unreachable', t['unreachable'], None),
|
colorize('unreachable', t['unreachable'], None),
|
||||||
colorize('failed', t['failures'], None)),
|
colorize('failed', t['failures'], None)),
|
||||||
log_only=True
|
log_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
print ""
|
print ""
|
||||||
if len(failed_hosts) > 0:
|
if len(failed_hosts) > 0:
|
||||||
return 2
|
return 2
|
||||||
|
|
|
@ -63,6 +63,7 @@ class PlayBook(object):
|
||||||
sudo_user = C.DEFAULT_SUDO_USER,
|
sudo_user = C.DEFAULT_SUDO_USER,
|
||||||
extra_vars = None,
|
extra_vars = None,
|
||||||
only_tags = None,
|
only_tags = None,
|
||||||
|
skip_tags = None,
|
||||||
subset = C.DEFAULT_SUBSET,
|
subset = C.DEFAULT_SUBSET,
|
||||||
inventory = None,
|
inventory = None,
|
||||||
check = False,
|
check = False,
|
||||||
|
@ -97,6 +98,8 @@ class PlayBook(object):
|
||||||
extra_vars = {}
|
extra_vars = {}
|
||||||
if only_tags is None:
|
if only_tags is None:
|
||||||
only_tags = [ 'all' ]
|
only_tags = [ 'all' ]
|
||||||
|
if skip_tags is None:
|
||||||
|
skip_tags = []
|
||||||
|
|
||||||
self.check = check
|
self.check = check
|
||||||
self.diff = diff
|
self.diff = diff
|
||||||
|
@ -117,6 +120,7 @@ class PlayBook(object):
|
||||||
self.global_vars = {}
|
self.global_vars = {}
|
||||||
self.private_key_file = private_key_file
|
self.private_key_file = private_key_file
|
||||||
self.only_tags = only_tags
|
self.only_tags = only_tags
|
||||||
|
self.skip_tags = skip_tags
|
||||||
self.any_errors_fatal = any_errors_fatal
|
self.any_errors_fatal = any_errors_fatal
|
||||||
|
|
||||||
self.callbacks.playbook = self
|
self.callbacks.playbook = self
|
||||||
|
@ -216,11 +220,14 @@ class PlayBook(object):
|
||||||
for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
|
for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
|
||||||
play = Play(self, play_ds, play_basedir)
|
play = Play(self, play_ds, play_basedir)
|
||||||
assert play is not None
|
assert play is not None
|
||||||
|
|
||||||
matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
|
matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
|
||||||
matched_tags_all = matched_tags_all | matched_tags
|
matched_tags_all = matched_tags_all | matched_tags
|
||||||
unmatched_tags_all = unmatched_tags_all | unmatched_tags
|
unmatched_tags_all = unmatched_tags_all | unmatched_tags
|
||||||
|
|
||||||
|
# Remove tasks we wish to skip
|
||||||
|
matched_tags = matched_tags - set(self.skip_tags)
|
||||||
|
|
||||||
# if we have matched_tags, the play must be run.
|
# if we have matched_tags, the play must be run.
|
||||||
# if the play contains no tasks, assume we just want to gather facts
|
# if the play contains no tasks, assume we just want to gather facts
|
||||||
# in this case there are actually 3 meta tasks (handler flushes) not 0
|
# in this case there are actually 3 meta tasks (handler flushes) not 0
|
||||||
|
@ -228,9 +235,11 @@ class PlayBook(object):
|
||||||
if (len(matched_tags) > 0 or len(play.tasks()) == 3):
|
if (len(matched_tags) > 0 or len(play.tasks()) == 3):
|
||||||
plays.append(play)
|
plays.append(play)
|
||||||
|
|
||||||
# if the playbook is invoked with --tags that don't exist at all in the playbooks
|
# if the playbook is invoked with --tags or --skip-tags that don't
|
||||||
# then we need to raise an error so that the user can correct the arguments.
|
# exist at all in the playbooks then we need to raise an error so that
|
||||||
unknown_tags = set(self.only_tags) - (matched_tags_all | unmatched_tags_all)
|
# 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')
|
unknown_tags.discard('all')
|
||||||
|
|
||||||
if len(unknown_tags) > 0:
|
if len(unknown_tags) > 0:
|
||||||
|
@ -331,7 +340,7 @@ class PlayBook(object):
|
||||||
ansible.callbacks.set_task(self.callbacks, None)
|
ansible.callbacks.set_task(self.callbacks, None)
|
||||||
ansible.callbacks.set_task(self.runner_callbacks, None)
|
ansible.callbacks.set_task(self.runner_callbacks, None)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# load up an appropriate ansible runner to run the task in parallel
|
# load up an appropriate ansible runner to run the task in parallel
|
||||||
results = self._run_task_internal(task)
|
results = self._run_task_internal(task)
|
||||||
|
|
||||||
|
@ -340,7 +349,7 @@ class PlayBook(object):
|
||||||
if results is None:
|
if results is None:
|
||||||
hosts_remaining = False
|
hosts_remaining = False
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
contacted = results.get('contacted', {})
|
contacted = results.get('contacted', {})
|
||||||
self.stats.compute(results, ignore_errors=task.ignore_errors)
|
self.stats.compute(results, ignore_errors=task.ignore_errors)
|
||||||
|
|
||||||
|
@ -408,7 +417,7 @@ class PlayBook(object):
|
||||||
|
|
||||||
self.callbacks.on_setup()
|
self.callbacks.on_setup()
|
||||||
self.inventory.restrict_to(host_list)
|
self.inventory.restrict_to(host_list)
|
||||||
|
|
||||||
ansible.callbacks.set_task(self.callbacks, None)
|
ansible.callbacks.set_task(self.callbacks, None)
|
||||||
ansible.callbacks.set_task(self.runner_callbacks, None)
|
ansible.callbacks.set_task(self.runner_callbacks, None)
|
||||||
|
|
||||||
|
@ -438,10 +447,10 @@ class PlayBook(object):
|
||||||
|
|
||||||
def generate_retry_inventory(self, replay_hosts):
|
def generate_retry_inventory(self, replay_hosts):
|
||||||
'''
|
'''
|
||||||
called by /usr/bin/ansible when a playbook run fails. It generates a inventory
|
called by /usr/bin/ansible when a playbook run fails. It generates a inventory
|
||||||
that allows re-running on ONLY the failed hosts. This may duplicate some
|
that allows re-running on ONLY the failed hosts. This may duplicate some
|
||||||
variable information in group_vars/host_vars but that is ok, and expected.
|
variable information in group_vars/host_vars but that is ok, and expected.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
buf = StringIO.StringIO()
|
buf = StringIO.StringIO()
|
||||||
for x in replay_hosts:
|
for x in replay_hosts:
|
||||||
|
@ -507,7 +516,7 @@ class PlayBook(object):
|
||||||
|
|
||||||
# meta tasks are an internalism and are not valid for end-user playbook usage
|
# meta tasks are an internalism and are not valid for end-user playbook usage
|
||||||
# here a meta task is a placeholder that signals handlers should be run
|
# here a meta task is a placeholder that signals handlers should be run
|
||||||
|
|
||||||
if task.meta == 'flush_handlers':
|
if task.meta == 'flush_handlers':
|
||||||
for handler in play.handlers():
|
for handler in play.handlers():
|
||||||
if len(handler.notified_by) > 0:
|
if len(handler.notified_by) > 0:
|
||||||
|
@ -530,11 +539,17 @@ class PlayBook(object):
|
||||||
for x in self.only_tags:
|
for x in self.only_tags:
|
||||||
|
|
||||||
for y in task.tags:
|
for y in task.tags:
|
||||||
if (x==y):
|
if x == y:
|
||||||
should_run = True
|
should_run = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Check for tags that we need to skip
|
||||||
if should_run:
|
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):
|
if not self._run_task(play, task, False):
|
||||||
# whether no hosts matched is fatal or not depends if it was on the initial step.
|
# 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
|
# if we got exactly no hosts on the first step (setup!) then the host group
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue