mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
several fixes to cli tools
- fixed issue with previous commit with bad constants vs C ref on become - added list-tags - rearranged common options to utils/cli.py - added generic validate for both vault and become conflicts - removed dupes and conflicting options
This commit is contained in:
parent
93c9803818
commit
b370728439
3 changed files with 63 additions and 49 deletions
|
@ -38,7 +38,7 @@ class SortedOptParser(optparse.OptionParser):
|
||||||
self.option_list.sort(key=operator.methodcaller('get_opt_string'))
|
self.option_list.sort(key=operator.methodcaller('get_opt_string'))
|
||||||
return optparse.OptionParser.format_help(self, formatter=None)
|
return optparse.OptionParser.format_help(self, formatter=None)
|
||||||
|
|
||||||
def base_parser(usage="", output_opts=False, runas_opts=False,
|
def base_parser(usage="", output_opts=False, runas_opts=False, meta_opts=False,
|
||||||
async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, diff_opts=False):
|
async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, diff_opts=False):
|
||||||
''' create an options parser for any ansible script '''
|
''' create an options parser for any ansible script '''
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ def base_parser(usage="", output_opts=False, runas_opts=False,
|
||||||
help="specify inventory host file (default=%s)" % C.DEFAULT_HOST_LIST,
|
help="specify inventory host file (default=%s)" % C.DEFAULT_HOST_LIST,
|
||||||
default=C.DEFAULT_HOST_LIST)
|
default=C.DEFAULT_HOST_LIST)
|
||||||
parser.add_option('-k', '--ask-pass', default=False, dest='ask_pass', action='store_true',
|
parser.add_option('-k', '--ask-pass', default=False, dest='ask_pass', action='store_true',
|
||||||
help='ask for SSH password')
|
help='ask for connection password')
|
||||||
parser.add_option('--private-key', default=C.DEFAULT_PRIVATE_KEY_FILE, dest='private_key_file',
|
parser.add_option('--private-key', default=C.DEFAULT_PRIVATE_KEY_FILE, dest='private_key_file',
|
||||||
help='use this file to authenticate the connection')
|
help='use this file to authenticate the connection')
|
||||||
parser.add_option('--ask-vault-pass', default=False, dest='ask_vault_pass', action='store_true',
|
parser.add_option('--ask-vault-pass', default=False, dest='ask_vault_pass', action='store_true',
|
||||||
|
@ -64,14 +64,16 @@ def base_parser(usage="", output_opts=False, runas_opts=False,
|
||||||
parser.add_option('-M', '--module-path', dest='module_path',
|
parser.add_option('-M', '--module-path', dest='module_path',
|
||||||
help="specify path(s) to module library (default=%s)" % C.DEFAULT_MODULE_PATH,
|
help="specify path(s) to module library (default=%s)" % C.DEFAULT_MODULE_PATH,
|
||||||
default=None)
|
default=None)
|
||||||
|
parser.add_option('-e', '--extra-vars', dest="extra_vars", action="append",
|
||||||
|
help="set additional variables as key=value or YAML/JSON", default=[])
|
||||||
|
|
||||||
if subset_opts:
|
if subset_opts:
|
||||||
parser.add_option('-l', '--limit', default=C.DEFAULT_SUBSET, dest='subset',
|
parser.add_option('-l', '--limit', default=C.DEFAULT_SUBSET, dest='subset',
|
||||||
help='further limit selected hosts to an additional pattern')
|
help='further limit selected hosts to an additional pattern')
|
||||||
|
parser.add_option('-t', '--tags', dest='tags', default='all',
|
||||||
parser.add_option('-T', '--timeout', default=C.DEFAULT_TIMEOUT, type='int',
|
help="only run plays and tasks tagged with these values")
|
||||||
dest='timeout',
|
parser.add_option('--skip-tags', dest='skip_tags',
|
||||||
help="override the SSH timeout in seconds (default=%s)" % C.DEFAULT_TIMEOUT)
|
help="only run plays and tasks whose tags do not match these values")
|
||||||
|
|
||||||
if output_opts:
|
if output_opts:
|
||||||
parser.add_option('-o', '--one-line', dest='one_line', action='store_true',
|
parser.add_option('-o', '--one-line', dest='one_line', action='store_true',
|
||||||
|
@ -85,28 +87,32 @@ def base_parser(usage="", output_opts=False, runas_opts=False,
|
||||||
help='ask for sudo password (deprecated, use become)')
|
help='ask for sudo password (deprecated, use become)')
|
||||||
parser.add_option('--ask-su-pass', default=False, dest='ask_su_pass', action='store_true',
|
parser.add_option('--ask-su-pass', default=False, dest='ask_su_pass', action='store_true',
|
||||||
help='ask for su password (deprecated, use become)')
|
help='ask for su password (deprecated, use become)')
|
||||||
parser.add_option("-s", "--sudo", default=constants.DEFAULT_SUDO, action="store_true", dest='sudo',
|
parser.add_option("-s", "--sudo", default=C.DEFAULT_SUDO, action="store_true", dest='sudo',
|
||||||
help="run operations with sudo (nopasswd) (deprecated, use become)")
|
help="run operations with sudo (nopasswd) (deprecated, use become)")
|
||||||
parser.add_option('-U', '--sudo-user', dest='sudo_user', default=None,
|
parser.add_option('-U', '--sudo-user', dest='sudo_user', default=None,
|
||||||
help='desired sudo user (default=root) (deprecated, use become)')
|
help='desired sudo user (default=root) (deprecated, use become)')
|
||||||
parser.add_option('-S', '--su', default=constants.DEFAULT_SU, action='store_true',
|
parser.add_option('-S', '--su', default=C.DEFAULT_SU, action='store_true',
|
||||||
help='run operations with su (deprecated, use become)')
|
help='run operations with su (deprecated, use become)')
|
||||||
parser.add_option('-R', '--su-user', default=None,
|
parser.add_option('-R', '--su-user', default=None,
|
||||||
help='run operations with su as this user (default=%s) (deprecated, use become)' % constants.DEFAULT_SU_USER)
|
help='run operations with su as this user (default=%s) (deprecated, use become)' % C.DEFAULT_SU_USER)
|
||||||
|
|
||||||
# consolidated privilege escalation (become)
|
# consolidated privilege escalation (become)
|
||||||
parser.add_option("-b", "--become", default=constants.DEFAULT_BECOME, action="store_true", dest='become',
|
parser.add_option("-b", "--become", default=C.DEFAULT_BECOME, action="store_true", dest='become',
|
||||||
help="run operations with become (nopasswd implied)")
|
help="run operations with become (nopasswd implied)")
|
||||||
parser.add_option('--become-method', dest='become_method', default=constants.DEFAULT_BECOME_METHOD, type='string',
|
parser.add_option('--become-method', dest='become_method', default=C.DEFAULT_BECOME_METHOD, type='string',
|
||||||
help="privilege escalation method to use (default=%s), valid choices: [ %s ]" % (constants.DEFAULT_BECOME_METHOD, ' | '.join(constants.BECOME_METHODS)))
|
help="privilege escalation method to use (default=%s), valid choices: [ %s ]" % (C.DEFAULT_BECOME_METHOD, ' | '.join(C.BECOME_METHODS)))
|
||||||
parser.add_option('--become-user', default=None, dest='become_user', type='string',
|
parser.add_option('--become-user', default=None, dest='become_user', type='string',
|
||||||
help='run operations as this user (default=%s)' % constants.DEFAULT_BECOME_USER)
|
help='run operations as this user (default=%s)' % C.DEFAULT_BECOME_USER)
|
||||||
parser.add_option('--ask-become-pass', default=False, dest='become_ask_pass', action='store_true',
|
parser.add_option('--ask-become-pass', default=False, dest='become_ask_pass', action='store_true',
|
||||||
help='ask for privilege escalation password')
|
help='ask for privilege escalation password')
|
||||||
|
|
||||||
|
|
||||||
if connect_opts:
|
if connect_opts:
|
||||||
parser.add_option('-c', '--connection', dest='connection', default=C.DEFAULT_TRANSPORT, help="connection type to use (default=%s)" % C.DEFAULT_TRANSPORT)
|
parser.add_option('-c', '--connection', dest='connection', default=C.DEFAULT_TRANSPORT,
|
||||||
|
help="connection type to use (default=%s)" % C.DEFAULT_TRANSPORT)
|
||||||
|
parser.add_option('-T', '--timeout', default=C.DEFAULT_TIMEOUT, type='int', dest='timeout',
|
||||||
|
help="override the connection timeout in seconds (default=%s)" % C.DEFAULT_TIMEOUT)
|
||||||
|
|
||||||
|
|
||||||
if async_opts:
|
if async_opts:
|
||||||
parser.add_option('-P', '--poll', default=C.DEFAULT_POLL_INTERVAL, type='int',
|
parser.add_option('-P', '--poll', default=C.DEFAULT_POLL_INTERVAL, type='int',
|
||||||
|
@ -117,14 +123,20 @@ def base_parser(usage="", output_opts=False, runas_opts=False,
|
||||||
|
|
||||||
if check_opts:
|
if check_opts:
|
||||||
parser.add_option("-C", "--check", default=False, dest='check', action='store_true',
|
parser.add_option("-C", "--check", default=False, dest='check', action='store_true',
|
||||||
help="don't make any changes; instead, try to predict some of the changes that may occur"
|
help="don't make any changes; instead, try to predict some of the changes that may occur")
|
||||||
)
|
parser.add_option('--syntax-check', dest='syntax', action='store_true',
|
||||||
|
help="perform a syntax check on the playbook, but do not execute it")
|
||||||
|
|
||||||
if diff_opts:
|
if diff_opts:
|
||||||
parser.add_option("-D", "--diff", default=False, dest='diff', action='store_true',
|
parser.add_option("-D", "--diff", default=False, dest='diff', action='store_true',
|
||||||
help="when changing (small) files and templates, show the differences in those files; works great with --check"
|
help="when changing (small) files and templates, show the differences in those files; works great with --check"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if meta_opts:
|
||||||
|
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")
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
@ -219,3 +231,23 @@ def _gitinfo():
|
||||||
f.close()
|
f.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def validate_conflicts(parser, options):
|
||||||
|
|
||||||
|
# Check for vault related conflicts
|
||||||
|
if (options.ask_vault_pass and options.vault_password_file):
|
||||||
|
parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive")
|
||||||
|
|
||||||
|
|
||||||
|
# Check for privilege escalation conflicts
|
||||||
|
if (options.su or options.su_user or options.ask_su_pass) and \
|
||||||
|
(options.sudo or options.sudo_user or options.ask_sudo_pass) or \
|
||||||
|
(options.su or options.su_user or options.ask_su_pass) and \
|
||||||
|
(options.become or options.become_user or options.become_ask_pass) or \
|
||||||
|
(options.sudo or options.sudo_user or options.ask_sudo_pass) and \
|
||||||
|
(options.become or options.become_user or options.become_ask_pass):
|
||||||
|
|
||||||
|
parser.error("Sudo arguments ('--sudo', '--sudo-user', and '--ask-sudo-pass') "
|
||||||
|
"and su arguments ('-su', '--su-user', and '--ask-su-pass') "
|
||||||
|
"and become arguments ('--become', '--become-user', and '--ask-become-pass')"
|
||||||
|
" are exclusive of each other")
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ from ansible.inventory import Inventory
|
||||||
from ansible.parsing import DataLoader
|
from ansible.parsing import DataLoader
|
||||||
from ansible.parsing.splitter import parse_kv
|
from ansible.parsing.splitter import parse_kv
|
||||||
from ansible.playbook.play import Play
|
from ansible.playbook.play import Play
|
||||||
from ansible.utils.cli import base_parser
|
from ansible.utils.cli import base_parser, validate_conflicts
|
||||||
from ansible.vars import VariableManager
|
from ansible.vars import VariableManager
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
|
@ -45,15 +45,14 @@ class Cli(object):
|
||||||
|
|
||||||
parser = base_parser(
|
parser = base_parser(
|
||||||
usage='%prog <host-pattern> [options]',
|
usage='%prog <host-pattern> [options]',
|
||||||
runas_opts=True,
|
runas_opts=True,
|
||||||
subset_opts=True,
|
|
||||||
async_opts=True,
|
async_opts=True,
|
||||||
output_opts=True,
|
output_opts=True,
|
||||||
connect_opts=True,
|
connect_opts=True,
|
||||||
check_opts=True,
|
check_opts=True,
|
||||||
diff_opts=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# options unique to ansible ad-hoc
|
||||||
parser.add_option('-a', '--args', dest='module_args',
|
parser.add_option('-a', '--args', dest='module_args',
|
||||||
help="module arguments", default=C.DEFAULT_MODULE_ARGS)
|
help="module arguments", default=C.DEFAULT_MODULE_ARGS)
|
||||||
parser.add_option('-m', '--module-name', dest='module_name',
|
parser.add_option('-m', '--module-name', dest='module_name',
|
||||||
|
@ -66,15 +65,7 @@ class Cli(object):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# su and sudo command line arguments need to be mutually exclusive
|
validate_conflicts(parser,options)
|
||||||
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")
|
|
||||||
|
|
||||||
return (options, args)
|
return (options, args)
|
||||||
|
|
||||||
|
@ -113,8 +104,6 @@ class Cli(object):
|
||||||
variable_manager = VariableManager()
|
variable_manager = VariableManager()
|
||||||
|
|
||||||
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=options.inventory)
|
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=options.inventory)
|
||||||
if options.subset:
|
|
||||||
inventory.subset(options.subset)
|
|
||||||
|
|
||||||
hosts = inventory.list_hosts(pattern)
|
hosts = inventory.list_hosts(pattern)
|
||||||
if len(hosts) == 0:
|
if len(hosts) == 0:
|
||||||
|
|
|
@ -12,7 +12,7 @@ from ansible.parsing import DataLoader
|
||||||
from ansible.parsing.splitter import parse_kv
|
from ansible.parsing.splitter import parse_kv
|
||||||
from ansible.playbook import Playbook
|
from ansible.playbook import Playbook
|
||||||
from ansible.playbook.task import Task
|
from ansible.playbook.task import Task
|
||||||
from ansible.utils.cli import base_parser
|
from ansible.utils.cli import base_parser, validate_conflicts
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.utils.unicode import to_unicode
|
||||||
from ansible.utils.vars import combine_vars
|
from ansible.utils.vars import combine_vars
|
||||||
from ansible.utils.vault import read_vault_file
|
from ansible.utils.vault import read_vault_file
|
||||||
|
@ -30,31 +30,22 @@ def main(args):
|
||||||
parser = base_parser(
|
parser = base_parser(
|
||||||
usage = "%prog playbook.yml",
|
usage = "%prog playbook.yml",
|
||||||
connect_opts=True,
|
connect_opts=True,
|
||||||
|
meta_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,
|
||||||
)
|
)
|
||||||
parser.add_option('--vault-password', dest="vault_password",
|
|
||||||
help="password for vault encrypted files")
|
# ansible playbook specific opts
|
||||||
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',
|
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")
|
||||||
parser.add_option('--force-handlers', dest='force_handlers', action='store_true',
|
parser.add_option('--list-tags', dest='listtags', action='store_true',
|
||||||
help="run handlers even if a task fails")
|
help="list all available tags")
|
||||||
parser.add_option('--flush-cache', dest='flush_cache', action='store_true',
|
|
||||||
help="clear the fact cache")
|
|
||||||
|
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
|
|
||||||
|
@ -62,6 +53,8 @@ def main(args):
|
||||||
parser.print_help(file=sys.stderr)
|
parser.print_help(file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
validate_conflicts(parser,options)
|
||||||
|
|
||||||
vault_pass = None
|
vault_pass = None
|
||||||
if options.ask_vault_pass:
|
if options.ask_vault_pass:
|
||||||
# FIXME: prompt here
|
# FIXME: prompt here
|
||||||
|
|
Loading…
Reference in a new issue