mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
3316b87059
A recent change to ansible-playbook to support json extra-vars also inadvertently broke the script when no extra-vars are provided. Simply checking to make sure it is defined and truthy should take care of the issue.
242 lines
9.1 KiB
Python
Executable file
242 lines
9.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
|
|
|
# This file is part of Ansible
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#######################################################
|
|
|
|
import sys
|
|
import os
|
|
|
|
import ansible.playbook
|
|
import ansible.constants as C
|
|
import ansible.utils.template
|
|
from ansible import errors
|
|
from ansible import callbacks
|
|
from ansible import utils
|
|
from ansible.color import ANSIBLE_COLOR, stringc
|
|
from ansible.callbacks import display
|
|
|
|
def colorize(lead, num, color):
|
|
""" Print 'lead' = 'num' in 'color' """
|
|
if num != 0 and ANSIBLE_COLOR and color is not None:
|
|
return "%s%s%-15s" % (stringc(lead, color), stringc("=", color), stringc(str(num), color))
|
|
else:
|
|
return "%s=%-4s" % (lead, str(num))
|
|
|
|
def hostcolor(host, stats, color=True):
|
|
if ANSIBLE_COLOR and color:
|
|
if stats['failures'] != 0 or stats['unreachable'] != 0:
|
|
return "%-37s" % stringc(host, 'red')
|
|
elif stats['changed'] != 0:
|
|
return "%-37s" % stringc(host, 'yellow')
|
|
else:
|
|
return "%-37s" % stringc(host, 'green')
|
|
return "%-26s" % host
|
|
|
|
|
|
def main(args):
|
|
''' run ansible-playbook operations '''
|
|
|
|
# create parser for CLI options
|
|
usage = "%prog playbook.yml"
|
|
parser = utils.base_parser(
|
|
constants=C,
|
|
usage=usage,
|
|
connect_opts=True,
|
|
runas_opts=True,
|
|
subset_opts=True,
|
|
check_opts=True,
|
|
diff_opts=True
|
|
)
|
|
parser.add_option('-e', '--extra-vars', dest="extra_vars", default=None,
|
|
help="set additional key=value variables from the CLI")
|
|
parser.add_option('-t', '--tags', dest='tags', default='all',
|
|
help="only run plays and tasks tagged with these values")
|
|
# FIXME: list hosts is a common option and can be moved to utils/__init__.py
|
|
parser.add_option('--list-hosts', dest='listhosts', action='store_true',
|
|
help="dump out a list of hosts, each play will run against, does not run playbook!")
|
|
parser.add_option('--syntax-check', dest='syntax', action='store_true',
|
|
help="do a playbook syntax check on the playbook, do not execute the playbook")
|
|
parser.add_option('--list-tasks', dest='listtasks', action='store_true',
|
|
help="do list all tasks that would be executed")
|
|
parser.add_option('--step', dest='step', action='store_true',
|
|
help="one-step-at-a-time: confirm each task before running")
|
|
parser.add_option('--start-at-task', dest='start_at',
|
|
help="start the playbook with a task matching this name")
|
|
|
|
options, args = parser.parse_args(args)
|
|
|
|
if len(args) == 0:
|
|
parser.print_help(file=sys.stderr)
|
|
return 1
|
|
|
|
inventory = ansible.inventory.Inventory(options.inventory)
|
|
inventory.subset(options.subset)
|
|
if len(inventory.list_hosts()) == 0:
|
|
raise errors.AnsibleError("provided hosts list is empty")
|
|
|
|
sshpass = None
|
|
sudopass = None
|
|
if not options.listhosts and not options.syntax and not options.listtasks:
|
|
options.ask_pass = options.ask_pass or C.DEFAULT_ASK_PASS
|
|
options.ask_sudo_pass = options.ask_sudo_pass or C.DEFAULT_ASK_SUDO_PASS
|
|
( sshpass, sudopass ) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass)
|
|
if options.sudo_user or options.ask_sudo_pass:
|
|
options.sudo = True
|
|
options.sudo_user = options.sudo_user or C.DEFAULT_SUDO_USER
|
|
if options.extra_vars and options.extra_vars[0] in '[{':
|
|
extra_vars = utils.json_loads(options.extra_vars)
|
|
else:
|
|
extra_vars = utils.parse_kv(options.extra_vars)
|
|
only_tags = options.tags.split(",")
|
|
|
|
for playbook in args:
|
|
if not os.path.exists(playbook):
|
|
raise errors.AnsibleError("the playbook: %s could not be found" % playbook)
|
|
if not os.path.isfile(playbook):
|
|
raise errors.AnsibleError("the playbook: %s does not appear to be a file" % playbook)
|
|
|
|
# run all playbooks specified on the command line
|
|
for playbook in args:
|
|
|
|
stats = callbacks.AggregateStats()
|
|
playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
|
|
if options.step:
|
|
playbook_cb.step = options.step
|
|
if options.start_at:
|
|
playbook_cb.start_at = options.start_at
|
|
runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
|
|
|
|
pb = ansible.playbook.PlayBook(
|
|
playbook=playbook,
|
|
module_path=options.module_path,
|
|
inventory=inventory,
|
|
forks=options.forks,
|
|
remote_user=options.remote_user,
|
|
remote_pass=sshpass,
|
|
callbacks=playbook_cb,
|
|
runner_callbacks=runner_cb,
|
|
stats=stats,
|
|
timeout=options.timeout,
|
|
transport=options.connection,
|
|
sudo=options.sudo,
|
|
sudo_user=options.sudo_user,
|
|
sudo_pass=sudopass,
|
|
extra_vars=extra_vars,
|
|
private_key_file=options.private_key_file,
|
|
only_tags=only_tags,
|
|
check=options.check,
|
|
diff=options.diff
|
|
)
|
|
|
|
if options.listhosts or options.listtasks:
|
|
print ''
|
|
print 'playbook: %s' % playbook
|
|
print ''
|
|
playnum = 0
|
|
for (play_ds, play_basedir) in zip(pb.playbook, pb.play_basedirs):
|
|
playnum += 1
|
|
play = ansible.playbook.Play(pb, play_ds, play_basedir)
|
|
label = play.name
|
|
if options.listhosts:
|
|
hosts = pb.inventory.list_hosts(play.hosts)
|
|
print ' play #%d (%s): host count=%d' % (playnum, label, len(hosts))
|
|
for host in hosts:
|
|
print ' %s' % host
|
|
if options.listtasks:
|
|
matched_tags, unmatched_tags = play.compare_tags(pb.only_tags)
|
|
unmatched_tags.discard('all')
|
|
unknown_tags = set(pb.only_tags) - (matched_tags | unmatched_tags)
|
|
if unknown_tags:
|
|
continue
|
|
print ' play #%d (%s): task count=%d' % (playnum, label, len(play.tasks()))
|
|
for task in play.tasks():
|
|
if set(task.tags).intersection(pb.only_tags):
|
|
if getattr(task, 'name', None) is not None:
|
|
# meta tasks have no names
|
|
print ' %s' % task.name
|
|
print ''
|
|
continue
|
|
|
|
if options.syntax:
|
|
# if we've not exited by now then we are fine.
|
|
print 'Playbook Syntax is fine'
|
|
return 0
|
|
|
|
failed_hosts = []
|
|
|
|
try:
|
|
|
|
pb.run()
|
|
|
|
hosts = sorted(pb.stats.processed.keys())
|
|
display(callbacks.banner("PLAY RECAP"))
|
|
playbook_cb.on_stats(pb.stats)
|
|
|
|
for h in hosts:
|
|
t = pb.stats.summarize(h)
|
|
if t['unreachable'] > 0 or t['failures'] > 0:
|
|
failed_hosts.append(h)
|
|
|
|
if len(failed_hosts) > 0:
|
|
filename = pb.generate_retry_inventory(failed_hosts)
|
|
if filename:
|
|
display(" to retry, use: --limit @%s\n" % filename)
|
|
|
|
for h in hosts:
|
|
t = pb.stats.summarize(h)
|
|
|
|
display("%s : %s %s %s %s" % (
|
|
hostcolor(h, t),
|
|
colorize('ok', t['ok'], 'green'),
|
|
colorize('changed', t['changed'], 'yellow'),
|
|
colorize('unreachable', t['unreachable'], 'red'),
|
|
colorize('failed', t['failures'], 'red')),
|
|
screen_only=True
|
|
)
|
|
|
|
display("%s : %s %s %s %s" % (
|
|
hostcolor(h, t, False),
|
|
colorize('ok', t['ok'], None),
|
|
colorize('changed', t['changed'], None),
|
|
colorize('unreachable', t['unreachable'], None),
|
|
colorize('failed', t['failures'], None)),
|
|
log_only=True
|
|
)
|
|
|
|
|
|
print ""
|
|
if len(failed_hosts) > 0:
|
|
return 2
|
|
|
|
except errors.AnsibleError, e:
|
|
display("ERROR: %s" % e, color='red')
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
display(" ", log_only=True)
|
|
display(" ".join(sys.argv), log_only=True)
|
|
display(" ", log_only=True)
|
|
try:
|
|
sys.exit(main(sys.argv[1:]))
|
|
except errors.AnsibleError, e:
|
|
display("ERROR: %s" % e, color='red', stderr=True)
|
|
sys.exit(1)
|
|
|