Custom module error

457 views
Skip to first unread message

Adam Shantz

unread,
Aug 8, 2017, 1:28:17 PM8/8/17
to Ansible Development
Hi all - 

I'm working on a custom module in python that takes a subset of an XML config, and turns it into JSON so I can use it with an Ansible playbook & Jinja2 template. 

My python code works fine to parse the output, but my module continually fails for reasons I can't explain.  Can someone give me a hint?

Module code:
#!/usr/bin/python

ANSIBLE_METADATA = {
    'metadata_version': '1.0',
    'status': ['preview'],
    'supported_by': 'curated'
}

import os
import shutil
import tempfile
import traceback
import xml.etree.cElementTree as etree
import json


from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_bytes, to_native

from collections import defaultdict

class Xml2Dict(dict):
    def __init__(self, parent_element):
        if parent_element.items():
            self.updateDict( dict(parent_element.items()) )
        for element in parent_element:
            if len(element):
                aDict = Xml2Dict(element)
                self.updateDict({element.tag: aDict})
            elif element.items():    # items() is special for attributes
                elementattrib= element.items()
                if element.text:
                    elementattrib.append((element.tag,element.text ))     # add tag:text if exist
                self.updateDict({element.tag: dict(elementattrib)})
            else:
                self.updateDict({element.tag: element.text})

    def updateDict (self, aDict ):
        for key in aDict.keys():   # keys() includes tag and attributes
            if key in self:
                value = self.pop(key)
                if type(value) is not list:
                    listOfDicts = []
                    listOfDicts.append(value)
                    listOfDicts.append(aDict[key])
                    self.update({key: listOfDicts})
                else:
                    value.append(aDict[key])
                    self.update({key: value})
            else:
                self.update({key:aDict[key]})  # it was self.update(aDict)

