1# This code is part of Ansible, but is an independent component. 2# This particular file snippet, and this file snippet only, is BSD licensed. 3# Modules you write using this snippet, which is embedded dynamically by Ansible 4# still belong to the author of the module, and may assign their own license 5# to the complete work. 6# 7# (c) 2016 Red Hat Inc. 8# 9# Redistribution and use in source and binary forms, with or without modification, 10# are permitted provided that the following conditions are met: 11# 12# * Redistributions of source code must retain the above copyright 13# notice, this list of conditions and the following disclaimer. 14# * Redistributions in binary form must reproduce the above copyright notice, 15# this list of conditions and the following disclaimer in the documentation 16# and/or other materials provided with the distribution. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28import json 29 30from ansible.module_utils._text import to_text 31from ansible.module_utils.basic import env_fallback 32from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( 33 to_list, 34) 35from ansible.module_utils.connection import Connection, ConnectionError 36 37_DEVICE_CONFIGS = {} 38 39ios_provider_spec = { 40 "host": dict(), 41 "port": dict(type="int"), 42 "username": dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])), 43 "password": dict( 44 fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True 45 ), 46 "ssh_keyfile": dict( 47 fallback=(env_fallback, ["ANSIBLE_NET_SSH_KEYFILE"]), type="path" 48 ), 49 "authorize": dict( 50 fallback=(env_fallback, ["ANSIBLE_NET_AUTHORIZE"]), type="bool" 51 ), 52 "auth_pass": dict( 53 fallback=(env_fallback, ["ANSIBLE_NET_AUTH_PASS"]), no_log=True 54 ), 55 "timeout": dict(type="int"), 56} 57ios_argument_spec = { 58 "provider": dict( 59 type="dict", options=ios_provider_spec, removed_in_version=2.14 60 ) 61} 62 63 64def get_provider_argspec(): 65 return ios_provider_spec 66 67 68def get_connection(module): 69 if hasattr(module, "_ios_connection"): 70 return module._ios_connection 71 72 capabilities = get_capabilities(module) 73 network_api = capabilities.get("network_api") 74 if network_api == "cliconf": 75 module._ios_connection = Connection(module._socket_path) 76 else: 77 module.fail_json(msg="Invalid connection type %s" % network_api) 78 79 return module._ios_connection 80 81 82def get_capabilities(module): 83 if hasattr(module, "_ios_capabilities"): 84 return module._ios_capabilities 85 try: 86 capabilities = Connection(module._socket_path).get_capabilities() 87 except ConnectionError as exc: 88 module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) 89 module._ios_capabilities = json.loads(capabilities) 90 return module._ios_capabilities 91 92 93def get_defaults_flag(module): 94 connection = get_connection(module) 95 try: 96 out = connection.get_defaults_flag() 97 except ConnectionError as exc: 98 module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) 99 return to_text(out, errors="surrogate_then_replace").strip() 100 101 102def get_config(module, flags=None): 103 flags = to_list(flags) 104 105 section_filter = False 106 if flags and "section" in flags[-1]: 107 section_filter = True 108 109 flag_str = " ".join(flags) 110 111 try: 112 return _DEVICE_CONFIGS[flag_str] 113 except KeyError: 114 connection = get_connection(module) 115 try: 116 out = connection.get_config(flags=flags) 117 except ConnectionError as exc: 118 if section_filter: 119 # Some ios devices don't understand `| section foo` 120 out = get_config(module, flags=flags[:-1]) 121 else: 122 module.fail_json( 123 msg=to_text(exc, errors="surrogate_then_replace") 124 ) 125 cfg = to_text(out, errors="surrogate_then_replace").strip() 126 _DEVICE_CONFIGS[flag_str] = cfg 127 return cfg 128 129 130def run_commands(module, commands, check_rc=True): 131 connection = get_connection(module) 132 try: 133 return connection.run_commands(commands=commands, check_rc=check_rc) 134 except ConnectionError as exc: 135 module.fail_json(msg=to_text(exc)) 136 137 138def load_config(module, commands): 139 connection = get_connection(module) 140 141 try: 142 resp = connection.edit_config(commands) 143 return resp.get("response") 144 except ConnectionError as exc: 145 module.fail_json(msg=to_text(exc)) 146 147 148def normalize_interface(name): 149 """Return the normalized interface name 150 """ 151 if not name: 152 return 153 154 def _get_number(name): 155 digits = "" 156 for char in name: 157 if char.isdigit() or char in "/.": 158 digits += char 159 return digits 160 161 if name.lower().startswith("gi"): 162 if_type = "GigabitEthernet" 163 elif name.lower().startswith("te"): 164 if_type = "TenGigabitEthernet" 165 elif name.lower().startswith("fa"): 166 if_type = "FastEthernet" 167 elif name.lower().startswith("fo"): 168 if_type = "FortyGigabitEthernet" 169 elif name.lower().startswith("et"): 170 if_type = "Ethernet" 171 elif name.lower().startswith("vl"): 172 if_type = "Vlan" 173 elif name.lower().startswith("lo"): 174 if_type = "loopback" 175 elif name.lower().startswith("po"): 176 if_type = "port-channel" 177 elif name.lower().startswith("nv"): 178 if_type = "nve" 179 elif name.lower().startswith("twe"): 180 if_type = "TwentyFiveGigE" 181 elif name.lower().startswith("hu"): 182 if_type = "HundredGigE" 183 else: 184 if_type = None 185 186 number_list = name.split(" ") 187 if len(number_list) == 2: 188 if_number = number_list[-1].strip() 189 else: 190 if_number = _get_number(name) 191 192 if if_type: 193 proper_interface = if_type + if_number 194 else: 195 proper_interface = name 196 197 return proper_interface 198