diff --git a/lib/ansible/module_common.py b/lib/ansible/module_common.py index 882e5cda7b1..d8e87a8bf4f 100644 --- a/lib/ansible/module_common.py +++ b/lib/ansible/module_common.py @@ -677,6 +677,52 @@ class AnsibleModule(object): self.set_context_if_different(src, context, False) os.rename(src, dest) + def run_command(self, args, **kwargs): + ''' + Execute a command, returns rc, stdout, and stderr. + args is the command to run + If args is a list, the command will be run with shell=False. + Otherwise, the command will be run with shell=True when args is a string. + kwargs is a dict of keyword arguments: + - fail_on_rc_non_zero (boolean) Whether to call fail_json in case of + non zero RC. Default is False. + - close_fds (boolean) See documentation for subprocess.Popen(). + Default is False. + - executable (string) See documentation for subprocess.Popen(). + Default is None. + ''' + if isinstance(args, list): + kwargs['shell'] = False + elif isinstance(args, basestring): + kwargs['shell'] = True + else: + msg = "Argument 'args' to run_command must be list or string" + self.fail_json(rc=257, cmd=args, msg=msg) + if 'fail_on_rc_non_zero' not in kwargs: + kwargs['fail_on_rc_non_zero'] = False + if 'close_fds' not in kwargs: + kwargs['close_fds'] = False + if 'executable' not in kwargs: + kwargs['executable'] = None + rc = 0 + msg = None + try: + cmd = subprocess.Popen(args, + executable=kwargs['executable'], + shell=kwargs['shell'], + close_fds=kwargs['close_fds'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = cmd.communicate() + rc = cmd.returncode + except (OSError, IOError), e: + self.fail_json(rc=e.errno, msg=str(e), cmd=args) + except: + self.fail_json(rc=257, msg=traceback.format_exc(), cmd=args) + if rc != 0 and kwargs['fail_on_rc_non_zero']: + msg = err.rstrip() + self.fail_json(cmd=args, rc=rc, stdout=out, stderr=err, msg=msg) + return (rc, out, err) + # == END DYNAMICALLY INSERTED CODE === """ diff --git a/library/apt b/library/apt index b15580070bd..6df89aaf216 100644 --- a/library/apt +++ b/library/apt @@ -93,22 +93,6 @@ warnings.filterwarnings('ignore', "apt API not stable yet", FutureWarning) APT_PATH = "/usr/bin/apt-get" APT = "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical %s" % APT_PATH -def run_apt(command): - try: - cmd = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - except (OSError, IOError), e: - rc = 1 - err = str(e) - out = '' - except: - rc = 1 - err = traceback.format_exc() - out = '' - else: - rc = cmd.returncode - return rc, out, err - def package_split(pkgspec): parts = pkgspec.split('=') if len(parts) > 1: @@ -154,7 +138,7 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None, install_reco if not install_recommends: cmd += " --no-install-recommends" - rc, out, err = run_apt(cmd) + rc, out, err = m.run_command(cmd) if rc: m.fail_json(msg="'apt-get install %s' failed: %s" % (packages, err)) else: @@ -175,7 +159,7 @@ def remove(m, pkgspec, cache, purge=False): else: purge = '--purge' if purge else '' cmd = "%s -q -y %s remove %s" % (APT, purge,packages) - rc, out, err = run_apt(cmd) + rc, out, err = m.run_command(cmd) if rc: m.fail_json(msg="'apt-get remove %s' failed: %s" % (packages, err)) m.exit_json(changed=True) diff --git a/library/apt_repository b/library/apt_repository index 1d7d1446f91..ce73700e6b7 100644 --- a/library/apt_repository +++ b/library/apt_repository @@ -59,15 +59,10 @@ import platform APT = "/usr/bin/apt-get" ADD_APT_REPO = 'add-apt-repository' -def _run(cmd): +def check_cmd_needs_y(): if platform.dist()[0] == 'debian' or float(platform.dist()[1]) >= 11.10: - cmd = cmd + ' -y' - # returns (rc, stdout, stderr) from shell command - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - stdout, stderr = process.communicate() - return (process.returncode, stdout, stderr) - + return True + return False def main(): add_apt_repository = None @@ -80,11 +75,14 @@ def main(): module = AnsibleModule(argument_spec=arg_spec) add_apt_repository = module.get_bin_path(ADD_APT_REPO, True) + if check_cmd_needs_y(): + add_apt_repository += ' -y' repo = module.params['repo'] state = module.params['state'] - rc, out, err = _run('%s "%s" --remove' % (add_apt_repository, repo)) + cmd = '%s "%s" --remove' % (add_apt_repository, repo) + rc, out, err = module.run_command(cmd) existed = 'Error' not in out if state == 'absent': @@ -95,7 +93,7 @@ def main(): cmd = '%s "%s"' % (add_apt_repository, repo) - rc, out, err = _run(cmd) + rc, out, err = module.run_command(cmd) changed = rc == 0 and not existed @@ -103,7 +101,7 @@ def main(): module.fail_json(msg=err) if changed: - rc, out, err = _run('%s update' % APT) + rc, out, err = module.run_command('%s update' % APT) module.exit_json(changed=changed, repo=repo, state=state) diff --git a/library/command b/library/command index 58e63cc613f..c3dc4cdb4d9 100644 --- a/library/command +++ b/library/command @@ -18,7 +18,6 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . -import subprocess import sys import datetime import traceback @@ -100,13 +99,7 @@ def main(): args = shlex.split(args) startd = datetime.datetime.now() - try: - cmd = subprocess.Popen(args, executable=executable, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - except (OSError, IOError), e: - module.fail_json(rc=e.errno, msg=str(e), cmd=args) - except: - module.fail_json(rc=257, msg=traceback.format_exc(), cmd=args) + rc, out, err = module.run_command(args, shell=shell, executable=executable) endd = datetime.datetime.now() delta = endd - startd @@ -120,7 +113,7 @@ def main(): cmd = args, stdout = out.rstrip("\r\n"), stderr = err.rstrip("\r\n"), - rc = cmd.returncode, + rc = rc, start = str(startd), end = str(endd), delta = str(delta), diff --git a/library/cron b/library/cron index 16451b9686f..b92e0e0f026 100644 --- a/library/cron +++ b/library/cron @@ -122,19 +122,13 @@ author: Dane Summers import re import tempfile -def get_jobs_file(user,tmpfile): +def get_jobs_file(module, user, tmpfile): cmd = "crontab -l %s > %s" % (user,tmpfile) - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) + return module.run_command(cmd) -def install_jobs(user,tmpfile): +def install_jobs(module, user, tmpfile): cmd = "crontab %s %s" % (user,tmpfile) - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) + return module.run_command(cmd) def get_jobs(tmpfile): lines = open(tmpfile).read().splitlines() @@ -155,13 +149,9 @@ def find_job(name,tmpfile): return j return [] -def add_job(name,job,tmpfile): +def add_job(module,name,job,tmpfile): cmd = "echo \"#Ansible: %s\n%s\" >> %s" % (name,job,tmpfile) - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) - + return module.run_command(cmd) def update_job(name,job,tmpfile): return _update_job(name,job,tmpfile,do_add_job) @@ -269,17 +259,17 @@ def main(): if job is None and do_install: module.fail_json(msg="You must specify 'job' to install a new cron job") tmpfile = tempfile.NamedTemporaryFile() - (rc, out, err) = get_jobs_file(user,tmpfile.name) + (rc, out, err) = get_jobs_file(module,user,tmpfile.name) if rc != 0 and rc != 1: # 1 can mean that there are no jobs. module.fail_json(msg=err) (handle,backupfile) = tempfile.mkstemp(prefix='crontab') - (rc, out, err) = get_jobs_file(user,backupfile) + (rc, out, err) = get_jobs_file(module,user,backupfile) if rc != 0 and rc != 1: module.fail_json(msg=err) old_job = find_job(name,backupfile) if do_install: if len(old_job) == 0: - (rc, out, err) = add_job(name,job,tmpfile.name) + (rc, out, err) = add_job(module,name,job,tmpfile.name) changed = True if len(old_job) > 0 and old_job[1] != job: (rc, out, err) = update_job(name,job,tmpfile.name) @@ -293,7 +283,7 @@ def main(): if changed: if backup: module.backup_local(backupfile) - (rc, out, err) = install_jobs(user,tmpfile.name) + (rc, out, err) = install_jobs(module,user,tmpfile.name) if (rc != 0): module.fail_json(msg=err) diff --git a/library/easy_install b/library/easy_install index a48e9b8656e..fedcaac74b5 100644 --- a/library/easy_install +++ b/library/easy_install @@ -55,27 +55,19 @@ requirements: [ "virtualenv" ] author: Matt Wright ''' -def _ensure_virtualenv(env, virtualenv): +def _ensure_virtualenv(module, env, virtualenv): if os.path.exists(os.path.join(env, 'bin', 'activate')): return 0, '', '' else: - return _run('%s %s' % (virtualenv, env)) + return module.run_command('%s %s' % (virtualenv, env)) -def _is_package_installed(name, easy_install): +def _is_package_installed(module, name, easy_install): cmd = '%s --dry-run %s' % (easy_install, name) - rc, status_stdout, status_stderr = _run(cmd) + rc, status_stdout, status_stderr = module.run_command(cmd) return not ('Reading' in status_stdout or 'Downloading' in status_stdout) -def _run(cmd): - # returns (rc, stdout, stderr) from shell command - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - stdout, stderr = process.communicate() - return (process.returncode, stdout, stderr) - - def main(): arg_spec = dict( name=dict(required=True), @@ -97,7 +89,7 @@ def main(): if virtualenv is None: module.fail_json(msg='virtualenv is not installed') - rc_venv, out_venv, err_venv = _ensure_virtualenv(env, virtualenv) + rc_venv, out_venv, err_venv = _ensure_virtualenv(module, env, virtualenv) rc += rc_venv out += out_venv @@ -105,11 +97,11 @@ def main(): cmd = None changed = False - installed = _is_package_installed(name, easy_install) + installed = _is_package_installed(module, name, easy_install) if not installed: cmd = '%s %s' % (easy_install, name) - rc_pip, out_pip, err_pip = _run(cmd) + rc_pip, out_pip, err_pip = module.run_command(cmd) rc += rc_pip out += out_pip diff --git a/library/facter b/library/facter index 8df12886196..9f6523e7fe9 100644 --- a/library/facter +++ b/library/facter @@ -38,25 +38,14 @@ requirements: [ "facter", "ruby-json" ] author: Michael DeHaan ''' -import subprocess - -def get_facter_data(): - p = subprocess.Popen(["/usr/bin/env", "facter", "--json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return rc, out, err - - def main(): module = AnsibleModule( argument_spec = dict() ) - rc, out, err = get_facter_data() - if rc != 0: - module.fail_json(msg=err) - else: - module.exit_json(**json.loads(out)) + cmd = ["/usr/bin/env", "facter", "--json"] + rc, out, err = module.run_command(cmd, fail_on_rc_non_zero=True) + module.exit_json(**json.loads(out)) # this is magic, see lib/ansible/module_common.py #<> diff --git a/library/fireball b/library/fireball index a3b09f45d86..6eb363723ed 100644 --- a/library/fireball +++ b/library/fireball @@ -70,7 +70,6 @@ import base64 import syslog import signal import time -import subprocess import signal syslog.openlog('ansible-%s' % os.path.basename(__file__)) @@ -153,15 +152,14 @@ def command(data): return dict(failed=True, msg='internal error: executable is required') log("executing: %s" % data['cmd']) - p = subprocess.Popen(data['cmd'], executable=data['executable'], shell=True, stdout=subprocess.PIPE, close_fds=True) - (stdout, stderr) = p.communicate() + rc, stdout, stderr = module.run_command(data['cmd'], executable=data['executable'], close_fds=True) if stdout is None: stdout = '' if stderr is None: stderr = '' log("got stdout: %s" % stdout) - return dict(rc=p.returncode, stdout=stdout, stderr=stderr) + return dict(rc=rc, stdout=stdout, stderr=stderr) def fetch(data): if 'in_path' not in data: diff --git a/library/git b/library/git index d1d78401fc3..b63b3f94d7a 100644 --- a/library/git +++ b/library/git @@ -64,12 +64,6 @@ examples: import re import tempfile -def _run(args): - cmd = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) - def get_version(dest): ''' samples the version of the git repo ''' os.chdir(dest) @@ -78,7 +72,7 @@ def get_version(dest): sha = sha[0].split()[1] return sha -def clone(repo, dest, remote): +def clone(module, repo, dest, remote): ''' makes a new git repo if it does not already exist ''' dest_dirname = os.path.dirname(dest) try: @@ -86,7 +80,8 @@ def clone(repo, dest, remote): except: pass os.chdir(dest_dirname) - return _run("git clone -o %s %s %s" % (remote, repo, dest)) + return module.run_command("git clone -o %s %s %s" % (remote, repo, dest), + fail_on_rc_non_zero=True) def has_local_mods(dest): os.chdir(dest) @@ -104,12 +99,12 @@ def reset(module,dest,force): os.chdir(dest) if not force and has_local_mods(dest): module.fail_json(msg="Local modifications exist in repository (force=no).") - return _run("git reset --hard HEAD") + return module.run_command("git reset --hard HEAD", fail_on_rc_non_zero=True) def get_branches(module, dest): os.chdir(dest) branches = [] - (rc, out, err) = _run("git branch -a") + (rc, out, err) = module.run_command("git branch -a") if rc != 0: module.fail_json(msg="Could not determine branch data - received %s" % out) for line in out.split('\n'): @@ -185,11 +180,11 @@ def get_head_branch(module, dest, remote): def fetch(module, repo, dest, version, remote): ''' updates repo from remote sources ''' os.chdir(dest) - (rc, out1, err1) = _run("git fetch %s" % remote) + (rc, out1, err1) = module.run_command("git fetch %s" % remote) if rc != 0: module.fail_json(msg="Failed to download remote objects and refs") - (rc, out2, err2) = _run("git fetch --tags %s" % remote) + (rc, out2, err2) = module.run_command("git fetch --tags %s" % remote) if rc != 0: module.fail_json(msg="Failed to download remote objects and refs") return (rc, out1 + out2, err1 + err2) @@ -203,7 +198,7 @@ def switch_version(module, dest, remote, version): if not is_local_branch(module, dest, version): cmd = "git checkout --track -b %s %s/%s" % (version, remote, version) else: - (rc, out, err) = _run("git checkout --force %s" % version) + (rc, out, err) = module.run_command("git checkout --force %s" % version) if rc != 0: module.fail_json(msg="Failed to checkout branch %s" % version) cmd = "git reset --hard %s/%s" % (remote, version) @@ -211,11 +206,11 @@ def switch_version(module, dest, remote, version): cmd = "git checkout --force %s" % version else: branch = get_head_branch(module, dest, remote) - (rc, out, err) = _run("git checkout --force %s" % branch) + (rc, out, err) = module.run_command("git checkout --force %s" % branch) if rc != 0: module.fail_json(msg="Failed to checkout branch %s" % branch) cmd = "git reset --hard %s" % remote - return _run(cmd) + return module.run_command(cmd, fail_on_rc_non_zero=True) # =========================================== @@ -245,9 +240,7 @@ def main(): before = None local_mods = False if not os.path.exists(gitconfig): - (rc, out, err) = clone(repo, dest, remote) - if rc != 0: - module.fail_json(msg=err) + (rc, out, err) = clone(module, repo, dest, remote) else: # else do a pull local_mods = has_local_mods(dest) @@ -262,8 +255,6 @@ def main(): # switch to version specified regardless of whether # we cloned or pulled (rc, out, err) = switch_version(module, dest, remote, version) - if rc != 0: - module.fail_json(msg=err) # determine if we changed anything after = get_version(dest) diff --git a/library/group b/library/group index 44b4c783e10..8f3dec41fa7 100644 --- a/library/group +++ b/library/group @@ -91,10 +91,7 @@ class Group(object): syslog.openlog('ansible-%s' % os.path.basename(__file__)) syslog.syslog(syslog.LOG_NOTICE, 'Command %s' % '|'.join(cmd)) - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return (rc, out, err) + return self.module.run_command(cmd) def group_del(self): cmd = [self.module.get_bin_path('groupdel', True), self.name] diff --git a/library/mount b/library/mount index a0b80a9151a..eba89afb503 100644 --- a/library/mount +++ b/library/mount @@ -187,7 +187,7 @@ def unset_mount(**kwargs): return (args['name'], changed) -def mount(**kwargs): +def mount(module, **kwargs): """ mount up a path or remount if needed """ name = kwargs['name'] @@ -196,25 +196,23 @@ def mount(**kwargs): else: cmd = [ '/bin/mount', name ] - call = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = call.communicate() - if call.returncode == 0: + rc, out, err = module.run_command(cmd) + if rc == 0: return 0, '' else: - return call.returncode, out+err + return rc, out+err -def umount(**kwargs): +def umount(module, **kwargs): """ unmount a path """ name = kwargs['name'] cmd = ['/bin/umount', name] - call = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = call.communicate() - if call.returncode == 0: + rc, out, err = module.run_command(cmd) + if rc == 0: return 0, '' else: - return call.returncode, out+err + return rc, out+err def main(): @@ -258,7 +256,7 @@ def main(): name, changed = unset_mount(**args) if changed: if os.path.ismount(name): - res,msg = umount(**args) + res,msg = umount(module, **args) if res: module.fail_json(msg="Error unmounting %s: %s" % (name, msg)) @@ -272,7 +270,7 @@ def main(): if state == 'unmounted': if os.path.ismount(name): - res,msg = umount(**args) + res,msg = umount(module, **args) if res: module.fail_json(msg="Error unmounting %s: %s" % (name, msg)) changed = True @@ -291,10 +289,10 @@ def main(): res = 0 if os.path.ismount(name): if changed: - res,msg = mount(**args) + res,msg = mount(module, **args) else: changed = True - res,msg = mount(**args) + res,msg = mount(module, **args) if res: module.fail_json(msg="Error mounting %s: %s" % (name, msg)) diff --git a/library/ohai b/library/ohai index 791a2cb5402..fc5538d2356 100644 --- a/library/ohai +++ b/library/ohai @@ -38,21 +38,13 @@ requirements: [ "ohai" ] author: Michael DeHaan ''' -def get_ohai_data(): - p = subprocess.Popen(["/usr/bin/env", "ohai"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return rc, out, err - def main(): module = AnsibleModule( argument_spec = dict() ) - rc, out, err = get_ohai_data() - if rc != 0: - module.fail_json(msg=err) - else: - module.exit_json(**json.loads(out)) + cmd = ["/usr/bin/env", "ohai"] + rc, out, err = module.run_command(cmd, fail_on_rc_non_zero=True) + module.exit_json(**json.loads(out)) # this is magic, see lib/ansible/module_common.py #<> diff --git a/library/pip b/library/pip index 5d52ca5b8d1..db86a58b2fe 100644 --- a/library/pip +++ b/library/pip @@ -114,14 +114,6 @@ def _get_pip(module, env): return pip -def _run(cmd): - # returns (rc, stdout, stderr) from shell command - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - stdout, stderr = process.communicate() - return (process.returncode, stdout, stderr) - - def _fail(module, cmd, out, err): msg = '' if out: @@ -173,7 +165,7 @@ def main(): virtualenv = module.get_bin_path('virtualenv', True) if not os.path.exists(os.path.join(env, 'bin', 'activate')): cmd = '%s %s' % (virtualenv, env) - rc, out_venv, err_venv = _run(cmd) + rc, out_venv, err_venv = module.run_command(cmd) out += out_venv err += err_venv if rc != 0: @@ -191,7 +183,7 @@ def main(): elif requirements: cmd += ' -r %s' % requirements - rc, out_pip, err_pip = _run(cmd) + rc, out_pip, err_pip = module.run_command(cmd) out += out_pip err += err_pip if rc == 1 and state == 'absent' and 'not installed' in out_pip: diff --git a/library/service b/library/service index 3889e4fefe9..9eca4522887 100644 --- a/library/service +++ b/library/service @@ -139,10 +139,7 @@ class Service(object): syslog.openlog('ansible-%s' % os.path.basename(__file__)) syslog.syslog(syslog.LOG_NOTICE, 'Command %s' % '|'.join(cmd)) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return (rc, out, err) + return self.module.run_command(cmd) def check_ps(self): # Set ps flags diff --git a/library/setup b/library/setup index ce0bb9a7521..aa54f87a300 100644 --- a/library/setup +++ b/library/setup @@ -178,10 +178,8 @@ class Facts(object): lsb_path = module.get_bin_path('lsb_release') if lsb_path is None: return self.facts - cmd = subprocess.Popen([lsb_path, "-a"], shell=False, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - if cmd.returncode == 0: + rc, out, err = module.run_command([lsb_path, "-a"]) + if rc == 0: self.facts['lsb'] = {} for line in out.split('\n'): if len(line) < 1: @@ -381,9 +379,7 @@ class SunOSHardware(Hardware): return self.facts def get_cpu_facts(self): - cmd = subprocess.Popen("/usr/sbin/psrinfo -v", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/sbin/psrinfo -v") self.facts['processor'] = [] for line in out.split('\n'): if 'processor operates' in line: @@ -394,15 +390,11 @@ class SunOSHardware(Hardware): self.facts['processor_count'] = len(self.facts['processor']) def get_memory_facts(self): - cmd = subprocess.Popen("/usr/sbin/prtconf", shell=False, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command(["/usr/sbin/prtconf"]) for line in out.split('\n'): if 'Memory size' in line: self.facts['memtotal_mb'] = line.split()[2] - cmd = subprocess.Popen("/usr/sbin/swap -s", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/sbin/swap -s") allocated = long(out.split()[1][:-1]) reserved = long(out.split()[5][:-1]) used = long(out.split()[8][:-1]) @@ -436,17 +428,14 @@ class FreeBSDHardware(Hardware): def get_cpu_facts(self): self.facts['processor'] = [] - cmd = subprocess.Popen("/sbin/sysctl -n hw.ncpu", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/sbin/sysctl -n hw.ncpu") self.facts['processor_count'] = out.strip() try: dmesg_boot = open(FreeBSDHardware.DMESG_BOOT) except IOError: - dmesg_cmd = subprocess.Popen("/sbin/dmesg", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - dmesg_boot = dmesg_cmd.stdout + rc, out, err = module.run_command("/sbin/dmesg") + dmesg_boot = out for line in dmesg_boot.readlines(): if 'CPU:' in line: @@ -457,9 +446,7 @@ class FreeBSDHardware(Hardware): def get_memory_facts(self): - cmd = subprocess.Popen("/sbin/sysctl vm.stats", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/sbin/sysctl vm.stats") for line in out.split('\n'): data = line.split() if 'vm.stats.vm.v_page_size' in line: @@ -474,9 +461,7 @@ class FreeBSDHardware(Hardware): # Device 1M-blocks Used Avail Capacity # /dev/ada0p3 314368 0 314368 0% # - cmd = subprocess.Popen("/usr/sbin/swapinfo -m", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/sbin/swapinfo -m") lines = out.split('\n') if len(lines[-1]) == 0: lines.pop() @@ -557,12 +542,12 @@ class LinuxNetwork(Network): for v in 'v4', 'v6': if v == 'v6' and not socket.has_ipv6: continue - output = subprocess.Popen(command[v], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] - if not output: + rc, out, err = module.run_command(command[v]) + if not out: # v6 routing may result in # RTNETLINK answers: Invalid argument continue - words = output.split('\n')[0].split() + words = out.split('\n')[0].split() # A valid output starts with the queried address on the first line if len(words) > 0 and words[0] == command[v][-1]: for i in range(len(words) - 1): @@ -580,8 +565,8 @@ class LinuxNetwork(Network): all_ipv4_addresses = [], all_ipv6_addresses = [], ) - output = subprocess.Popen([ip_path, 'addr', 'show'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] - for line in output.split('\n'): + rc, out, err = module.run_command([ip_path, 'addr', 'show']) + for line in out.split('\n'): if line: words = line.split() if not line.startswith(' '): @@ -825,9 +810,7 @@ class SunOSVirtual(Virtual): return self.facts def get_virtual_facts(self): - cmd = subprocess.Popen("/usr/sbin/prtdiag", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/sbin/prtdiag") for line in out.split('\n'): if 'VMware' in line: self.facts['virtualization_type'] = 'vmware' @@ -843,9 +826,7 @@ class SunOSVirtual(Virtual): self.facts['virtualization_role'] = 'guest' # Check if it's a zone if os.path.exists("/usr/bin/zonename"): - cmd = subprocess.Popen("/usr/bin/zonename", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/bin/zonename") if out.rstrip() != "global": self.facts['container'] = 'zone' # Check if it's a branded zone (i.e. Solaris 8/9 zone) @@ -854,9 +835,7 @@ class SunOSVirtual(Virtual): # If it's a zone check if we can detect if our global zone is itself virtualized. # Relies on the "guest tools" (e.g. vmware tools) to be installed if 'container' in self.facts and self.facts['container'] == 'zone': - cmd = subprocess.Popen("/usr/sbin/modinfo", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/sbin/modinfo") for line in out.split('\n'): if 'VMware' in line: self.facts['virtualization_type'] = 'vmware' @@ -895,9 +874,7 @@ def run_setup(module): # ruby-json is ALSO installed, include facter data in the JSON if os.path.exists("/usr/bin/facter"): - cmd = subprocess.Popen("/usr/bin/facter --json", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/bin/facter --json") facter = True try: facter_ds = json.loads(out) @@ -912,9 +889,7 @@ def run_setup(module): # templating w/o making a nicer key for it (TODO) if os.path.exists("/usr/bin/ohai"): - cmd = subprocess.Popen("/usr/bin/ohai", shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() + rc, out, err = module.run_command("/usr/bin/ohai") ohai = True try: ohai_ds = json.loads(out) diff --git a/library/subversion b/library/subversion index 1a964b28fef..336ab2746c2 100644 --- a/library/subversion +++ b/library/subversion @@ -85,11 +85,7 @@ class Subversion(object): if self.password: bits.append("--password '%s'" % self.password) bits.append(args) - cmd = subprocess.Popen(' '.join(bits), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - rc = cmd.returncode - if rc != 0: - self.module.fail_json(msg=err) + rc, out, err = self.module.run_command(' '.join(bits), fail_on_rc_non_zero=True) return out.splitlines() def checkout(self): diff --git a/library/supervisorctl b/library/supervisorctl index 6afef6b2b33..89c2e476b19 100644 --- a/library/supervisorctl +++ b/library/supervisorctl @@ -45,24 +45,6 @@ requirements: [ ] author: Matt Wright ''' -def _is_present(name, supervisorctl): - rc, out, err = _run('%s status' % supervisorctl) - return name in out - - -def _is_running(name, supervisorctl): - rc, out, err = _run('%s status %s' % (supervisorctl, name)) - return 'RUNNING' in out - - -def _run(cmd): - # returns (rc, stdout, stderr) from shell command - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - stdout, stderr = process.communicate() - return (process.returncode, stdout, stderr) - - def main(): arg_spec = dict( name=dict(required=True), @@ -76,12 +58,13 @@ def main(): SUPERVISORCTL = module.get_bin_path('supervisorctl', True) - present = _is_present(name, SUPERVISORCTL) + rc, out, err = module.run_command('%s status' % supervisorctl) + present = name in out if state == 'present': if not present: - _run('%s reread' % SUPERVISORCTL) - rc, out, err = _run('%s add %s' % (SUPERVISORCTL, name)) + module.run_command('%s reread' % SUPERVISORCTL, fail_on_rc_non_zero=True) + rc, out, err = module.run_command('%s add %s' % (SUPERVISORCTL, name)) if '%s: added process group' % name in out: module.exit_json(changed=True, name=name, state=state) @@ -90,13 +73,14 @@ def main(): module.exit_json(changed=False, name=name, state=state) - running = _is_running(name, SUPERVISORCTL) + rc, out, err = module.run_command('%s status %s' % (supervisorctl, name)) + running = 'RUNNING' in out if running and state == 'started': module.exit_json(changed=False, name=name, state=state) if running and state == 'stopped': - rc, out, err = _run('%s stop %s' % (SUPERVISORCTL, name)) + rc, out, err = module.run_command('%s stop %s' % (SUPERVISORCTL, name)) if '%s: stopped' % name in out: module.exit_json(changed=True, name=name, state=state) @@ -104,8 +88,8 @@ def main(): module.fail_json(msg=out) elif running and state == 'restarted': - rc, out, err = _run('%s update %s' % (SUPERVISORCTL, name)) - rc, out, err = _run('%s restart %s' % (SUPERVISORCTL, name)) + rc, out, err = module.run_command('%s update %s' % (SUPERVISORCTL, name)) + rc, out, err = module.run_command('%s restart %s' % (SUPERVISORCTL, name)) if '%s: stopped' % name in out and '%s: started' % name in out: module.exit_json(changed=True, name=name, state=state) @@ -113,7 +97,7 @@ def main(): module.fail_json(msg=out) elif not running and state == 'started': - rc, out, err = _run('%s start %s' % (SUPERVISORCTL, name)) + rc, out, err = module.run_command('%s start %s' % (SUPERVISORCTL, name)) if '%s: started' % name in out: module.exit_json(changed=True, name=name, state=state) diff --git a/library/svr4pkg b/library/svr4pkg index 8ce8fd628e4..58c5f8b369e 100644 --- a/library/svr4pkg +++ b/library/svr4pkg @@ -69,8 +69,8 @@ def package_installed(module, name): cmd = [module.get_bin_path('pkginfo', True)] cmd.append('-q') cmd.append(name) - res = subprocess.call(cmd) - if res == 0: + rc, out, err = module.run_command(' '.join(cmd), shell=False) + if rc == 0: return True else: return False @@ -102,10 +102,7 @@ basedir=default def run_command(module, cmd): progname = cmd[0] cmd[0] = module.get_bin_path(progname, True) - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return (rc, out, err) + return module.run_command(cmd) def package_install(module, name, src, proxy): adminfile = create_admin_file() diff --git a/library/user b/library/user index 34d7ef17bfa..0a0327d2f7a 100644 --- a/library/user +++ b/library/user @@ -223,10 +223,7 @@ class User(object): syslog.openlog('ansible-%s' % os.path.basename(__file__)) syslog.syslog(syslog.LOG_NOTICE, 'Command %s' % '|'.join(cmd)) - p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = p.communicate() - rc = p.returncode - return (rc, out, err) + return self.module.run_command(cmd) def remove_user_userdel(self): cmd = [self.module.get_bin_path('userdel', True)] diff --git a/library/yum b/library/yum index 81b4aa97f07..5c310c8409f 100644 --- a/library/yum +++ b/library/yum @@ -135,9 +135,9 @@ def is_installed(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_ else: cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, pkgspec] - rc,out,err = run(cmd) + rc,out,err = module.run_command(cmd) cmd = repoq + ["--disablerepo=*", "--pkgnarrow=installed", "--qf", qf, "--whatprovides", pkgspec] - rc2,out2,err2 = run(cmd) + rc2,out2,err2 = module.run_command(cmd) if rc == 0 and rc2 == 0: out += out2 return [ p for p in out.split('\n') if p.strip() ] @@ -170,7 +170,7 @@ def is_available(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_ else: cmd = repoq + ["--qf", qf, pkgspec] - rc,out,err = run(cmd) + rc,out,err = module.run_command(cmd) if rc == 0: return [ p for p in out.split('\n') if p.strip() ] else: @@ -211,7 +211,7 @@ def is_update(module, repoq, pkgspec, conf_file, qf=def_qf, en_repos=[], dis_rep else: cmd = repoq + ["--pkgnarrow=updates", "--qf", qf, pkgspec] - rc,out,err = run(cmd) + rc,out,err = module.run_command(cmd) if rc == 0: return set([ p for p in out.split('\n') if p.strip() ]) @@ -248,9 +248,9 @@ def what_provides(module, repoq, req_spec, conf_file, qf=def_qf, en_repos=[], d else: cmd = repoq + ["--qf", qf, "--whatprovides", req_spec] - rc,out,err = run(cmd) + rc,out,err = module.run_command(cmd) cmd = repoq + ["--qf", qf, req_spec] - rc2,out2,err2 = run(cmd) + rc2,out2,err2 = module.run_command(cmd) if rc == 0 and rc2 == 0: out += out2 pkgs = set([ p for p in out.split('\n') if p.strip() ]) @@ -267,7 +267,7 @@ def local_nvra(path): cmd = ['/bin/rpm', '-qp' ,'--qf', '%{name}-%{version}-%{release}.%{arch}\n', path ] - rc, out, err = run(cmd) + rc, out, err = module.run_command(cmd) if rc != 0: return None nvra = out.split('\n')[0] @@ -300,7 +300,7 @@ def pkg_to_dict(pkgstr): def repolist(repoq, qf="%{repoid}"): cmd = repoq + ["--qf", qf, "-a"] - rc,out,err = run(cmd) + rc,out,err = module.run_command(cmd) ret = [] if rc == 0: ret = set([ p for p in out.split('\n') if p.strip() ]) @@ -324,30 +324,6 @@ def list_stuff(module, conf_file, stuff): else: return [ pkg_to_dict(p) for p in is_installed(module, repoq, stuff, conf_file, qf=qf) + is_available(module, repoq, stuff, conf_file, qf=qf) if p.strip() ] -def run(command): - - try: - cmd = subprocess.Popen(command, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - except (OSError, IOError), e: - rc = 1 - err = str(e) - out = '' - except: - rc = 1 - err = traceback.format_exc() - out = '' - if out is None: - out = '' - if err is None: - err = '' - else: - rc = cmd.returncode - - return rc, out, err - - def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): res = {} @@ -414,7 +390,7 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): pkg = spec cmd = yum_basecmd + ['install', pkg] - rc, out, err = run(cmd) + rc, out, err = module.run_command(cmd) res['rc'] += rc res['results'].append(out) @@ -449,7 +425,7 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): # run an actual yum transaction cmd = yum_basecmd + ["remove", pkg] - rc, out, err = run(cmd) + rc, out, err = module.run_command(cmd) res['rc'] += rc res['results'].append(out) @@ -518,7 +494,7 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos): pkg = spec cmd = yum_basecmd + [basecmd, pkg] - rc, out, err = run(cmd) + rc, out, err = module.run_command(cmd) res['rc'] += rc res['results'].append(out)