Server IP : 85.214.239.14 / Your IP : 3.145.11.15 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /usr/lib/python3/dist-packages/ansible_collections/cisco/nxos/plugins/modules/ |
Upload File : |
#!/usr/bin/python # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. # from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: nxos_bgp_neighbor extends_documentation_fragment: - cisco.nxos.nxos short_description: (deprecated, removed after 2023-01-27) Manages BGP neighbors configurations. description: - Manages BGP neighbors configurations on NX-OS switches. version_added: 1.0.0 author: Gabriele Gerbino (@GGabriele) deprecated: alternative: nxos_bgp_global why: Updated module released with more functionality. removed_at_date: '2023-01-27' notes: - Tested against NXOSv 7.3.(0)D1(1) on VIRL - Unsupported for Cisco MDS - C(state=absent) removes the whole BGP neighbor configuration. - Default, where supported, restores params default value. options: asn: description: - BGP autonomous system number. Valid values are string, Integer in ASPLAIN or ASDOT notation. required: true type: str vrf: description: - Name of the VRF. The name 'default' is a valid VRF representing the global bgp. default: default type: str neighbor: description: - Neighbor Identifier. Valid values are string. Neighbors may use IPv4 or IPv6 notation, with or without prefix length. required: true type: str description: description: - Description of the neighbor. type: str bfd: description: - Enables/Disables BFD for a given neighbor. - "Dependency: ''feature bfd''" type: str choices: - enable - disable connected_check: description: - Configure whether or not to check for directly connected peer. type: bool capability_negotiation: description: - Configure whether or not to negotiate capability with this neighbor. type: bool dynamic_capability: description: - Configure whether or not to enable dynamic capability. type: bool ebgp_multihop: description: - Specify multihop TTL for a remote peer. Valid values are integers between 2 and 255, or keyword 'default' to disable this property. type: str local_as: description: - Specify the local-as number for the eBGP neighbor. Valid values are String or Integer in ASPLAIN or ASDOT notation, or 'default', which means not to configure it. type: str log_neighbor_changes: description: - Specify whether or not to enable log messages for neighbor up/down event. choices: - enable - disable - inherit type: str low_memory_exempt: description: - Specify whether or not to shut down this neighbor under memory pressure. type: bool maximum_peers: description: - Specify Maximum number of peers for this neighbor prefix Valid values are between 1 and 1000, or 'default', which does not impose the limit. Note that this parameter is accepted only on neighbors with address/prefix. type: str pwd: description: - Specify the password for neighbor. Valid value is string. type: str pwd_type: description: - Specify the encryption type the password will use. Valid values are '3des' or 'cisco_type_7' encryption or keyword 'default'. choices: - 3des - cisco_type_7 - default type: str remote_as: description: - Specify Autonomous System Number of the neighbor. Valid values are String or Integer in ASPLAIN or ASDOT notation, or 'default', which means not to configure it. type: str remove_private_as: description: - Specify the config to remove private AS number from outbound updates. Valid values are 'enable' to enable this config, 'disable' to disable this config, 'all' to remove all private AS number, or 'replace-as', to replace the private AS number. choices: - enable - disable - all - replace-as type: str shutdown: description: - Configure to administratively shutdown this neighbor. type: bool suppress_4_byte_as: description: - Configure to suppress 4-byte AS Capability. type: bool timers_keepalive: description: - Specify keepalive timer value. Valid values are integers between 0 and 3600 in terms of seconds, or 'default', which is 60. type: str timers_holdtime: description: - Specify holdtime timer value. Valid values are integers between 0 and 3600 in terms of seconds, or 'default', which is 180. type: str transport_passive_only: description: - Specify whether or not to only allow passive connection setup. Valid values are 'true', 'false', and 'default', which defaults to 'false'. This property can only be configured when the neighbor is in 'ip' address format without prefix length. type: bool update_source: description: - Specify source interface of BGP session and updates. type: str state: description: - Determines whether the config should be present or not on the device. default: present choices: - present - absent type: str peer_type: description: - Specify the peer type for BGP session. choices: - fabric_border_leaf - fabric_external - disable type: str version_added: 1.1.0 """ EXAMPLES = """ # create a new neighbor - cisco.nxos.nxos_bgp_neighbor: asn: 65535 neighbor: 192.0.2.3 local_as: 20 remote_as: 30 bfd: enable description: just a description update_source: Ethernet1/3 state: present peer_type: fabric_external """ RETURN = """ commands: description: commands sent to the device returned: always type: list sample: ["router bgp 65535", "neighbor 192.0.2.3", "remote-as 30", "update-source Ethernet1/3", "description just a description", "local-as 20", "peer-type fabric-external"] """ import re from ansible.module_utils.basic import AnsibleModule from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( CustomNetworkConfig, ) from ansible_collections.cisco.nxos.plugins.module_utils.network.nxos.nxos import ( get_config, load_config, ) BOOL_PARAMS = [ "capability_negotiation", "shutdown", "connected_check", "dynamic_capability", "low_memory_exempt", "suppress_4_byte_as", "transport_passive_only", ] PARAM_TO_COMMAND_KEYMAP = { "asn": "router bgp", "bfd": "bfd", "capability_negotiation": "dont-capability-negotiate", "connected_check": "disable-connected-check", "description": "description", "dynamic_capability": "dynamic-capability", "ebgp_multihop": "ebgp-multihop", "local_as": "local-as", "log_neighbor_changes": "log-neighbor-changes", "low_memory_exempt": "low-memory exempt", "maximum_peers": "maximum-peers", "neighbor": "neighbor", "pwd": "password", "pwd_type": "password", "remote_as": "remote-as", "remove_private_as": "remove-private-as", "shutdown": "shutdown", "suppress_4_byte_as": "capability suppress 4-byte-as", "timers_keepalive": "timers", "timers_holdtime": "timers", "transport_passive_only": "transport connection-mode passive", "update_source": "update-source", "vrf": "vrf", "peer_type": "peer-type", } PARAM_TO_DEFAULT_KEYMAP = { "bfd": "disable", "shutdown": False, "dynamic_capability": True, "timers_keepalive": 60, "timers_holdtime": 180, "peer_type": "disable", } def get_value(arg, config): command = PARAM_TO_COMMAND_KEYMAP[arg] has_command = re.search(r"^\s+{0}$".format(command), config, re.M) has_command_val = re.search(r"(?:\s+{0}\s*)(?P<value>.*)$".format(command), config, re.M) if arg == "dynamic_capability": has_no_command = re.search(r"\s+no\s{0}\s*$".format(command), config, re.M) value = True if has_no_command: value = False elif arg in BOOL_PARAMS: value = False if has_command: value = True elif arg == "log_neighbor_changes": value = "" if has_command: value = "enable" elif has_command_val: value = "disable" elif arg == "remove_private_as": value = "disable" if has_command: value = "enable" elif has_command_val: value = has_command_val.group("value") elif arg == "bfd": value = "enable" if has_command else "disable" elif arg == "peer_type": value = "disable" if has_command_val: value = has_command_val.group("value").replace("-", "_") else: value = "" if has_command_val: value = has_command_val.group("value") if command in ["timers", "password"]: split_value = value.split() value = "" if arg in ["timers_keepalive", "pwd_type"]: value = split_value[0] elif arg in ["timers_holdtime", "pwd"] and len(split_value) == 2: value = split_value[1] return value def get_existing(module, args, warnings): existing = {} netcfg = CustomNetworkConfig(indent=2, contents=get_config(module)) asn_regex = re.compile(r".*router\sbgp\s(?P<existing_asn>\d+(\.\d+)?).*", re.S) match_asn = asn_regex.match(str(netcfg)) if match_asn: existing_asn = match_asn.group("existing_asn") parents = ["router bgp {0}".format(existing_asn)] if module.params["vrf"] != "default": parents.append("vrf {0}".format(module.params["vrf"])) parents.append("neighbor {0}".format(module.params["neighbor"])) config = netcfg.get_section(parents) if config: for arg in args: if arg not in ["asn", "vrf", "neighbor"]: existing[arg] = get_value(arg, config) existing["asn"] = existing_asn existing["neighbor"] = module.params["neighbor"] existing["vrf"] = module.params["vrf"] else: warnings.append("The BGP process didn't exist but the task just created it.") return existing def apply_key_map(key_map, table): new_dict = {} for key in table: new_key = key_map.get(key) if new_key: new_dict[new_key] = table.get(key) return new_dict def state_present(module, existing, proposed, candidate): commands = list() proposed_commands = apply_key_map(PARAM_TO_COMMAND_KEYMAP, proposed) existing_commands = apply_key_map(PARAM_TO_COMMAND_KEYMAP, existing) for key, value in proposed_commands.items(): if value is True: commands.append(key) elif value is False: commands.append("no {0}".format(key)) elif value == "default": if existing_commands.get(key): if key == "password": commands.append("no password") else: existing_value = existing_commands.get(key) commands.append("no {0} {1}".format(key, existing_value)) else: if key == "log-neighbor-changes": if value == "enable": commands.append("{0}".format(key)) elif value == "disable": commands.append("{0} {1}".format(key, value)) elif value == "inherit": if existing_commands.get(key): commands.append("no {0}".format(key)) elif key == "password": pwd_type = module.params["pwd_type"] if pwd_type == "3des": pwd_type = 3 else: pwd_type = 7 command = "{0} {1} {2}".format(key, pwd_type, value) if command not in commands: commands.append(command) elif key == "remove-private-as": if value == "enable": command = "{0}".format(key) commands.append(command) elif value == "disable": if existing_commands.get(key) != "disable": command = "no {0}".format(key) commands.append(command) else: command = "{0} {1}".format(key, value) commands.append(command) elif key == "timers": if proposed["timers_keepalive"] != PARAM_TO_DEFAULT_KEYMAP.get( "timers_keepalive", ) or proposed["timers_holdtime"] != PARAM_TO_DEFAULT_KEYMAP.get("timers_holdtime"): command = "timers {0} {1}".format( proposed["timers_keepalive"], proposed["timers_holdtime"], ) if command not in commands: commands.append(command) elif key == "bfd": no_cmd = "no " if value == "disable" else "" commands.append(no_cmd + key) elif key == "peer-type": if value == "disable": if existing_commands.get(key) != "disable": command = "no {0}".format(key) commands.append(command) elif value == "fabric_external": ptype = "fabric-external" command = "{0} {1}".format(key, ptype) commands.append(command) elif value == "fabric_border_leaf": ptype = "fabric-border-leaf" command = "{0} {1}".format(key, ptype) commands.append(command) else: command = "{0} {1}".format(key, value) commands.append(command) if commands: parents = ["router bgp {0}".format(module.params["asn"])] if module.params["vrf"] != "default": parents.append("vrf {0}".format(module.params["vrf"])) parents.append("neighbor {0}".format(module.params["neighbor"])) # make sure that local-as is the last command in the list. local_as_command = "local-as {0}".format(module.params["local_as"]) if local_as_command in commands: commands.remove(local_as_command) commands.append(local_as_command) candidate.add(commands, parents=parents) def state_absent(module, existing, proposed, candidate): commands = [] parents = ["router bgp {0}".format(module.params["asn"])] if module.params["vrf"] != "default": parents.append("vrf {0}".format(module.params["vrf"])) commands.append("no neighbor {0}".format(module.params["neighbor"])) candidate.add(commands, parents=parents) def main(): argument_spec = dict( asn=dict(required=True, type="str"), vrf=dict(required=False, type="str", default="default"), neighbor=dict(required=True, type="str"), description=dict(required=False, type="str"), bfd=dict(required=False, type="str", choices=["enable", "disable"]), capability_negotiation=dict(required=False, type="bool"), connected_check=dict(required=False, type="bool"), dynamic_capability=dict(required=False, type="bool"), ebgp_multihop=dict(required=False, type="str"), local_as=dict(required=False, type="str"), log_neighbor_changes=dict( required=False, type="str", choices=["enable", "disable", "inherit"], ), low_memory_exempt=dict(required=False, type="bool"), maximum_peers=dict(required=False, type="str"), pwd=dict(required=False, type="str"), pwd_type=dict( required=False, type="str", choices=["3des", "cisco_type_7", "default"], ), remote_as=dict(required=False, type="str"), remove_private_as=dict( required=False, type="str", choices=["enable", "disable", "all", "replace-as"], ), shutdown=dict(required=False, type="bool"), suppress_4_byte_as=dict(required=False, type="bool"), timers_keepalive=dict(required=False, type="str"), timers_holdtime=dict(required=False, type="str"), transport_passive_only=dict(required=False, type="bool"), update_source=dict(required=False, type="str"), state=dict(choices=["present", "absent"], default="present", required=False), peer_type=dict( required=False, type="str", choices=["disable", "fabric_border_leaf", "fabric_external"], ), ) module = AnsibleModule( argument_spec=argument_spec, required_together=[ ["timers_holdtime", "timers_keepalive"], ["pwd", "pwd_type"], ], supports_check_mode=True, ) warnings = list() result = dict(changed=False, warnings=warnings) state = module.params["state"] if module.params["pwd_type"] == "default": module.params["pwd_type"] = "0" args = PARAM_TO_COMMAND_KEYMAP.keys() existing = get_existing(module, args, warnings) if existing.get("asn") and state == "present": if existing["asn"] != module.params["asn"]: module.fail_json( msg="Another BGP ASN already exists.", proposed_asn=module.params["asn"], existing_asn=existing.get("asn"), ) proposed_args = dict((k, v) for k, v in module.params.items() if v is not None and k in args) proposed = {} for key, value in proposed_args.items(): if key not in ["asn", "vrf", "neighbor", "pwd_type"]: if str(value).lower() == "default": value = PARAM_TO_DEFAULT_KEYMAP.get(key, "default") if key == "bfd": if existing.get("bfd", "disable") != value: proposed[key] = value elif existing.get(key) != value: proposed[key] = value candidate = CustomNetworkConfig(indent=3) if state == "present": state_present(module, existing, proposed, candidate) elif state == "absent" and existing: state_absent(module, existing, proposed, candidate) if candidate: candidate = candidate.items_text() if not module.check_mode: load_config(module, candidate) result["changed"] = True result["commands"] = candidate else: result["commands"] = [] module.exit_json(**result) if __name__ == "__main__": main()