Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the python used with test-module to run modules #19591

Merged
merged 2 commits into from
Jan 18, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 52 additions & 31 deletions hacking/test-module
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
# test-module -m ../library/file/lineinfile -a "dest=/etc/exports line='/srv/home hostname1(rw,sync)'" --check
# test-module -m ../library/commands/command -a "echo hello" -n -o "test_hello"

import base64
import optparse
import os
import subprocess
Expand All @@ -49,6 +48,7 @@ try:
except ImportError:
import simplejson as json


def parse():
"""parse command line

Expand All @@ -61,12 +61,11 @@ def parse():
help="REQUIRED: full path of module source to execute")
parser.add_option('-a', '--args', dest='module_args', default="",
help="module argument string")
parser.add_option('-D', '--debugger', dest='debugger',
parser.add_option('-D', '--debugger', dest='debugger',
help="path to python debugger (e.g. /usr/bin/pdb)")
parser.add_option('-I', '--interpreter', dest='interpreter',
help="path to interpreter to use for this module (e.g. ansible_python_interpreter=/usr/bin/python)",
metavar='INTERPRETER_TYPE=INTERPRETER_PATH',
default='python={0}'.format(sys.executable))
metavar='INTERPRETER_TYPE=INTERPRETER_PATH')
parser.add_option('-c', '--check', dest='check', action='store_true',
help="run the module in check mode")
parser.add_option('-n', '--noexecute', dest='execute', action='store_false',
Expand All @@ -81,6 +80,7 @@ def parse():
else:
return options, args


def write_argsfile(argstring, json=False):
""" Write args to a file for old-style module's use. """
argspath = os.path.expanduser("~/.ansible_test_module_arguments")
Expand All @@ -92,17 +92,33 @@ def write_argsfile(argstring, json=False):
argsfile.close()
return argspath

def boilerplate_module(modfile, args, interpreter, check, destfile):

def get_interpreters(interpreter):
result = dict()
if interpreter:
if '=' not in interpreter:
print("interpreter must by in the form of ansible_python_interpreter=/usr/bin/python")
sys.exit(1)
interpreter_type, interpreter_path = interpreter.split('=')
if not interpreter_type.startswith('ansible_'):
interpreter_type = 'ansible_%s' % interpreter_type
if not interpreter_type.endswith('_interpreter'):
interpreter_type = '%s_interpreter' % interpreter_type
result[interpreter_type] = interpreter_path
return result


def boilerplate_module(modfile, args, interpreters, check, destfile):
""" simulate what ansible does with new style modules """

#module_fh = open(modfile)
#module_data = module_fh.read()
#module_fh.close()
# module_fh = open(modfile)
# module_data = module_fh.read()
# module_fh.close()

#replacer = module_common.ModuleReplacer()
# replacer = module_common.ModuleReplacer()
loader = DataLoader()

#included_boilerplate = module_data.find(module_common.REPLACER) != -1 or module_data.find("import ansible.module_utils") != -1
# included_boilerplate = module_data.find(module_common.REPLACER) != -1 or module_data.find("import ansible.module_utils") != -1

complex_args = {}

Expand All @@ -122,20 +138,10 @@ def boilerplate_module(modfile, args, interpreter, check, destfile):
parsed_args = parse_kv(args)
complex_args = utils_vars.combine_vars(complex_args, parsed_args)

task_vars = {}
if interpreter:
if '=' not in interpreter:
print("interpreter must by in the form of ansible_python_interpreter=/usr/bin/python")
sys.exit(1)
interpreter_type, interpreter_path = interpreter.split('=')
if not interpreter_type.startswith('ansible_'):
interpreter_type = 'ansible_%s' % interpreter_type
if not interpreter_type.endswith('_interpreter'):
interpreter_type = '%s_interpreter' % interpreter_type
task_vars[interpreter_type] = interpreter_path
task_vars = interpreters

if check:
complex_args['_ansible_check_mode'] = True
complex_args['_ansible_check_mode'] = True

modname = os.path.basename(modfile)
modname = os.path.splitext(modname)[0]
Expand All @@ -160,10 +166,17 @@ def boilerplate_module(modfile, args, interpreter, check, destfile):

return (modfile2_path, modname, module_style)

def ansiballz_setup(modfile, modname):

def ansiballz_setup(modfile, modname, interpreters):
os.system("chmod +x %s" % modfile)

cmd = subprocess.Popen([modfile, 'explode'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if 'ansible_python_interpreter' in interpreters:
command = [interpreters['ansible_python_interpreter']]
else:
command = []
command.extend([modfile, 'explode'])

cmd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()
lines = out.splitlines()
if len(lines) != 2 or 'Module expanded into' not in lines[0]:
Expand All @@ -179,16 +192,21 @@ def ansiballz_setup(modfile, modname):
print("* ansiballz module detected; extracted module source to: %s" % debug_dir)
return modfile, argsfile

def runtest(modfile, argspath, modname, module_style):

def runtest(modfile, argspath, modname, module_style, interpreters):
"""Test run a module, piping it's output for reporting."""
if module_style == 'ansiballz':
modfile, argspath = ansiballz_setup(modfile, modname)
modfile, argspath = ansiballz_setup(modfile, modname, interpreters)
if 'ansible_python_interpreter' in interpreters:
invoke = "%s " % interpreters['ansible_python_interpreter']
else:
invoke = ""

os.system("chmod +x %s" % modfile)

invoke = "%s" % (modfile)
invoke = "%s%s" % (invoke, modfile)
if argspath is not None:
invoke = "%s %s" % (modfile, argspath)
invoke = "%s %s" % (invoke, argspath)

cmd = subprocess.Popen(invoke, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate()
Expand All @@ -210,6 +228,7 @@ def runtest(modfile, argspath, modname, module_style):
print("PARSED OUTPUT")
print(jsonify(results,format=True))


def rundebug(debugger, modfile, argspath, modname, module_style):
"""Run interactively with console debugger."""

Expand All @@ -221,10 +240,12 @@ def rundebug(debugger, modfile, argspath, modname, module_style):
else:
subprocess.call("%s %s" % (debugger, modfile), shell=True)


def main():

options, args = parse()
(modfile, modname, module_style) = boilerplate_module(options.module_path, options.module_args, options.interpreter, options.check, options.filename)
interpreters = get_interpreters(options.interpreter)
(modfile, modname, module_style) = boilerplate_module(options.module_path, options.module_args, interpreters, options.check, options.filename)

argspath = None
if module_style not in ('new', 'ansiballz'):
Expand All @@ -234,15 +255,15 @@ def main():
argspath = write_argsfile(options.module_args, json=False)
else:
raise Exception("internal error, unexpected module style: %s" % module_style)

if options.execute:
if options.debugger:
rundebug(options.debugger, modfile, argspath, modname, module_style)
else:
runtest(modfile, argspath, modname, module_style)
runtest(modfile, argspath, modname, module_style, interpreters)

if __name__ == "__main__":
try:
main()
finally:
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)