summaryrefslogtreecommitdiff
path: root/v2/bin/ansible-playbook
blob: e7a60939733b2147de0b1e302e03323d9764961d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/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)