2aeb79f45f
This is incomplete work, and requires some minor tweeks to the integration tests which are not included in this commit.
162 lines
7.2 KiB
Python
Executable file
162 lines
7.2 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
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
|
|
from ansible.utils.vars import combine_vars
|
|
from ansible.vars import VariableManager
|
|
|
|
#---------------------------------------------------------------------------------------------------
|
|
|
|
def main(args):
|
|
''' run ansible-playbook operations '''
|
|
|
|
# create parser for CLI options
|
|
parser = base_parser(
|
|
usage = "%prog playbook.yml",
|
|
connect_opts=True,
|
|
runas_opts=True,
|
|
subset_opts=True,
|
|
check_opts=True,
|
|
diff_opts=True
|
|
)
|
|
#parser.add_option('--vault-password', dest="vault_password",
|
|
# help="password for vault encrypted files")
|
|
parser.add_option('-e', '--extra-vars', dest="extra_vars", action="append",
|
|
help="set additional variables as key=value or YAML/JSON", default=[])
|
|
parser.add_option('-t', '--tags', dest='tags', default='all',
|
|
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',
|
|
help="perform a syntax check on the playbook, but do not execute it")
|
|
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('--force-handlers', dest='force_handlers', action='store_true',
|
|
help="run handlers even if a task fails")
|
|
parser.add_option('--flush-cache', dest='flush_cache', action='store_true',
|
|
help="clear the fact cache")
|
|
|
|
options, args = parser.parse_args(args)
|
|
|
|
if len(args) == 0:
|
|
parser.print_help(file=sys.stderr)
|
|
return 1
|
|
|
|
#---------------------------------------------------------------------------------------------------
|
|
# FIXME: su/sudo stuff needs to be generalized
|
|
# su and sudo command line arguments need to be mutually exclusive
|
|
#if (options.su or options.su_user or options.ask_su_pass) and \
|
|
# (options.sudo or options.sudo_user or options.ask_sudo_pass):
|
|
# parser.error("Sudo arguments ('--sudo', '--sudo-user', and '--ask-sudo-pass') "
|
|
# "and su arguments ('-su', '--su-user', and '--ask-su-pass') are "
|
|
# "mutually exclusive")
|
|
#
|
|
#if (options.ask_vault_pass and options.vault_password_file):
|
|
# parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive")
|
|
#
|
|
#sshpass = None
|
|
#sudopass = None
|
|
#su_pass = None
|
|
#vault_pass = None
|
|
#
|
|
#options.ask_vault_pass = options.ask_vault_pass or C.DEFAULT_ASK_VAULT_PASS
|
|
#
|
|
#if options.listhosts or options.syntax or options.listtasks:
|
|
# (_, _, _, vault_pass) = utils.ask_passwords(ask_vault_pass=options.ask_vault_pass)
|
|
#else:
|
|
# options.ask_pass = options.ask_pass or C.DEFAULT_ASK_PASS
|
|
# # Never ask for an SSH password when we run with local connection
|
|
# if options.connection == "local":
|
|
# options.ask_pass = False
|
|
# options.ask_sudo_pass = options.ask_sudo_pass or C.DEFAULT_ASK_SUDO_PASS
|
|
# options.ask_su_pass = options.ask_su_pass or C.DEFAULT_ASK_SU_PASS
|
|
# (sshpass, sudopass, su_pass, vault_pass) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass, ask_su_pass=options.ask_su_pass, ask_vault_pass=options.ask_vault_pass)
|
|
# options.sudo_user = options.sudo_user or C.DEFAULT_SUDO_USER
|
|
# options.su_user = options.su_user or C.DEFAULT_SU_USER
|
|
#
|
|
## read vault_pass from a file
|
|
#if not options.ask_vault_pass and options.vault_password_file:
|
|
# vault_pass = utils.read_vault_file(options.vault_password_file)
|
|
# END FIXME
|
|
#---------------------------------------------------------------------------------------------------
|
|
|
|
# FIXME: this hard-coded value will be removed after fixing the removed block
|
|
# above, which dealt wtih asking for passwords during runtime
|
|
vault_pass = 'testing'
|
|
loader = DataLoader(vault_password=vault_pass)
|
|
|
|
extra_vars = {}
|
|
for extra_vars_opt in options.extra_vars:
|
|
if extra_vars_opt.startswith("@"):
|
|
# Argument is a YAML file (JSON is a subset of YAML)
|
|
data = loader.load_from_file(extra_vars_opt[1:])
|
|
extra_vars = combine_vars(extra_vars, data)
|
|
elif extra_vars_opt and extra_vars_opt[0] in '[{':
|
|
# Arguments as YAML
|
|
data = loader.load(extra_vars)
|
|
extra_vars = combine_vars(extra_vars, data)
|
|
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)
|
|
inventory.subset(options.subset)
|
|
if len(inventory.list_hosts()) == 0:
|
|
raise AnsibleError("provided hosts list is empty")
|
|
|
|
# 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, options=options)
|
|
return pbex.run()
|
|
|
|
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 AnsibleError, e:
|
|
#display("ERROR: %s" % e, color='red', stderr=True)
|
|
print e
|
|
sys.exit(1)
|
|
except KeyboardInterrupt, ke:
|
|
#display("ERROR: interrupted", color='red', stderr=True)
|
|
print "keyboard interrupt"
|
|
sys.exit(1)
|
|
|