Added warnings to command module

Generate warnings when users are shelling out to commands
rather than using modules

Can be turned off on a per-action line with the documented
warn=False flag. Can be turned off globally using
command_warnings = False in ansible config file.

Print out warnings using the standard playbook callbacks.

Created some additional tests in TestRunner.test_command
and also a demonstration playbook.
reviewable/pr18780/r1
Will Thames 11 years ago committed by Michael DeHaan
parent 3373e82d83
commit 9686385898

@ -67,6 +67,12 @@ options:
required: false required: false
default: null default: null
version_added: "0.9" version_added: "0.9"
warn:
description:
- turn off warnings about running a command that is provided by an Ansible module.
required: false
default: True
version_added: "1.5"
notes: notes:
- If you want to run a command through the shell (say you are using C(<), - If you want to run a command through the shell (say you are using C(<),
C(>), C(|), etc), you actually want the M(shell) module instead. The C(>), C(|), etc), you actually want the M(shell) module instead. The
@ -108,7 +114,27 @@ EXAMPLES = '''
# that was matched in the first 'quote' is found, or the end of # that was matched in the first 'quote' is found, or the end of
# the line is reached # the line is reached
PARAM_REGEX = re.compile(r'(^|\s)(creates|removes|chdir|executable|NO_LOG)=(?P<quote>[\'"])?(.*?)(?(quote)(?<!\\)(?P=quote))((?<!\\)(?=\s)|$)') PARAM_REGEX = re.compile(r'(^|\s)(creates|removes|chdir|executable|NO_LOG|warn)=(?P<quote>[\'"])?(.*?)(?(quote)(?<!\\)(?P=quote))((?<!\\)(?=\s)|$)')
def check_command(commandline):
arguments = { 'chown': 'owner', 'chmod': 'mode', 'chgrp': 'group',
'ln': 'state=link', 'mkdir': 'state=directory',
'rmdir': 'state=absent', 'rm': 'state=absent', 'touch': 'state=touch' }
commands = { 'git': 'git', 'hg': 'hg', 'curl': 'get_url', 'wget': 'get_url',
'svn': 'subversion', 'service': 'service',
'mount': 'mount', 'rpm': 'yum', 'yum': 'yum', 'apt-get': 'apt-get',
'tar': 'unarchive', 'unzip': 'unarchive', 'sed': 'template or lineinfile',
'echo': 'template or lineinfile', 'cp': 'synchronize or copy',
'rsync': 'synchronize' }
warnings = list()
command = os.path.basename(commandline.split()[0])
if command in arguments:
warnings.append("Consider using file module with %s rather than running %s" % (arguments[command], command))
if command in commands:
warnings.append("Consider using %s module rather than running %s" % (commands[command], command))
return warnings
def main(): def main():
@ -122,6 +148,7 @@ def main():
args = module.params['args'] args = module.params['args']
creates = module.params['creates'] creates = module.params['creates']
removes = module.params['removes'] removes = module.params['removes']
warn = module.params.get('warn', True)
if args.strip() == '': if args.strip() == '':
module.fail_json(rc=256, msg="no command given") module.fail_json(rc=256, msg="no command given")
@ -157,6 +184,10 @@ def main():
rc=0 rc=0
) )
warnings = list()
if warn:
warnings = check_command(args)
if not shell: if not shell:
args = shlex.split(args) args = shlex.split(args)
startd = datetime.datetime.now() startd = datetime.datetime.now()
@ -172,14 +203,15 @@ def main():
err = '' err = ''
module.exit_json( module.exit_json(
cmd = args, cmd = args,
stdout = out.rstrip("\r\n"), stdout = out.rstrip("\r\n"),
stderr = err.rstrip("\r\n"), stderr = err.rstrip("\r\n"),
rc = rc, rc = rc,
start = str(startd), start = str(startd),
end = str(endd), end = str(endd),
delta = str(delta), delta = str(delta),
changed = True changed = True,
warnings = warnings
) )
# import module snippets # import module snippets
@ -206,6 +238,7 @@ class CommandModule(AnsibleModule):
params['removes'] = None params['removes'] = None
params['shell'] = False params['shell'] = False
params['executable'] = None params['executable'] = None
params['warn'] = True
if "#USE_SHELL" in args: if "#USE_SHELL" in args:
args = args.replace("#USE_SHELL", "") args = args.replace("#USE_SHELL", "")
params['shell'] = True params['shell'] = True
@ -236,6 +269,7 @@ class CommandModule(AnsibleModule):
# Remove any of the above k=v params from the args string # Remove any of the above k=v params from the args string
args = PARAM_REGEX.sub('', args) args = PARAM_REGEX.sub('', args)
params['args'] = args.strip() params['args'] = args.strip()
return (params, params['args']) return (params, params['args'])
main() main()

@ -41,6 +41,12 @@ options:
required: false required: false
default: null default: null
version_added: "0.9" version_added: "0.9"
warn:
description:
- turn off warnings about running a command that is provided by an Ansible module.
required: false
default: True
version_added: "1.5"
notes: notes:
- If you want to execute a command securely and predictably, it may be - If you want to execute a command securely and predictably, it may be
better to use the M(command) module instead. Best practices when writing better to use the M(command) module instead. Best practices when writing

Loading…
Cancel
Save