fixed ansible pull, reorged validate function for cli to be function specific like parser
added missing cmd_functions with run_cmd, mostly for ansible pull
This commit is contained in:
parent
3bcbdf6841
commit
5aec5e5eb0
5 changed files with 96 additions and 29 deletions
|
@ -174,32 +174,34 @@ class CLI(object):
|
|||
options.become_method = 'su'
|
||||
|
||||
|
||||
def validate_conflicts(self):
|
||||
def validate_conflicts(self, vault_opts=False, runas_opts=False):
|
||||
''' check for conflicting options '''
|
||||
|
||||
op = self.options
|
||||
|
||||
# Check for vault related conflicts
|
||||
if (op.ask_vault_pass and op.vault_password_file):
|
||||
self.parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive")
|
||||
if vault_opts:
|
||||
# Check for vault related conflicts
|
||||
if (op.ask_vault_pass and op.vault_password_file):
|
||||
self.parser.error("--ask-vault-pass and --vault-password-file are mutually exclusive")
|
||||
|
||||
|
||||
# Check for privilege escalation conflicts
|
||||
if (op.su or op.su_user or op.ask_su_pass) and \
|
||||
(op.sudo or op.sudo_user or op.ask_sudo_pass) or \
|
||||
(op.su or op.su_user or op.ask_su_pass) and \
|
||||
(op.become or op.become_user or op.become_ask_pass) or \
|
||||
(op.sudo or op.sudo_user or op.ask_sudo_pass) and \
|
||||
(op.become or op.become_user or op.become_ask_pass):
|
||||
if runas_opts:
|
||||
# Check for privilege escalation conflicts
|
||||
if (op.su or op.su_user or op.ask_su_pass) and \
|
||||
(op.sudo or op.sudo_user or op.ask_sudo_pass) or \
|
||||
(op.su or op.su_user or op.ask_su_pass) and \
|
||||
(op.become or op.become_user or op.become_ask_pass) or \
|
||||
(op.sudo or op.sudo_user or op.ask_sudo_pass) and \
|
||||
(op.become or op.become_user or op.become_ask_pass):
|
||||
|
||||
self.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")
|
||||
self.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")
|
||||
|
||||
@staticmethod
|
||||
def base_parser(usage="", output_opts=False, runas_opts=False, meta_opts=False, runtask_opts=False, vault_opts=False,
|
||||
async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, diff_opts=False, epilog=None):
|
||||
async_opts=False, connect_opts=False, subset_opts=False, check_opts=False, diff_opts=False, epilog=None, fork_opts=False):
|
||||
''' create an options parser for most ansible scripts '''
|
||||
|
||||
#FIXME: implemente epilog parsing
|
||||
|
@ -211,8 +213,6 @@ class CLI(object):
|
|||
help="verbose mode (-vvv for more, -vvvv to enable connection debugging)")
|
||||
|
||||
if runtask_opts:
|
||||
parser.add_option('-f','--forks', dest='forks', default=C.DEFAULT_FORKS, type='int',
|
||||
help="specify number of parallel processes to use (default=%s)" % C.DEFAULT_FORKS)
|
||||
parser.add_option('-i', '--inventory-file', dest='inventory',
|
||||
help="specify inventory host file (default=%s)" % C.DEFAULT_HOST_LIST,
|
||||
default=C.DEFAULT_HOST_LIST)
|
||||
|
@ -223,6 +223,10 @@ class CLI(object):
|
|||
parser.add_option('-e', '--extra-vars', dest="extra_vars", action="append",
|
||||
help="set additional variables as key=value or YAML/JSON", default=[])
|
||||
|
||||
if fork_opts:
|
||||
parser.add_option('-f','--forks', dest='forks', default=C.DEFAULT_FORKS, type='int',
|
||||
help="specify number of parallel processes to use (default=%s)" % C.DEFAULT_FORKS)
|
||||
|
||||
if vault_opts:
|
||||
parser.add_option('--ask-vault-pass', default=False, dest='ask_vault_pass', action='store_true',
|
||||
help='ask for vault password')
|
||||
|
@ -273,7 +277,7 @@ class CLI(object):
|
|||
if connect_opts:
|
||||
parser.add_option('-k', '--ask-pass', default=False, dest='ask_pass', action='store_true',
|
||||
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','--key-file', default=C.DEFAULT_PRIVATE_KEY_FILE, dest='private_key_file',
|
||||
help='use this file to authenticate the connection')
|
||||
parser.add_option('-u', '--user', default=C.DEFAULT_REMOTE_USER, dest='remote_user',
|
||||
help='connect as this user (default=%s)' % C.DEFAULT_REMOTE_USER)
|
||||
|
@ -282,7 +286,6 @@ class CLI(object):
|
|||
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:
|
||||
parser.add_option('-P', '--poll', default=C.DEFAULT_POLL_INTERVAL, type='int',
|
||||
dest='poll_interval',
|
||||
|
|
|
@ -60,7 +60,7 @@ class AdHocCLI(CLI):
|
|||
raise AnsibleOptionsError("Missing target hosts")
|
||||
|
||||
self.display.verbosity = self.options.verbosity
|
||||
self.validate_conflicts()
|
||||
self.validate_conflicts(runas_opts=True, vault_opts=True)
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ class PlaybookCLI(CLI):
|
|||
diff_opts=True,
|
||||
runtask_opts=True,
|
||||
vault_opts=True,
|
||||
fork_opts=True,
|
||||
)
|
||||
|
||||
# ansible playbook specific opts
|
||||
|
@ -76,7 +77,7 @@ class PlaybookCLI(CLI):
|
|||
raise AnsibleOptionsError("You must specify a playbook file to run")
|
||||
|
||||
self.display.verbosity = self.options.verbosity
|
||||
self.validate_conflicts()
|
||||
self.validate_conflicts(runas_opts=True, vault_opts=True)
|
||||
|
||||
def run(self):
|
||||
|
||||
|
|
|
@ -21,12 +21,15 @@ import os
|
|||
import random
|
||||
import shutil
|
||||
import socket
|
||||
import sys
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||
from ansible.cli import CLI
|
||||
from ansible.utils.display import Display
|
||||
from ansible.utils.vault import read_vault_file
|
||||
from ansible.utils.plugins import module_finder
|
||||
from ansible.utils.cmd_functions import run_cmd
|
||||
|
||||
########################################################
|
||||
|
||||
|
@ -48,6 +51,7 @@ class PullCLI(CLI):
|
|||
usage='%prog <host-pattern> [options]',
|
||||
connect_opts=True,
|
||||
vault_opts=True,
|
||||
runtask_opts=True,
|
||||
)
|
||||
|
||||
# options unique to pull
|
||||
|
@ -87,7 +91,7 @@ class PullCLI(CLI):
|
|||
raise AnsibleOptionsError("Unsuported repo module %s, choices are %s" % (self.options.module_name, ','.join(self.SUPPORTED_REPO_MODULES)))
|
||||
|
||||
self.display.verbosity = self.options.verbosity
|
||||
self.validate_conflicts()
|
||||
self.validate_conflicts(vault_opts=True)
|
||||
|
||||
def run(self):
|
||||
''' use Runner lib to do SSH things '''
|
||||
|
@ -120,12 +124,12 @@ class PullCLI(CLI):
|
|||
if self.options.accept_host_key:
|
||||
repo_opts += ' accept_hostkey=yes'
|
||||
|
||||
if self.options.key_file:
|
||||
repo_opts += ' key_file=%s' % options.key_file
|
||||
if self.options.private_key_file:
|
||||
repo_opts += ' key_file=%s' % self.options.private_key_file
|
||||
|
||||
path = utils.plugins.module_finder.find_plugin(options.module_name)
|
||||
path = module_finder.find_plugin(self.options.module_name)
|
||||
if path is None:
|
||||
raise AnsibleOptionsError(("module '%s' not found.\n" % options.module_name))
|
||||
raise AnsibleOptionsError(("module '%s' not found.\n" % self.options.module_name))
|
||||
|
||||
bin_path = os.path.dirname(os.path.abspath(__file__))
|
||||
cmd = '%s/ansible localhost -i "%s" %s -m %s -a "%s"' % (
|
||||
|
@ -141,7 +145,7 @@ class PullCLI(CLI):
|
|||
time.sleep(self.options.sleep);
|
||||
|
||||
# RUN the Checkout command
|
||||
rc, out, err = cmd_functions.run_cmd(cmd, live=True)
|
||||
rc, out, err = run_cmd(cmd, live=True)
|
||||
|
||||
if rc != 0:
|
||||
if self.options.force:
|
||||
|
@ -173,7 +177,7 @@ class PullCLI(CLI):
|
|||
os.chdir(self.options.dest)
|
||||
|
||||
# RUN THE PLAYBOOK COMMAND
|
||||
rc, out, err = cmd_functions.run_cmd(cmd, live=True)
|
||||
rc, out, err = run_cmd(cmd, live=True)
|
||||
|
||||
if self.options.purge:
|
||||
os.chdir('/')
|
||||
|
|
59
lib/ansible/utils/cmd_functions.py
Normal file
59
lib/ansible/utils/cmd_functions.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
# (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 os
|
||||
import sys
|
||||
import shlex
|
||||
import subprocess
|
||||
import select
|
||||
|
||||
def run_cmd(cmd, live=False, readsize=10):
|
||||
|
||||
#readsize = 10
|
||||
|
||||
cmdargs = shlex.split(cmd)
|
||||
p = subprocess.Popen(cmdargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
rpipes = [p.stdout, p.stderr]
|
||||
while True:
|
||||
rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)
|
||||
|
||||
if p.stdout in rfd:
|
||||
dat = os.read(p.stdout.fileno(), readsize)
|
||||
if live:
|
||||
sys.stdout.write(dat)
|
||||
stdout += dat
|
||||
if dat == '':
|
||||
rpipes.remove(p.stdout)
|
||||
if p.stderr in rfd:
|
||||
dat = os.read(p.stderr.fileno(), readsize)
|
||||
stderr += dat
|
||||
if live:
|
||||
sys.stdout.write(dat)
|
||||
if dat == '':
|
||||
rpipes.remove(p.stderr)
|
||||
# only break out if we've emptied the pipes, or there is nothing to
|
||||
# read from and the process has finished.
|
||||
if (not rpipes or not rfd) and p.poll() is not None:
|
||||
break
|
||||
# Calling wait while there are still pipes to read can cause a lock
|
||||
elif not rpipes and p.poll() == None:
|
||||
p.wait()
|
||||
|
||||
return p.returncode, stdout, stderr
|
Loading…
Reference in a new issue