def main():
    """ main entry point for module execution
    """
    backup_spec = dict(filename=dict(), dir_path=dict(type='path'))
    argument_spec = dict(
        src=dict(type='path'),
        lines=dict(aliases=['commands'], type='list'),
        parents=dict(type='list'),
        before=dict(type='list'),
        after=dict(type='list'),
        match=dict(default='line', choices=['line', 'strict', 'exact',
                                            'none']),
        replace=dict(default='line', choices=['line', 'block']),
        multiline_delimiter=dict(default='@'),
        running_config=dict(aliases=['config']),
        intended_config=dict(),
        defaults=dict(type='bool', default=False),
        backup=dict(type='bool', default=False),
        backup_options=dict(type='dict', options=backup_spec),
        save_when=dict(choices=['always', 'never', 'modified', 'changed'],
                       default='never'),
        diff_against=dict(choices=['startup', 'intended', 'running']),
        diff_ignore_lines=dict(type='list'),
    )

    argument_spec.update(huawei_s_argument_spec)

    mutually_exclusive = [('lines', 'src'), ('parents', 'src')]

    required_if = [('match', 'strict', ['lines']),
                   ('match', 'exact', ['lines']),
                   ('replace', 'block', ['lines']),
                   ('diff_against', 'intended', ['intended_config'])]

    module = AnsibleModule(argument_spec=argument_spec,
                           mutually_exclusive=mutually_exclusive,
                           required_if=required_if,
                           supports_check_mode=True)
    if module.params['diff_against'] != None:
        module._diff = True

    result = {'changed': False}

    warnings = list()
    check_args(module, warnings)
    result['warnings'] = warnings

    diff_ignore_lines = module.params['diff_ignore_lines']
    config = None
    contents = None
    flags = get_defaults_flag(module) if module.params['defaults'] else []
    connection = get_connection(module)

    if module.params['backup'] or (module._diff and
                                   module.params['diff_against'] == 'running'):
        contents = get_config(module, flags=flags)
        config = NetworkConfig(indent=1, contents=contents)
        if module.params['backup']:
            result['__backup__'] = contents

    if any((module.params['lines'], module.params['src'])):
        match = module.params['match']
        replace = module.params['replace']
        path = module.params['parents']

        candidate = get_candidate_config(module)
        running = get_running_config(module, contents, flags=flags)
        try:
            response = connection.get_diff(candidate=candidate,
                                           running=running,
                                           diff_match=match,
                                           diff_ignore_lines=diff_ignore_lines,
                                           path=path,
                                           diff_replace=replace)
        except ConnectionError as exc:
            module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

        config_diff = response['config_diff']
        banner_diff = response['banner_diff']

        if config_diff or banner_diff:
            commands = config_diff.split('\n')

            if module.params['before']:
                commands[:0] = module.params['before']

            if module.params['after']:
                commands.extend(module.params['after'])

            result['commands'] = commands
            result['updates'] = commands
            result['banners'] = banner_diff

            # send the configuration commands to the device and merge
            # them with the current running config
            if not module.check_mode:
                if commands:
                    edit_config_or_macro(connection, commands)
                if banner_diff:
                    connection.edit_banner(candidate=json.dumps(banner_diff),
                                           multiline_delimiter=module.
                                           params['multiline_delimiter'])

            result['changed'] = True

    running_config = module.params['running_config']
    startup_config = None

    if module.params['save_when'] == 'always':
        save_config(module, result)
    elif module.params['save_when'] == 'modified':
        output = run_commands(
            module,
            ['display current-configuration', 'display saved-configuration'])

        running_config = NetworkConfig(indent=1,
                                       contents=output[0],
                                       ignore_lines=diff_ignore_lines)
        startup_config = NetworkConfig(indent=1,
                                       contents=output[1],
                                       ignore_lines=diff_ignore_lines)

        if running_config.sha1 != startup_config.sha1:
            save_config(module, result)
    elif module.params['save_when'] == 'changed' and result['changed']:
        save_config(module, result)

    if module._diff:
        if not running_config:
            output = run_commands(module, 'display current-configuration')
            contents = output[0]
        else:
            contents = running_config

        # recreate the object in order to process diff_ignore_lines
        running_config = NetworkConfig(indent=1,
                                       contents=contents,
                                       ignore_lines=diff_ignore_lines)

        if module.params['diff_against'] == 'running':
            if module.check_mode:
                module.warn(
                    "unable to perform diff against running-config due to check mode"
                )
                contents = None
            else:
                contents = config.config_text

        elif module.params['diff_against'] == 'startup':
            if not startup_config:
                output = run_commands(module, 'display saved-configuration')
                contents = output[0]
            else:
                contents = startup_config.config_text

        elif module.params['diff_against'] == 'intended':
            contents = module.params['intended_config']

        if contents is not None:
            base_config = NetworkConfig(indent=1,
                                        contents=contents,
                                        ignore_lines=diff_ignore_lines)

            if running_config.sha1 != base_config.sha1:
                if module.params['diff_against'] == 'intended':
                    before = running_config
                    after = base_config
                elif module.params['diff_against'] in ('startup', 'running'):
                    before = base_config
                    after = running_config

                result.update({
                    'changed': True,
                    'diff': {
                        'before': str(before),
                        'after': str(after)
                    }
                })

    module.exit_json(**result)