def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        src=dict(type='path')
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # change is if this module effectively modified the target
    # state will include any data that you want your module to pass back
    # for consumption, for example, in a subsequent task
    result = dict(
        changed=False,
        original_message='',
        message='',
        failed=''
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    src = module.params['src']
#    b_src = to_bytes(src, errors='surrogate_or_strict')

#    if not os.path.exists(b_src):
#        module.fail_json(msg="Source %s not found" % (src))
#    if not os.access(b_src, os.R_OK):
#        module.fail_json(msg="Source %s not readable" % (src))
#    if os.path.isdir(b_src):
#        module.fail_json(msg="Directory specified as the source instead of a file: %s" % (src))

#    if os.path.exists(b_src):
#        b_src = os.path.realpath(b_src)
#        src = to_native(b_src, errors='surrogate_or_strict')
#        if os.access(b_src, os.R_OK):
    tree = etree.ElementTree(file=src)
    #print tree.getroot()
    root = tree.getroot()
    #print "tag=%s, attrib=%s" % (root.tag, root.attrib)

    from pprint import pprint
    #router = pprint(etree_to_dict(root))
    router = Xml2Dict(root)

    for key in router['swiftlet'][4].iteritems():
        if key[0] == 'aliases':
            for item in enumerate(key[1]['alias']):
                dest = str(item[1]['map-to'])
                name = str(item[1]['name'])
    #            print dest + ":" + name

    queuesList = []
    for key in router['swiftlet'][9].iteritems():
        if key[0] == 'queues':
            for item in enumerate(key[1]['queue']):
                name = str(item[1]['name'])
                attrList = item[1]
                print attrList
                queueDict = {}

                if len(attrList) == 1:
                    queueDict[name] = {"propertyCount" : len(attrList)}
                else:
                    for attrib, value in attrList.iteritems():
                        if attrib != "name":
                            if name in queueDict:
                                queueDict[name][attrib] = value
                            else:
                                queueDict[name] = {attrib : value}
                    if name in queueDict:
                        queueDict[name]["propertyCount"] = len(attrList)
                    else:
                        queueDict[name] = {"propertyCount" : len(attrList)}

                queuesList.append(queueDict)

    output = json.dumps(queuesList)

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
#    if module.check_mode:
#        return result

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    result['original_message'] = module.params['src']
    result['message'] = 'goodbye'

    # use whatever logic you need to determine whether or not this module
    # made any modifications to your target
#    if module.params['src']:
#        result['changed'] = True

    # during the execution of the module, if there is an exception or a
    # conditional state that effectively causes a failure, run
    # AnsibleModule.fail_json() to pass in the message and the result
#    if module.params['src'] == 'fail me':
#        module.fail_json(msg='You requested this to fail', **result)

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    module.exit_json(
        changed=True,
        failed=False)


def main():
    run_module()


if __name__ == '__main__':
    main()


Results:
TASK [test module] *******************************************************************************************************************************************
task path: /home/ec2-user/ansible/testmod.yml:7
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/_text.py
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/basic.py
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/six/__init__.py
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/parsing/convert_bool.py
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/parsing/__init__.py
Using module_utils file /home/ec2-user/ansible/lib/ansible/module_utils/pycompat24.py
Using module file /home/ec2-user/ansible/lib/ansible/modules/messaging/new_module.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ec2-user
<127.0.0.1> EXEC /bin/sh -c 'echo ~ && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224 `" && echo ansible-tmp-1502132102.2-141765875120224="` echo /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224 `" ) && sleep 0'
<127.0.0.1> PUT /tmp/tmpHHjMUg TO /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224/new_module.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224/ /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224/new_module.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/home/ec2-user/ansible/venv/bin/python /home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224/new_module.py; rm -rf "/home/ec2-user/.ansible/tmp/ansible-tmp-1502132102.2-141765875120224/" > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "", 
    "module_stdout": "{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'name': 'test'}\n\n{\"invocation\": {\"module_args\": {\"src\": \"/home/ec2-user/ansible/routerconfig.xml\"}}, \"failed\": false, \"changed\": true}\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}
        to retry, use: --limit @/home/ec2-user/ansible/testmod.retry

PLAY RECAP ***************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1   



My playbook is below:

- name: test
  gather_facts: yes
  hosts: localhost
  connection: local

  tasks:
    - name: test module
      new_module:
        src: /home/ec2-user/ansible/routerconfig.xml
      register: testout


    - name: debug
      debug:
        msg: '{{testout}}'

Adrian Likins

unread,
Aug 8, 2017, 3:12:39 PM8/8/17
to Adam Shantz, Ansible Development
First glance, looks like quoting issue. Module output seems to include a mix of single and double quotes. module output should be json with double quotes.

Looks like:

   output = json.dumps(queuesList)

is going to make output a string with json in it. If you want the
structured data in the result, you will want to include queuesList
as a value to exit_json()

    # assumes queuesList object can be json serialized. If not, you will need to wrap it or transform it
    # to something that is (eg, a dict with string keys and values)
    module.exit_json(changed=True, failed=False, {'queueslist': queuesList})

(your pasted code also doesn't include 'output' in it's returns in exit_json or fail_json. Those need to include the data to be returned)


Can you post the stdout output from the module called directly?

a couple of ways to do that:


1. use hacking/test-module

    # from ansible src checkout, assuming custom module is at ~/new_module

    $ hacking/test-module -m ~/new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'

2. use ad hoc mode

   # assumes new_module is somewhere on ansible module library path

   $ ansible -v localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'


--
You received this message because you are subscribed to the Google Groups "Ansible Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-devel+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Adam Shantz

unread,
Aug 9, 2017, 1:40:43 PM8/9/17
to Ansible Development, a.mo...@gmail.com
Hi Adrian - 

I think you're right about the quoting.  Here's the ouput without any modifications to my module:

ansible -v localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'
Using /etc/ansible/ansible.cfg as config file
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

localhost | FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "", 
    "module_stdout": "{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'name': 'test'}\n\n{\"invocation\": {\"module_args\": {\"src\": \"/home/ec2-user/ansible/routerconfig.xml\"}}, \"failed\": false, \"changed\": true}\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}


When I add:
    module.exit_json(changed=True, failed=False, {'queueslist': queuesList})
I get the following output:
ansible -vvv localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'
ansible 2.4.0 (devel ca7ce4459d) last updated 2017/08/07 10:33:25 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/ec2-user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ec2-user/ansible/lib/ansible
  executable location = /home/ec2-user/ansible/bin/ansible
  python version = 2.6.6 (r266:84292, Nov 21 2013, 10:50:32) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]
Using /etc/ansible/ansible.cfg as config file
Parsed /etc/ansible/hosts inventory source with ini plugin
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

META: ran handlers
The full traceback is:
Traceback (most recent call last):
  File "/home/ec2-user/ansible/lib/ansible/executor/task_executor.py", line 125, in run
    res = self._execute()
  File "/home/ec2-user/ansible/lib/ansible/executor/task_executor.py", line 526, in _execute
    result = self._handler.run(task_vars=variables)
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/normal.py", line 45, in run
    results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars, wrap_async=wrap_async))
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/__init__.py", line 629, in _execute_module
    (module_style, shebang, module_data, module_path) = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/__init__.py", line 164, in _configure_module
    environment=final_environment)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 869, in modify_module
    environment=environment)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 695, in _find_module_utils
    recursive_finder(module_name, b_module_data, py_module_names, py_module_cache, zf)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 466, in recursive_finder
    tree = ast.parse(data)
  File "/usr/lib64/python2.6/ast.py", line 37, in parse
    return compile(expr, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 162
SyntaxError: non-keyword arg after keyword arg (<unknown>, line 162)

localhost | FAILED! => {
    "failed": true, 
    "msg": "Unexpected failure during module execution.", 
    "stdout": ""
}

If I change that line to be:
    module.exit_json(changed=True, failed=False, {'queueslist': output})
I get the following output:
ansible -vvv localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'
ansible 2.4.0 (devel ca7ce4459d) last updated 2017/08/07 10:33:25 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/ec2-user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ec2-user/ansible/lib/ansible
  executable location = /home/ec2-user/ansible/bin/ansible
  python version = 2.6.6 (r266:84292, Nov 21 2013, 10:50:32) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]
