Example #1
0
def get_connection(module):
    global _CONNECTION
    if _CONNECTION:
        return _CONNECTION
    _CONNECTION = Connection(module)

    context = module.params['context']

    if context:
        if context == 'system':
            command = 'changeto system'
        else:
            command = 'changeto context %s' % context
        _CONNECTION.get(command)

    return _CONNECTION
Example #2
0
def get_connection(module):
    global _CONNECTION
    if _CONNECTION:
        return _CONNECTION
    _CONNECTION = Connection(module)

    context = module.params['context']

    if context:
        if context == 'system':
            command = 'changeto system'
        else:
            command = 'changeto context %s' % context
        _CONNECTION.get(command)

    return _CONNECTION
def get_connection(module):
    global _CONNECTION
    if _CONNECTION:
        return _CONNECTION
    _CONNECTION = Connection(module._socket_path)

    # Not all modules include the 'context' key.
    context = module.params.get('context')

    if context:
        if context == 'system':
            command = 'changeto system'
        else:
            command = 'changeto context %s' % context
        _CONNECTION.get(command)

    return _CONNECTION
Example #4
0
 def _run_command(self, command, task_vars):
     socket_path = getattr(self._connection,
                           'socket_path') or task_vars.get('ansible_socket')
     connection = Connection(socket_path)
     try:
         output = connection.get(command)
     except ConnectionError as exc:
         raise AnsibleError(to_text(exc))
     return output
Example #5
0
def main():
    module = AnsibleModule(
        argument_spec=dict(endpoint=dict(type="str", required=True), ),
        supports_check_mode=False,
    )

    conn = Connection(module._socket_path)
    status, _, data = conn.get(module.params["endpoint"])
    module.exit_json(changed=True, status=status, response=str(data))
Example #6
0
def get_connection(module):
    global _CONNECTION
    if _CONNECTION:
        return _CONNECTION
    _CONNECTION = Connection(module._socket_path)

    context = None
    try:
        context = module.params['context']
    except KeyError:
        context = None

    if context:
        if context == 'system':
            command = 'changeto system'
        else:
            command = 'changeto context %s' % context
        _CONNECTION.get(command)

    return _CONNECTION
Example #7
0
def get_connection(module):
    global _CONNECTION
    if _CONNECTION:
        return _CONNECTION
    _CONNECTION = Connection(module._socket_path)

    context = None
    try:
        context = module.params['context']
    except KeyError:
        context = None

    if context:
        if context == 'system':
            command = 'changeto system'
        else:
            command = 'changeto context %s' % context
        _CONNECTION.get(command)

    return _CONNECTION
def main():
    argument_spec = dict(
        compare=dict(type='dict', required=False),
        sendonly=dict(type='bool', default=False, required=False),
    )
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    if not PY3:
        module.fail_json(msg="pyATS/Genie requires Python 3")

    if not HAS_GENIE:
        module.fail_json(msg="Genie not found Run 'pip install genie'")

    if not HAS_PYATS:
        module.fail_json(msg="pyATS not found. Run 'pip install pyats'")

    if module.check_mode and not module.params['command'].startswith('show'):
        module.fail_json(
            msg='Only show commands are supported when using check_mode, not '
            'executing %s' % module.params['command'])

    warnings = list()
    result = {'changed': False, 'warnings': warnings}

    connection = Connection(module._socket_path)

    response = ''
    try:
        response = connection.get(command='show run')
    except ConnectionError as exc:
        module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

    config = Config(response)
    config.tree()

    if module.params['compare']:
        diff = Diff(config.config, module.params['compare'])
        diff.findDiff()
    else:
        diff = None

    try:
        result['json'] = module.from_json(response)
    except ValueError:
        pass

    result.update({
        'stdout': response,
        'structured': config.config,
        'diff': "{0}".format(diff)
    })

    module.exit_json(**result)