Пример #2
0
def main():
    """ main entry point for module execution
    """
    backup_spec = dict(filename=dict(), dir_path=dict(type='path'))

    argument_spec = dict(
        src=dict(type='path'),
        lines=dict(aliases=['commands'], type='list'),
        parents=dict(type='list'),
        before=dict(type='list'),
        after=dict(type='list'),
        match=dict(default='line', choices=['line', 'strict', 'exact',
                                            'none']),
        replace=dict(default='line', choices=['line', 'block']),
        running_config=dict(aliases=['config']),
        intended_config=dict(),
        backup=dict(type='bool', default=False),
        backup_options=dict(type='dict', options=backup_spec),
        save_when=dict(choices=['always', 'never', 'modified', 'changed'],
                       default='never'),
        diff_against=dict(choices=['running', 'startup', 'intended']),
        diff_ignore_lines=dict(type='list'),
    )

    argument_spec.update(aoscx_argument_spec)

    mutually_exclusive = [('lines', 'src'), ('parents', 'src')]

    required_if = [('match', 'strict', ['lines']),
                   ('match', 'exact', ['lines']),
                   ('replace', 'block', ['lines']),
                   ('diff_against', 'intended', ['intended_config'])]

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

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

    config = None

    if module.params['diff_against'] is not None:
        module._diff = True

    if module.params['backup'] or (module._diff and
                                   module.params['diff_against'] == 'running'):
        contents = get_config(module)
        config = NetworkConfig(contents=contents)
        if module.params['backup']:
            result['__backup__'] = contents
            result['backup_options'] = module.params['backup_options']
            if module.params['backup_options']:
                if 'dir_path' in module.params['backup_options']:
                    dir_path = module.params['backup_options']['dir_path']
                else:
                    dir_path = ""
                if 'filename' in module.params['backup_options']:
                    filename = module.params['backup_options']['filename']
                else:
                    filename = "backup.cfg"

                with open(dir_path + '/' + filename, 'w') as backupfile:
                    backupfile.write(contents)
                    backupfile.write("\n")

    if any((module.params['src'], module.params['lines'])):
        match = module.params['match']
        replace = module.params['replace']

        candidate = get_candidate(module)

        if match != 'none':
            config = get_running_config(module, config)
            path = module.params['parents']
            configobjs = candidate.difference(config,
                                              match=match,
                                              replace=replace,
                                              path=path)
        else:
            configobjs = candidate.items

        if configobjs:
            commands = dumps(configobjs, 'commands').split('\n')

            if module.params['before']:
                commands[:0] = module.params['before']

            if module.params['after']:
                commands.extend(module.params['after'])

            result['commands'] = commands
            result['updates'] = commands

            if not module.check_mode:
                load_config(module, commands)

            result['changed'] = True

    running_config = None
    startup_config = None

    diff_ignore_lines = module.params['diff_ignore_lines']
    if diff_ignore_lines is None:
        diff_ignore_lines = []

    diff_ignore_lines.append("Current configuration:")
    diff_ignore_lines.append("Startup configuration:")

    if module.params['save_when'] == 'always':
        save_config(module, result)
    elif module.params['save_when'] == 'modified':
        output = run_commands(module,
                              ['show running-config', 'show startup-config'])

        running_config = NetworkConfig(contents=output[0],
                                       ignore_lines=diff_ignore_lines)
        startup_config = NetworkConfig(contents=output[1],
                                       ignore_lines=diff_ignore_lines)

        if running_config.sha1 != startup_config.sha1:
            save_config(module, result)
    elif module.params['save_when'] == 'changed':
        if result['changed']:
            save_config(module, result)

    if module._diff:
        if not running_config:
            output = run_commands(module, 'show running-config')
            contents = output[0]
        else:
            contents = running_config.config_text

        # recreate the object in order to process diff_ignore_lines
        running_config = NetworkConfig(contents=contents,
                                       ignore_lines=diff_ignore_lines)

        if module.params['diff_against'] == 'running':
            if module.check_mode:
                module.warn("unable to perform diff against "
                            "running-config due to check mode")
                contents = None
            else:
                contents = config.config_text

        elif module.params['diff_against'] == 'startup':
            if not startup_config:
                output = run_commands(module, 'show startup-config')
                contents = output[0]
            else:
                contents = startup_config.config_text

        elif module.params['diff_against'] == 'intended':
            with open(module.params['intended_config'], 'r') as intended_file:
                contents = intended_file.read()
        if contents is not None:
            base_config = NetworkConfig(contents=contents,
                                        ignore_lines=diff_ignore_lines)

            if running_config.sha1 != base_config.sha1:
                result.update({
                    'changed': True,
                    'diff': {
                        'before': str(base_config),
                        'after': str(running_config)
                    }
                })

    module.exit_json(**result)