Using /etc/ansible/ansible.cfg as config file
Parsed /etc/ansible/hosts inventory source with ini plugin
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

META: ran handlers
The full traceback is:
Traceback (most recent call last):
  File "/home/ec2-user/ansible/lib/ansible/executor/task_executor.py", line 125, in run
    res = self._execute()
  File "/home/ec2-user/ansible/lib/ansible/executor/task_executor.py", line 526, in _execute
    result = self._handler.run(task_vars=variables)
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/normal.py", line 45, in run
    results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars, wrap_async=wrap_async))
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/__init__.py", line 629, in _execute_module
    (module_style, shebang, module_data, module_path) = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
  File "/home/ec2-user/ansible/lib/ansible/plugins/action/__init__.py", line 164, in _configure_module
    environment=final_environment)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 869, in modify_module
    environment=environment)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 695, in _find_module_utils
    recursive_finder(module_name, b_module_data, py_module_names, py_module_cache, zf)
  File "/home/ec2-user/ansible/lib/ansible/executor/module_common.py", line 466, in recursive_finder
    tree = ast.parse(data)
  File "/usr/lib64/python2.6/ast.py", line 37, in parse
    return compile(expr, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 163
SyntaxError: non-keyword arg after keyword arg (<unknown>, line 163)

localhost | FAILED! => {
    "failed": true, 
    "msg": "Unexpected failure during module execution.", 
    "stdout": ""
}


Sorry if I'm being dense here.  I'm sure it's something I'm doing wrong, but I don't know how to tell what it is.  

To unsubscribe from this group and stop receiving emails from it, send an email to ansible-deve...@googlegroups.com.

Adrian Likins

unread,
Aug 9, 2017, 2:13:17 PM8/9/17
to Adam Shantz, Ansible Development
comments inl

On Wed, Aug 9, 2017 at 1:40 PM, Adam Shantz <a.mo...@gmail.com> wrote:
Hi Adrian - 

I think you're right about the quoting.  Here's the ouput without any modifications to my module:

ansible -v localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'
Using /etc/ansible/ansible.cfg as config file
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

localhost | FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "", 
    "module_stdout": "{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'name': 'test'}\n\n{\"invocation\": {\"module_args\": {\"src\": \"/home/ec2-user/ansible/routerconfig.xml\"}}, \"failed\": false, \"changed\": true}\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}


When I add:
    module.exit_json(changed=True, failed=False, {'queueslist': queuesList})
 
<..>

  File "<unknown>", line 162
SyntaxError: non-keyword arg after keyword arg (<unknown>, line 162)


Ah, sorry I should have said:

   module.exit_json(changed=True, failed=False, queueslist=queuesList)
 
The adds 'queueslist' item to the return data dict with a value of the queuesList object.

The module will try to serialize the keyword args as a dict, add it to the rest of the return
object, and print the JSON to stdout. ansible will wrap that up in but the module by
itself will do that (ie, as invoked by 'test-module')

The module output should look something roughly like:


{

    "invocation": {
        "module_args": {
            "src": "/home/ec2-user/ansible/routerconfig.xml"
        }
    },
    "failed": false,
    "changed": true,
    "queueslist": ["whatever_a_queuesList_serializes_to_item1",
                         "another_item_in_queueslist"]
}



If I change that line to be:
    module.exit_json(changed=True, failed=False, {'queueslist': output})
SyntaxError: non-keyword arg after keyword arg (<unknown>, line 163)

Same issue as above (ie, my bad example)

Sorry if I'm being dense here.  I'm sure it's something I'm doing wrong, but I don't know how to tell what it is. 

The next issue will be if queuesList is json serializable or not. If you get an error about that, you will likely need to
build a simpler object (like a dict) from queuesList to serialize.

Adam Shantz

unread,
Aug 9, 2017, 2:52:05 PM8/9/17
to Ansible Development, a.mo...@gmail.com
Thanks.  I changed my module & the result is below.  I guess since queuesList is technically a list of dicts, it can't be automatically serialized?  If I change it from a list to a dict, then I assume things should be easier to handle automatically?  I guess I need to do more research on how to serialize things.


localhost | FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "", 
    "module_stdout": "{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'name': 'test'}\n\n{\"invocation\": {\"module_args\": {\"src\": \"/home/ec2-user/ansible/routerconfig.xml\"}}, \"failed\": false, \"changed\": true, \"queueslist\": [{\"q1\": {\"cache-size\": \"5000\", \"flowcontrol-start-queuesize\": \"-1\", \"propertyCount\": 5, \"cleanup-interval\": \"-1\", \"persistence-mode\": \"non_persistent\"}}, {\"q2\": {\"cache-size\": \"5000\", \"flowcontrol-start-queuesize\": \"-1\", \"propertyCount\": 5, \"cleanup-interval\": \"-1\", \"persistence-mode\": \"non_persistent\"}}, {\"q3\": {\"cache-size\": \"5000\", \"flowcontrol-start-queuesize\": \"-1\", \"propertyCount\": 5, \"cleanup-interval\": \"-1\", \"persistence-mode\": \"non_persistent\"}}, {\"test\": {\"propertyCount\": 1}}]}\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}

Adrian Likins

unread,
Aug 9, 2017, 3:51:17 PM8/9/17
to Adam Shantz, Ansible Development
comments inl

On Wed, Aug 9, 2017 at 1:40 PM, Adam Shantz <a.mo...@gmail.com> wrote:
Hi Adrian - 

I think you're right about the quoting.  Here's the ouput without any modifications to my module:

ansible -v localhost -m new_module -a 'src=/home/ec2-user/ansible/routerconfig.xml'
Using /etc/ansible/ansible.cfg as config file
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

localhost | FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "", 
    "module_stdout": "{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}\n{'name': 'test'}\n\n{\"invocation\": {\"module_args\": {\"src\": \"/home/ec2-user/ansible/routerconfig.xml\"}}, \"failed\": false, \"changed\": true}\n", 
    "msg": "MODULE FAILURE", 
    "rc": 0
}


