Force command action to not be executed by the shell unless specifically enabled

This commit is contained in:
James Tanner 2014-03-10 16:11:24 -05:00 committed by James Cammarata
parent 5bc6eafba5
commit a02641c020
19 changed files with 427 additions and 245 deletions

View file

@ -990,12 +990,13 @@ class AnsibleModule(object):
# rename might not preserve context
self.set_context_if_different(dest, context, False)
def run_command(self, args, check_rc=False, close_fds=False, executable=None, data=None, binary_data=False, path_prefix=None):
def run_command(self, args, check_rc=False, close_fds=False, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False):
'''
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.
If args is a string and use_unsafe_shell=False it will split args to a list and run with shell=False
If args is a string and use_unsafe_shell=True it run with shell=True.
Other arguments:
- check_rc (boolean) Whether to call fail_json in case of
non zero RC. Default is False.
@ -1004,13 +1005,18 @@ class AnsibleModule(object):
- executable (string) See documentation for subprocess.Popen().
Default is None.
'''
shell = False
if isinstance(args, list):
shell = False
elif isinstance(args, basestring):
pass
elif isinstance(args, basestring) and use_unsafe_shell:
shell = True
elif isinstance(args, basestring):
args = shlex.split(args)
else:
msg = "Argument 'args' to run_command must be list or string"
self.fail_json(rc=257, cmd=args, msg=msg)
rc = 0
msg = None
st_in = None
@ -1022,25 +1028,25 @@ class AnsibleModule(object):
if data:
st_in = subprocess.PIPE
kwargs = dict(
executable=executable,
shell=shell,
close_fds=close_fds,
stdin= st_in,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
if path_prefix:
kwargs['env'] = env
if cwd:
kwargs['cwd'] = cwd
try:
if path_prefix is not None:
cmd = subprocess.Popen(args,
executable=executable,
shell=shell,
close_fds=close_fds,
stdin=st_in,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
else:
cmd = subprocess.Popen(args,
executable=executable,
shell=shell,
close_fds=close_fds,
stdin=st_in,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
cmd = subprocess.Popen(args, **kwargs)
if data:
if not binary_data:
data += '\\n'

View file

@ -0,0 +1,252 @@
import os
import re
import types
import ConfigParser
import shlex
class RegistrationBase(object):
def __init__(self, module, username=None, password=None):
self.module = module
self.username = username
self.password = password
def configure(self):
raise NotImplementedError("Must be implemented by a sub-class")
def enable(self):
# Remove any existing redhat.repo
redhat_repo = '/etc/yum.repos.d/redhat.repo'
if os.path.isfile(redhat_repo):
os.unlink(redhat_repo)
def register(self):
raise NotImplementedError("Must be implemented by a sub-class")
def unregister(self):
raise NotImplementedError("Must be implemented by a sub-class")
def unsubscribe(self):
raise NotImplementedError("Must be implemented by a sub-class")
def update_plugin_conf(self, plugin, enabled=True):
plugin_conf = '/etc/yum/pluginconf.d/%s.conf' % plugin
if os.path.isfile(plugin_conf):
cfg = ConfigParser.ConfigParser()
cfg.read([plugin_conf])
if enabled:
cfg.set('main', 'enabled', 1)
else:
cfg.set('main', 'enabled', 0)
fd = open(plugin_conf, 'rwa+')
cfg.write(fd)
fd.close()
def subscribe(self, **kwargs):
raise NotImplementedError("Must be implemented by a sub-class")
class Rhsm(RegistrationBase):
def __init__(self, module, username=None, password=None):
RegistrationBase.__init__(self, module, username, password)
self.config = self._read_config()
self.module = module
def _read_config(self, rhsm_conf='/etc/rhsm/rhsm.conf'):
'''
Load RHSM configuration from /etc/rhsm/rhsm.conf.
Returns:
* ConfigParser object
'''
# Read RHSM defaults ...
cp = ConfigParser.ConfigParser()
cp.read(rhsm_conf)
# Add support for specifying a default value w/o having to standup some configuration
# Yeah, I know this should be subclassed ... but, oh well
def get_option_default(self, key, default=''):
sect, opt = key.split('.', 1)
if self.has_section(sect) and self.has_option(sect, opt):
return self.get(sect, opt)
else:
return default
cp.get_option = types.MethodType(get_option_default, cp, ConfigParser.ConfigParser)
return cp
def enable(self):
'''
Enable the system to receive updates from subscription-manager.
This involves updating affected yum plugins and removing any
conflicting yum repositories.
'''
RegistrationBase.enable(self)
self.update_plugin_conf('rhnplugin', False)
self.update_plugin_conf('subscription-manager', True)
def configure(self, **kwargs):
'''
Configure the system as directed for registration with RHN
Raises:
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'config']
# Pass supplied **kwargs as parameters to subscription-manager. Ignore
# non-configuration parameters and replace '_' with '.'. For example,
# 'server_hostname' becomes '--system.hostname'.
for k,v in kwargs.items():
if re.search(r'^(system|rhsm)_', k):
args.append('--%s=%s' % (k.replace('_','.'), v))
self.module.run_command(args, check_rc=True)
@property
def is_registered(self):
'''
Determine whether the current system
Returns:
* Boolean - whether the current system is currently registered to
RHN.
'''
# Quick version...
if False:
return os.path.isfile('/etc/pki/consumer/cert.pem') and \
os.path.isfile('/etc/pki/consumer/key.pem')
args = ['subscription-manager', 'identity']
rc, stdout, stderr = self.module.run_command(args, check_rc=False)
if rc == 0:
return True
else:
return False
def register(self, username, password, autosubscribe, activationkey):
'''
Register the current system to the provided RHN server
Raises:
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'register']
# Generate command arguments
if activationkey:
args.append('--activationkey "%s"' % activationkey)
else:
if autosubscribe:
args.append('--autosubscribe')
if username:
args.extend(['--username', username])
if password:
args.extend(['--password', password])
# Do the needful...
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def unsubscribe(self):
'''
Unsubscribe a system from all subscribed channels
Raises:
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'unsubscribe', '--all']
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def unregister(self):
'''
Unregister a currently registered system
Raises:
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'unregister']
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def subscribe(self, regexp):
'''
Subscribe current system to available pools matching the specified
regular expression
Raises:
* Exception - if error occurs while running command
'''
# Available pools ready for subscription
available_pools = RhsmPools(self.module)
for pool in available_pools.filter(regexp):
pool.subscribe()
class RhsmPool(object):
'''
Convenience class for housing subscription information
'''
def __init__(self, module, **kwargs):
self.module = module
for k,v in kwargs.items():
setattr(self, k, v)
def __str__(self):
return str(self.__getattribute__('_name'))
def subscribe(self):
args = "subscription-manager subscribe --pool %s" % self.PoolId
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
if rc == 0:
return True
else:
return False
class RhsmPools(object):
"""
This class is used for manipulating pools subscriptions with RHSM
"""
def __init__(self, module):
self.module = module
self.products = self._load_product_list()
def __iter__(self):
return self.products.__iter__()
def _load_product_list(self):
"""
Loads list of all availaible pools for system in data structure
"""
args = "subscription-manager list --available"
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
products = []
for line in stdout.split('\n'):
# Remove leading+trailing whitespace
line = line.strip()
# An empty line implies the end of a output group
if len(line) == 0:
continue
# If a colon ':' is found, parse
elif ':' in line:
(key, value) = line.split(':',1)
key = key.strip().replace(" ", "") # To unify
value = value.strip()
if key in ['ProductName', 'SubscriptionName']:
# Remember the name for later processing
products.append(RhsmPool(self.module, _name=value, key=value))
elif products:
# Associate value with most recently recorded product
products[-1].__setattr__(key, value)
# FIXME - log some warning?
#else:
# warnings.warn("Unhandled subscription key/value: %s/%s" % (key,value))
return products
def filter(self, regexp='^$'):
'''
Return a list of RhsmPools whose name matches the provided regular expression
'''
r = re.compile(regexp)
for product in self.products:
if r.search(product._name):
yield product

View file

@ -32,7 +32,7 @@ class LookupModule(object):
ret = []
for term in terms:
p = subprocess.Popen(term, cwd=self.basedir, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p = subprocess.Popen(term, cwd=self.basedir, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(stdout, stderr) = p.communicate()
if p.returncode == 0:
ret.append(stdout.decode("utf-8").rstrip())

View file

@ -113,13 +113,14 @@ class VMNotFound(Exception):
class LibvirtConnection(object):
def __init__(self, uri):
def __init__(self, uri, module):
cmd = subprocess.Popen("uname -r", shell=True, stdout=subprocess.PIPE,
close_fds=True)
output = cmd.communicate()[0]
self.module = module
if output.find("xen") != -1:
cmd = "uname -r"
rc, stdout, stderr = self.module.run_command(cmd)
if stdout.find("xen") != -1:
conn = libvirt.open(None)
else:
conn = libvirt.open(uri)
@ -221,11 +222,12 @@ class LibvirtConnection(object):
class Virt(object):
def __init__(self, uri):
def __init__(self, uri, module):
self.module = module
self.uri = uri
def __get_conn(self):
self.conn = LibvirtConnection(self.uri)
self.conn = LibvirtConnection(self.uri, self.module)
return self.conn
def get_vm(self, vmid):
@ -399,7 +401,7 @@ def core(module):
uri = module.params.get('uri', None)
xml = module.params.get('xml', None)
v = Virt(uri)
v = Virt(uri, module)
res = {}
if state and command=='list_vms':

View file

@ -136,7 +136,7 @@ def main():
args = shlex.split(args)
startd = datetime.datetime.now()
rc, out, err = module.run_command(args, executable=executable)
rc, out, err = module.run_command(args, executable=executable, use_unsafe_shell=shell)
endd = datetime.datetime.now()
delta = endd - startd

View file

@ -16,8 +16,6 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import subprocess
DOCUMENTATION = '''
---
module: synchronize
@ -272,6 +270,13 @@ def main():
cmd = cmd + " --rsync-path '%s'" %(rsync_path)
changed_marker = '<<CHANGED>>'
cmd = cmd + " --out-format='" + changed_marker + "%i %n%L'"
# expand the paths
if '@' not in source:
source = os.path.expanduser(source)
if '@' not in dest:
dest = os.path.expanduser(dest)
cmd = ' '.join([cmd, source, dest])
cmdstr = cmd
(rc, out, err) = module.run_command(cmd)

View file

@ -44,8 +44,6 @@ EXAMPLES = '''
- local_action: osx_say msg="{{inventory_hostname}} is all done" voice=Zarvox
'''
import subprocess
DEFAULT_VOICE='Trinoids'
def say(module, msg, voice):

View file

@ -151,8 +151,8 @@ def main():
command = '%s %s' % (virtualenv, env)
if site_packages:
command += ' --system-site-packages'
os.chdir(tempfile.gettempdir())
rc_venv, out_venv, err_venv = module.run_command(command)
cwd = tempfile.gettempdir()
rc_venv, out_venv, err_venv = module.run_command(command, cwd=cwd)
rc += rc_venv
out += out_venv

View file

@ -125,10 +125,11 @@ class Npm(object):
cmd.append(self.name_version)
#If path is specified, cd into that path and run the command.
cwd = None
if self.path:
os.chdir(self.path)
cwd = self.path
rc, out, err = self.module.run_command(cmd, check_rc=check_rc)
rc, out, err = self.module.run_command(cmd, check_rc=check_rc, cwd=cwd)
return out
return ''

View file

@ -90,7 +90,8 @@ def query_package(module, name, state="installed"):
# pacman -Q returns 0 if the package is installed,
# 1 if it is not installed
if state == "installed":
rc = os.system("pacman -Q %s" % (name))
cmd = "pacman -Q %s" % (name)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc == 0:
return True
@ -99,7 +100,8 @@ def query_package(module, name, state="installed"):
def update_package_db(module):
rc = os.system("pacman -Syy > /dev/null")
cmd = "pacman -Syy > /dev/null"
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg="could not update package db")
@ -118,7 +120,8 @@ def remove_packages(module, packages):
if not query_package(module, package):
continue
rc = os.system("pacman -%s %s --noconfirm > /dev/null" % (args, package))
cmd = "pacman -%s %s --noconfirm > /dev/null" % (args, package)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg="failed to remove %s" % (package))
@ -145,7 +148,8 @@ def install_packages(module, packages, package_files):
else:
params = '-S %s' % package
rc = os.system("pacman %s --noconfirm > /dev/null" % (params))
cmd = "pacman %s --noconfirm > /dev/null" % (params)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg="failed to install %s" % (package))

View file

@ -253,10 +253,10 @@ def main():
cmd = '%s --no-site-packages %s' % (virtualenv, env)
else:
cmd = '%s %s' % (virtualenv, env)
os.chdir(tempfile.gettempdir())
this_dir = tempfile.gettempdir()
if chdir:
os.chdir(chdir)
rc, out_venv, err_venv = module.run_command(cmd)
this_dir = os.path.join(this_dir, chdir)
rc, out_venv, err_venv = module.run_command(cmd, cwd=this_dir)
out += out_venv
err += err_venv
if rc != 0:
@ -298,10 +298,11 @@ def main():
if module.check_mode:
module.exit_json(changed=True)
os.chdir(tempfile.gettempdir())
this_dir = tempfile.gettempdir()
if chdir:
os.chdir(chdir)
rc, out_pip, err_pip = module.run_command(cmd, path_prefix=path_prefix)
this_dir = os.path.join(this_dir, chdir)
rc, out_pip, err_pip = module.run_command(cmd, path_prefix=path_prefix, cwd=this_dir)
out += out_pip
err += err_pip
if rc == 1 and state == 'absent' and 'not installed' in out_pip:

View file

@ -75,39 +75,13 @@ EXAMPLES = '''
import os
import re
import types
import subprocess
import ConfigParser
import shlex
class CommandException(Exception):
pass
def run_command(args):
'''
Convenience method to run a command, specified as a list of arguments.
Returns:
* tuple - (stdout, stder, retcode)
'''
# Coerce into a string
if isinstance(args, str):
args = shlex.split(args)
# Run desired command
proc = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(stdout, stderr) = proc.communicate()
returncode = proc.poll()
if returncode != 0:
cmd = ' '.join(args)
raise CommandException("Command failed (%s): %s\n%s" % (returncode, cmd, stdout))
return (stdout, stderr, returncode)
class RegistrationBase (object):
def __init__(self, username=None, password=None):
class RegistrationBase(object):
def __init__(self, module, username=None, password=None):
self.module = module
self.username = username
self.password = password
@ -147,9 +121,10 @@ class RegistrationBase (object):
class Rhsm(RegistrationBase):
def __init__(self, username=None, password=None):
RegistrationBase.__init__(self, username, password)
def __init__(self, module, username=None, password=None):
RegistrationBase.__init__(self, module, username, password)
self.config = self._read_config()
self.module = module
def _read_config(self, rhsm_conf='/etc/rhsm/rhsm.conf'):
'''
@ -199,8 +174,8 @@ class Rhsm(RegistrationBase):
for k,v in kwargs.items():
if re.search(r'^(system|rhsm)_', k):
args.append('--%s=%s' % (k.replace('_','.'), v))
run_command(args)
self.module.run_command(args, check_rc=True)
@property
def is_registered(self):
@ -216,13 +191,11 @@ class Rhsm(RegistrationBase):
os.path.isfile('/etc/pki/consumer/key.pem')
args = ['subscription-manager', 'identity']
try:
(stdout, stderr, retcode) = run_command(args)
except CommandException, e:
return False
else:
# Display some debug output
rc, stdout, stderr = self.module.run_command(args, check_rc=False)
if rc == 0:
return True
else:
return False
def register(self, username, password, autosubscribe, activationkey):
'''
@ -244,7 +217,7 @@ class Rhsm(RegistrationBase):
args.extend(['--password', password])
# Do the needful...
run_command(args)
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def unsubscribe(self):
'''
@ -253,7 +226,7 @@ class Rhsm(RegistrationBase):
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'unsubscribe', '--all']
run_command(args)
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def unregister(self):
'''
@ -262,7 +235,7 @@ class Rhsm(RegistrationBase):
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'unregister']
run_command(args)
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def subscribe(self, regexp):
'''
@ -273,7 +246,7 @@ class Rhsm(RegistrationBase):
'''
# Available pools ready for subscription
available_pools = RhsmPools()
available_pools = RhsmPools(self.module)
for pool in available_pools.filter(regexp):
pool.subscribe()
@ -284,7 +257,8 @@ class RhsmPool(object):
Convenience class for housing subscription information
'''
def __init__(self, **kwargs):
def __init__(self, module, **kwargs):
self.module = module
for k,v in kwargs.items():
setattr(self, k, v)
@ -292,15 +266,20 @@ class RhsmPool(object):
return str(self.__getattribute__('_name'))
def subscribe(self):
(stdout, stderr, retcode) = run_command("subscription-manager subscribe --pool %s" % self.PoolId)
return True
args = "subscription-manager subscribe --pool %s" % self.PoolId
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
if rc == 0:
return True
else:
return False
class RhsmPools(object):
"""
This class is used for manipulating pools subscriptions with RHSM
"""
def __init__(self):
def __init__(self, module):
self.module = module
self.products = self._load_product_list()
def __iter__(self):
@ -310,7 +289,8 @@ class RhsmPools(object):
"""
Loads list of all availaible pools for system in data structure
"""
(stdout, stderr, retval) = run_command("subscription-manager list --available")
args = "subscription-manager list --available"
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
products = []
for line in stdout.split('\n'):
@ -326,7 +306,7 @@ class RhsmPools(object):
value = value.strip()
if key in ['ProductName', 'SubscriptionName']:
# Remember the name for later processing
products.append(RhsmPool(_name=value, key=value))
products.append(RhsmPool(self.module, _name=value, key=value))
elif products:
# Associate value with most recently recorded product
products[-1].__setattr__(key, value)
@ -348,7 +328,7 @@ class RhsmPools(object):
def main():
# Load RHSM configuration from file
rhn = Rhsm()
rhn = Rhsm(AnsibleModule())
module = AnsibleModule(
argument_spec = dict(
@ -364,6 +344,7 @@ def main():
)
)
rhn.module = module
state = module.params['state']
username = module.params['username']
password = module.params['password']

View file

@ -72,12 +72,7 @@ EXAMPLES = '''
'''
import sys
import os
import re
import types
import subprocess
import ConfigParser
import shlex
import xmlrpclib
import urlparse
@ -90,75 +85,9 @@ except ImportError, e:
module.fail_json(msg="Unable to import up2date_client. Is 'rhn-client-tools' installed?\n%s" % e)
class CommandException(Exception):
pass
def run_command(args):
'''
Convenience method to run a command, specified as a list of arguments.
Returns:
* tuple - (stdout, stder, retcode)
'''
# Coerce into a string
if isinstance(args, str):
args = shlex.split(args)
# Run desired command
proc = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(stdout, stderr) = proc.communicate()
returncode = proc.poll()
if returncode != 0:
cmd = ' '.join(args)
raise CommandException("Command failed (%s): %s\n%s" % (returncode, cmd, stdout))
return (stdout, stderr, returncode)
class RegistrationBase (object):
def __init__(self, username=None, password=None):
self.username = username
self.password = password
def configure(self):
raise NotImplementedError("Must be implemented by a sub-class")
def enable(self):
# Remove any existing redhat.repo
redhat_repo = '/etc/yum.repos.d/redhat.repo'
if os.path.isfile(redhat_repo):
os.unlink(redhat_repo)
def register(self):
raise NotImplementedError("Must be implemented by a sub-class")
def unregister(self):
raise NotImplementedError("Must be implemented by a sub-class")
def unsubscribe(self):
raise NotImplementedError("Must be implemented by a sub-class")
def update_plugin_conf(self, plugin, enabled=True):
plugin_conf = '/etc/yum/pluginconf.d/%s.conf' % plugin
if os.path.isfile(plugin_conf):
cfg = ConfigParser.ConfigParser()
cfg.read([plugin_conf])
if enabled:
cfg.set('main', 'enabled', 1)
else:
cfg.set('main', 'enabled', 0)
fd = open(plugin_conf, 'rwa+')
cfg.write(fd)
fd.close()
def subscribe(self, **kwargs):
raise NotImplementedError("Must be implemented by a sub-class")
class Rhn(RegistrationBase):
def __init__(self, username=None, password=None):
def __init__(self, module, username=None, password=None):
RegistrationBase.__init__(self, username, password)
self.config = self.load_config()
@ -271,7 +200,7 @@ class Rhn(RegistrationBase):
register_cmd += " --activationkey '%s'" % activationkey
# FIXME - support --profilename
# FIXME - support --systemorgid
run_command(register_cmd)
rc, stdout, stderr = self.module.run_command(register_command, check_rc=True)
def api(self, method, *args):
'''
@ -309,14 +238,14 @@ class Rhn(RegistrationBase):
Subscribe to requested yum repositories using 'rhn-channel' command
'''
rhn_channel_cmd = "rhn-channel --user='%s' --password='%s'" % (self.username, self.password)
(stdout, stderr, rc) = run_command(rhn_channel_cmd + " --available-channels")
rc, stdout, stderr = self.module.run_command(rhn_channel_cmd + " --available-channels", check_rc=True)
# Enable requested repoid's
for wanted_channel in channels:
# Each inserted repo regexp will be matched. If no match, no success.
for availaible_channel in stdout.rstrip().split('\n'): # .rstrip() because of \n at the end -> empty string at the end
if re.search(wanted_repo, available_channel):
run_command(rhn_channel_cmd + " --add --channel=%s" % available_channel)
rc, stdout, stderr = self.module.run_command(rhn_channel_cmd + " --add --channel=%s" % available_channel, check_rc=True)
def main():
@ -379,4 +308,6 @@ def main():
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.redhat import *
main()

View file

@ -91,7 +91,8 @@ def query_package(module, name):
# rpm -q returns 0 if the package is installed,
# 1 if it is not installed
rc = os.system("rpm -q %s" % (name))
cmd = "rpm -q %s" % (name)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc == 0:
return True
else:
@ -103,13 +104,14 @@ def query_package_provides(module, name):
# rpm -q returns 0 if the package is installed,
# 1 if it is not installed
rc = os.system("rpm -q --provides %s >/dev/null" % (name))
cmd = "rpm -q --provides %s >/dev/null" % (name)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
return rc == 0
def update_package_db(module):
rc = os.system("urpmi.update -a -q")
cmd = "urpmi.update -a -q"
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg="could not update package db")
@ -123,7 +125,8 @@ def remove_packages(module, packages):
if not query_package(module, package):
continue
rc = os.system("%s --auto %s > /dev/null" % (URPME_PATH, package))
cmd = "%s --auto %s > /dev/null" % (URPME_PATH, package)
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg="failed to remove %s" % (package))

View file

@ -75,16 +75,17 @@ class Bzr(object):
self.version = version
self.bzr_path = bzr_path
def _command(self, args_list, **kwargs):
def _command(self, args_list, cwd=None, **kwargs):
(rc, out, err) = self.module.run_command(
[self.bzr_path] + args_list, **kwargs)
[self.bzr_path] + args_list, cwd=cwd, **kwargs)
return (rc, out, err)
def get_version(self):
'''samples the version of the bzr branch'''
os.chdir(self.dest)
cmd = "%s revno" % self.bzr_path
revno = os.popen(cmd).read().strip()
rc, stdout, stderr = self.module.run_command(cmd, cwd=self.dest)
revno = stdout.strip()
return revno
def clone(self):
@ -94,17 +95,18 @@ class Bzr(object):
os.makedirs(dest_dirname)
except:
pass
os.chdir(dest_dirname)
if self.version.lower() != 'head':
args_list = ["branch", "-r", self.version, self.parent, self.dest]
else:
args_list = ["branch", self.parent, self.dest]
return self._command(args_list, check_rc=True)
return self._command(args_list, check_rc=True, cwd=dest_dirname)
def has_local_mods(self):
os.chdir(self.dest)
cmd = "%s status -S" % self.bzr_path
lines = os.popen(cmd).read().splitlines()
rc, stdout, stderr = self.module.run_command(cmd, cwd=self.dest)
lines = stdout.splitlines()
lines = filter(lambda c: not re.search('^\\?\\?.*$', c), lines)
return len(lines) > 0
@ -114,30 +116,27 @@ class Bzr(object):
Discards any changes to tracked files in the working
tree since that commit.
'''
os.chdir(self.dest)
if not force and self.has_local_mods():
self.module.fail_json(msg="Local modifications exist in branch (force=no).")
return self._command(["revert"], check_rc=True)
return self._command(["revert"], check_rc=True, cwd=self.dest)
def fetch(self):
'''updates branch from remote sources'''
os.chdir(self.dest)
if self.version.lower() != 'head':
(rc, out, err) = self._command(["pull", "-r", self.version])
(rc, out, err) = self._command(["pull", "-r", self.version], cwd=self.dest)
else:
(rc, out, err) = self._command(["pull"])
(rc, out, err) = self._command(["pull"], cwd=self.dest)
if rc != 0:
self.module.fail_json(msg="Failed to pull")
return (rc, out, err)
def switch_version(self):
'''once pulled, switch to a particular revno or revid'''
os.chdir(self.dest)
if self.version.lower() != 'head':
args_list = ["revert", "-r", self.version]
else:
args_list = ["revert"]
return self._command(args_list, check_rc=True)
return self._command(args_list, check_rc=True, cwd=self.dest)
# ===========================================

View file

@ -181,11 +181,12 @@ def set_git_ssh(ssh_wrapper, key_file, ssh_opts):
if ssh_opts:
os.environ["GIT_SSH_OPTS"] = ssh_opts
def get_version(git_path, dest, ref="HEAD"):
def get_version(module, git_path, dest, ref="HEAD"):
''' samples the version of the git repo '''
os.chdir(dest)
cmd = "%s rev-parse %s" % (git_path, ref)
sha = os.popen(cmd).read().rstrip("\n")
rc, stdout, stderr = module.run_command(cmd, cwd=dest)
sha = stdout.rstrip('\n')
return sha
def clone(git_path, module, repo, dest, remote, depth, version, bare, reference):
@ -195,7 +196,6 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare, reference)
os.makedirs(dest_dirname)
except:
pass
os.chdir(dest_dirname)
cmd = [ git_path, 'clone' ]
if bare:
cmd.append('--bare')
@ -209,19 +209,19 @@ def clone(git_path, module, repo, dest, remote, depth, version, bare, reference)
if reference:
cmd.extend([ '--reference', str(reference) ])
cmd.extend([ repo, dest ])
module.run_command(cmd, check_rc=True)
module.run_command(cmd, check_rc=True, cwd=dest_dirname)
if bare:
os.chdir(dest)
if remote != 'origin':
module.run_command([git_path, 'remote', 'add', remote, repo], check_rc=True)
module.run_command([git_path, 'remote', 'add', remote, repo], check_rc=True, cwd=dest)
def has_local_mods(git_path, dest, bare):
def has_local_mods(module, git_path, dest, bare):
if bare:
return False
os.chdir(dest)
cmd = "%s status -s" % (git_path,)
lines = os.popen(cmd).read().splitlines()
lines = filter(lambda c: not re.search('^\\?\\?.*$', c), lines)
cmd = "%s status -s" % (git_path)
rc, stdout, stderr = module.run_command(cmd, cwd=dest)
lines = stdout.splitlines()
return len(lines) > 0
def reset(git_path, module, dest):
@ -230,16 +230,16 @@ def reset(git_path, module, dest):
Discards any changes to tracked files in working
tree since that commit.
'''
os.chdir(dest)
cmd = "%s reset --hard HEAD" % (git_path,)
return module.run_command(cmd, check_rc=True)
return module.run_command(cmd, check_rc=True, cwd=dest)
def get_remote_head(git_path, module, dest, version, remote, bare):
cloning = False
cwd = None
if remote == module.params['repo']:
cloning = True
else:
os.chdir(dest)
cwd = dest
if version == 'HEAD':
if cloning:
# cloning the repo, just get the remote's HEAD version
@ -255,7 +255,7 @@ def get_remote_head(git_path, module, dest, version, remote, bare):
# appears to be a sha1. return as-is since it appears
# cannot check for a specific sha1 on remote
return version
(rc, out, err) = module.run_command(cmd, check_rc=True )
(rc, out, err) = module.run_command(cmd, check_rc=True, cwd=cwd)
if len(out) < 1:
module.fail_json(msg="Could not determine remote revision for %s" % version)
rev = out.split()[0]
@ -270,10 +270,9 @@ def is_remote_tag(git_path, module, dest, remote, version):
return False
def get_branches(git_path, module, dest):
os.chdir(dest)
branches = []
cmd = '%s branch -a' % (git_path,)
(rc, out, err) = module.run_command(cmd)
(rc, out, err) = module.run_command(cmd, cwd=dest)
if rc != 0:
module.fail_json(msg="Could not determine branch data - received %s" % out)
for line in out.split('\n'):
@ -281,10 +280,9 @@ def get_branches(git_path, module, dest):
return branches
def get_tags(git_path, module, dest):
os.chdir(dest)
tags = []
cmd = '%s tag' % (git_path,)
(rc, out, err) = module.run_command(cmd)
(rc, out, err) = module.run_command(cmd, cwd=dest)
if rc != 0:
module.fail_json(msg="Could not determine tag data - received %s" % out)
for line in out.split('\n'):
@ -352,18 +350,17 @@ def get_head_branch(git_path, module, dest, remote, bare=False):
def fetch(git_path, module, repo, dest, version, remote, bare):
''' updates repo from remote sources '''
os.chdir(dest)
if bare:
(rc, out1, err1) = module.run_command([git_path, 'fetch', remote, '+refs/heads/*:refs/heads/*'])
(rc, out1, err1) = module.run_command([git_path, 'fetch', remote, '+refs/heads/*:refs/heads/*'], cwd=dest)
else:
(rc, out1, err1) = module.run_command("%s fetch %s" % (git_path, remote))
(rc, out1, err1) = module.run_command("%s fetch %s" % (git_path, remote), cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to download remote objects and refs")
if bare:
(rc, out2, err2) = module.run_command([git_path, 'fetch', remote, '+refs/tags/*:refs/tags/*'])
(rc, out2, err2) = module.run_command([git_path, 'fetch', remote, '+refs/tags/*:refs/tags/*'], cwd=dest)
else:
(rc, out2, err2) = module.run_command("%s fetch --tags %s" % (git_path, remote))
(rc, out2, err2) = module.run_command("%s fetch --tags %s" % (git_path, remote), cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to download remote objects and refs")
(rc, out3, err3) = submodule_update(git_path, module, dest)
@ -371,28 +368,26 @@ def fetch(git_path, module, repo, dest, version, remote, bare):
def submodule_update(git_path, module, dest):
''' init and update any submodules '''
os.chdir(dest)
# skip submodule commands if .gitmodules is not present
if not os.path.exists(os.path.join(dest, '.gitmodules')):
return (0, '', '')
cmd = [ git_path, 'submodule', 'sync' ]
(rc, out, err) = module.run_command(cmd, check_rc=True)
(rc, out, err) = module.run_command(cmd, check_rc=True, cwd=dest)
cmd = [ git_path, 'submodule', 'update', '--init', '--recursive' ]
(rc, out, err) = module.run_command(cmd)
(rc, out, err) = module.run_command(cmd, cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to init/update submodules")
return (rc, out, err)
def switch_version(git_path, module, dest, remote, version):
''' once pulled, switch to a particular SHA, tag, or branch '''
os.chdir(dest)
cmd = ''
if version != 'HEAD':
if is_remote_branch(git_path, module, dest, remote, version):
if not is_local_branch(git_path, module, dest, version):
cmd = "%s checkout --track -b %s %s/%s" % (git_path, version, remote, version)
else:
(rc, out, err) = module.run_command("%s checkout --force %s" % (git_path, version))
(rc, out, err) = module.run_command("%s checkout --force %s" % (git_path, version), cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to checkout branch %s" % version)
cmd = "%s reset --hard %s/%s" % (git_path, remote, version)
@ -400,11 +395,11 @@ def switch_version(git_path, module, dest, remote, version):
cmd = "%s checkout --force %s" % (git_path, version)
else:
branch = get_head_branch(git_path, module, dest, remote)
(rc, out, err) = module.run_command("%s checkout --force %s" % (git_path, branch))
(rc, out, err) = module.run_command("%s checkout --force %s" % (git_path, branch), cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to checkout branch %s" % branch)
cmd = "%s reset --hard %s" % (git_path, remote)
(rc, out1, err1) = module.run_command(cmd)
(rc, out1, err1) = module.run_command(cmd, cwd=dest)
if rc != 0:
if version != 'HEAD':
module.fail_json(msg="Failed to checkout %s" % (version))
@ -484,12 +479,12 @@ def main():
# Just return having found a repo already in the dest path
# this does no checking that the repo is the actual repo
# requested.
before = get_version(git_path, dest)
before = get_version(module, git_path, dest)
module.exit_json(changed=False, before=before, after=before)
else:
# else do a pull
local_mods = has_local_mods(git_path, dest, bare)
before = get_version(git_path, dest)
local_mods = has_local_mods(module, git_path, dest, bare)
before = get_version(module, git_path, dest)
if local_mods:
# failure should happen regardless of check mode
if not force:
@ -519,7 +514,7 @@ def main():
switch_version(git_path, module, dest, remote, version)
# determine if we changed anything
after = get_version(git_path, dest)
after = get_version(module, git_path, dest)
changed = False
if before != after or local_mods:

View file

@ -207,7 +207,9 @@ class Service(object):
os._exit(0)
# Start the command
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=lambda: os.close(pipe[1]))
if isinstance(cmd, basestring):
cmd = shlex.split(cmd)
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=lambda: os.close(pipe[1]))
stdout = ""
stderr = ""
fds = [p.stdout, p.stderr]

View file

@ -29,7 +29,6 @@ import socket
import struct
import datetime
import getpass
import subprocess
import ConfigParser
import StringIO
@ -1430,7 +1429,8 @@ class LinuxNetwork(Network):
"""
platform = 'Linux'
def __init__(self):
def __init__(self, module):
self.module = module
Network.__init__(self)
def populate(self):
@ -1616,12 +1616,15 @@ class LinuxNetwork(Network):
ips['all_ipv6_addresses'].append(address)
ip_path = module.get_bin_path("ip")
primary_data = subprocess.Popen(
[ip_path, 'addr', 'show', 'primary', device],
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
secondary_data = subprocess.Popen(
[ip_path, 'addr', 'show', 'secondary', device],
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
args = [ip_path, 'addr', 'show', 'primary', device]
rc, stdout, stderr = self.module.run_command(args)
primary_data = stdout
args = [ip_path, 'addr', 'show', 'secondary', device]
rc, stdout, stderr = self.module.run_command(args)
secondary_data = stdout
parse_ip_output(primary_data)
parse_ip_output(secondary_data, secondary=True)
@ -2281,11 +2284,11 @@ def get_file_content(path, default=None):
data = default
return data
def ansible_facts():
def ansible_facts(module):
facts = {}
facts.update(Facts().populate())
facts.update(Hardware().populate())
facts.update(Network().populate())
facts.update(Network(module).populate())
facts.update(Virtual().populate())
return facts
@ -2294,7 +2297,7 @@ def ansible_facts():
def run_setup(module):
setup_options = {}
facts = ansible_facts()
facts = ansible_facts(module)
for (k, v) in facts.items():
setup_options["ansible_%s" % k.replace('-', '_')] = v

View file

@ -232,7 +232,6 @@ def main():
_ensure_virtualenv(module)
os.chdir(app_path)
cmd = "python manage.py %s" % (command, )
if command in noinput_commands:
@ -251,7 +250,7 @@ def main():
if module.params[param]:
cmd = '%s %s' % (cmd, module.params[param])
rc, out, err = module.run_command(cmd)
rc, out, err = module.run_command(cmd, cwd=app_path)
if rc != 0:
if command == 'createcachetable' and 'table' in err and 'already exists' in err:
out = 'Already exists.'