Example #9
0
def main():
    """entry point for module execution
    """
    argument_spec = dict(commands=dict(type='list', required=True),
                         wait_for=dict(type='list', aliases=['waitfor']),
                         match=dict(default='all', choices=['all', 'any']),
                         retries=dict(default=10, type='int'),
                         interval=dict(default=1, type='int'))
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    warnings = list()
    result = {'changed': False, 'warnings': warnings}

    wait_for = module.params['wait_for'] or list()
    try:
        conditionals = [Conditional(c) for c in wait_for]
    except AttributeError as exc:
        module.fail_json(msg=to_text(exc))

    commands = parse_commands(module, warnings)
    retries = module.params['retries']
    interval = module.params['interval']
    match = module.params['match']

    connection = Connection(module._socket_path)
    for attempt in range(retries):
        responses = []
        try:
            for command in commands:
                responses.append(connection.get(**command))
        except ConnectionError as exc:
            module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

        for item in list(conditionals):
            if item(responses):
                if match == 'any':
                    conditionals = list()
                    break
                conditionals.remove(item)

        if not conditionals:
            break

        time.sleep(interval)

    if conditionals:
        failed_conditions = [item.raw for item in conditionals]
        msg = 'One or more conditional statements have not been satisfied'
        module.fail_json(msg=msg, failed_conditions=failed_conditions)

    result.update({'stdout': responses, 'stdout_lines': to_lines(responses)})

    module.exit_json(**result)
Example #10
0
def main():
    """main entry point for module execution
    """
    argument_spec = dict(command=dict(required=True), )

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    command = module.params['command']

    connection = Connection(module._socket_path)
    output = connection.get(command=command)

    result = {'changed': False, 'text': output}

    module.exit_json(**result)
Example #11
0
def main():
    """entry point for module execution
    """
    argument_spec = dict(
        command=dict(type="str", required=True),
        prompt=dict(type="list", required=False),
        answer=dict(type="list", required=False),
        newline=dict(type="bool", default=True, required=False),
        sendonly=dict(type="bool", default=False, required=False),
        check_all=dict(type="bool", default=False, required=False),
    )
    required_together = [["prompt", "answer"]]
    module = AnsibleModule(
        argument_spec=argument_spec,
        required_together=required_together,
        supports_check_mode=True,
    )

    if module.check_mode and not module.params["command"].startswith("show"):
        module.fail_json(
            msg="Only show commands are supported when using check_mode, not "
            "executing %s" % module.params["command"]
        )

    warnings = list()
    result = {"changed": False, "warnings": warnings}

    connection = Connection(module._socket_path)
    response = ""
    try:
        response = connection.get(**module.params)
    except ConnectionError as exc:
        module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))

    if not module.params["sendonly"]:
        try:
            result["json"] = module.from_json(response)
        except ValueError:
            pass

        result.update({"stdout": response})

    module.exit_json(**result)
def main():
    """entry point for module execution
    """
    argument_spec = dict(
        command=dict(type='str', required=True),
        prompt=dict(type='list', required=False),
        answer=dict(type='list', required=False),
        newline=dict(type='bool', default=True, required=False),
        sendonly=dict(type='bool', default=False, required=False),
        check_all=dict(type='bool', default=False, required=False),
    )
    required_together = [['prompt', 'answer']]
    module = AnsibleModule(argument_spec=argument_spec, required_together=required_together,
                           supports_check_mode=True)

    if module.check_mode and not module.params['command'].startswith('show'):
        module.fail_json(
            msg='Only show commands are supported when using check_mode, not '
            'executing %s' % module.params['command']
        )

    warnings = list()
    result = {'changed': False, 'warnings': warnings}

    connection = Connection(module._socket_path)
    response = ''
    try:
        response = connection.get(**module.params)
    except ConnectionError as exc:
        module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

    if not module.params['sendonly']:
        try:
            result['json'] = module.from_json(response)
        except ValueError:
            pass

        result.update({
            'stdout': response,
        })

    module.exit_json(**result)
Example #13
0
 def _run_command(self):
     """ Run a command on the host
     If socket_path exists, assume it's a network device
     else, run a low level command
     """
     command = self._task.args.get("command")
     if command:
         socket_path = self._connection.socket_path
         if socket_path:
             connection = Connection(socket_path)
             try:
                 response = connection.get(command=command)
                 self._result["stdout"] = response
                 self._result["stdout_lines"] = response.splitlines()
             except AnsibleConnectionError as exc:
                 self._result["failed"] = True
                 self._result["msg"] = [to_text(exc)]
         else:
             result = self._low_level_execute_command(cmd=command)
             if result["rc"]:
                 self._result["failed"] = True
                 self._result["msg"] = result["stderr"]
             self._result["stdout"] = result["stdout"]
             self._result["stdout_lines"] = result["stdout_lines"]
Example #14
0
    def run(self, tmp=None, task_vars=None):
        ''' handler for cli operations '''

        if task_vars is None:
            task_vars = dict()

        result = super(ActionModule, self).run(tmp, task_vars)
        del tmp  # tmp no longer has any effect

        try:
            command = self._task.args['command']
            parser = self._task.args.get('parser')
            engine = self._task.args.get('engine', 'command_parser')
            if engine == 'textfsm_parser':
                name = self._task.args.get('name')
            elif engine == 'command_parser' and self._task.args.get('name'):
                display.warning(
                    'name is unnecessary when using command_parser and will be ignored'
                )
                del self._task.args['name']
        except KeyError as exc:
            raise AnsibleError(to_text(exc))

        socket_path = getattr(self._connection,
                              'socket_path') or task_vars.get('ansible_socket')
        connection = Connection(socket_path)

        # make command a required argument
        if not command:
            raise AnsibleError('missing required argument `command`')

        try:
            output = connection.get(command)
        except ConnectionError as exc:
            raise AnsibleError(to_text(exc))

        result['stdout'] = output

        # try to convert the cli output to native json
        try:
            json_data = json.loads(output)
        except Exception:
            json_data = None

        result['json'] = json_data

        if parser:
            if engine not in ('command_parser', 'textfsm_parser'):
                raise AnsibleError(
                    'missing or invalid value for argument engine')

            new_task = self._task.copy()
            new_task.args = {'file': parser, 'content': (json_data or output)}
            if engine == 'textfsm_parser':
                new_task.args.update({'name': name})

            kwargs = {
                'task': new_task,
                'connection': self._connection,
                'play_context': self._play_context,
                'loader': self._loader,
                'templar': self._templar,
                'shared_loader_obj': self._shared_loader_obj
            }

            task_parser = self._shared_loader_obj.action_loader.get(
                engine, **kwargs)
            result.update(task_parser.run(task_vars=task_vars))

        self._remove_tmp_path(self._connection._shell.tmpdir)

        # this is needed so the strategy plugin can identify the connection as
        # a persistent connection and track it, otherwise the connection will
        # not be closed at the end of the play
        socket_path = getattr(self._connection,
                              'socket_path') or task_vars.get('ansible_socket')
        self._task.args['_ansible_socket'] = socket_path

        return result
Example #15
0
def main():
    argument_spec = dict(command=dict(type='str', required=True),
                prompt=dict(type='list', required=False),
                answer=dict(type='list', required=False),
                compare=dict(type='dict', required=False),
                sendonly=dict(type='bool', default=False, required=False),
                # newline=dict(type='bool', default=True, required=False),
                # check_all=dict(type='bool', default=False, required=False),
    )
    required_together = [['prompt', 'answer']]
    module = AnsibleModule(argument_spec=argument_spec, required_together=required_together,
                           supports_check_mode=True)

    if not PY3:
        module.fail_json(msg="pyATS/Genie requires Python 3")

    if not HAS_GENIE:
        module.fail_json(msg="Genie not found. Run 'pip install genie'")

    if not HAS_PYATS:
        module.fail_json(msg="pyATS not found. Run 'pip install pyats'")

    if module.check_mode and not module.params['command'].startswith('show'):
        module.fail_json(
            msg='Only show commands are supported when using check_mode, not '
            'executing %s' % module.params['command']
        )

    warnings = list()
    result = {'changed': False, 'warnings': warnings}

    connection = Connection(module._socket_path)

    capabilities = json.loads(connection.get_capabilities())

    if capabilities['device_info']['network_os'] == 'ios':
        genie_os = 'iosxe'
    else:
        genie_os = capabilities['device_info']['network_os']

    compare = module.params.pop('compare')

    response = ''
    try:
        response = connection.get(**module.params)
    except ConnectionError as exc:
        module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

    device = Device("uut", os=genie_os)

    device.custom.setdefault("abstraction", {})["order"] = ["os"]
    device.cli = AttrDict({"execute": None})

    try:
        get_parser(module.params['command'], device)
    except Exception as e:
        module.fail_json(msg="Unable to find parser for command '{0}' ({1})".format(module.params['command'], e))

    try:
        parsed_output = device.parse(module.params['command'], output=response)
    except Exception as e:
        module.fail_json(msg="Unable to parse output for command '{0}' ({1})".format(module.params['command'], e))

    # import sys;
    # sys.stdin = open('/dev/tty')
    # import pdb;
    # pdb.set_trace()


    if compare:
        diff = Diff(parsed_output, compare, exclude=get_parser_exclude(module.params['command'], device))
        diff.findDiff()
    else:
        diff = None


    if not module.params['sendonly']:
        try:
            result['json'] = module.from_json(response)
        except ValueError:
            pass

        result.update({
            'stdout': response,
            'structured': parsed_output,
            'diff': "{0}".format(diff),
            'exclude': get_parser_exclude(module.params['command'], device),
        })

    module.exit_json(**result)
Example #16
0
def main():
    """ main entry point for module execution
    """
    entries_spec = dict(seqno=dict(type='int', required=True),
                        rule=dict(default='permit', choices=['permit',
                                                             'deny']),
                        prefix=dict(),
                        ge=dict(),
                        le=dict(),
                        eq=dict())

    argument_spec = dict(name=dict(required=True),
                         entries=dict(type='list',
                                      elements='dict',
                                      options=entries_spec),
                         replace=dict(type='bool', default=False),
                         state=dict(default='present',
                                    choices=['present', 'absent']))

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    connection = Connection(module._socket_path)

    if not check_version(connection, 4, 15):
        module.fail_json('failed version check')

    result = {'changed': False}

    commands = list()

    if module.params['state'] == 'absent':
        out = connection.get('show ip prefix-list %s' % module.params['name'])
        if out:
            commands.append('no ip prefix-list %s' % module.params['name'])

    elif module.params['state'] == 'present':
        if module.params['replace']:
            commands.append('no ip prefix-list %s' % module.params['name'])

        commands.append('ip prefix-list %s' % module.params['name'])

        out = connection.get('show ip prefix-list %s' % module.params['name'])
        config_lines = out.split('\n')

        for item in module.params['entries']:
            entry = configure(item)

            if entry in config_lines:
                break

            seqno = 'seqno %s' % item['seqno']
            if seqno in out:
                commands.append('no seq %s' % module.params['seqno'])

            commands.append(entry)

        commands.append('exit')

    if commands:
        commit = not module.check_mode
        resp = connection.load_config(commands, commit)
        if resp.get('diff'):
            result['changed'] = True
            if module._diff:
                result['diff'] = {'prepared': resp['diff']}

    module.exit_json(**result)
Example #17
0
    def run(self, tmp=None, task_vars=None):
        ''' handler for cli operations '''

        if task_vars is None:
            task_vars = dict()

        result = super(ActionModule, self).run(tmp, task_vars)
        del tmp  # tmp no longer has any effect

        try:
            command = self._task.args['command']
            parser = self._task.args.get('parser')
            engine = self._task.args.get('engine', 'command_parser')
        except KeyError as exc:
            raise AnsibleError(to_text(exc))

        socket_path = getattr(self._connection, 'socket_path') or task_vars.get('ansible_socket')
        connection = Connection(socket_path)

        try:
            output = connection.get(command)
        except ConnectionError as exc:
            raise AnsibleError(to_text(exc))

        result['stdout'] = output

        # try to convert the cli output to native json
        try:
            json_data = json.loads(output)
        except:
            json_data = None

        result['json'] = json_data

        if parser:
            if engine not in ('command_parser', 'textfsm_parser', 'text_parser', 'textfsm'):
                raise AnsibleError('missing or invalid value for argument engine')

            if engine == 'text_parser':
                display.deprecated(msg='the `text_parser` module has been deprecated, please use `command_parser` instead',
                                   version='2.6',
                                   removed=False)
            if engine == 'textfsm':
                display.deprecated(msg='the `textfsm` module has been deprecated, please use `textfsm_parser` instead',
                                   version='2.6',
                                   removed=False)

            new_task = self._task.copy()
            new_task.args = {
                'file': parser,
                'content': (json_data or output)
            }

            kwargs = {
                'task': new_task,
                'connection': self._connection,
                'play_context': self._play_context,
                'loader': self._loader,
                'templar': self._templar,
                'shared_loader_obj': self._shared_loader_obj
            }

            task_parser = self._shared_loader_obj.action_loader.get(engine, **kwargs)
            result.update(task_parser.run(task_vars=task_vars))

        self._remove_tmp_path(self._connection._shell.tmpdir)

        # this is needed so the strategy plugin can identify the connection as
        # a persistent connection and track it, otherwise the connection will
        # not be closed at the end of the play
        socket_path = getattr(self._connection, 'socket_path') or task_vars.get('ansible_socket')
        self._task.args['_ansible_socket'] = socket_path

        return result
Example #18
0
def main():
    """ main entry point for module execution
    """
    entries_spec = {
        'rule': dict(default='permit', choices=['permit', 'deny']),
        'seqno': dict(type='int'),
        'description': dict(),
        'include_route_map': dict(aliases=['sub_route_map']),
        'continue': dict(type='bool'),
        'continue_seqno': dict(type='int'),
        'match_ip_address_prefix_list': dict(),
        'match_ip_address_access_list': dict(),
        'set_tag': dict(type='int')
    }

    argument_spec = dict(name=dict(required=True),
                         entries=dict(type='list',
                                      elements='dict',
                                      options=entries_spec),
                         replace=dict(type='bool', default=False),
                         state=dict(default='present',
                                    choices=['present', 'absent']))

    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    connection = Connection(module._socket_path)

    if not check_version(connection, 4, 15):
        module.fail_json(msg='failed version check')

    result = {'changed': False}

    commands = list()

    if module.params['state'] == 'absent':
        out = connection.get('show route-map %s' % module.params['name'])
        if out:
            commands.append('no route-map %s' % module.params['name'])

    elif module.params['state'] == 'present':
        if module.params['replace']:
            commands.append('no route-map %s' % module.params['name'])

        try:
            for entry in module.params['entries']:
                commands.extend(configure(module.params['name'], entry))
        except ValueError as exc:
            module.fail_json(msg=to_text(exc))

        commands.append('exit')

    if commands:
        commit = not module.check_mode
        resp = connection.load_config(commands, commit)
        if resp.get('diff'):
            result['changed'] = True
            if module._diff:
                result['diff'] = {'prepared': resp['diff']}

    module.exit_json(**result)
Example #19
0
def main():
    """entry point for module execution
    """
    argument_spec = dict(commands=dict(type='list'),
                         rpcs=dict(type='list'),
                         display=dict(choices=['text', 'json', 'xml', 'set'],
                                      aliases=['format', 'output']),
                         wait_for=dict(type='list', aliases=['waitfor']),
                         match=dict(default='all', choices=['all', 'any']),
                         retries=dict(default=10, type='int'),
                         interval=dict(default=1, type='int'))

    argument_spec.update(junos_argument_spec)

    required_one_of = [('commands', 'rpcs')]

    module = AnsibleModule(argument_spec=argument_spec,
                           required_one_of=required_one_of,
                           supports_check_mode=True)

    warnings = list()
    check_args(module, warnings)

    if module.params['provider'] and module.params['provider'][
            'transport'] == 'cli':
        if any((module.params['wait_for'], module.params['match'],
                module.params['rpcs'])):
            module.warn(
                'arguments wait_for, match, rpcs are not supported when using transport=cli'
            )
        commands = module.params['commands']
        conn = Connection(module)
        output = list()
        for cmd in commands:
            output.append(conn.get(cmd))
        lines = [out.split('\n') for out in output]
        result = {'changed': False, 'stdout': output, 'stdout_lines': lines}
        module.exit_json(**result)

    items = list()
    items.extend(parse_commands(module, warnings))
    items.extend(parse_rpcs(module))

    wait_for = module.params['wait_for'] or list()
    conditionals = [Conditional(c) for c in wait_for]

    retries = module.params['retries']
    interval = module.params['interval']
    match = module.params['match']

    while retries > 0:
        responses = rpc(module, items)
        transformed = list()
        output = list()
        for item, resp in zip(items, responses):
            if item['xattrs']['format'] == 'xml':
                if not HAS_JXMLEASE:
                    module.fail_json(
                        msg=
                        'jxmlease is required but does not appear to be installed. '
                        'It can be installed using `pip install jxmlease`')

                try:
                    json_resp = jxmlease.parse(resp)
                    transformed.append(json_resp)
                    output.append(json_resp)
                except:
                    raise ValueError(resp)
            else:
                transformed.append(resp)

        for item in list(conditionals):
            try:
                if item(transformed):
                    if match == 'any':
                        conditionals = list()
                        break
                    conditionals.remove(item)
            except FailedConditionalError:
                pass

        if not conditionals:
            break

        time.sleep(interval)
        retries -= 1

    if conditionals:
        failed_conditions = [item.raw for item in conditionals]
        msg = 'One or more conditional statements have not be satisfied'
        module.fail_json(msg=msg, failed_conditions=failed_conditions)

    result = {
        'changed': False,
        'warnings': warnings,
        'stdout': responses,
        'stdout_lines': to_lines(responses)
    }

    if output:
        result['output'] = output

    module.exit_json(**result)
