rework run_command's env setting to not change os.environ for the rest of the module.

New param to run_command to modify the environment for just this invocation.
Documentation and comment adjustments.
This commit is contained in:
Toshio Kuratomi 2016-01-20 09:04:44 -08:00
parent 3d7efff30c
commit f1033f2194

View file

@ -363,8 +363,8 @@ class AnsibleModule(object):
if k not in self.argument_spec: if k not in self.argument_spec:
self.argument_spec[k] = v self.argument_spec[k] = v
# check the locale as set by the current environment, and # check the locale as set by the current environment, and reset to
# reset to LANG=C if it's an invalid/unavailable locale # a known valid (LANG=C) if it's an invalid/unavailable locale
self._check_locale() self._check_locale()
(self.params, self.args) = self._load_params() (self.params, self.args) = self._load_params()
@ -866,7 +866,7 @@ class AnsibleModule(object):
# setting the locale to '' uses the default locale # setting the locale to '' uses the default locale
# as it would be returned by locale.getdefaultlocale() # as it would be returned by locale.getdefaultlocale()
locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_ALL, '')
except locale.Error, e: except locale.Error:
# fallback to the 'C' locale, which may cause unicode # fallback to the 'C' locale, which may cause unicode
# issues but is preferable to simply failing because # issues but is preferable to simply failing because
# of an unknown locale # of an unknown locale
@ -1412,25 +1412,29 @@ class AnsibleModule(object):
# rename might not preserve context # rename might not preserve context
self.set_context_if_different(dest, context, False) self.set_context_if_different(dest, context, False)
def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False, prompt_regex=None): def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False, prompt_regex=None, environ_update=None):
''' '''
Execute a command, returns rc, stdout, and stderr. 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. :arg args: is the command to run
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 list, the command will be run with shell=False.
If args is a string and use_unsafe_shell=True it run with shell=True. * If args is a string and use_unsafe_shell=False it will split args to a list and run with shell=False
Other arguments: * If args is a string and use_unsafe_shell=True it runs with shell=True.
- check_rc (boolean) Whether to call fail_json in case of :kw check_rc: Whether to call fail_json in case of non zero RC.
non zero RC. Default is False. Default False
- close_fds (boolean) See documentation for subprocess.Popen(). :kw close_fds: See documentation for subprocess.Popen(). Default True
Default is True. :kw executable: See documentation for subprocess.Popen(). Default None
- executable (string) See documentation for subprocess.Popen(). :kw data: If given, information to write to the stdin of the command
Default is None. :kw binary_data: If False, append a newline to the data. Default False
- prompt_regex (string) A regex string (not a compiled regex) which :kw path_prefix: If given, additional path to find the command in.
can be used to detect prompts in the stdout This adds to the PATH environment vairable so helper commands in
which would otherwise cause the execution the same directory can also be found
to hang (especially if no input data is :kw cwd: iIf given, working directory to run the command inside
specified) :kw use_unsafe_shell: See `args` parameter. Default False
:kw prompt_regex: Regex string (not a compiled regex) which can be
used to detect prompts in the stdout which would otherwise cause
the execution to hang (especially if no input data is specified)
:kwarg environ_update: dictionary to *update* os.environ with
''' '''
shell = False shell = False
@ -1461,10 +1465,15 @@ class AnsibleModule(object):
msg = None msg = None
st_in = None st_in = None
# Set a temporart env path if a prefix is passed # Manipulate the environ we'll send to the new process
env=os.environ old_env_vals = {}
if environ_update:
for key, val in environ_update.items():
old_env_vals[key] = os.environ.get(key, None)
os.environ[key] = val
if path_prefix: if path_prefix:
env['PATH']="%s:%s" % (path_prefix, env['PATH']) old_env_vals['PATH'] = os.environ['PATH']
os.environ['PATH'] = "%s:%s" % (path_prefix, os.environ['PATH'])
# create a printable version of the command for use # create a printable version of the command for use
# in reporting later, which strips out things like # in reporting later, which strips out things like
@ -1505,11 +1514,10 @@ class AnsibleModule(object):
close_fds=close_fds, close_fds=close_fds,
stdin=st_in, stdin=st_in,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE stderr=subprocess.PIPE,
env=os.environ,
) )
if path_prefix:
kwargs['env'] = env
if cwd and os.path.isdir(cwd): if cwd and os.path.isdir(cwd):
kwargs['cwd'] = cwd kwargs['cwd'] = cwd
@ -1578,6 +1586,13 @@ class AnsibleModule(object):
except: except:
self.fail_json(rc=257, msg=traceback.format_exc(), cmd=clean_args) self.fail_json(rc=257, msg=traceback.format_exc(), cmd=clean_args)
# Restore env settings
for key, val in old_env_vals.items():
if val is None:
del os.environ[key]
else:
os.environ[key] = val
if rc != 0 and check_rc: if rc != 0 and check_rc:
msg = heuristic_log_sanitize(stderr.rstrip()) msg = heuristic_log_sanitize(stderr.rstrip())
self.fail_json(cmd=clean_args, rc=rc, stdout=stdout, stderr=stderr, msg=msg) self.fail_json(cmd=clean_args, rc=rc, stdout=stdout, stderr=stderr, msg=msg)