Пример #3
0
def run_module():
    # define available arguments/parameters a user can pass to the module
    module_args = dict(
        host=dict(type="str", required=True),
        port=dict(type="int", required=False),
        protocol=dict(type="str", required=False),
        username=dict(type="str", required=True),
        password=dict(type="str", required=True, no_log=True),
        os=dict(type="str", required=True),
        feature=dict(type="str", required=True),
        compare_to=dict(type="raw", required=False),
        exclude=dict(type="list", required=False),
        no_default_exclusion=dict(type="bool", required=False),
        colors=dict(type="bool", required=False)
    )
    # TODO: Add protocol so Unicon can use anything
    # print(type(module_args['compare_to']))
    # 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)

    # 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)

    host = module.params["host"]
    if module.params.get("port") is not None:
        port = module.params["port"]
    else:
        port = 22
    username = module.params["username"]
    password = module.params["password"]
    os = module.params["os"]
    feature = module.params["feature"]
    if module.params.get("compare_to"):
        # compare_to = json.loads(module.params.get("compare_to"))
        compare_to = module.params.get("compare_to")
    if module.params.get("exclude"):
        excluded_keys = module.params.get("exclude")
    if module.params.get("no_default_exclusion") is False:
        no_default_exclusion = False
    elif module.params.get("no_default_exclusion") is None:
        no_default_exclusion = False
    else:
        no_default_exclusion = True
    if module.params.get("colors") is False:
        colors = False
    elif module.params.get("colors") is not None:
        colors = True
    else:
        colors = True
    if module.params.get("protocol") == "telnet":
        protocol = "telnet"
    else:
        protocol = "ssh"

    # 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:
        module.exit_json(**result)

    # Check user input
    for k, v in module.params.items():
        if k == "port" and v is not None:
            if not isinstance(v, int) and v not in range(1-65535):
                raise AnsibleError(
                    "The {} parameter must be an integer between 0-65535".format(k)
                )
        elif k == "compare_to":
            pass
        elif k == "port":
            pass
        elif k == "exclude":
            pass
        elif k == "colors":
            pass
        elif k == "no_default_exclusion":
            pass
        elif k == "protocol":
            pass
        else:
            if not isinstance(v, string_types):
                raise AnsibleError(
                    "The {} parameter must be a string such as a hostname or IP address.".format(
                        k
                    )
                )

    # Did the user pass in a feature that is supported on a given platform
    genie_ops = importlib.util.find_spec("genie.libs.ops")
    ops_file_obj = Path(genie_ops.origin).parent.joinpath("ops.json")
    with open(ops_file_obj, "r") as f:
        ops_json = json.load(f)
    supported_features = [k for k, _ in ops_json.items()]

    # Load in default exclusions for diffs for all features for genie learn
    # genie_yamls = importlib.util.find_spec("genie.libs.sdk.genie_yamls")
    # genie_excludes = Path(genie_yamls.origin).parent.joinpath("pts_datafile.yaml")
    # with open(genie_excludes, "r") as f:
    #     diff_excludes = json.load(f)
    # supported_features = [k for k, _ in ops_json.items()]

    default_excludes = {}
    from importlib import import_module
    for i in supported_features:
        modulename = "genie.libs.ops.{}.{}".format(i, i)
        package_name = i.capitalize()
        try:
            this_module = import_module(modulename, package_name)
            this_class = getattr(this_module, package_name)
            this_excludes = this_class.exclude
            default_excludes.update({i: this_excludes})
        except AttributeError:
            default_excludes.update({i: []})

        # this_module = __import__(modulename)
        # default_excludes.append({i: this_module.i)
        # from genie.libs.ops.i.i import Interface

    # Is the feature even supported?
    if feature not in supported_features:
        raise AnsibleError(
            "The feature entered is not supported on the current version of Genie.\nCurrently supported features: {0}\n{1}".format(
                to_native(supported_features),
                "https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/models",
            )
        )

    # Is the feature supported on the OS that was provided from the user?
    for f in ops_json.items():
        if feature == f[0]:
            if os not in [k for k, _ in f[1].items()]:
                raise AnsibleError(
                    "The {0} feature entered is not supported on {1}.\nCurrently supported features & platforms:\n{2}".format(
                        feature, os,
                        "https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/models",
                    )
                )

    testbed = {
        "devices": {
            host: {
                "ip": host,
                "port": port,
                "protocol": protocol,
                "username": username,
                "password": password,
                "os": os,
            }
        }
    }

    tb = load(testbed)
    dev = tb.devices[host]
    dev.connect(log_stdout=False, learn_hostname=True)
    output = dev.learn(feature)

    # Do diff if compare_to was provided
    if module.params.get("compare_to"):
        # do genie diff
        # print(type(compare_to['genie'][feature]))
        # print(type(output.info))
        # dd = Diff({"a": "yes"}, {"a": "no"})
        # with open('/tmp/compare_to.txt', 'w') as f:
        #     f.write(json.dumps(compare_to['genie'][feature]))
        # with open('/tmp/output.txt', 'w') as f:
        #     f.write(json.dumps(output.info))

        before = compare_to['genie'][feature]
        current = json.dumps(output.info)
        current = json.loads(current)
        # current = eval(str(output.info))
        try:
            excluded_keys
            if no_default_exclusion:
                merged_exclusions = excluded_keys
            else:
                merged_exclusions = list(set().union(excluded_keys, default_excludes[feature]))
            dd = Diff(before, current, exclude=merged_exclusions)
        except NameError:
            if len(default_excludes[feature]) > 0:
                if no_default_exclusion:
                    dd = Diff(before, current)
                else:
                    dd = Diff(before, current, exclude=default_excludes[feature])
            else:
                dd = Diff(before, current)
        dd.findDiff()
        if colors:
            result.update({"diff": {"prepared": '\n'.join(color_diff(str(dd)))}})
        else:
            result.update({"diff": {"prepared": str(dd)}})
        module._diff = True
        if len(str(dd)) > 0:
            result['changed'] = True

    feature_data = {
        feature: output.info
    }

    result.update({"genie": feature_data})

    # use whatever logic you need to determine whether or not this module
    # made any modifications to your target
    # if module.params['new']:
    #     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['name'] == '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(**result)