When I add:
    module.exit_json(changed=True, failed=False, {'queueslist': queuesList})
 
<..>

  File "<unknown>", line 162
SyntaxError: non-keyword arg after keyword arg (<unknown>, line 162)


Ah, sorry I should have said:

   module.exit_json(changed=True, failed=False, queueslist=queuesList)
 
The adds 'queueslist' item to the return data dict with a value of the queuesList object.

{'changed':
exit_json will try to
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-devel+unsubscribe@googlegroups.com.

Adrian Likins

unread,
Aug 9, 2017, 4:02:00 PM8/9/17
to Adam Shantz, Ansible Development
A list should be fine, and looking at how queuesList is populated, I don't see any obvious that would not be json serializable.

But to diagnose/debug further, really need the stdout output from invoking the module directly. ie:

# cd to your ansible src checkout
$ cd ~/src/ansible
$ source hacking/env-setup
$ hacking/test-module -m /path/to/your/new_module.py -a 'src=/home/ec2-user/ansible/routerconfig.xml'

Looks like your module is writing to stdout from somewhere other than module.exit_json(), likely via print() in the module code.

The module output has to be _just_ valid json on stdout (the data that exit_json() writes to stdout). Anything else will cause
failures.

ie, the module stdout is:


"{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q1', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}
{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q2', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}
{'cache-size': '5000', 'flowcontrol-start-queuesize': '-1', 'name': 'q3', 'cleanup-interval': '-1', 'persistence-mode': 'non_persistent'}
{'name': 'test'}

{"invocation": {"module_args": {"src": "/home/ec2-user/ansible/routerconfig.xml"}}, "failed": false, "changed": true, "queueslist": [{"q1": {"cache-size": "5000", "flowcontrol-start-queuesize": "-1", "propertyCount": 5, "cleanup-interval": "-1", "persistence-mode": "non_persistent"}}, {"q2": {"cache-size": "5000", "flowcontrol-start-queuesize": "-1", "propertyCount": 5, "cleanup-interval": "-1", "persistence-mode": "non_persistent"}}, {"q3": {"cache-size": "5000", "flowcontrol-start-queuesize": "-1", "propertyCount": 5, "cleanup-interval": "-1", "persistence-mode": "non_persistent"}}, {"test": {"propertyCount": 1}}]}

That first blob looks like debug output to stdout, which is confusing the module runner. rm it, or write debug info to stderr to avoid the problem.

--
You received this message because you are subscribed to the Google Groups "Ansible Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-devel+unsubscribe@googlegroups.com.

Adam Shantz

unread,
Aug 16, 2017, 8:07:32 PM8/16/17
to Ansible Development, a.mo...@gmail.com
Hey Adrian - 

It's taken me a few days to get back to this, but I wanted to thank you for your advice.  You were right about me having an extra print statement in my python & it throwing things off.  I finally went through it slowly & figured it out (much simpler than I was making it out to be).  Thanks again!

-Adam
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-deve...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages