ansible/v2/bin/ansible-playbook
Brian Coca d732c94ac2 a bunch of updates to connection info and related, to pass down passwords
also now options populate required fields in required order allowing play to override
added capture of debug in action plugins when stdout is not json
2015-04-06 22:35:02 -04:00

167 lines
6.7 KiB
Python
Executable file

#!/usr/bin/env python
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import stat
import sys
from ansible import constants as C
from ansible.errors import AnsibleError
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.inventory import Inventory
from ansible.parsing import DataLoader
from ansible.parsing.splitter import parse_kv
from ansible.playbook import Playbook
from ansible.playbook.task import Task
from ansible.utils.cli import base_parser, validate_conflicts, normalize_become_options, ask_passwords
from ansible.utils.display import Display
from ansible.utils.unicode import to_unicode
from ansible.utils.vars import combine_vars
from ansible.utils.vault import read_vault_file
from ansible.vars import VariableManager
#---------------------------------------------------------------------------------------------------
def main(display, args):
''' run ansible-playbook operations '''
# create parser for CLI options
parser = base_parser(
usage = "%prog playbook.yml",
connect_opts=True,
meta_opts=True,
runas_opts=True,
subset_opts=True,
check_opts=True,
diff_opts=True,
)
# ansible playbook specific opts
parser.add_option('--list-tasks', dest='listtasks', action='store_true',
help="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 at the task matching this name")
parser.add_option('--list-tags', dest='listtags', action='store_true',
help="list all available tags")
options, args = parser.parse_args(args)
if len(args) == 0:
parser.print_help(file=sys.stderr)
return 1
display.verbosity = options.verbosity
validate_conflicts(parser,options)
# Note: slightly wrong, this is written so that implicit localhost
# Manage passwords
sshpass = None
becomepass = None
vault_pass = None
# don't deal with privilege escalation when we don't need to
if not options.listhosts and not options.listtasks and not options.listtags:
normalize_become_options(options)
(sshpass, becomepass, vault_pass) = ask_passwords(options)
if options.vault_password_file:
# read vault_pass from a file
vault_pass = read_vault_file(options.vault_password_file)
loader = DataLoader(vault_password=vault_pass)
extra_vars = {}
for extra_vars_opt in options.extra_vars:
extra_vars_opt = to_unicode(extra_vars_opt, errors='strict')
if extra_vars_opt.startswith(u"@"):
# Argument is a YAML file (JSON is a subset of YAML)
data = loader.load_from_file(extra_vars_opt[1:])
elif extra_vars_opt and extra_vars_opt[0] in u'[{':
# Arguments as YAML
data = loader.load(extra_vars_opt)
else:
# Arguments as Key-value
data = parse_kv(extra_vars_opt)
extra_vars = combine_vars(extra_vars, data)
# FIXME: this should be moved inside the playbook executor code
only_tags = options.tags.split(",")
skip_tags = options.skip_tags
if options.skip_tags is not None:
skip_tags = options.skip_tags.split(",")
# initial error check, to make sure all specified playbooks are accessible
# before we start running anything through the playbook executor
for playbook in args:
if not os.path.exists(playbook):
raise AnsibleError("the playbook: %s could not be found" % playbook)
if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)):
raise AnsibleError("the playbook: %s does not appear to be a file" % playbook)
# create the variable manager, which will be shared throughout
# the code, ensuring a consistent view of global variables
variable_manager = VariableManager()
variable_manager.set_extra_vars(extra_vars)
# create the inventory, and filter it based on the subset specified (if any)
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=options.inventory)
variable_manager.set_inventory(inventory)
# (which is not returned in list_hosts()) is taken into account for
# warning if inventory is empty. But it can't be taken into account for
# checking if limit doesn't match any hosts. Instead we don't worry about
# limit if only implicit localhost was in inventory to start with.
#
# Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts())
no_hosts = False
if len(inventory.list_hosts()) == 0:
# Empty inventory
display.warning("provided hosts list is empty, only localhost is available")
no_hosts = True
inventory.subset(options.subset)
if len(inventory.list_hosts()) == 0 and no_hosts is False:
# Invalid limit
raise errors.AnsibleError("Specified --limit does not match any hosts")
# create the playbook executor, which manages running the plays via a task queue manager
pbex = PlaybookExecutor(playbooks=args, inventory=inventory, variable_manager=variable_manager, loader=loader, display=display, options=options, conn_pass=sshpass, become_pass=becomepass)
results = pbex.run()
if isinstance(results, list):
for p in results:
display.display('\nplaybook: %s\n' % p['playbook'])
for play in p['plays']:
if options.listhosts:
display.display("\n %s (%s): host count=%d" % (play['name'], play['pattern'], len(play['hosts'])))
for host in play['hosts']:
display.display(" %s" % host)
if options.listtasks: #TODO: do we want to display block info?
display.display("\n %s" % (play['name']))
for task in play['tasks']:
display.display(" %s" % task)
if options.listtags: #TODO: fix once we figure out block handling above
display.display("\n %s: tags count=%d" % (play['name'], len(play['tags'])))
for tag in play['tags']:
display.display(" %s" % tag)
return 0
else:
return results
if __name__ == "__main__":
display = Display()
#display.display(" ".join(sys.argv), log_only=True)
try:
sys.exit(main(display, sys.argv[1:]))
except AnsibleError as e:
display.display("[ERROR]: %s" % e, color='red', stderr=True)
sys.exit(1)
except KeyboardInterrupt:
display.display("[ERROR]: interrupted", color='red', stderr=True)
sys.exit(1)