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:
Brian Coca 2015-06-09 17:24:06 -04:00
parent 3bcbdf6841
commit 5aec5e5eb0
5 changed files with 96 additions and 29 deletions

View file

@ -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',

View file

@ -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

View file

@ -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):

View file

@ -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('/')

View 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