1#
2# (c) 2020 Peter Sprygada, <psprygada@ansible.com>
3# (c) 2020 Red Hat, Inc
4#
5# Copyright (c) 2020 Dell Inc.
6#
7# This code is part of Ansible, but is an independent component.
8# This particular file snippet, and this file snippet only, is BSD licensed.
9# Modules you write using this snippet, which is embedded dynamically by Ansible
10# still belong to the author of the module, and may assign their own license
11# to the complete work.
12#
13# Redistribution and use in source and binary forms, with or without modification,
14# are permitted provided that the following conditions are met:
15#
16#    * Redistributions of source code must retain the above copyright
17#      notice, this list of conditions and the following disclaimer.
18#    * Redistributions in binary form must reproduce the above copyright notice,
19#      this list of conditions and the following disclaimer in the documentation
20#      and/or other materials provided with the distribution.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31#
32
33from __future__ import (absolute_import, division, print_function)
34
35import re
36
37from ansible.module_utils._text import to_text
38from ansible.module_utils.basic import env_fallback
39from ansible.module_utils.connection import exec_command
40from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list, ComplexList
41from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, ConfigLine
42
43__metaclass__ = type
44
45_DEVICE_CONFIGS = {}
46
47WARNING_PROMPTS_RE = [
48    r"[\r\n]?\[confirm yes/no\]:\s?$",
49    r"[\r\n]?\[y/n\]:\s?$",
50    r"[\r\n]?\[yes/no\]:\s?$"
51]
52
53os10_provider_spec = {
54    'host': dict(),
55    'port': dict(type='int'),
56    'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
57    'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
58    'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
59    'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
60    'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True),
61    'timeout': dict(type='int'),
62}
63os10_argument_spec = {
64    'provider': dict(type='dict', options=os10_provider_spec),
65}
66
67
68def check_args(module, warnings):
69    pass
70
71
72def get_config(module, flags=None):
73    flags = [] if flags is None else flags
74
75    cmd = 'show running-configuration'
76    cmd += ' '.join(flags)
77    cmd = cmd.strip()
78
79    try:
80        return _DEVICE_CONFIGS[cmd]
81    except KeyError:
82        rc, out, err = exec_command(module, cmd)
83        if rc != 0:
84            module.fail_json(msg='unable to retrieve current config', stderr=to_text(err, errors='surrogate_or_strict'))
85        cfg = to_text(out, errors='surrogate_or_strict').strip()
86        _DEVICE_CONFIGS[cmd] = cfg
87        return cfg
88
89
90def to_commands(module, commands):
91    spec = {
92        'command': dict(key=True),
93        'prompt': dict(),
94        'answer': dict()
95    }
96    transform = ComplexList(spec, module)
97    return transform(commands)
98
99
100def run_commands(module, commands, check_rc=True):
101    responses = list()
102    commands = to_commands(module, to_list(commands))
103    for cmd in commands:
104        cmd = module.jsonify(cmd)
105        rc, out, err = exec_command(module, cmd)
106        if check_rc and rc != 0:
107            module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc)
108        responses.append(to_text(out, errors='surrogate_or_strict'))
109    return responses
110
111
112def load_config(module, commands):
113    rc, out, err = exec_command(module, 'configure terminal')
114    if rc != 0:
115        module.fail_json(msg='unable to enter configuration mode', err=to_text(err, errors='surrogate_or_strict'))
116
117    commands.append('commit')
118    for command in to_list(commands):
119        if command == 'end':
120            continue
121        rc, out, err = exec_command(module, command)
122        if rc != 0:
123            module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), command=command, rc=rc)
124
125    exec_command(module, 'end')
126
127
128def get_sublevel_config(running_config, module):
129    contents = list()
130    current_config_contents = list()
131    running_config = NetworkConfig(contents=running_config, indent=1)
132    obj = running_config.get_object(module.params['parents'])
133    if obj:
134        contents = obj.children
135    contents[:0] = module.params['parents']
136
137    indent = 0
138    for c in contents:
139        if isinstance(c, str):
140            current_config_contents.append(c.rjust(len(c) + indent, ' '))
141        if isinstance(c, ConfigLine):
142            current_config_contents.append(c.raw)
143        indent = 1
144    sublevel_config = '\n'.join(current_config_contents)
145
146    return sublevel_config
147