Example #20
0
def main():
    """entry point for module execution
    """
    argument_spec = dict(
        commands=dict(type='list'),
        rpcs=dict(type='list'),

        display=dict(choices=['text', 'json', 'xml', 'set'], aliases=['format', 'output']),

        wait_for=dict(type='list', aliases=['waitfor']),
        match=dict(default='all', choices=['all', 'any']),

        retries=dict(default=10, type='int'),
        interval=dict(default=1, type='int')
    )

    argument_spec.update(junos_argument_spec)

    required_one_of = [('commands', 'rpcs')]

    module = AnsibleModule(argument_spec=argument_spec,
                           required_one_of=required_one_of,
                           supports_check_mode=True)

    warnings = list()
    check_args(module, warnings)

    if module.params['provider'] and module.params['provider']['transport'] == 'cli':
        if any((module.params['wait_for'], module.params['match'], module.params['rpcs'])):
            module.warn('arguments wait_for, match, rpcs are not supported when using transport=cli')
        commands = module.params['commands']
        conn = Connection(module)
        output = list()
        for cmd in commands:
            output.append(conn.get(cmd))
        lines = [out.split('\n') for out in output]
        result = {'changed': False, 'stdout': output, 'stdout_lines': lines}
        module.exit_json(**result)

    items = list()
    items.extend(parse_commands(module, warnings))
    items.extend(parse_rpcs(module))

    wait_for = module.params['wait_for'] or list()
    conditionals = [Conditional(c) for c in wait_for]

    retries = module.params['retries']
    interval = module.params['interval']
    match = module.params['match']

    while retries > 0:
        responses = rpc(module, items)
        transformed = list()
        output = list()
        for item, resp in zip(items, responses):
            if item['xattrs']['format'] == 'xml':
                if not HAS_JXMLEASE:
                    module.fail_json(msg='jxmlease is required but does not appear to be installed. '
                                         'It can be installed using `pip install jxmlease`')

                try:
                    json_resp = jxmlease.parse(resp)
                    transformed.append(json_resp)
                    output.append(json_resp)
                except:
                    raise ValueError(resp)
            else:
                transformed.append(resp)

        for item in list(conditionals):
            try:
                if item(transformed):
                    if match == 'any':
                        conditionals = list()
                        break
                    conditionals.remove(item)
            except FailedConditionalError:
                pass

        if not conditionals:
            break

        time.sleep(interval)
        retries -= 1

    if conditionals:
        failed_conditions = [item.raw for item in conditionals]
        msg = 'One or more conditional statements have not be satisfied'
        module.fail_json(msg=msg, failed_conditions=failed_conditions)

    result = {
        'changed': False,
        'warnings': warnings,
        'stdout': responses,
        'stdout_lines': to_lines(responses)
    }

    if output:
        result['output'] = output

    module.exit_json(**result)