diff options
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/ios/plugins/modules')
35 files changed, 21820 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py new file mode 100644 index 00000000..75094a92 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py @@ -0,0 +1,598 @@ +#!/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/>. +# +""" +The module file for ios_acl_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_acl_interfaces +short_description: ACL interfaces resource module +description: This module configures and manages the access-control (ACL) attributes + of interfaces on IOS platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL +options: + config: + description: A dictionary of ACL interfaces options + type: list + elements: dict + suboptions: + name: + description: Full name of the interface excluding any logical unit number, + i.e. GigabitEthernet0/1. + type: str + required: true + access_groups: + description: Specify access-group for IP access list (standard or extended). + type: list + elements: dict + suboptions: + afi: + description: Specifies the AFI for the ACLs to be configured on this interface. + type: str + required: true + choices: + - ipv4 + - ipv6 + acls: + description: Specifies the ACLs for the provided AFI. + type: list + elements: dict + suboptions: + name: + description: Specifies the name of the IPv4/IPv4 ACL for the interface. + type: str + required: true + direction: + description: + - Specifies the direction of packets that the ACL will be applied + on. + - With one direction already assigned, other acl direction cannot + be same. + type: str + required: true + choices: + - in + - out + running_config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. + There are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(running_config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. This + value of this option should be the output received from device by executing + command. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged +""" +EXAMPLES = """ +# Using Merged + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# interface GigabitEthernet0/2 +# ip access-group 123 out + +- name: Merge module attributes of given access-groups + cisco.ios.ios_acl_interfaces: + config: + - name: GigabitEthernet0/1 + access_groups: + - afi: ipv4 + acls: + - name: 110 + direction: in + - name: 123 + direction: out + - afi: ipv6 + acls: + - name: test_v6 + direction: out + - name: temp_v6 + direction: in + - name: GigabitEthernet0/2 + access_groups: + - afi: ipv4 + acls: + - name: 100 + direction: in + state: merged + +# Commands Fired: +# --------------- +# +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 100 in +# ip access-group 123 out + + +# After state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +# Using Replaced + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +- name: Replace module attributes of given access-groups + cisco.ios.ios_acl_interfaces: + config: + - name: GigabitEthernet0/1 + access_groups: + - afi: ipv4 + acls: + - name: 100 + direction: out + - name: 110 + direction: in + state: replaced + +# Commands Fired: +# --------------- +# +# interface GigabitEthernet0/1 +# no ip access-group 123 out +# no ipv6 traffic-filter temp_v6 in +# no ipv6 traffic-filter test_v6 out +# ip access-group 100 out + +# After state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 100 out +# ip access-group 110 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +# Using Overridden + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +- name: Overridden module attributes of given access-groups + cisco.ios.ios_acl_interfaces: + config: + - name: GigabitEthernet0/1 + access_groups: + - afi: ipv4 + acls: + - name: 100 + direction: out + - name: 110 + direction: in + state: overridden + +# Commands Fired: +# --------------- +# +# interface GigabitEthernet0/1 +# no ip access-group 123 out +# no ipv6 traffic-filter test_v6 out +# no ipv6 traffic-filter temp_v6 in +# ip access-group 100 out +# interface GigabitEthernet0/2 +# no ip access-group 110 in +# no ip access-group 123 out + +# After state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 100 out +# ip access-group 110 in +# interface GigabitEthernet0/2 + +# Using Deleted + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +- name: Delete module attributes of given Interface + cisco.ios.ios_acl_interfaces: + config: + - name: GigabitEthernet0/1 + state: deleted + +# Commands Fired: +# --------------- +# +# interface GigabitEthernet0/1 +# no ip access-group 110 in +# no ip access-group 123 out +# no ipv6 traffic-filter test_v6 out +# no ipv6 traffic-filter temp_v6 in + +# After state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +# Using DELETED without any config passed +#"(NOTE: This will delete all of configured resource module attributes from each configured interface)" + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +- name: Delete module attributes of given access-groups from ALL Interfaces + cisco.ios.ios_acl_interfaces: + config: + state: deleted + +# Commands Fired: +# --------------- +# +# interface GigabitEthernet0/1 +# no ip access-group 110 in +# no ip access-group 123 out +# no ipv6 traffic-filter test_v6 out +# no ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# no ip access-group 110 out +# no ip access-group 123 out + +# After state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# interface GigabitEthernet0/2 + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +- name: Gather listed acl interfaces with provided configurations + cisco.ios.ios_acl_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "name": "Loopback888" +# }, +# { +# "name": "GigabitEthernet0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "110" +# }, +# { +# "direction": "out", +# "name": "123" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "direction": "in", +# "name": "temp_v6" +# }, +# { +# "direction": "out", +# "name": "test_v6" +# } +# ], +# "afi": "ipv6" +# } +# ], +# "name": "GigabitEthernet0/1" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "100" +# }, +# { +# "direction": "out", +# "name": "123" +# } +# ], +# "afi": "ipv4" +# } +# ], +# "name": "GigabitEthernet0/2" +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter +# interface Loopback888 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter test_v6 out +# ipv6 traffic-filter temp_v6 in +# interface GigabitEthernet0/2 +# ip access-group 110 in +# ip access-group 123 out + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_acl_interfaces: + config: + - name: GigabitEthernet0/1 + access_groups: + - afi: ipv4 + acls: + - name: 110 + direction: in + - name: 123 + direction: out + - afi: ipv6 + acls: + - name: test_v6 + direction: out + - name: temp_v6 + direction: in + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "ip access-group 110 in", +# "ip access-group 123 out", +# "ipv6 traffic-filter temp_v6 in", +# "ipv6 traffic-filter test_v6 out" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# ip access-group 110 in +# ip access-group 123 out +# ipv6 traffic-filter temp_v6 in +# ipv6 traffic-filter test_v6 out + +- name: Parse the commands for provided configuration + cisco.ios.ios_acl_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "110" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "direction": "in", +# "name": "temp_v6" +# } +# ], +# "afi": "ipv6" +# } +# ], +# "name": "GigabitEthernet0/1" +# } +# ] +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/1', 'ip access-group 110 in', 'ipv6 traffic-filter test_v6 out'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import ( + Acl_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.acl_interfaces.acl_interfaces import ( + Acl_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Acl_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Acl_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py new file mode 100644 index 00000000..1f1b2831 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py @@ -0,0 +1,1415 @@ +#!/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/>. +# +""" +The module file for ios_acls +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_acls +short_description: ACLs resource module +description: This module configures and manages the named or numbered ACLs on IOS + platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL +options: + config: + description: A dictionary of ACL options. + type: list + elements: dict + suboptions: + afi: + description: + - The Address Family Indicator (AFI) for the Access Control Lists (ACL). + required: true + type: str + choices: + - ipv4 + - ipv6 + acls: + description: + - A list of Access Control Lists (ACL). + type: list + elements: dict + suboptions: + name: + description: The name or the number of the ACL. + required: true + type: str + acl_type: + description: + - ACL type + - Note, it's mandatory and required for Named ACL, but for Numbered ACL + it's not mandatory. + type: str + choices: + - extended + - standard + aces: + description: The entries within the ACL. + elements: dict + type: list + suboptions: + grant: + description: Specify the action. + type: str + choices: + - permit + - deny + sequence: + description: + - Sequence Number for the Access Control Entry(ACE). + - Refer to vendor documentation for valid values. + type: int + evaluate: + description: Evaluate an access list + type: str + protocol: + description: + - Specify the protocol to match. + - Refer to vendor documentation for valid values. + type: str + protocol_options: + description: protocol type. + type: dict + suboptions: + protocol_number: + description: An IP protocol number + type: int + ahp: + description: Authentication Header Protocol. + type: bool + eigrp: + description: Cisco's EIGRP routing protocol. + type: bool + esp: + description: Encapsulation Security Payload. + type: bool + gre: + description: Cisco's GRE tunneling. + type: bool + hbh: + description: Hop by Hop options header. Valid for IPV6 + type: bool + icmp: + description: Internet Control Message Protocol. + type: dict + suboptions: + administratively_prohibited: + description: Administratively prohibited + type: bool + alternate_address: + description: Alternate address + type: bool + conversion_error: + description: Datagram conversion + type: bool + dod_host_prohibited: + description: Host prohibited + type: bool + dod_net_prohibited: + description: Net prohibited + type: bool + echo: + description: Echo (ping) + type: bool + echo_reply: + description: Echo reply + type: bool + general_parameter_problem: + description: Parameter problem + type: bool + host_isolated: + description: Host isolated + type: bool + host_precedence_unreachable: + description: Host unreachable for precedence + type: bool + host_redirect: + description: Host redirect + type: bool + host_tos_redirect: + description: Host redirect for TOS + type: bool + host_tos_unreachable: + description: Host unreachable for TOS + type: bool + host_unknown: + description: Host unknown + type: bool + host_unreachable: + description: Host unreachable + type: bool + information_reply: + description: Information replies + type: bool + information_request: + description: Information requests + type: bool + mask_reply: + description: Mask replies + type: bool + mask_request: + description: mask_request + type: bool + mobile_redirect: + description: Mobile host redirect + type: bool + net_redirect: + description: Network redirect + type: bool + net_tos_redirect: + description: Net redirect for TOS + type: bool + net_tos_unreachable: + description: Network unreachable for TOS + type: bool + net_unreachable: + description: Net unreachable + type: bool + network_unknown: + description: Network unknown + type: bool + no_room_for_option: + description: Parameter required but no room + type: bool + option_missing: + description: Parameter required but not present + type: bool + packet_too_big: + description: Fragmentation needed and DF set + type: bool + parameter_problem: + description: All parameter problems + type: bool + port_unreachable: + description: Port unreachable + type: bool + precedence_unreachable: + description: Precedence cutoff + type: bool + protocol_unreachable: + description: Protocol unreachable + type: bool + reassembly_timeout: + description: Reassembly timeout + type: bool + redirect: + description: All redirects + type: bool + router_advertisement: + description: Router discovery advertisements + type: bool + router_solicitation: + description: Router discovery solicitations + type: bool + source_quench: + description: Source quenches + type: bool + source_route_failed: + description: Source route failed + type: bool + time_exceeded: + description: All time exceededs + type: bool + timestamp_reply: + description: Timestamp replies + type: bool + timestamp_request: + description: Timestamp requests + type: bool + traceroute: + description: Traceroute + type: bool + ttl_exceeded: + description: TTL exceeded + type: bool + unreachable: + description: All unreachables + type: bool + igmp: + description: Internet Gateway Message Protocol. + type: dict + suboptions: + dvmrp: + description: Distance Vector Multicast Routing Protocol(2) + type: bool + host_query: + description: IGMP Membership Query(0) + type: bool + mtrace_resp: + description: Multicast Traceroute Response(7) + type: bool + mtrace_route: + description: Multicast Traceroute(8) + type: bool + pim: + description: Protocol Independent Multicast(3) + type: bool + trace: + description: Multicast trace(4) + type: bool + v1host_report: + description: IGMPv1 Membership Report(1) + type: bool + v2host_report: + description: IGMPv2 Membership Report(5) + type: bool + v2leave_group: + description: IGMPv2 Leave Group(6) + type: bool + v3host_report: + description: IGMPv3 Membership Report(9) + type: bool + ip: + description: Any Internet Protocol. + type: bool + ipv6: + description: Any IPv6. + type: bool + ipinip: + description: IP in IP tunneling. + type: bool + nos: + description: KA9Q NOS compatible IP over IP tunneling. + type: bool + ospf: + description: OSPF routing protocol. + type: bool + pcp: + description: Payload Compression Protocol. + type: bool + pim: + description: Protocol Independent Multicast. + type: bool + sctp: + description: Stream Control Transmission Protocol. + type: bool + udp: + description: User Datagram Protocol. + type: bool + tcp: + description: Match TCP packet flags + type: dict + suboptions: + ack: + description: Match on the ACK bit + type: bool + established: + description: Match established connections + type: bool + fin: + description: Match on the FIN bit + type: bool + psh: + description: Match on the PSH bit + type: bool + rst: + description: Match on the RST bit + type: bool + syn: + description: Match on the SYN bit + type: bool + urg: + description: Match on the URG bit + type: bool + source: + description: Specify the packet source. + type: dict + suboptions: + address: + description: Source network address. + type: str + wildcard_bits: + description: Destination wildcard bits, valid with IPV4 address. + type: str + any: + description: Match any source address. + type: bool + host: + description: A single source host + type: str + port_protocol: + description: + - Specify the destination port along with protocol. + - Note, Valid with TCP/UDP protocol_options + type: dict + suboptions: + eq: + description: Match only packets on a given port number. + type: str + gt: + description: Match only packets with a greater port number. + type: str + lt: + description: Match only packets with a lower port number. + type: str + neq: + description: Match only packets not on a given port number. + type: str + range: + description: Port group. + type: dict + suboptions: + start: + description: Specify the start of the port range. + type: int + end: + description: Specify the end of the port range. + type: int + destination: + description: Specify the packet destination. + type: dict + suboptions: + address: + description: Host address to match, or any single host address. + type: str + wildcard_bits: + description: Destination wildcard bits, valid with IPV4 address. + type: str + any: + description: Match any source address. + type: bool + host: + description: A single destination host + type: str + port_protocol: + description: + - Specify the destination port along with protocol. + - Note, Valid with TCP/UDP protocol_options + type: dict + suboptions: + eq: + description: Match only packets on a given port number. + type: str + gt: + description: Match only packets with a greater port number. + type: str + lt: + description: Match only packets with a lower port number. + type: str + neq: + description: Match only packets not on a given port number. + type: str + range: + description: Port group. + type: dict + suboptions: + start: + description: Specify the start of the port range. + type: int + end: + description: Specify the end of the port range. + type: int + dscp: + description: Match packets with given dscp value. + type: str + fragments: + description: Check non-initial fragments. + type: str + log: + description: Log matches against this entry. + type: str + log_input: + description: Log matches against this entry, including input interface. + type: str + option: + description: + - Match packets with given IP Options value. + - Valid only for named acls. + type: dict + suboptions: + add_ext: + description: Match packets with Address Extension Option (147). + type: bool + any_options: + description: Match packets with ANY Option. + type: bool + com_security: + description: Match packets with Commercial Security Option (134). + type: bool + dps: + description: Match packets with Dynamic Packet State Option (151). + type: bool + encode: + description: Match packets with Encode Option (15). + type: bool + eool: + description: Match packets with End of Options (0). + type: bool + ext_ip: + description: Match packets with Extended IP Option (145). + type: bool + ext_security: + description: Match packets with Extended Security Option (133). + type: bool + finn: + description: Match packets with Experimental Flow Control Option + (205). + type: bool + imitd: + description: Match packets with IMI Traffic Desriptor Option (144). + type: bool + lsr: + description: Match packets with Loose Source Route Option (131). + type: bool + mtup: + description: Match packets with MTU Probe Option (11). + type: bool + mtur: + description: Match packets with MTU Reply Option (12). + type: bool + no_op: + description: Match packets with No Operation Option (1). + type: bool + nsapa: + description: Match packets with NSAP Addresses Option (150). + type: bool + record_route: + description: Match packets with Record Route Option (7). + type: bool + router_alert: + description: Match packets with Router Alert Option (148). + type: bool + sdb: + description: Match packets with Selective Directed Broadcast Option + (149). + type: bool + security: + description: Match packets with Basic Security Option (130). + type: bool + ssr: + description: Match packets with Strict Source Routing Option (137). + type: bool + stream_id: + description: Match packets with Stream ID Option (136). + type: bool + timestamp: + description: Match packets with Time Stamp Option (68). + type: bool + traceroute: + description: Match packets with Trace Route Option (82). + type: bool + ump: + description: Match packets with Upstream Multicast Packet Option + (152). + type: bool + visa: + description: Match packets with Experimental Access Control Option + (142). + type: bool + zsu: + description: Match packets with Experimental Measurement Option + (10). + type: bool + precedence: + description: Match packets with given precedence value. + type: int + time_range: + description: Specify a time-range. + type: str + tos: + description: + - Match packets with given TOS value. + - Note, DSCP and TOS are mutually exclusive + type: dict + suboptions: + service_value: + description: Type of service value + type: int + max_reliability: + description: Match packets with max reliable TOS (2). + type: bool + max_throughput: + description: Match packets with max throughput TOS (4). + type: bool + min_delay: + description: Match packets with min delay TOS (8). + type: bool + min_monetary_cost: + description: Match packets with min monetary cost TOS (1). + type: bool + normal: + description: Match packets with normal TOS (0). + type: bool + ttl: + description: Match packets with given TTL value. + type: dict + suboptions: + eq: + description: Match only packets on a given TTL number. + type: int + gt: + description: Match only packets with a greater TTL number. + type: int + lt: + description: Match only packets with a lower TTL number. + type: int + neq: + description: Match only packets not on a given TTL number. + type: int + range: + description: Match only packets in the range of TTLs. + type: dict + suboptions: + start: + description: Specify the start of the port range. + type: int + end: + description: Specify the end of the port range. + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS + device by executing the command B(sh access-list). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# vios#sh access-lists +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10 + +- name: Merge provided configuration with device configuration + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: std_acl + acl_type: standard + aces: + - grant: deny + source: + address: 192.168.1.200 + - grant: deny + source: + address: 192.168.2.0 + wildcard_bits: 0.0.0.255 + - name: 110 + aces: + - sequence: 10 + protocol_options: + icmp: + traceroute: true + - grant: deny + protocol_options: + tcp: + ack: true + source: + host: 198.51.100.0 + destination: + host: 198.51.110.0 + port_protocol: + eq: telnet + - name: test + acl_type: extended + aces: + - grant: deny + protocol_options: + tcp: + fin: true + source: + address: 192.0.2.0 + wildcard_bits: 0.0.0.255 + destination: + address: 192.0.3.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: www + option: + traceroute: true + ttl: + eq: 10 + - name: 123 + aces: + - grant: deny + protocol_options: + tcp: + ack: true + source: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + destination: + address: 198.51.101.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + tos: + service_value: 12 + - grant: deny + protocol_options: + tcp: + ack: true + source: + address: 192.0.3.0 + wildcard_bits: 0.0.0.255 + destination: + address: 192.0.4.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: www + dscp: ef + ttl: + lt: 20 + - afi: ipv6 + acls: + - name: R1_TRAFFIC + aces: + - grant: deny + protocol_options: + tcp: + ack: true + source: + any: true + port_protocol: + eq: www + destination: + any: true + port_protocol: + eq: telnet + dscp: af11 + state: merged + +# Commands fired: +# --------------- +# +# - ip access-list standard std_acl +# - deny 192.168.1.200 +# - deny 192.168.2.0 0.0.0.255 +# - ip access-list extended 110 +# - no 10 +# - 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# - deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# - ip access-list extended test +# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# - ip access-list extended 123 +# - deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# - deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# - ipv6 access-list R1_TRAFFIC +# - deny tcp any eq www any eq telnet ack dscp af11 + +# After state: +# ------------ +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + + +# Using replaced + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + + +- name: Replaces device configuration of listed acls with provided configuration + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: 110 + aces: + - grant: deny + protocol_options: + tcp: + syn: true + source: + address: 192.0.2.0 + wildcard_bits: 0.0.0.255 + destination: + address: 192.0.3.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: www + dscp: ef + ttl: + eq: 10 + - name: 150 + aces: + - grant: deny + sequence: 20 + protocol_options: + tcp: + syn: true + source: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + destination: + address: 198.51.110.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + dscp: ef + ttl: + eq: 10 + state: replaced + +# Commands fired: +# --------------- +# +# - no ip access-list extended 110 +# - ip access-list extended 110 +# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10 +# - ip access-list extended 150 +# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10 + +# After state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10 +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list 150 +# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +# Using overridden + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +- name: Override device configuration of all acls with provided configuration + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: 110 + aces: + - grant: deny + sequence: 20 + protocol_options: + tcp: + ack: true + source: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + destination: + address: 198.51.110.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: www + dscp: ef + ttl: + eq: 10 + - name: 150 + aces: + - grant: deny + sequence: 10 + protocol_options: + tcp: + syn: true + source: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + destination: + address: 198.51.110.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + dscp: ef + ttl: + eq: 10 + state: overridden + +# Commands fired: +# --------------- +# +# - no ip access-list standard std_acl +# - no ip access-list extended 110 +# - no ip access-list extended 123 +# - no ip access-list extended 150 +# - no ip access-list extended test +# - no ipv6 access-list R1_TRAFFIC +# - ip access-list extended 150 +# - 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10 +# - ip access-list extended 110 +# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10 + +# After state: +# ------------- +# +# vios#sh access-lists +# Extended IP access list 110 +# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10 +# Extended IP access list 150 +# 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10 + +# Using Deleted + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +- name: "Delete ACLs (Note: This won't delete the all configured ACLs)" + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: test + acl_type: extended + - name: 110 + - afi: ipv6 + acls: + - name: R1_TRAFFIC + state: deleted + +# Commands fired: +# --------------- +# +# - no ip access-list extended test +# - no ip access-list extended 110 +# - no ipv6 access-list R1_TRAFFIC + +# After state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +- name: "Delete ACLs based on AFI (Note: This won't delete the all configured ACLs)" + cisco.ios.ios_acls: + config: + - afi: ipv4 + state: deleted + +# Commands fired: +# --------------- +# +# - no ip access-list standard std_acl +# - no ip access-list extended test +# - no ip access-list extended 110 +# - no ip access-list extended 123 + +# After state: +# ------------- +# +# vios#sh access-lists +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured ACLs)" + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +- name: 'Delete ALL of configured ACLs (Note: This WILL delete the all configured + ACLs)' + cisco.ios.ios_acls: + state: deleted + +# Commands fired: +# --------------- +# +# - no ip access-list extended test +# - no ip access-list extended 110 +# - no ip access-list extended 123 +# - no ip access-list extended test +# - no ipv6 access-list R1_TRAFFIC + +# After state: +# ------------- +# +# vios#sh access-lists + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh access-lists +# Standard IP access list std_acl +# 10 deny 192.168.1.200 +# 20 deny 192.168.2.0, wildcard bits 0.0.0.255 +# Extended IP access list 110 +# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10 +# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack +# Extended IP access list 123 +# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12 +# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20 +# Extended IP access list test +# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10 +# IPv6 access list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 sequence 10 + +- name: Gather listed acls with provided configurations + cisco.ios.ios_acls: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "address": "192.0.3.0", +# "wildcard_bits": "0.0.0.255" +# }, +# "dscp": "ef", +# "grant": "deny", +# "protocol_options": { +# "icmp": { +# "echo": true +# } +# }, +# "sequence": 10, +# "source": { +# "address": "192.0.2.0", +# "wildcard_bits": "0.0.0.255" +# }, +# "ttl": { +# "eq": 10 +# } +# } +# ], +# "acl_type": "extended", +# "name": "110" +# }, +# { +# "aces": [ +# { +# "destination": { +# "address": "198.51.101.0", +# "port_protocol": { +# "eq": "telnet" +# }, +# "wildcard_bits": "0.0.0.255" +# }, +# "grant": "deny", +# "protocol_options": { +# "tcp": { +# "ack": true +# } +# }, +# "sequence": 10, +# "source": { +# "address": "198.51.100.0", +# "wildcard_bits": "0.0.0.255" +# }, +# "tos": { +# "service_value": 12 +# } +# }, +# { +# "destination": { +# "address": "192.0.4.0", +# "port_protocol": { +# "eq": "www" +# }, +# "wildcard_bits": "0.0.0.255" +# }, +# "dscp": "ef", +# "grant": "deny", +# "protocol_options": { +# "tcp": { +# "ack": true +# } +# }, +# "sequence": 20, +# "source": { +# "address": "192.0.3.0", +# "wildcard_bits": "0.0.0.255" +# }, +# "ttl": { +# "lt": 20 +# } +# } +# ], +# "acl_type": "extended", +# "name": "123" +# }, +# { +# "aces": [ +# { +# "destination": { +# "address": "192.0.3.0", +# "port_protocol": { +# "eq": "www" +# }, +# "wildcard_bits": "0.0.0.255" +# }, +# "grant": "deny", +# "option": { +# "traceroute": true +# }, +# "protocol_options": { +# "tcp": { +# "fin": true +# } +# }, +# "sequence": 10, +# "source": { +# "address": "192.0.2.0", +# "wildcard_bits": "0.0.0.255" +# }, +# "ttl": { +# "eq": 10 +# } +# } +# ], +# "acl_type": "extended", +# "name": "test_acl" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "any": true, +# "port_protocol": { +# "eq": "telnet" +# } +# }, +# "dscp": "af11", +# "grant": "deny", +# "protocol_options": { +# "tcp": { +# "ack": true +# } +# }, +# "sequence": 10, +# "source": { +# "any": true, +# "port_protocol": { +# "eq": "www" +# } +# } +# } +# ], +# "name": "R1_TRAFFIC" +# } +# ], +# "afi": "ipv6" +# } +# ] + +# Using Rendered + +- name: Rendered the provided configuration with the exisiting running configuration + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: 110 + aces: + - grant: deny + sequence: 10 + protocol_options: + tcp: + syn: true + source: + address: 192.0.2.0 + wildcard_bits: 0.0.0.255 + destination: + address: 192.0.3.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: www + dscp: ef + ttl: + eq: 10 + - name: 150 + aces: + - grant: deny + protocol_options: + tcp: + syn: true + source: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + destination: + address: 198.51.110.0 + wildcard_bits: 0.0.0.255 + port_protocol: + eq: telnet + dscp: ef + ttl: + eq: 10 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "ip access-list extended 110", +# "10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10", +# "ip access-list extended 150", +# "deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# ipv6 access-list R1_TRAFFIC +# deny tcp any eq www any eq telnet ack dscp af11 + +- name: Parse the commands for provided configuration + cisco.ios.ios_acls: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "any": true, +# "port_protocol": { +# "eq": "telnet" +# } +# }, +# "dscp": "af11", +# "grant": "deny", +# "protocol_options": { +# "tcp": { +# "ack": true +# } +# }, +# "source": { +# "any": true, +# "port_protocol": { +# "eq": "www" +# } +# } +# } +# ], +# "name": "R1_TRAFFIC" +# } +# ], +# "afi": "ipv6" +# } +# ] +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['ip access-list extended 110', 'deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acls.acls import ( + AclsArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.acls.acls import ( + Acls, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=AclsArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Acls(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py new file mode 100644 index 00000000..4370857b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py @@ -0,0 +1,188 @@ +#!/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: ios_banner +author: Ricardo Carrillo Cruz (@rcarrillocruz) +short_description: Manage multiline banners on Cisco IOS devices +description: +- This will configure both login and motd banners on remote devices running Cisco + IOS. It allows playbooks to add or remote banner text from the active running configuration. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +options: + banner: + description: + - Specifies which banner should be configured on the remote device. In Ansible + 2.4 and earlier only I(login) and I(motd) were supported. + required: true + choices: + - login + - motd + - exec + - incoming + - slip-ppp + type: str + text: + description: + - The banner text that should be present in the remote device running configuration. This + argument accepts a multiline string, with no empty lines. Requires I(state=present). + type: str + state: + description: + - Specifies whether or not the configuration is present in the current devices + active running configuration. + default: present + type: str + choices: + - present + - absent +""" +EXAMPLES = """ +- name: configure the login banner + cisco.ios.ios_banner: + banner: login + text: | + this is my login banner + that contains a multiline + string + state: present + +- name: remove the motd banner + cisco.ios.ios_banner: + banner: motd + state: absent + +- name: Configure banner from file + cisco.ios.ios_banner: + banner: motd + text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}" + state: present +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - banner login + - this is my login banner + - that contains a multiline + - string +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from re import search, M + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + state = module.params["state"] + if state == "absent" and "text" in have.keys() and have["text"]: + commands.append("no banner %s" % module.params["banner"]) + elif state == "present": + if want["text"] and (want["text"] != have.get("text")): + banner_cmd = "banner %s" % module.params["banner"] + banner_cmd += " @\n" + banner_cmd += want["text"].strip("\n") + banner_cmd += "\n@" + commands.append(banner_cmd) + return commands + + +def map_config_to_obj(module): + """ + This function gets the banner config without stripping any whitespaces, + and then fetches the required banner from it. + :param module: + :return: banner config dict object. + """ + out = get_config( + module, flags="| begin banner %s" % module.params["banner"] + ) + if out: + regex = "banner " + module.params["banner"] + " ^C\n" + if search("banner " + module.params["banner"], out, M): + output = str((out.split(regex))[1].split("^C\n")[0]) + else: + output = None + else: + output = None + obj = {"banner": module.params["banner"], "state": "absent"} + if output: + obj["text"] = output + obj["state"] = "present" + return obj + + +def map_params_to_obj(module): + text = module.params["text"] + return { + "banner": module.params["banner"], + "text": text, + "state": module.params["state"], + } + + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + banner=dict( + required=True, + choices=["login", "motd", "exec", "incoming", "slip-ppp"], + ), + text=dict(), + state=dict(default="present", choices=["present", "absent"]), + ) + argument_spec.update(ios_argument_spec) + required_if = [("state", "present", ("text",))] + module = AnsibleModule( + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have), module) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py new file mode 100644 index 00000000..bc189436 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py @@ -0,0 +1,509 @@ +#!/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: ios_bgp +author: Nilashish Chakraborty (@NilashishC) +short_description: Configure global BGP protocol settings on Cisco IOS. +description: +- This module provides configuration management of global BGP parameters on devices + running Cisco IOS +version_added: 1.0.0 +notes: +- Tested against Cisco IOS Version 15.6(3)M2 +options: + config: + description: + - Specifies the BGP related configuration. + type: dict + suboptions: + bgp_as: + description: + - Specifies the BGP Autonomous System (AS) number to configure on the device. + type: int + required: true + router_id: + description: + - Configures the BGP routing process router-id value. + type: str + default: + log_neighbor_changes: + description: + - Enable/disable logging neighbor up/down and reset reason. + type: bool + neighbors: + description: + - Specifies BGP neighbor related configurations. + type: list + elements: dict + suboptions: + neighbor: + description: + - Neighbor router address. + required: true + type: str + remote_as: + description: + - Remote AS of the BGP neighbor to configure. + type: int + required: true + update_source: + description: + - Source of the routing updates. + type: str + password: + description: + - Password to authenticate the BGP peer connection. + type: str + enabled: + description: + - Administratively shutdown or enable a neighbor. + type: bool + description: + description: + - Neighbor specific description. + type: str + ebgp_multihop: + description: + - Specifies the maximum hop count for EBGP neighbors not on directly connected + networks. + - The range is from 1 to 255. + type: int + peer_group: + description: + - Name of the peer group that the neighbor is a member of. + type: str + timers: + description: + - Specifies BGP neighbor timer related configurations. + type: dict + suboptions: + keepalive: + description: + - Frequency (in seconds) with which the device sends keepalive messages + to its peer. + - The range is from 0 to 65535. + type: int + required: true + holdtime: + description: + - Interval (in seconds) after not receiving a keepalive message that + IOS declares a peer dead. + - The range is from 0 to 65535. + type: int + required: true + min_neighbor_holdtime: + description: + - Interval (in seconds) specifying the minimum acceptable hold-time + from a BGP neighbor. + - The minimum acceptable hold-time must be less than, or equal to, + the interval specified in the holdtime argument. + - The range is from 0 to 65535. + type: int + local_as: + description: + - The local AS number for the neighbor. + type: int + networks: + description: + - Specify Networks to announce via BGP. + - For operation replace, this option is mutually exclusive with networks option + under address_family. + - For operation replace, if the device already has an address family activated, + this option is not allowed. + type: list + elements: dict + suboptions: + prefix: + description: + - Network ID to announce via BGP. + required: true + type: str + masklen: + description: + - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.). + type: int + route_map: + description: + - Route map to modify the attributes. + type: str + address_family: + description: + - Specifies BGP address family related configurations. + type: list + elements: dict + suboptions: + afi: + description: + - Type of address family to configure. + choices: + - ipv4 + - ipv6 + required: true + type: str + safi: + description: + - Specifies the type of cast for the address family. + choices: + - flowspec + - unicast + - multicast + - labeled-unicast + default: unicast + type: str + synchronization: + description: + - Enable/disable IGP synchronization. + type: bool + auto_summary: + description: + - Enable/disable automatic network number summarization. + type: bool + redistribute: + description: + - Specifies the redistribute information from another routing protocol. + type: list + elements: dict + suboptions: + protocol: + description: + - Specifies the protocol for configuring redistribute information. + choices: + - ospf + - ospfv3 + - eigrp + - isis + - static + - connected + - odr + - lisp + - mobile + - rip + required: true + type: str + id: + description: + - Identifier for the routing protocol for configuring redistribute + information. + - Valid for protocols 'ospf', 'ospfv3' and 'eigrp'. + type: str + metric: + description: + - Specifies the metric for redistributed routes. + type: int + route_map: + description: + - Specifies the route map reference. + type: str + networks: + description: + - Specify Networks to announce via BGP. + - For operation replace, this option is mutually exclusive with root level + networks option. + type: list + elements: dict + suboptions: + prefix: + description: + - Network ID to announce via BGP. + required: true + type: str + masklen: + description: + - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.). + type: int + route_map: + description: + - Route map to modify the attributes. + type: str + neighbors: + description: + - Specifies BGP neighbor related configurations in Address Family configuration + mode. + type: list + elements: dict + suboptions: + neighbor: + description: + - Neighbor router address. + required: true + type: str + advertisement_interval: + description: + - Minimum interval between sending BGP routing updates for this neighbor. + type: int + route_reflector_client: + description: + - Specify a neighbor as a route reflector client. + type: bool + route_server_client: + description: + - Specify a neighbor as a route server client. + type: bool + activate: + description: + - Enable the Address Family for this Neighbor. + type: bool + remove_private_as: + description: + - Remove the private AS number from outbound updates. + type: bool + next_hop_self: + description: + - Enable/disable the next hop calculation for this neighbor. + type: bool + next_hop_unchanged: + description: + - Propagate next hop unchanged for iBGP paths to this neighbor. + type: bool + maximum_prefix: + description: + - Maximum number of prefixes to accept from this peer. + - The range is from 1 to 2147483647. + type: int + prefix_list_in: + description: + - Name of ip prefix-list to apply to incoming prefixes. + type: str + prefix_list_out: + description: + - Name of ip prefix-list to apply to outgoing prefixes. + type: str + operation: + description: + - Specifies the operation to be performed on the BGP process configured on the + device. + - In case of merge, the input configuration will be merged with the existing BGP + configuration on the device. + - In case of replace, if there is a diff between the existing configuration and + the input configuration, the existing configuration will be replaced by the + input configuration for every option that has the diff. + - In case of override, all the existing BGP configuration will be removed from + the device and replaced with the input configuration. + - In case of delete the existing BGP configuration will be removed from the device. + default: merge + type: str + choices: + - merge + - replace + - override + - delete +""" +EXAMPLES = """ +- name: configure global bgp as 64496 + cisco.ios.ios_bgp: + config: + bgp_as: 64496 + router_id: 192.0.2.1 + log_neighbor_changes: true + neighbors: + - neighbor: 203.0.113.5 + remote_as: 64511 + timers: + keepalive: 300 + holdtime: 360 + min_neighbor_holdtime: 360 + - neighbor: 198.51.100.2 + remote_as: 64498 + networks: + - prefix: 198.51.100.0 + route_map: RMAP_1 + - prefix: 192.0.2.0 + masklen: 23 + address_family: + - afi: ipv4 + safi: unicast + redistribute: + - protocol: ospf + id: 223 + metric: 10 + operation: merge + +- name: Configure BGP neighbors + cisco.ios.ios_bgp: + config: + bgp_as: 64496 + neighbors: + - neighbor: 192.0.2.10 + remote_as: 64496 + password: ansible + description: IBGP_NBR_1 + ebgp_multihop: 100 + timers: + keepalive: 300 + holdtime: 360 + min_neighbor_holdtime: 360 + - neighbor: 192.0.2.15 + remote_as: 64496 + description: IBGP_NBR_2 + ebgp_multihop: 150 + operation: merge + +- name: Configure root-level networks for BGP + cisco.ios.ios_bgp: + config: + bgp_as: 64496 + networks: + - prefix: 203.0.113.0 + masklen: 27 + route_map: RMAP_1 + - prefix: 203.0.113.32 + masklen: 27 + route_map: RMAP_2 + operation: merge + +- name: Configure BGP neighbors under address family mode + cisco.ios.ios_bgp: + config: + bgp_as: 64496 + address_family: + - afi: ipv4 + safi: unicast + neighbors: + - neighbor: 203.0.113.10 + activate: yes + maximum_prefix: 250 + advertisement_interval: 120 + - neighbor: 192.0.2.15 + activate: yes + route_reflector_client: true + operation: merge + +- name: remove bgp as 64496 from config + cisco.ios.ios_bgp: + config: + bgp_as: 64496 + operation: delete +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - router bgp 64496 + - bgp router-id 192.0.2.1 + - bgp log-neighbor-changes + - neighbor 203.0.113.5 remote-as 64511 + - neighbor 203.0.113.5 timers 300 360 360 + - neighbor 198.51.100.2 remote-as 64498 + - network 198.51.100.0 route-map RMAP_1 + - network 192.0.2.0 mask 255.255.254.0 + - address-family ipv4 + - redistribute ospf 223 metric 70 + - exit-address-family +""" +from ansible.module_utils._text import to_text +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.module import ( + NetworkModule, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.process import ( + REDISTRIBUTE_PROTOCOLS, +) + + +def main(): + """ main entry point for module execution + """ + network_spec = { + "prefix": dict(required=True), + "masklen": dict(type="int"), + "route_map": dict(), + } + redistribute_spec = { + "protocol": dict(choices=REDISTRIBUTE_PROTOCOLS, required=True), + "id": dict(), + "metric": dict(type="int"), + "route_map": dict(), + } + timer_spec = { + "keepalive": dict(type="int", required=True), + "holdtime": dict(type="int", required=True), + "min_neighbor_holdtime": dict(type="int"), + } + neighbor_spec = { + "neighbor": dict(required=True), + "remote_as": dict(type="int", required=True), + "local_as": dict(type="int"), + "update_source": dict(), + "password": dict(no_log=True), + "enabled": dict(type="bool"), + "description": dict(), + "ebgp_multihop": dict(type="int"), + "timers": dict(type="dict", options=timer_spec), + "peer_group": dict(), + } + af_neighbor_spec = { + "neighbor": dict(required=True), + "activate": dict(type="bool"), + "advertisement_interval": dict(type="int"), + "remove_private_as": dict(type="bool"), + "next_hop_self": dict(type="bool"), + "next_hop_unchanged": dict(type="bool"), + "route_reflector_client": dict(type="bool"), + "route_server_client": dict(type="bool"), + "maximum_prefix": dict(type="int"), + "prefix_list_in": dict(), + "prefix_list_out": dict(), + } + address_family_spec = { + "afi": dict(choices=["ipv4", "ipv6"], required=True), + "safi": dict( + choices=["flowspec", "labeled-unicast", "multicast", "unicast"], + default="unicast", + ), + "auto_summary": dict(type="bool"), + "synchronization": dict(type="bool"), + "networks": dict(type="list", elements="dict", options=network_spec), + "redistribute": dict( + type="list", elements="dict", options=redistribute_spec + ), + "neighbors": dict( + type="list", elements="dict", options=af_neighbor_spec + ), + } + config_spec = { + "bgp_as": dict(type="int", required=True), + "router_id": dict(), + "log_neighbor_changes": dict(type="bool"), + "neighbors": dict(type="list", elements="dict", options=neighbor_spec), + "address_family": dict( + type="list", elements="dict", options=address_family_spec + ), + "networks": dict(type="list", elements="dict", options=network_spec), + } + argument_spec = { + "config": dict(type="dict", options=config_spec), + "operation": dict( + default="merge", choices=["merge", "replace", "override", "delete"] + ), + } + module = NetworkModule( + argument_spec=argument_spec, supports_check_mode=True + ) + try: + result = module.edit_config(config_filter="| section ^router bgp") + except Exception as exc: + module.fail_json(msg=to_text(exc)) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py new file mode 100644 index 00000000..8e401986 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py @@ -0,0 +1,2139 @@ +#!/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/>. +# +""" +The module file for ios_bgp_global +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_bgp_global +short_description: Global BGP resource module +description: This module configures and manages the attributes of global bgp on Cisco IOS. +version_added: 1.3.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL +options: + config: + description: A list of configurations for global bgp. + type: dict + suboptions: + as_number: + description: Autonomous system number. + type: str + required: true + aggregate_address: + description: Configure BGP aggregate entries + type: dict + suboptions: + address: + description: Aggregate address + type: str + netmask: + description: Aggregate mask + type: str + advertise_map: + description: Set condition to advertise attribute + type: str + as_confed_set: + description: Generate AS confed set path information + type: bool + as_set: + description: Generate AS set path information + type: bool + attribute_map: + description: Set attributes of aggregate + type: str + summary_only: + description: Filter more specific routes from updates + type: bool + suppress_map: + description: Conditionally filter more specific routes from updates + type: str + auto_summary: + description: Enable automatic network number summarization + type: bool + bgp: + description: Enable address family and enter its config mode + type: dict + suboptions: + additional_paths: + description: Additional paths in the BGP table + type: dict + suboptions: + install: + description: Additional paths to install into RIB + type: bool + receive: + description: Receive additional paths from neighbors + type: bool + select: + description: Selection criteria to pick the paths + type: dict + suboptions: + all: + description: Select all available paths + type: bool + best: + description: Select best N paths (2-3). + type: int + best_external: + description: Select best-external path + type: bool + group_best: + description: Select group-best path + type: bool + send: + description: Send additional paths to neighbors + type: bool + advertise_best_external: + description: Advertise best external path to internal peers + type: bool + aggregate_timer: + description: + - Configure Aggregation Timer + - Please refer vendor documentation for valid values + type: int + always_compare_med: + description: Allow comparing MED from different neighbors + type: bool + asnotation: + description: + - Change the default asplain notation + - asdot notation + type: bool + bestpath: + description: Change the default bestpath selection + type: list + elements: dict + suboptions: + aigp: + description: + - if both paths doesn't have aigp ignore on bestpath comparision + - ignore + type: bool + compare_routerid: + description: Compare router-id for identical EBGP paths + type: bool + cost_community: + description: cost community + type: bool + igp_metric: + description: + - igp metric + - Ignore igp metric in bestpath selection + type: bool + med: + description: MED attribute + type: dict + suboptions: + confed: + description: Compare MED among confederation paths + type: bool + missing_as_worst: + description: Treat missing MED as the least preferred one + type: bool + client_to_client: + description: Configure client to client route reflection + type: dict + suboptions: + set: + description: set reflection of routes allowed + type: bool + all: + description: inter-cluster and intra-cluster (default) + type: bool + intra_cluster: + description: + - intra cluster reflection + - intra-cluster reflection for cluster-id + type: str + cluster_id: + description: + - Configure Route-Reflector Cluster-id (peers may reset) + - A.B.C.D/Please refer vendor documentation for valid Route-Reflector Cluster-id + type: bool + confederation: + description: AS confederation parameters + type: dict + suboptions: + identifier: + description: + - Set routing domain confederation AS + - AS number + type: str + peers: + description: + - Peer ASs in BGP confederation + - AS number + type: str + consistency_checker: + description: Consistency-checker + type: dict + suboptions: + auto_repair: + description: Auto-Repair + type: dict + suboptions: + set: + description: Enable Auto-Repair + type: bool + interval: + description: + - Set the bgp consistency checker + - Please refer vendor documentation for valid values + type: int + error_message: + description: Log Error-Msg + type: dict + suboptions: + set: + description: Enable Error-Msg + type: bool + interval: + description: + - Set the bgp consistency checker + - Please refer vendor documentation for valid values + type: int + dampening: + description: Enable route-flap dampening + type: dict + suboptions: + penalty_half_time: + description: + - Half-life time for the penalty + - Please refer vendor documentation for valid values + type: int + reuse_route_val: + description: + - Value to start reusing a route + - Please refer vendor documentation for valid values + type: int + suppress_route_val: + description: + - Value to start suppressing a route + - Please refer vendor documentation for valid values + type: int + max_suppress: + description: + - Maximum duration to suppress a stable route + - Please refer vendor documentation for valid values + type: int + route_map: + description: Route-map to specify criteria for dampening + type: str + deterministic_med: + description: Pick the best-MED path among paths advertised from the neighboring AS + type: bool + dmzlink_bw: + description: Use DMZ Link Bandwidth as weight for BGP multipaths + type: bool + enforce_first_as: + description: Enforce the first AS for EBGP routes(default) + type: bool + enhanced_error: + description: Enabled BGP Enhanced error handling + type: bool + fast_external_fallover: + description: Immediately reset session if a link to a directly connected external peer goes down + type: bool + graceful_restart: + description: Graceful restart capability parameters + type: dict + suboptions: + set: + description: Set Graceful-Restart + type: bool + extended: + description: Enable Graceful-Restart Extension + type: bool + restart_time: + description: + - Set the max time needed to restart and come back up + - Please refer vendor documentation for valid values + type: int + stalepath_time: + description: + - Set the max time to hold onto restarting peer's stale paths + - Please refer vendor documentation for valid values + type: int + graceful_shutdown: + description: Graceful shutdown capability parameters + type: dict + suboptions: + neighbors: + description: Gracefully shut down all neigbors + type: dict + suboptions: + time: + description: + - time in seconds + - Please refer vendor documentation for valid values + type: int + activate: + description: Activate graceful shutdown of all neigbors + type: bool + vrfs: + description: Gracefully shut down all vrf neigbors + type: dict + suboptions: + time: + description: + - time in seconds + - Please refer vendor documentation for valid values + type: int + activate: + description: Activate graceful shutdown of all neigbors + type: bool + community: + description: + - Set Community for Gshut routes + - community number/community number in aa:nn format + type: str + local_preference: + description: + - Set Local Preference for Gshut routes + - Please refer vendor documentation for valid values + type: int + inject_map: + description: Routemap which specifies prefixes to inject + type: dict + suboptions: + name: + description: route-map name + type: str + exist_map_name: + description: route-map name + type: str + copy_attributes: + description: Copy attributes from aggregate + type: bool + listen: + description: Neighbor subnet range listener + type: dict + suboptions: + limit: + description: + - Set the max limit for the dynamic subnet range neighbors + - Please refer vendor documentation for valid values + type: int + range: + description: Subnet network range + type: dict + suboptions: + ipv4_with_subnet: + description: IPv4 subnet range(A.B.C.D/nn) + type: str + ipv6_with_subnet: + description: IPv6 subnet range(X:X:X:X::X/<0-128>) + type: str + peer_group: + description: Member of the peer-group + type: str + log_neighbor_changes: + description: Log neighbor up/down and reset reason + type: bool + maxas_limit: + description: + - Allow AS-PATH attribute from any neighbor imposing a limit on number of ASes + - Please refer vendor documentation for valid values + type: int + maxcommunity_limit: + description: + - Allow COMMUNITY attribute from any neighbor imposing a limit on number of communities + - Please refer vendor documentation for valid values + type: int + maxextcommunity_limit: + description: + - Allow EXTENDED COMMUNITY attribute from any neighbor imposing a limit on number of extended communities + - Please refer vendor documentation for valid values + type: int + nexthop: + description: Nexthop tracking commands + type: dict + suboptions: + route_map: + description: Route map for valid nexthops + type: str + trigger: + description: nexthop trackings + type: dict + suboptions: + delay: + description: + - Set the delay to tigger nexthop tracking + - Please refer vendor documentation for valid values + type: int + enable: + description: Enable nexthop tracking + type: bool + nopeerup_delay: + description: Set how long BGP will wait for the first peer to come up before beginning the update delay or + graceful restart timers (in seconds) + type: list + elements: dict + suboptions: + cold_boot: + description: + - How long to wait for the first peer to come up upon a cold boot + - Please refer vendor documentation for valid values + type: int + nsf_switchover: + description: + - How long to wait for the first peer, post NSF switchover + - Please refer vendor documentation for valid values + type: int + post_boot: + description: + - How long to wait for the first peer to come up once the system is already + booted and all peers go down + - Please refer vendor documentation for valid values + type: int + user_initiated: + description: + - How long to wait for the first peer, post a manual clear of BGP peers by the admin user + - Please refer vendor documentation for valid values + type: int + recursion: + description: + - recursion rule for the nexthops + - recursion via host for the nexthops + type: bool + redistribute_internal: + description: Allow redistribution of iBGP into IGPs (dangerous) + type: bool + refresh: + description: refresh + type: dict + suboptions: + max_eor_time: + description: + - Configure refresh max-eor time + - Please refer vendor documentation for valid values + type: int + stalepath_time: + description: + - Configure refresh stale-path time + - Please refer vendor documentation for valid values + type: int + regexp: + description: + - Select regular expression engine + - Enable bounded-execution-time regular expression engine + type: bool + route_map: + description: + - route-map control commands + - Have route-map set commands take priority over BGP commands such as next-hop unchanged + type: bool + router_id: + description: Override configured router identifier (peers will reset) + type: dict + suboptions: + address: + description: Manually configured router identifier(A.B.C.D) + type: str + interface: + description: Use IPv4 address on interface + type: str + vrf: + description: + - vrf-specific router id configuration + - Automatically assign per-vrf bgp router id + type: bool + scan_time: + description: + - Configure background scanner interval + - Please refer vendor documentation for valid values + type: int + slow_peer: + description: Configure slow-peer + type: dict + suboptions: + detection: + description: Slow-peer detection + type: dict + suboptions: + set: + description: Slow-peer detection + type: bool + threshold: + description: + - Set the slow-peer detection threshold + - Please refer vendor documentation for valid values + type: int + split_update_group: + description: Configure slow-peer split-update-group + type: dict + suboptions: + dynamic: + description: Dynamically split the slow peer to slow-update group + type: bool + permanent: + description: Keep the slow-peer permanently in slow-update group + type: int + snmp: + description: + - BGP SNMP options + - BGP SNMP trap options + - Use cbgpPeer2Type as part of index for traps + type: bool + sso: + description: + - Stateful Switchover + - Enable SSO only for Route-Refresh capable peers + type: bool + soft_reconfig_backup: + description: Use soft-reconfiguration inbound only when route-refresh is not negotiated + type: bool + suppress_inactive: + description: Suppress routes that are not in the routing table + type: bool + transport: + description: + - Global enable/disable transport session parameters + - Transport path MTU discovery + type: bool + update_delay: + description: + - Set the max initial delay for sending update + - Please refer vendor documentation for valid values + type: int + update_group: + description: + - Manage peers in bgp update groups + - Split update groups based on Policy + - Keep peers with as-override in different update groups + type: bool + upgrade_cli: + description: Upgrade to hierarchical AFI mode + type: dict + suboptions: + set: + description: enable upgrade to hierarchical AFI mode + type: bool + af_mode: + description: Upgrade to AFI mode + type: bool + bmp: + description: BGP Monitoring Protocol) + type: dict + suboptions: + buffer_size: + description: + - BMP Buffer Size + - Please refer vendor documentation for valid values + type: int + initial_refresh: + description: Initial Refresh options + type: dict + suboptions: + delay: + description: Delay before Initial Refresh + type: int + skip: + description: skip all refreshes + type: bool + server: + description: + - Server Information + - Please refer vendor documentation for valid values + type: int + default_information: + description: + - Control distribution of default information + - Distribute a default route + type: bool + default_metric: + description: + - Set metric of redistributed routes + - Please refer vendor documentation for valid values + type: int + distance: + description: Define an administrative distance + type: dict + suboptions: + admin: + description: Administrative distance + type: dict + suboptions: + distance: + description: + - Administrative distance + - Please refer vendor documentation for valid values + type: int + address: + description: IP Source address (A.B.C.D) + type: str + wildcard_bit: + description: Wildcard bits (A.B.C.D) + type: str + acl: + description: + - IP Standard access list number + - IP Standard expanded access list number + - Standard access-list name + type: str + bgp: + description: BGP distance + type: dict + suboptions: + routes_external: + description: + - Distance for routes external to the AS + - Please refer vendor documentation for valid values + type: int + routes_internal: + description: + - Distance for routes internal to the AS + - Please refer vendor documentation for valid values + type: int + routes_local: + description: + - Distance for local routes + - Please refer vendor documentation for valid values + type: int + mbgp: + description: MBGP distance + type: dict + suboptions: + routes_external: + description: + - Distance for routes external to the AS + - Please refer vendor documentation for valid values + type: int + routes_internal: + description: + - Distance for routes internal to the AS + - Please refer vendor documentation for valid values + type: int + routes_local: + description: + - Distance for local routes + - Please refer vendor documentation for valid values + type: int + distribute_list: + description: Filter networks in routing updates + type: dict + suboptions: + acl: + description: IP access list number/name + type: str + in: + description: Filter incoming routing updates + type: bool + out: + description: Filter outgoing routing updates + type: bool + interface: + description: interface details + type: str + maximum_paths: + description: Forward packets over multiple paths + type: dict + suboptions: + paths: + description: Number of paths + type: int + eibgp: + description: Both eBGP and iBGP paths as multipath + type: int + ibgp: + description: iBGP-multipath + type: int + maximum_secondary_paths: + description: Maximum secondary paths + type: dict + suboptions: + paths: + description: Number of secondary paths + type: int + eibgp: + description: Both eBGP and iBGP paths as secondary multipath + type: int + ibgp: + description: iBGP-secondary-multipath + type: int + neighbor: + description: Specify a neighbor router + type: list + elements: dict + suboptions: + address: + description: Neighbor address (A.B.C.D) + type: str + tag: + description: Neighbor tag + type: str + ipv6_adddress: + description: Neighbor ipv6 address (X:X:X:X::X) + type: str + activate: + description: Enable the Address Family for this Neighbor + type: bool + additional_paths: + description: Negotiate additional paths capabilities with this neighbor + type: dict + suboptions: + disable: + description: Disable additional paths for this neighbor + type: bool + receive: + description: Receive additional paths from neighbors + type: bool + send: + description: Send additional paths to neighbors + type: bool + advertise: + description: Advertise to this neighbor + type: dict + suboptions: + additional_paths: + description: Advertise additional paths + type: dict + suboptions: + all: + description: Select all available paths + type: bool + best: + description: Select best N paths (2-3). + type: int + group_best: + description: Select group-best path + type: bool + best_external: + description: Advertise best-external (at RRs best-internal) path + type: bool + diverse_path: + description: Advertise additional paths + type: dict + suboptions: + backup: + description: Diverse path can be backup path + type: bool + mpath: + description: Diverse path can be multipath + type: bool + advertise_map: + description: specify route-map for conditional advertisement + type: dict + suboptions: + name: + description: advertise route-map name + type: str + exist_map: + description: + - advertise prefix only if prefix is in the condition exists + - condition route-map name + type: str + non_exist_map: + description: + - advertise prefix only if prefix in the condition does not exist + - condition route-map name + type: str + advertisement_interval: + description: Minimum interval between sending BGP routing updates + type: int + aigp: + description: AIGP on neighbor + type: dict + suboptions: + enable: + description: Enable AIGP + type: bool + send: + description: Cost community or MED carrying AIGP VALUE + type: dict + suboptions: + cost_community: + description: Cost extended community carrying AIGP Value + type: dict + suboptions: + id: + description: + - Community ID + - Please refer vendor documentation for valid values + type: int + poi: + description: Point of Insertion + type: dict + suboptions: + igp_cost: + description: Point of Insertion After IGP + type: bool + pre_bestpath: + description: Point of Insertion At Beginning + type: bool + transitive: + description: Cost community is Transitive + type: bool + med: + description: Med carrying AIGP Value + type: bool + allow_policy: + description: Enable the policy support for this IBGP Neighbor + type: bool + allowas_in: + description: Accept as-path with my AS present in it + type: int + as_override: + description: + - Override matching AS-number while sending update + - Maintain Split Horizon while sending update + type: bool + bmp_activate: + description: Activate the BMP monitoring for a BGP peer + type: dict + suboptions: + all: + description: Activate BMP monitoring for all servers + type: bool + server: + description: + - Activate BMP for server + - BMP Server Number + - Please refer vendor documentation for valid values + type: int + capability: + description: + - Advertise capability to the peer + - Advertise ORF capability to the peer + - Advertise prefixlist ORF capability to this neighbor + type: dict + suboptions: + both: + description: Capability to SEND and RECEIVE the ORF to/from this neighbor + type: bool + receive: + description: Capability to RECEIVE the ORF from this neighbor + type: bool + send: + description: Capability to SEND the ORF to this neighbor + type: bool + cluster_id: + description: + - Configure Route-Reflector Cluster-id (peers may reset) + - Route-Reflector Cluster-id as 32 bit quantity, or + Route-Reflector Cluster-id in IP address format (A.B.C.D) + type: str + default_originate: + description: Originate default route to this neighbor + type: dict + suboptions: + set: + description: Originate default route to this neighbor + type: bool + route_map: + description: Route-map to specify criteria to originate default + type: str + description: + description: Neighbor specific description + type: str + disable_connected_check: + description: one-hop away EBGP peer using loopback address + type: bool + distribute_list: + description: Filter updates to/from this neighbor + type: dict + suboptions: + acl: + description: IP access list number/name + type: str + in: + description: Filter incoming updates + type: bool + out: + description: Filter outgoing updates + type: bool + dmzlink_bw: + description: Propagate the DMZ link bandwidth + type: bool + ebgp_multihop: + description: Allow EBGP neighbors not on directly connected networks + type: dict + suboptions: + enable: + description: Allow EBGP neighbors not on directly connected networks + type: bool + hop_count: + description: + - Maximum hop count + - Please refer vendor documentation for valid values + type: int + fall_over: + description: Session fall on peer route lost + type: dict + suboptions: + bfd: + description: Use BFD to detect failure + type: dict + suboptions: + set: + description: set bfd + type: bool + multi_hop: + description: Force BFD multi-hop to detect failure + type: bool + single_hop: + description: Force BFD single-hop to detect failure + type: bool + route_map: + description: Route map for peer route + type: str + filter_list: + description: Establish BGP filters + type: dict + suboptions: + path_acl: + description: AS path access list + type: str + in: + description: Filter incoming updates + type: bool + out: + description: Filter outgoing updates + type: bool + ha_mode: + description: high availability mode + type: dict + suboptions: + set: + description: set ha-mode and graceful-restart for this peer + type: bool + disable: + description: disable graceful-restart + type: bool + inherit: + description: + - Inherit a template + - Inherit a peer-session template and Template name + type: str + local_as: + description: Specify a local-as number + type: dict + suboptions: + set: + description: set local-as number + type: bool + number: + description: + - AS number used as local AS + - Please refer vendor documentation for valid values + type: int + dual_as: + description: Accept either real AS or local AS from the ebgp peer + type: bool + no_prepend: + description: Do not prepend local-as to updates from ebgp peers + type: dict + suboptions: + set: + description: Set prepend + type: bool + replace_as: + description: Replace real AS with local AS in the EBGP updates + type: bool + log_neighbor_changes: + description: Log neighbor up/down and reset reason + type: dict + suboptions: + set: + description: set Log neighbor up/down and reset + type: bool + disable: + description: disable Log neighbor up/down and reset + type: bool + maximum_prefix: + description: Maximum number of prefixes accepted from this peer + type: dict + suboptions: + max_no: + description: maximum no. of prefix limit + type: int + threshold_val: + description: Threshold value (%) at which to generate a warning msg + type: int + restart: + description: Restart bgp connection after limit is exceeded + type: int + warning_only: + description: Only give warning message when limit is exceeded + type: bool + next_hop_self: + description: Disable the next hop calculation for this neighbor + type: dict + suboptions: + set: + description: Enable next-hop-self + type: bool + all: + description: Enable next-hop-self for both eBGP and iBGP received paths + type: bool + next_hop_unchanged: + description: + - Propagate next hop unchanged for iBGP paths to this neighbor + - Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor + type: dict + suboptions: + set: + description: Enable next-hop-unchanged + type: bool + allpaths: + description: Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor + type: bool + password: + description: Set a password + type: str + path_attribute: + description: BGP optional attribute filtering + type: dict + suboptions: + discard: + description: Discard matching path-attribute for this neighbor + type: dict + suboptions: + type: + description: + - path attribute type + - Please refer vendor documentation for valid values + type: int + range: + description: path attribute range + type: dict + suboptions: + start: + description: + - path attribute range start value + - Please refer vendor documentation for valid values + type: int + end: + description: + - path attribute range end value + - Please refer vendor documentation for valid values + type: int + in: + description: Perform inbound path-attribute filtering + type: bool + treat_as_withdraw: + description: Treat-as-withdraw matching path-attribute for this neighbor + type: dict + suboptions: + type: + description: + - path attribute type + - Please refer vendor documentation for valid values + type: int + range: + description: path attribute range + type: dict + suboptions: + start: + description: + - path attribute range start value + - Please refer vendor documentation for valid values + type: int + end: + description: + - path attribute range end value + - Please refer vendor documentation for valid values + type: int + in: + description: Perform inbound path-attribute filtering + type: bool + peer_group: + description: Member of the peer-group + type: str + remote_as: + description: + - Specify a BGP neighbor + - AS of remote neighbor + type: int + remove_private_as: + description: Remove private AS number from outbound updates + type: dict + suboptions: + set: + description: Remove private AS number + type: bool + all: + description: Remove all private AS numbers + type: bool + replace_as: + description: Replace all private AS numbers with local AS + type: bool + route_map: + description: Apply route map to neighbor + type: dict + suboptions: + name: + description: Replace all private AS numbers with local AS + type: str + in: + description: Apply map to incoming routes + type: bool + out: + description: Apply map to outbound routes + type: bool + route_reflector_client: + description: Configure a neighbor as Route Reflector client + type: bool + route_server_client: + description: Configure a neighbor as Route Server client + type: dict + suboptions: + set: + description: Set Route Server client + type: bool + context: + description: + - Specify Route Server context for neighbor + - Route Server context name + type: str + send_community: + description: Send Community attribute to this neighbor + type: dict + suboptions: + set: + description: Set send Community attribute to this neighbor + type: bool + both: + description: Send Standard and Extended Community attributes + type: bool + extended: + description: Send Extended Community attribute + type: bool + standard: + description: Send Standard Community attribute + type: bool + send_label: + description: Send NLRI + MPLS Label to this peer + type: dict + suboptions: + set: + description: Set send NLRI + MPLS Label to this peer + type: bool + explicit_null: + description: Advertise Explicit Null label in place of Implicit Null + type: bool + shutdown: + description: Administratively shut down this neighbor + type: dict + suboptions: + set: + description: shut down + type: bool + graceful: + description: + - Gracefully shut down this neighbor + - time in seconds + - Please refer vendor documentation for valid values + type: int + slow_peer: + description: Configure slow-peer + type: dict + suboptions: + detection: + description: Configure slow-peer + type: dict + suboptions: + enable: + description: Enable slow-peer detection + type: bool + disable: + description: Disable slow-peer detection + type: bool + threshold: + description: Set the slow-peer detection threshold + type: int + split_update_group: + description: Configure slow-peer split-update-group + type: dict + suboptions: + dynamic: + description: Dynamically split the slow peer to slow-update group + type: dict + suboptions: + enable: + description: Enable slow-peer detection + type: bool + disable: + description: Disable slow-peer detection + type: bool + permanent: + description: Keep the slow-peer permanently in slow-update group + type: bool + static: + description: Static slow-peer + type: bool + soft_reconfiguration: + description: + - Per neighbor soft reconfiguration + - Allow inbound soft reconfiguration for this neighbor + type: bool + timers: + description: BGP per neighbor timers + type: dict + suboptions: + interval: + description: Keepalive interval + type: int + holdtime: + description: Holdtime + type: int + min_holdtime: + description: Minimum hold time from neighbor + type: int + translate_update: + description: Translate Update to MBGP format + type: dict + suboptions: + set: + description: Set Translate Update + type: bool + nlri: + description: Specify type of nlri to translate to + type: dict + suboptions: + multicast: + description: Translate Update to multicast nlri + type: bool + unicast: + description: Process Update as unicast nlri + type: bool + transport: + description: Transport options + type: dict + suboptions: + connection_mode: + description: Specify passive or active connection + type: dict + suboptions: + active: + description: Actively establish the TCP session + type: bool + passive: + description: Passively establish the TCP session + type: bool + multi_session: + description: Use Multi-session for transport + type: bool + path_mtu_discovery: + description: Use transport path MTU discovery + type: dict + suboptions: + set: + description: Use path MTU discovery + type: bool + disable: + description: disable + type: bool + ttl_security: + description: + - BGP ttl security check + - maximum number of hops + - Please refer vendor documentation for valid values + type: int + unsuppress_map: + description: + - Route-map to selectively unsuppress suppressed routes + - Name of route map + type: str + version: + description: + - Set the BGP version to match a neighbor + - Neighbor's BGP version + - Please refer vendor documentation for valid values + type: int + weight: + description: Set default weight for routes from this neighbor + type: int + redistribute: + description: Redistribute information from another routing protocol + type: list + elements: dict + suboptions: + application: + description: Application + type: dict + suboptions: + name: + description: Application name + type: str + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + bgp: + description: Border Gateway Protocol (BGP) + type: dict + suboptions: + as_number: + description: Autonomous system number + type: str + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + connected: + description: Connected + type: dict + suboptions: + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + eigrp: + description: Enhanced Interior Gateway Routing Protocol (EIGRP) + type: dict + suboptions: + as_number: + description: Autonomous system number + type: str + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + isis: + description: ISO IS-IS + type: dict + suboptions: + area_tag: + description: ISO routing area tag + type: str + clns: + description: Redistribution of OSI dynamic routes + type: bool + ip: + description: Redistribution of IP dynamic routes + type: bool + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + iso_igrp: + description: IGRP for OSI networks + type: dict + suboptions: + area_tag: + description: ISO routing area tag + type: str + route_map: + description: Route map reference + type: str + lisp: + description: Locator ID Separation Protocol (LISP) + type: dict + suboptions: + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + mobile: + description: Mobile routes + type: dict + suboptions: + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + odr: + description: On Demand stub Routes + type: dict + suboptions: + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + ospf: + description: Open Shortest Path First (OSPF) + type: dict + suboptions: + process_id: + description: Process ID + type: int + match: + description: On Demand stub Routes + type: dict + suboptions: + external: + description: Redistribute OSPF external routes + type: bool + internal: + description: Redistribute OSPF internal routes + type: bool + nssa_external: + description: Redistribute OSPF NSSA external routes + type: bool + type_1: + description: Redistribute NSSA external type 1 routes + type: bool + type_2: + description: Redistribute NSSA external type 2 routes + type: bool + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + vrf: + description: VPN Routing/Forwarding Instance + type: str + ospfv3: + description: OSPFv3 + type: dict + suboptions: + process_id: + description: Process ID + type: int + match: + description: On Demand stub Routes + type: dict + suboptions: + external: + description: Redistribute OSPF external routes + type: bool + internal: + description: Redistribute OSPF internal routes + type: bool + nssa_external: + description: Redistribute OSPF NSSA external routes + type: bool + type_1: + description: Redistribute NSSA external type 1 routes + type: bool + type_2: + description: Redistribute NSSA external type 2 routes + type: bool + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + rip: + description: Routing Information Protocol (RIP) + type: dict + suboptions: + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + static: + description: Static routes + type: dict + suboptions: + clns: + description: Redistribution of OSI static routes + type: bool + ip: + description: Redistribution of IP static routes + type: bool + metric: + description: Metric for redistributed routes + type: int + route_map: + description: Route map reference + type: str + vrf: + description: Specify a source VRF + type: dict + suboptions: + name: + description: Source VRF name + type: str + global: + description: global VRF + type: bool + route_server_context: + description: Enter route server context command mode + type: dict + suboptions: + name: + description: Name of route server context + type: str + address_family: + description: Enter address family command mode + type: dict + suboptions: + afi: + description: Address family + type: str + choices: ['ipv4', 'ipv6'] + modifier: + description: Address Family modifier + type: str + choices: ['multicast', 'unicast'] + import_map: + description: + - Import matching routes using a route map + - Name of route map + type: str + description: + description: Textual description of the router server context + type: str + scope: + description: Enter scope command mode + type: dict + suboptions: + global: + description: Global scope + type: bool + vrf: + description: + - VRF scope + - VPN Routing/Forwarding instance name + type: str + synchronization: + description: Perform IGP synchronization + type: bool + table_map: + description: Map external entry attributes into routing table + type: dict + suboptions: + name: + description: route-map name + type: str + filter: + description: Selective route download + type: bool + template: + description: Enter template command mode + type: dict + suboptions: + peer_policy: + description: Template configuration for policy parameters + type: str + peer_session: + description: Template configuration for session parameters + type: str + timers: + description: + - Adjust routing timers + - BGP timers + type: dict + suboptions: + keepalive: + description: Keepalive interval + type: int + holdtime: + description: Holdtime + type: int + min_holdtime: + description: Minimum hold time from neighbor + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS + device by executing the command B(sh running-config | section ^router bgp). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - purged + - gathered + - rendered + - parsed + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp + +- name: Merge provided configuration with device configuration + cisco.ios.ios_bgp_global: + config: + as_number: 65000 + bgp: + advertise_best_external: true + bestpath: + - compare_routerid: true + nopeerup_delay: + - post_boot: 10 + dampening: + penalty_half_time: 1 + reuse_route_val: 1 + suppress_route_val: 1 + max_suppress: 1 + graceful_shutdown: + neighbors: + time: 50 + community: 100 + local_preference: 100 + neighbor: + - address: 198.51.100.1 + description: merge neighbor + remote_as: 100 + aigp: + send: + cost_community: + id: 100 + poi: + igp_cost: true + transitive: true + route_map: + name: test-route + out: true + state: merged + +# Commands fired: +# --------------- +# +# "commands": [ +# "router bgp 65000", +# "bgp dampening 1 1 1 1", +# "bgp graceful-shutdown all neighbors 50 community 100 local-preference 100", +# "bgp advertise-best-external", +# "bgp nopeerup-delay post-boot 10", +# "bgp bestpath compare-routerid", +# "neighbor 198.51.100.1 remote-as 100", +# "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive", +# "neighbor 198.51.100.1 description merge neighbor", +# "neighbor 198.51.100.1 route-map test-route out" +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + + +# Using replaced + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + + +- name: Replaces device configuration of listed global BGP with provided configuration + cisco.ios.ios_bgp_global: + config: + as_number: 65000 + bgp: + advertise_best_external: true + bestpath: + - med: + confed: true + log_neighbor_changes: true + nopeerup_delay: + - post_boot: 10 + cold_boot: 20 + neighbor: + - address: 192.0.2.1 + description: replace neighbor + remote_as: 100 + slow_peer: + detection: + disable: true + state: replaced + +# Commands fired: +# --------------- +# +# "commands": [ +# "router bgp 65000" +# "no bgp dampening 1 1 1 1" +# "no timers bgp 100 200 150" +# "no bgp bestpath compare-routerid" +# "bgp bestpath med confed" +# "bgp nopeerup-delay cold-boot 20" +# "no neighbor 198.51.100.1 remote-as 100" +# "neighbor 192.0.2.1 remote-as 100" +# "no bgp graceful-shutdown all neighbors 50 local-preference 100 community 100" +# "no neighbor 198.51.100.1 route-map test-route out" +# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive" +# "no neighbor 198.51.100.1 description merge neighbor" +# "neighbor 192.0.2.1 slow-peer detection disable" +# "neighbor 192.0.2.1 description replace neighbor" +# ] + + +# After state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp log-neighbor-changes +# bgp nopeerup-delay cold-boot 20 +# bgp nopeerup-delay post-boot 10 +# bgp bestpath med confed +# bgp advertise-best-external +# redistribute connected metric 10 +# neighbor 192.0.2.1 remote-as 100 +# neighbor 192.0.2.1 description replace neighbor +# neighbor 192.0.2.1 slow-peer detection disable + +# Using Deleted + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + +- name: "Delete global BGP (Note: This won't delete the configured global BGP)" + cisco.ios.ios_bgp_global: + config: + as_number: 65000 + state: deleted + +# Commands fired: +# --------------- +# "commands": [ +# "router bgp 65000", +# "no bgp dampening 1 1 1 1", +# "no bgp graceful-shutdown all neighbors 50 community 100 local-preference 100", +# "no bgp advertise-best-external", +# "no bgp bestpath compare-routerid", +# "no bgp nopeerup-delay post-boot 10", +# "no neighbor 198.51.100.1 remote-as 100", +# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive", +# "no neighbor 198.51.100.1 description merge neighbor", +# "no neighbor 198.51.100.1 route-map test-route out" +# ] + + +# After state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 + + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured global BGP)" + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + + +- name: "Delete global BGP without config" + cisco.ios.ios_bgp_global: + state: deleted + +# Commands fired: +# --------------- +# "commands": [ +# "router bgp 65000", +# "no bgp dampening 1 1 1 1", +# "no bgp graceful-shutdown all neighbors 50 community 100 local-preference 100", +# "no bgp advertise-best-external", +# "no bgp bestpath compare-routerid", +# "no bgp nopeerup-delay post-boot 10", +# "no neighbor 198.51.100.1 remote-as 100", +# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive", +# "no neighbor 198.51.100.1 description merge neighbor", +# "no neighbor 198.51.100.1 route-map test-route out" +# ] + + +# After state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 + +# Using Purged +#"(NOTE: This WILL delete the configured global BGP)" + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + + +- name: 'Delete the configured global BGP (Note: This WILL delete the the configured + global BGP)' + cisco.ios.ios_bgp_global: + state: purged + +# Commands fired: +# --------------- +# "commands": [ +# "no router bgp 65000", +# ] + +# After state: +# ------------- +# +# vios#sh running-config | section ^router bgp + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^router bgp +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + + +- name: Gather listed global BGP with provided configurations + cisco.ios.ios_bgp_global: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": { +# "as_number": "65000", +# "bgp": { +# "advertise_best_external": true, +# "bestpath": [ +# { +# "compare_routerid": true +# } +# ], +# "dampening": { +# "max_suppress": 1, +# "penalty_half_time": 1, +# "reuse_route_val": 1, +# "suppress_route_val": 1 +# }, +# "graceful_shutdown": { +# "community": "100", +# "local_preference": 100, +# "neighbors": { +# "time": 50 +# } +# }, +# "nopeerup_delay": [ +# { +# "post_boot": 10 +# } +# ] +# }, +# "neighbor": [ +# { +# "address": "198.51.100.1", +# "aigp": { +# "send": { +# "cost_community": { +# "id": 100, +# "poi": { +# "igp_cost": true, +# "transitive": true +# } +# } +# } +# }, +# "description": "merge neighbor", +# "remote_as": 100, +# "route_map": { +# "name": "test-route", +# "out": true +# } +# } +# ] +# } + +# Using Rendered + +- name: Rendered the provided configuration with the exisiting running configuration + cisco.ios.ios_bgp_global: + config: + as_number: 65000 + bgp: + advertise_best_external: true + bestpath: + - compare_routerid: true + nopeerup_delay: + - post_boot: 10 + dampening: + penalty_half_time: 1 + reuse_route_val: 1 + suppress_route_val: 1 + max_suppress: 1 + graceful_shutdown: + neighbors: + time: 50 + community: 100 + local_preference: 100 + neighbor: + - address: 198.51.100.1 + description: merge neighbor + remote_as: 100 + aigp: + send: + cost_community: + id: 100 + poi: + igp_cost: true + transitive: true + route_map: + name: test-route + out: true + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "router bgp 65000", +# "bgp dampening 1 1 1 1", +# "bgp graceful-shutdown all neighbors 50 community 100 local-preference 100", +# "bgp advertise-best-external", +# "bgp nopeerup-delay post-boot 10", +# "bgp bestpath compare-routerid", +# "neighbor 198.51.100.1 remote-as 100", +# "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive", +# "neighbor 198.51.100.1 description merge neighbor", +# "neighbor 198.51.100.1 route-map test-route out" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# router bgp 65000 +# bgp nopeerup-delay post-boot 10 +# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 +# bgp bestpath compare-routerid +# bgp dampening 1 1 1 1 +# bgp advertise-best-external +# neighbor 198.51.100.1 remote-as 100 +# neighbor 198.51.100.1 description merge neighbor +# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive +# neighbor 198.51.100.1 route-map test-route out + +- name: Parse the commands for provided configuration + cisco.ios.ios_bgp_global: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": { +# "as_number": "65000", +# "bgp": { +# "advertise_best_external": true, +# "bestpath": [ +# { +# "compare_routerid": true +# } +# ], +# "dampening": { +# "max_suppress": 1, +# "penalty_half_time": 1, +# "reuse_route_val": 1, +# "suppress_route_val": 1 +# }, +# "graceful_shutdown": { +# "community": "100", +# "local_preference": 100, +# "neighbors": { +# "time": 50 +# } +# }, +# "nopeerup_delay": [ +# { +# "post_boot": 10 +# } +# ] +# }, +# "neighbor": [ +# { +# "address": "198.51.100.1", +# "aigp": { +# "send": { +# "cost_community": { +# "id": 100, +# "poi": { +# "igp_cost": true, +# "transitive": true +# } +# } +# } +# }, +# "description": "merge neighbor", +# "remote_as": 100, +# "route_map": { +# "name": "test-route", +# "out": true +# } +# } +# ] +# } + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ["router bgp 65000", "bgp nopeerup-delay post-boot 10", "bgp advertise-best-external"] +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.bgp_global.bgp_global import ( + Bgp_globalArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.bgp_global.bgp_global import ( + Bgp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Bgp_globalArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Bgp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py new file mode 100644 index 00000000..7c502974 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py @@ -0,0 +1,215 @@ +#!/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: ios_command +author: Peter Sprygada (@privateip) +short_description: Run commands on remote devices running Cisco IOS +description: +- Sends arbitrary commands to an ios node and returns the results read from the device. + This module includes an argument that will cause the module to wait for a specific + condition before returning or timing out if the condition is not met. +- This module does not support running commands in configuration mode. Please use + M(ios_config) to configure IOS devices. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +options: + commands: + description: + - List of commands to send to the remote ios device over the configured provider. + The resulting output from the command is returned. If the I(wait_for) argument + is provided, the module is not returned until the condition is satisfied or + the number of retries has expired. If a command sent to the device requires + answering a prompt, it is possible to pass a dict containing I(command), I(answer) + and I(prompt). Common answers are 'y' or "\\r" (carriage return, must be double + quotes). See examples. + required: true + type: list + elements: raw + wait_for: + description: + - List of conditions to evaluate against the output of the command. The task will + wait for each condition to be true before moving forward. If the conditional + is not true within the configured number of retries, the task fails. See examples. + aliases: + - waitfor + type: list + elements: str + match: + description: + - The I(match) argument is used in conjunction with the I(wait_for) argument to + specify the match policy. Valid values are C(all) or C(any). If the value + is set to C(all) then all conditionals in the wait_for must be satisfied. If + the value is set to C(any) then only one of the values must be satisfied. + default: all + type: str + choices: + - any + - all + retries: + description: + - Specifies the number of retries a command should by tried before it is considered + failed. The command is run on the target device every retry and evaluated against + the I(wait_for) conditions. + default: 10 + type: int + interval: + description: + - Configures the interval in seconds to wait between retries of the command. If + the command does not pass the specified conditions, the interval indicates how + long to wait before trying the command again. + default: 1 + type: int +""" +EXAMPLES = """ +- name: run show version on remote devices + cisco.ios.ios_command: + commands: show version + +- name: run show version and check to see if output contains IOS + cisco.ios.ios_command: + commands: show version + wait_for: result[0] contains IOS + +- name: run multiple commands on remote nodes + cisco.ios.ios_command: + commands: + - show version + - show interfaces + +- name: run multiple commands and evaluate the output + cisco.ios.ios_command: + commands: + - show version + - show interfaces + wait_for: + - result[0] contains IOS + - result[1] contains Loopback0 + +- name: run commands that require answering a prompt + cisco.ios.ios_command: + commands: + - command: clear counters GigabitEthernet0/1 + prompt: Clear "show interface" counters on this interface [confirm] + answer: y + - command: clear counters GigabitEthernet0/2 + prompt: '[confirm]' + answer: '\r' +""" +RETURN = """ +stdout: + description: The set of responses from the commands + returned: always apart from low level errors (such as action plugin) + type: list + sample: ['...', '...'] +stdout_lines: + description: The value of stdout split into a list + returned: always apart from low level errors (such as action plugin) + type: list + sample: [['...', '...'], ['...'], ['...']] +failed_conditions: + description: The list of conditionals that have failed + returned: failed + type: list + sample: ['...', '...'] +""" +import time +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import ( + Conditional, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + transform_commands, + to_lines, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + run_commands, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def parse_commands(module, warnings): + commands = transform_commands(module) + if module.check_mode: + for item in list(commands): + if not item["command"].startswith("show"): + warnings.append( + "Only show commands are supported when using check mode, not executing %s" + % item["command"] + ) + commands.remove(item) + return commands + + +def main(): + """main entry point for module execution + """ + argument_spec = dict( + commands=dict(type="list", elements="raw", required=True), + wait_for=dict(type="list", elements="str", aliases=["waitfor"]), + match=dict(default="all", choices=["all", "any"]), + retries=dict(default=10, type="int"), + interval=dict(default=1, type="int"), + ) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + warnings = list() + result = {"changed": False, "warnings": warnings} + commands = parse_commands(module, 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)) + retries = module.params["retries"] + interval = module.params["interval"] + match = module.params["match"] + while retries > 0: + responses = run_commands(module, commands) + for item in list(conditionals): + if item(responses): + if match == "any": + conditionals = list() + break + conditionals.remove(item) + 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 been satisfied" + module.fail_json(msg=msg, failed_conditions=failed_conditions) + result.update( + {"stdout": responses, "stdout_lines": list(to_lines(responses))} + ) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py new file mode 100644 index 00000000..260b74b0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py @@ -0,0 +1,593 @@ +#!/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: ios_config +author: Peter Sprygada (@privateip) +short_description: Manage Cisco IOS configuration sections +description: +- Cisco IOS configurations use a simple block indent file syntax for segmenting configuration + into sections. This module provides an implementation for working with IOS configuration + sections in a deterministic way. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +- Abbreviated commands are NOT idempotent, see L + (Network FAQ,../network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands). +- To ensure idempotency and correct diff the configuration lines in the relevant module options should be similar to how they + appear if present in the running configuration on device including the indentation. +options: + lines: + description: + - The ordered set of commands that should be configured in the section. The commands + must be the exact same commands as found in the device running-config to ensure + idempotency and correct diff. Be sure to note the configuration command syntax as + some commands are automatically modified by the device config parser. + type: list + elements: str + aliases: + - commands + parents: + description: + - The ordered set of parents that uniquely identify the section or hierarchy the + commands should be checked against. If the parents argument is omitted, the + commands are checked against the set of top level or global commands. + type: list + elements: str + src: + description: + - Specifies the source path to the file that contains the configuration or configuration + template to load. The path to the source file can either be the full path on + the Ansible control host or a relative path from the playbook or role root directory. This + argument is mutually exclusive with I(lines), I(parents). The configuration lines in the + source file should be similar to how it will appear if present in the running-configuration + of the device including the indentation to ensure idempotency and correct diff. + type: str + before: + description: + - The ordered set of commands to push on to the command stack if a change needs + to be made. This allows the playbook designer the opportunity to perform configuration + commands prior to pushing any changes without affecting how the set of commands + are matched against the system. + type: list + elements: str + after: + description: + - The ordered set of commands to append to the end of the command stack if a change + needs to be made. Just like with I(before) this allows the playbook designer + to append a set of commands to be executed after the command set. + type: list + elements: str + match: + description: + - Instructs the module on the way to perform the matching of the set of commands + against the current device config. If match is set to I(line), commands are + matched line by line. If match is set to I(strict), command lines are matched + with respect to position. If match is set to I(exact), command lines must be + an equal match. Finally, if match is set to I(none), the module will not attempt + to compare the source configuration with the running configuration on the remote + device. + choices: + - line + - strict + - exact + - none + type: str + default: line + replace: + description: + - Instructs the module on the way to perform the configuration on the device. + If the replace argument is set to I(line) then the modified lines are pushed + to the device in configuration mode. If the replace argument is set to I(block) + then the entire command block is pushed to the device in configuration mode + if any line is not correct. + default: line + choices: + - line + - block + type: str + multiline_delimiter: + description: + - This argument is used when pushing a multiline configuration element to the + IOS device. It specifies the character to use as the delimiting character. This + only applies to the configuration action. + default: '@' + type: str + backup: + description: + - This argument will cause the module to create a full backup of the current C(running-config) + from the remote device before any changes are made. If the C(backup_options) + value is not given, the backup file is written to the C(backup) folder in the + playbook root directory or role root directory, if playbook is part of an ansible + role. If the directory does not exist, it is created. + type: bool + default: no + running_config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. + There are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(running_config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. + The configuration lines for this option should be similar to how it will appear if present + in the running-configuration of the device including the indentation to ensure idempotency + and correct diff. + type: str + aliases: + - config + defaults: + description: + - This argument specifies whether or not to collect all defaults when getting + the remote device running config. When enabled, the module will get the current + config by issuing the command C(show running-config all). + type: bool + default: no + save_when: + description: + - When changes are made to the device running-configuration, the changes are not + copied to non-volatile storage by default. Using this argument will change + that before. If the argument is set to I(always), then the running-config will + always be copied to the startup-config and the I(modified) flag will always + be set to True. If the argument is set to I(modified), then the running-config + will only be copied to the startup-config if it has changed since the last save + to startup-config. If the argument is set to I(never), the running-config will + never be copied to the startup-config. If the argument is set to I(changed), + then the running-config will only be copied to the startup-config if the task + has made a change. I(changed) was added in Ansible 2.5. + default: never + choices: + - always + - never + - modified + - changed + type: str + diff_against: + description: + - When using the C(ansible-playbook --diff) command line argument the module can + generate diffs against different sources. + - When this option is configure as I(startup), the module will return the diff + of the running-config against the startup-config. + - When this option is configured as I(intended), the module will return the diff + of the running-config against the configuration provided in the C(intended_config) + argument. + - When this option is configured as I(running), the module will return the before + and after diff of the running-config with respect to any changes made to the + device configuration. + type: str + choices: + - running + - startup + - intended + diff_ignore_lines: + description: + - Use this argument to specify one or more lines that should be ignored during + the diff. This is used for lines in the configuration that are automatically + updated by the system. This argument takes a list of regular expressions or + exact line matches. + type: list + elements: str + intended_config: + description: + - The C(intended_config) provides the master configuration that the node should + conform to and is used to check the final running-config against. This argument + will not modify any settings on the remote device and is strictly used to check + the compliance of the current device's configuration against. When specifying + this argument, the task should also modify the C(diff_against) value and set + it to I(intended). The configuration lines for this value should be similar to how it + will appear if present in the running-configuration of the device including the indentation + to ensure correct diff. + type: str + backup_options: + description: + - This is a dict object containing configurable options related to backup file + path. The value of this option is read only when C(backup) is set to I(yes), + if C(backup) is set to I(no) this option will be silently ignored. + suboptions: + filename: + description: + - The filename to be used to store the backup configuration. If the filename + is not given it will be generated based on the hostname, current time and + date in format defined by <hostname>_config.<current-date>@<current-time> + type: str + dir_path: + description: + - This option provides the path ending with directory name in which the backup + configuration file will be stored. If the directory does not exist it will + be first created and the filename is either the value of C(filename) or + default filename as described in C(filename) options description. If the + path value is not given in that case a I(backup) directory will be created + in the current working directory and backup configuration will be copied + in C(filename) within I(backup) directory. + type: path + type: dict +""" +EXAMPLES = """ +- name: configure top level configuration + cisco.ios.ios_config: + lines: hostname {{ inventory_hostname }} + +- name: configure interface settings + cisco.ios.ios_config: + lines: + - description test interface + - ip address 172.31.1.1 255.255.255.0 + parents: interface Ethernet1 + +- name: configure ip helpers on multiple interfaces + cisco.ios.ios_config: + lines: + - ip helper-address 172.26.1.10 + - ip helper-address 172.26.3.8 + parents: '{{ item }}' + with_items: + - interface Ethernet1 + - interface Ethernet2 + - interface GigabitEthernet1 + +- name: configure policer in Scavenger class + cisco.ios.ios_config: + lines: + - conform-action transmit + - exceed-action drop + parents: + - policy-map Foo + - class Scavenger + - police cir 64000 + +- name: load new acl into device + cisco.ios.ios_config: + lines: + - 10 permit ip host 192.0.2.1 any log + - 20 permit ip host 192.0.2.2 any log + - 30 permit ip host 192.0.2.3 any log + - 40 permit ip host 192.0.2.4 any log + - 50 permit ip host 192.0.2.5 any log + parents: ip access-list extended test + before: no ip access-list extended test + match: exact + +- name: check the running-config against master config + cisco.ios.ios_config: + diff_against: intended + intended_config: "{{ lookup('file', 'master.cfg') }}" + +- name: check the startup-config against the running-config + cisco.ios.ios_config: + diff_against: startup + diff_ignore_lines: + - ntp clock .* + +- name: save running to startup when modified + cisco.ios.ios_config: + save_when: modified + +- name: for idempotency, use full-form commands + cisco.ios.ios_config: + lines: + # - shut + - shutdown + # parents: int gig1/0/11 + parents: interface GigabitEthernet1/0/11 + +# Set boot image based on comparison to a group_var (version) and the version +# that is returned from the `ios_facts` module +- name: SETTING BOOT IMAGE + cisco.ios.ios_config: + lines: + - no boot system + - boot system flash bootflash:{{new_image}} + host: '{{ inventory_hostname }}' + when: ansible_net_version != version +- name: render a Jinja2 template onto an IOS device + cisco.ios.ios_config: + backup: yes + src: ios_template.j2 + +- name: configurable backup path + cisco.ios.ios_config: + src: ios_template.j2 + backup: yes + backup_options: + filename: backup.cfg + dir_path: /home/user +""" +RETURN = """ +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1'] +commands: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1'] +backup_path: + description: The full path to the backup file + returned: when backup is yes + type: str + sample: /playbooks/ansible/backup/ios_config.2016-07-16@22:28:34 +filename: + description: The name of the backup file + returned: when backup is yes and filename is not specified in backup options + type: str + sample: ios_config.2016-07-16@22:28:34 +shortname: + description: The full path to the backup file excluding the timestamp + returned: when backup is yes and filename is not specified in backup options + type: str + sample: /playbooks/ansible/backup/ios_config +date: + description: The date extracted from the backup file name + returned: when backup is yes + type: str + sample: "2016-07-16" +time: + description: The time extracted from the backup file name + returned: when backup is yes + type: str + sample: "22:28:34" +""" +import json +from ansible.module_utils._text import to_text +from ansible.module_utils.connection import ConnectionError +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + run_commands, + get_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_defaults_flag, + get_connection, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) + + +def check_args(module, warnings): + if module.params["multiline_delimiter"]: + if len(module.params["multiline_delimiter"]) != 1: + module.fail_json( + msg="multiline_delimiter value can only be a single character" + ) + + +def edit_config_or_macro(connection, commands): + # only catch the macro configuration command, + # not negated 'no' variation. + if commands[0].startswith("macro name"): + connection.edit_macro(candidate=commands) + else: + connection.edit_config(candidate=commands) + + +def get_candidate_config(module): + candidate = "" + if module.params["src"]: + candidate = module.params["src"] + elif module.params["lines"]: + candidate_obj = NetworkConfig(indent=1) + parents = module.params["parents"] or list() + candidate_obj.add(module.params["lines"], parents=parents) + candidate = dumps(candidate_obj, "raw") + return candidate + + +def get_running_config(module, current_config=None, flags=None): + running = module.params["running_config"] + if not running: + if not module.params["defaults"] and current_config: + running = current_config + else: + running = get_config(module, flags=flags) + return running + + +def save_config(module, result): + result["changed"] = True + if not module.check_mode: + run_commands(module, "copy running-config startup-config\r") + else: + module.warn( + "Skipping command `copy running-config startup-config` due to check_mode. Configuration not copied to non-volatile storage" + ) + + +def main(): + """ main entry point for module execution + """ + backup_spec = dict(filename=dict(), dir_path=dict(type="path")) + argument_spec = dict( + src=dict(type="str"), + lines=dict(aliases=["commands"], type="list", elements="str"), + parents=dict(type="list", elements="str"), + before=dict(type="list", elements="str"), + after=dict(type="list", elements="str"), + 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", elements="str"), + ) + argument_spec.update(ios_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, + ) + 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"])): + msg = ( + "To ensure idempotency and correct diff the input configuration lines should be" + " similar to how they appear if present in the running configuration on device" + ) + if module.params["src"]: + msg += " including the indentation" + warnings.append(msg) + 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, ["show running-config", "show startup-config"] + ) + 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, "show running-config") + 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, "show startup-config") + 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) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py new file mode 100644 index 00000000..e66d9048 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py @@ -0,0 +1,236 @@ +#!/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: ios_facts +author: +- Peter Sprygada (@privateip) +- Sumit Jaiswal (@justjais) +short_description: Collect facts from remote devices running Cisco IOS +description: +- Collects a base set of device facts from a remote device that is running IOS. This + module prepends all of the base network fact keys with C(ansible_net_<fact>). The + facts module will always collect a base set of facts from the device and can enable + or disable collection of additional facts. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +options: + gather_subset: + description: + - When supplied, this argument restricts the facts collected to a given subset. + - Possible values for this argument include C(all), C(min), C(hardware), C(config), + and C(interfaces). + - Specify a list of values to include a larger subset. + - Use a value with an initial C(!) to collect all facts except that subset. + required: false + default: '!config' + type: list + elements: str + gather_network_resources: + description: + - When supplied, this argument will restrict the facts collected to a given subset. + Possible values for this argument include all and the resources like interfaces, + vlans etc. Can specify a list of values to include a larger subset. Values can + also be used with an initial C(M(!)) to specify that a specific subset should + not be collected. Valid subsets are 'all', 'interfaces', 'l2_interfaces', 'vlans', + 'lag_interfaces', 'lacp', 'lacp_interfaces', 'lldp_global', 'lldp_interfaces', + 'l3_interfaces', 'acl_interfaces', 'static_routes', 'acls'. + type: list + elements: str +""" +EXAMPLES = """ +- name: Gather all legacy facts + cisco.ios.ios_facts: + gather_subset: all + +- name: Gather only the config and default facts + cisco.ios.ios_facts: + gather_subset: + - config + +- name: Do not gather hardware facts + cisco.ios.ios_facts: + gather_subset: + - '!hardware' + +- name: Gather legacy and resource facts + cisco.ios.ios_facts: + gather_subset: all + gather_network_resources: all + +- name: Gather only the interfaces resource facts and no legacy facts + cisco.ios.ios_facts: + gather_subset: + - '!all' + - '!min' + gather_network_resources: + - interfaces + +- name: Gather interfaces resource and minimal legacy facts + cisco.ios.ios_facts: + gather_subset: min + gather_network_resources: interfaces + +- name: Gather L2 interfaces resource and minimal legacy facts + cisco.ios.ios_facts: + gather_subset: min + gather_network_resources: l2_interfaces + +- name: Gather L3 interfaces resource and minimal legacy facts + cisco.ios.ios_facts: + gather_subset: min + gather_network_resources: l3_interfaces +""" +RETURN = """ +ansible_net_gather_subset: + description: The list of fact subsets collected from the device + returned: always + type: list + +ansible_net_gather_network_resources: + description: The list of fact for network resource subsets collected from the device + returned: when the resource is configured + type: list + +# default +ansible_net_model: + description: The model name returned from the device + returned: always + type: str +ansible_net_serialnum: + description: The serial number of the remote device + returned: always + type: str +ansible_net_version: + description: The operating system version running on the remote device + returned: always + type: str +ansible_net_iostype: + description: The operating system type (IOS or IOS-XE) running on the remote device + returned: always + type: str +ansible_net_hostname: + description: The configured hostname of the device + returned: always + type: str +ansible_net_image: + description: The image file the device is running + returned: always + type: str +ansible_net_stacked_models: + description: The model names of each device in the stack + returned: when multiple devices are configured in a stack + type: list +ansible_net_stacked_serialnums: + description: The serial numbers of each device in the stack + returned: when multiple devices are configured in a stack + type: list +ansible_net_api: + description: The name of the transport + returned: always + type: str +ansible_net_python_version: + description: The Python version Ansible controller is using + returned: always + type: str + +# hardware +ansible_net_filesystems: + description: All file system names available on the device + returned: when hardware is configured + type: list +ansible_net_filesystems_info: + description: A hash of all file systems containing info about each file system (e.g. free and total space) + returned: when hardware is configured + type: dict +ansible_net_memfree_mb: + description: The available free memory on the remote device in Mb + returned: when hardware is configured + type: int +ansible_net_memtotal_mb: + description: The total memory on the remote device in Mb + returned: when hardware is configured + type: int + +# config +ansible_net_config: + description: The current active config from the device + returned: when config is configured + type: str + +# interfaces +ansible_net_all_ipv4_addresses: + description: All IPv4 addresses configured on the device + returned: when interfaces is configured + type: list +ansible_net_all_ipv6_addresses: + description: All IPv6 addresses configured on the device + returned: when interfaces is configured + type: list +ansible_net_interfaces: + description: A hash of all interfaces running on the system + returned: when interfaces is configured + type: dict +ansible_net_neighbors: + description: + - The list of CDP and LLDP neighbors from the remote device. If both, + CDP and LLDP neighbor data is present on one port, CDP is preferred. + returned: when interfaces is configured + type: dict +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.facts.facts import ( + FactsArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import ( + Facts, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def main(): + """ + Main entry point for module execution + + :returns: ansible_facts + """ + argument_spec = FactsArgs.argument_spec + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + warnings = [] + if module.params["gather_subset"] == "!config": + warnings.append( + "default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards" + ) + result = Facts(module).get_facts() + ansible_facts, additional_warnings = result + warnings.extend(additional_warnings) + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py new file mode 100644 index 00000000..a1e540bc --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py @@ -0,0 +1,597 @@ +#!/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: ios_interface +author: Ganesh Nalawade (@ganeshrn) +short_description: (deprecated, removed after 2022-06-01) Manage Interface on Cisco + IOS network devices +description: +- This module provides declarative management of Interfaces on Cisco IOS network devices. +version_added: 1.0.0 +deprecated: + alternative: ios_interfaces + why: Newer and updated modules released with more functionality in Ansible 2.9 + removed_at_date: '2022-06-01' +notes: +- Tested against IOS 15.6 +options: + name: + description: + - Name of the Interface. + type: str + description: + description: + - Description of Interface. + type: str + enabled: + description: + - Interface link status. + default: True + type: bool + speed: + description: + - Interface link speed. + type: str + mtu: + description: + - Maximum size of transmit packet. + type: str + duplex: + description: + - Interface link status + type: str + choices: + - full + - half + - auto + tx_rate: + description: + - Transmit rate in bits per second (bps). + - This is state check parameter only. + - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) + type: str + rx_rate: + description: + - Receiver rate in bits per second (bps). + - This is state check parameter only. + - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) + type: str + neighbors: + description: + - Check the operational state of given interface C(name) for CDP/LLDP neighbor. + - The following suboptions are available. + type: list + elements: dict + suboptions: + host: + description: + - CDP/LLDP neighbor host for given interface C(name). + type: str + port: + description: + - CDP/LLDP neighbor port to which given interface C(name) is connected. + type: str + aggregate: + description: List of Interfaces definitions. + type: list + elements: dict + suboptions: + name: + description: + - Name of the Interface. + required: true + type: str + description: + description: + - Description of Interface. + type: str + enabled: + description: + - Interface link status. + type: bool + speed: + description: + - Interface link speed. + type: str + mtu: + description: + - Maximum size of transmit packet. + type: str + duplex: + description: + - Interface link status + choices: + - full + - half + - auto + type: str + tx_rate: + description: + - Transmit rate in bits per second (bps). + - This is state check parameter only. + - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) + type: str + rx_rate: + description: + - Receiver rate in bits per second (bps). + - This is state check parameter only. + - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) + type: str + neighbors: + description: + - Check the operational state of given interface C(name) for CDP/LLDP neighbor. + - The following suboptions are available. + type: list + elements: dict + suboptions: + host: + description: + - CDP/LLDP neighbor host for given interface C(name). + type: str + port: + description: + - CDP/LLDP neighbor port to which given interface C(name) is connected. + type: str + delay: + description: + - Time in seconds to wait before checking for the operational state on remote + device. This wait is applicable for operational state argument which are I(state) + with values C(up)/C(down), I(tx_rate) and I(rx_rate). + type: int + state: + description: + - State of the Interface configuration, C(up) means present and operationally + up and C(down) means present and operationally C(down) + choices: + - present + - absent + - up + - down + type: str + delay: + description: + - Time in seconds to wait before checking for the operational state on remote + device. This wait is applicable for operational state argument which are I(state) + with values C(up)/C(down), I(tx_rate) and I(rx_rate). + default: 10 + type: int + state: + description: + - State of the Interface configuration, C(up) means present and operationally + up and C(down) means present and operationally C(down) + default: present + choices: + - present + - absent + - up + - down + type: str +extends_documentation_fragment: +- cisco.ios.ios + + +""" +EXAMPLES = """ +- name: configure interface + cisco.ios.ios_interface: + name: GigabitEthernet0/2 + description: test-interface + speed: 100 + duplex: half + mtu: 512 + +- name: remove interface + cisco.ios.ios_interface: + name: Loopback9 + state: absent + +- name: make interface up + cisco.ios.ios_interface: + name: GigabitEthernet0/2 + enabled: true + +- name: make interface down + cisco.ios.ios_interface: + name: GigabitEthernet0/2 + enabled: false + +- name: Check intent arguments + cisco.ios.ios_interface: + name: GigabitEthernet0/2 + state: up + tx_rate: ge(0) + rx_rate: le(0) + +- name: Check neighbors intent arguments + cisco.ios.ios_interface: + name: Gi0/0 + neighbors: + - port: eth0 + host: netdev + +- name: Config + intent + cisco.ios.ios_interface: + name: GigabitEthernet0/2 + enabled: false + state: down + +- name: Add interface using aggregate + cisco.ios.ios_interface: + aggregate: + - {name: GigabitEthernet0/1, mtu: 256, description: test-interface-1} + - {name: GigabitEthernet0/2, mtu: 516, description: test-interface-2} + duplex: full + speed: 100 + state: present + +- name: Delete interface using aggregate + cisco.ios.ios_interface: + aggregate: + - name: Loopback9 + - name: Loopback10 + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device. + returned: always, except for the platforms that use Netconf transport to manage the device. + type: list + sample: + - interface GigabitEthernet0/2 + - description test-interface + - duplex half + - mtu 512 +""" +import re +from copy import deepcopy +from time import sleep +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import exec_command +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + conditional, + remove_default_spec, +) + + +def validate_mtu(value, module): + if value and not 64 <= int(value) <= 9600: + module.fail_json(msg="mtu must be between 64 and 9600") + + +def validate_param_values(module, obj, param=None): + if param is None: + param = module.params + for key in obj: + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if callable(validator): + validator(param.get(key), module) + + +def parse_shutdown(configobj, name): + cfg = configobj["interface %s" % name] + cfg = "\n".join(cfg.children) + match = re.search("^shutdown", cfg, re.M) + if match: + return True + else: + return False + + +def parse_config_argument(configobj, name, arg=None): + cfg = configobj["interface %s" % name] + cfg = "\n".join(cfg.children) + match = re.search("%s (.+)$" % arg, cfg, re.M) + if match: + return match.group(1) + + +def search_obj_in_list(name, lst): + for o in lst: + if o["name"] == name: + return o + return None + + +def add_command_to_interface(interface, cmd, commands): + if interface not in commands: + commands.append(interface) + commands.append(cmd) + + +def map_config_to_obj(module): + config = get_config(module) + configobj = NetworkConfig(indent=1, contents=config) + match = re.findall("^interface (\\S+)", config, re.M) + if not match: + return list() + instances = list() + for item in set(match): + obj = { + "name": item, + "description": parse_config_argument( + configobj, item, "description" + ), + "speed": parse_config_argument(configobj, item, "speed"), + "duplex": parse_config_argument(configobj, item, "duplex"), + "mtu": parse_config_argument(configobj, item, "mtu"), + "disable": True if parse_shutdown(configobj, item) else False, + "state": "present", + } + instances.append(obj) + return instances + + +def map_params_to_obj(module): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + validate_param_values(module, item, item) + d = item.copy() + if d["enabled"]: + d["disable"] = False + else: + d["disable"] = True + obj.append(d) + else: + params = { + "name": module.params["name"], + "description": module.params["description"], + "speed": module.params["speed"], + "mtu": module.params["mtu"], + "duplex": module.params["duplex"], + "state": module.params["state"], + "delay": module.params["delay"], + "tx_rate": module.params["tx_rate"], + "rx_rate": module.params["rx_rate"], + "neighbors": module.params["neighbors"], + } + validate_param_values(module, params) + if module.params["enabled"]: + params.update({"disable": False}) + else: + params.update({"disable": True}) + obj.append(params) + return obj + + +def map_obj_to_commands(updates): + commands = list() + want, have = updates + args = "speed", "description", "duplex", "mtu" + for w in want: + name = w["name"] + disable = w["disable"] + state = w["state"] + obj_in_have = search_obj_in_list(name, have) + interface = "interface " + name + if state == "absent" and obj_in_have: + commands.append("no " + interface) + elif state in ("present", "up", "down"): + if obj_in_have: + for item in args: + candidate = w.get(item) + running = obj_in_have.get(item) + if candidate != running: + if candidate: + cmd = item + " " + str(candidate) + add_command_to_interface(interface, cmd, commands) + if disable and not obj_in_have.get("disable", False): + add_command_to_interface(interface, "shutdown", commands) + elif not disable and obj_in_have.get("disable", False): + add_command_to_interface( + interface, "no shutdown", commands + ) + else: + commands.append(interface) + for item in args: + value = w.get(item) + if value: + commands.append(item + " " + str(value)) + if disable: + commands.append("no shutdown") + return commands + + +def check_declarative_intent_params(module, want, result): + failed_conditions = [] + have_neighbors_lldp = None + have_neighbors_cdp = None + for w in want: + want_state = w.get("state") + want_tx_rate = w.get("tx_rate") + want_rx_rate = w.get("rx_rate") + want_neighbors = w.get("neighbors") + if ( + want_state not in ("up", "down") + and not want_tx_rate + and not want_rx_rate + and not want_neighbors + ): + continue + if result["changed"]: + sleep(w["delay"]) + command = "show interfaces %s" % w["name"] + rc, out, err = exec_command(module, command) + if rc != 0: + module.fail_json( + msg=to_text(err, errors="surrogate_then_replace"), + command=command, + rc=rc, + ) + if want_state in ("up", "down"): + match = re.search("%s (\\w+)" % "line protocol is", out, re.M) + have_state = None + if match: + have_state = match.group(1) + if have_state is None or not conditional( + want_state, have_state.strip() + ): + failed_conditions.append("state " + "eq(%s)" % want_state) + if want_tx_rate: + match = re.search("%s (\\d+)" % "output rate", out, re.M) + have_tx_rate = None + if match: + have_tx_rate = match.group(1) + if have_tx_rate is None or not conditional( + want_tx_rate, have_tx_rate.strip(), cast=int + ): + failed_conditions.append("tx_rate " + want_tx_rate) + if want_rx_rate: + match = re.search("%s (\\d+)" % "input rate", out, re.M) + have_rx_rate = None + if match: + have_rx_rate = match.group(1) + if have_rx_rate is None or not conditional( + want_rx_rate, have_rx_rate.strip(), cast=int + ): + failed_conditions.append("rx_rate " + want_rx_rate) + if want_neighbors: + have_host = [] + have_port = [] + + # Process LLDP neighbors + if have_neighbors_lldp is None: + rc, have_neighbors_lldp, err = exec_command( + module, "show lldp neighbors detail" + ) + if rc != 0: + module.fail_json( + msg=to_text(err, errors="surrogate_then_replace"), + command=command, + rc=rc, + ) + if have_neighbors_lldp: + lines = have_neighbors_lldp.strip().split("Local Intf: ") + for line in lines: + field = line.split("\n") + if field[0].strip() == w["name"]: + for item in field: + if item.startswith("System Name:"): + have_host.append(item.split(":")[1].strip()) + if item.startswith("Port Description:"): + have_port.append(item.split(":")[1].strip()) + # Process CDP neighbors + if have_neighbors_cdp is None: + rc, have_neighbors_cdp, err = exec_command( + module, "show cdp neighbors detail" + ) + if rc != 0: + module.fail_json( + msg=to_text(err, errors="surrogate_then_replace"), + command=command, + rc=rc, + ) + if have_neighbors_cdp: + neighbors_cdp = re.findall( + """Device ID: (.*?) +.*?Interface: (.*?), Port ID .outgoing port.: (.*?) +""", + have_neighbors_cdp, + re.S, + ) + for host, localif, remoteif in neighbors_cdp: + if localif == w["name"]: + have_host.append(host) + have_port.append(remoteif) + for item in want_neighbors: + host = item.get("host") + port = item.get("port") + if host and host not in have_host: + failed_conditions.append("host " + host) + if port and port not in have_port: + failed_conditions.append("port " + port) + return failed_conditions + + +def main(): + """ main entry point for module execution + """ + neighbors_spec = dict(host=dict(), port=dict()) + element_spec = dict( + name=dict(), + description=dict(), + speed=dict(), + mtu=dict(), + duplex=dict(choices=["full", "half", "auto"]), + enabled=dict(default=True, type="bool"), + tx_rate=dict(), + rx_rate=dict(), + neighbors=dict(type="list", elements="dict", options=neighbors_spec), + delay=dict(default=10, type="int"), + state=dict( + default="present", choices=["present", "absent", "up", "down"] + ), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["name"] = dict(required=True) + + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec) + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + required_one_of = [["name", "aggregate"]] + mutually_exclusive = [["name", "aggregate"]] + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have)) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + failed_conditions = check_declarative_intent_params(module, want, result) + if failed_conditions: + msg = "One or more conditional statements have not been satisfied" + module.fail_json(msg=msg, failed_conditions=failed_conditions) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py new file mode 100644 index 00000000..aeb1561d --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py @@ -0,0 +1,568 @@ +#!/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/>. +# +""" +The module file for ios_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: ios_interfaces +short_description: Interfaces resource module +description: This module manages the interface attributes of Cisco IOS network devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL +options: + config: + description: A dictionary of interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of interface, e.g. GigabitEthernet0/2, loopback999. + type: str + required: true + description: + description: + - Interface description. + type: str + enabled: + description: + - Administrative state of the interface. + - Set the value to C(true) to administratively enable the interface or C(false) + to disable it. + type: bool + default: true + speed: + description: + - Interface link speed. Applicable for Ethernet interfaces only. + type: str + mtu: + description: + - MTU for a specific interface. Applicable for Ethernet interfaces only. + - Refer to vendor documentation for valid values. + type: int + duplex: + description: + - Interface link status. Applicable for Ethernet interfaces only, either in + half duplex, full duplex or in automatic state which negotiates the duplex + automatically. + type: str + choices: + - full + - half + - auto + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show running-config | section ^interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str +""" + +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# no ip address +# duplex auto +# speed auto + +- name: Merge provided configuration with device configuration + cisco.ios.ios_interfaces: + config: + - name: GigabitEthernet0/2 + description: Configured and Merged by Ansible Network + enabled: true + - name: GigabitEthernet0/3 + description: Configured and Merged by Ansible Network + mtu: 2800 + enabled: false + speed: 100 + duplex: full + state: merged + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured and Merged by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured and Merged by Ansible Network +# mtu 2800 +# no ip address +# shutdown +# duplex full +# speed 100 + +# Using replaced + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# mtu 2000 +# no ip address +# shutdown +# duplex full +# speed 100 + +- name: Replaces device configuration of listed interfaces with provided configuration + cisco.ios.ios_interfaces: + config: + - name: GigabitEthernet0/3 + description: Configured and Replaced by Ansible Network + enabled: false + duplex: auto + mtu: 2500 + speed: 1000 + state: replaced + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured and Replaced by Ansible Network +# mtu 2500 +# no ip address +# shutdown +# duplex full +# speed 1000 + +# Using overridden + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface# +# interface GigabitEthernet0/1 +# description Configured by Ansible +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible +# mtu 2800 +# no ip address +# shutdown +# duplex full +# speed 100 + +- name: Override device configuration of all interfaces with provided configuration + cisco.ios.ios_interfaces: + config: + - name: GigabitEthernet0/2 + description: Configured and Overridden by Ansible Network + speed: 1000 + - name: GigabitEthernet0/3 + description: Configured and Overridden by Ansible Network + enabled: false + duplex: full + mtu: 2000 + state: overridden + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured and Overridden by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured and Overridden by Ansible Network +# mtu 2000 +# no ip address +# shutdown +# duplex full +# speed 100 + +# Using Deleted + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# mtu 2500 +# no ip address +# shutdown +# duplex full +# speed 1000 + +- name: "Delete module attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_interfaces: + config: + - name: GigabitEthernet0/2 + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# mtu 2500 +# no ip address +# shutdown +# duplex full +# speed 1000 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured resource module attributes from each configured interface)" + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# mtu 2500 +# no ip address +# shutdown +# duplex full +# speed 1000 + +- name: "Delete module attributes of all interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_interfaces: + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/3 +# no ip address +# duplex auto +# speed auto + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# description this is interface1 +# mtu 65 +# duplex auto +# speed 10 +# interface GigabitEthernet0/2 +# description this is interface2 +# mtu 110 +# shutdown +# duplex auto +# speed 100 + +- name: Gather listed interfaces with provided configurations + cisco.ios.ios_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "description": "this is interface1", +# "duplex": "auto", +# "enabled": true, +# "mtu": 65, +# "name": "GigabitEthernet0/1", +# "speed": "10" +# }, +# { +# "description": "this is interface2", +# "duplex": "auto", +# "enabled": false, +# "mtu": 110, +# "name": "GigabitEthernet0/2", +# "speed": "100" +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# description this is interface1 +# mtu 65 +# duplex auto +# speed 10 +# interface GigabitEthernet0/2 +# description this is interface2 +# mtu 110 +# shutdown +# duplex auto +# speed 100 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_interfaces: + config: + - name: GigabitEthernet0/1 + description: Configured by Ansible-Network + mtu: 110 + enabled: true + duplex: half + - name: GigabitEthernet0/2 + description: Configured by Ansible-Network + mtu: 2800 + enabled: false + speed: 100 + duplex: full + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "description Configured by Ansible-Network", +# "mtu 110", +# "duplex half", +# "no shutdown", +# "interface GigabitEthernet0/2", +# "description Configured by Ansible-Network", +# "mtu 2800", +# "speed 100", +# "duplex full", +# "shutdown" + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# description interfaces 0/1 +# mtu 110 +# duplex half +# no shutdown +# interface GigabitEthernet0/2 +# description interfaces 0/2 +# mtu 2800 +# speed 100 +# duplex full +# shutdown + +- name: Parse the commands for provided configuration + cisco.ios.ios_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "description": "interfaces 0/1", +# "duplex": "half", +# "enabled": true, +# "mtu": 110, +# "name": "GigabitEthernet0/1" +# }, +# { +# "description": "interfaces 0/2", +# "duplex": "full", +# "enabled": true, +# "mtu": 2800, +# "name": "GigabitEthernet0/2", +# "speed": "100" +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet 0/1', 'description This is test', 'speed 100'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.interfaces.interfaces import ( + InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.interfaces.interfaces import ( + Interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py new file mode 100644 index 00000000..dfe8ca63 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py @@ -0,0 +1,581 @@ +#!/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: ios_l2_interface +extends_documentation_fragment: +- cisco.ios.ios +short_description: (deprecated, removed after 2022-06-01) Manage Layer-2 interface + on Cisco IOS devices. +description: +- This module provides declarative management of Layer-2 interfaces on Cisco IOS devices. +version_added: 1.0.0 +deprecated: + alternative: ios_l2_interfaces + why: Newer and updated modules released with more functionality in Ansible 2.9 + removed_at_date: '2022-06-01' +author: +- Nathaniel Case (@Qalthos) +options: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + aliases: + - interface + type: str + mode: + description: + - Mode in which interface needs to be configured. + choices: + - access + - trunk + type: str + access_vlan: + description: + - Configure given VLAN in access port. If C(mode=access), used as the access VLAN + ID. + type: str + trunk_vlans: + description: + - List of VLANs to be configured in trunk port. If C(mode=trunk), used as the + VLAN range to ADD or REMOVE from the trunk. + type: str + native_vlan: + description: + - Native VLAN to be configured in trunk port. If C(mode=trunk), used as the trunk + native VLAN ID. + type: str + trunk_allowed_vlans: + description: + - List of allowed VLANs in a given trunk port. If C(mode=trunk), these are the + only VLANs that will be configured on the trunk, i.e. "2-10,15". + type: str + aggregate: + description: + - List of Layer-2 interface definitions. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + aliases: + - interface + type: str + mode: + description: + - Mode in which interface needs to be configured. + choices: + - access + - trunk + type: str + access_vlan: + description: + - Configure given VLAN in access port. If C(mode=access), used as the access VLAN + ID. + type: str + trunk_vlans: + description: + - List of VLANs to be configured in trunk port. If C(mode=trunk), used as the + VLAN range to ADD or REMOVE from the trunk. + type: str + native_vlan: + description: + - Native VLAN to be configured in trunk port. If C(mode=trunk), used as the trunk + native VLAN ID. + type: str + trunk_allowed_vlans: + description: + - List of allowed VLANs in a given trunk port. If C(mode=trunk), these are the + only VLANs that will be configured on the trunk, i.e. "2-10,15". + type: str + state: + description: + - Manage the state of the Layer-2 Interface configuration. + choices: + - present + - absent + - unconfigured + type: str + state: + description: + - Manage the state of the Layer-2 Interface configuration. + default: present + choices: + - present + - absent + - unconfigured + type: str + +""" +EXAMPLES = """ +- name: Ensure GigabitEthernet0/5 is in its default l2 interface state + ios.ios_l2_interface: + name: GigabitEthernet0/5 + state: unconfigured +- name: Ensure GigabitEthernet0/5 is configured for access vlan 20 + ios.ios_l2_interface: + name: GigabitEthernet0/5 + mode: access + access_vlan: 20 +- name: Ensure GigabitEthernet0/5 only has vlans 5-10 as trunk vlans + ios.ios_l2_interface: + name: GigabitEthernet0/5 + mode: trunk + native_vlan: 10 + trunk_allowed_vlans: 5-10 +- name: Ensure GigabitEthernet0/5 is a trunk port and ensure 2-50 are being tagged + (doesn't mean others aren't also being tagged) + ios.ios_l2_interface: + name: GigabitEthernet0/5 + mode: trunk + native_vlan: 10 + trunk_vlans: 2-50 +- name: Ensure these VLANs are not being tagged on the trunk + ios.ios_l2_interface: + name: GigabitEthernet0/5 + mode: trunk + trunk_vlans: 51-4094 + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always, except for the platforms that use Netconf transport to manage the device. + type: list + sample: + - interface GigabitEthernet0/5 + - switchport access vlan 20 +""" +import re +from copy import deepcopy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + load_config, + run_commands, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def get_interface_type(interface): + intf_type = "unknown" + if interface.upper()[:2] in ( + "ET", + "GI", + "FA", + "TE", + "FO", + "HU", + "TWE", + "TW", + ): + intf_type = "ethernet" + elif interface.upper().startswith("VL"): + intf_type = "svi" + elif interface.upper().startswith("LO"): + intf_type = "loopback" + elif interface.upper()[:2] in ("MG", "MA"): + intf_type = "management" + elif interface.upper().startswith("PO"): + intf_type = "portchannel" + elif interface.upper().startswith("NV"): + intf_type = "nve" + return intf_type + + +def is_switchport(name, module): + intf_type = get_interface_type(name) + if intf_type in ("ethernet", "portchannel"): + config = run_commands( + module, ["show interface {0} switchport".format(name)] + )[0] + match = re.search("Switchport: Enabled", config) + return bool(match) + return False + + +def interface_is_portchannel(name, module): + if get_interface_type(name) == "ethernet": + config = run_commands(module, ["show run interface {0}".format(name)])[ + 0 + ] + if any(c in config for c in ["channel group", "channel-group"]): + return True + return False + + +def get_switchport(name, module): + config = run_commands( + module, ["show interface {0} switchport".format(name)] + )[0] + mode = re.search("Administrative Mode: (?:.* )?(\\w+)$", config, re.M) + access = re.search("Access Mode VLAN: (\\d+)", config) + native = re.search("Trunking Native Mode VLAN: (\\d+)", config) + trunk = re.search("Trunking VLANs Enabled: (.+)$", config, re.M) + if mode: + mode = mode.group(1) + if access: + access = access.group(1) + if native: + native = native.group(1) + if trunk: + trunk = trunk.group(1) + if trunk == "ALL": + trunk = "1-4094" + switchport_config = { + "interface": name, + "mode": mode, + "access_vlan": access, + "native_vlan": native, + "trunk_vlans": trunk, + } + return switchport_config + + +def remove_switchport_config_commands(name, existing, proposed, module): + mode = proposed.get("mode") + commands = [] + command = None + if mode == "access": + av_check = existing.get("access_vlan") == proposed.get("access_vlan") + if av_check: + command = "no switchport access vlan {0}".format( + existing.get("access_vlan") + ) + commands.append(command) + elif mode == "trunk": + # Supported Remove Scenarios for trunk_vlans_list + # 1) Existing: 1,2,3 Proposed: 1,2,3 - Remove all + # 2) Existing: 1,2,3 Proposed: 1,2 - Remove 1,2 Leave 3 + # 3) Existing: 1,2,3 Proposed: 2,3 - Remove 2,3 Leave 1 + # 4) Existing: 1,2,3 Proposed: 4,5,6 - None removed. + # 5) Existing: None Proposed: 1,2,3 - None removed. + existing_vlans = existing.get("trunk_vlans_list") + proposed_vlans = proposed.get("trunk_vlans_list") + vlans_to_remove = set(proposed_vlans).intersection(existing_vlans) + if vlans_to_remove: + proposed_allowed_vlans = proposed.get("trunk_allowed_vlans") + remove_trunk_allowed_vlans = proposed.get( + "trunk_vlans", proposed_allowed_vlans + ) + command = "switchport trunk allowed vlan remove {0}".format( + remove_trunk_allowed_vlans + ) + commands.append(command) + native_check = existing.get("native_vlan") == proposed.get( + "native_vlan" + ) + if native_check and proposed.get("native_vlan"): + command = "no switchport trunk native vlan {0}".format( + existing.get("native_vlan") + ) + commands.append(command) + if commands: + commands.insert(0, "interface " + name) + return commands + + +def get_switchport_config_commands(name, existing, proposed, module): + """Gets commands required to config a given switchport interface + """ + proposed_mode = proposed.get("mode") + existing_mode = existing.get("mode") + commands = [] + command = None + if proposed_mode != existing_mode: + if proposed_mode == "trunk": + command = "switchport mode trunk" + elif proposed_mode == "access": + command = "switchport mode access" + if command: + commands.append(command) + if proposed_mode == "access": + av_check = str(existing.get("access_vlan")) == str( + proposed.get("access_vlan") + ) + if not av_check: + command = "switchport access vlan {0}".format( + proposed.get("access_vlan") + ) + commands.append(command) + elif proposed_mode == "trunk": + tv_check = existing.get("trunk_vlans_list") == proposed.get( + "trunk_vlans_list" + ) + if not tv_check: + if proposed.get("allowed"): + command = "switchport trunk allowed vlan {0}".format( + proposed.get("trunk_allowed_vlans") + ) + commands.append(command) + else: + existing_vlans = existing.get("trunk_vlans_list") + proposed_vlans = proposed.get("trunk_vlans_list") + vlans_to_add = set(proposed_vlans).difference(existing_vlans) + if vlans_to_add: + command = "switchport trunk allowed vlan add {0}".format( + proposed.get("trunk_vlans") + ) + commands.append(command) + native_check = str(existing.get("native_vlan")) == str( + proposed.get("native_vlan") + ) + if not native_check and proposed.get("native_vlan"): + command = "switchport trunk native vlan {0}".format( + proposed.get("native_vlan") + ) + commands.append(command) + if commands: + commands.insert(0, "interface " + name) + return commands + + +def is_switchport_default(existing): + """Determines if switchport has a default config based on mode + Args: + existing (dict): existing switchport configuration from Ansible mod + Returns: + boolean: True if switchport has OOB Layer 2 config, i.e. + vlan 1 and trunk all and mode is access + """ + c1 = str(existing["access_vlan"]) == "1" + c2 = str(existing["native_vlan"]) == "1" + c3 = existing["trunk_vlans"] == "1-4094" + c4 = existing["mode"] == "access" + default = c1 and c2 and c3 and c4 + return default + + +def default_switchport_config(name): + commands = [] + commands.append("interface " + name) + commands.append("switchport mode access") + commands.append("switch access vlan 1") + commands.append("switchport trunk native vlan 1") + commands.append("switchport trunk allowed vlan all") + return commands + + +def vlan_range_to_list(vlans): + result = [] + if vlans: + for part in vlans.split(","): + if part.lower() == "none": + break + if part: + if "-" in part: + start, stop = (int(i) for i in part.split("-")) + result.extend(range(start, stop + 1)) + else: + result.append(int(part)) + return sorted(result) + + +def get_list_of_vlans(module): + config = run_commands(module, ["show vlan"])[0] + vlans = set() + lines = config.strip().splitlines() + for line in lines: + line_parts = line.split() + if line_parts: + try: + int(line_parts[0]) + except ValueError: + continue + vlans.add(line_parts[0]) + return list(vlans) + + +def flatten_list(commands): + flat_list = [] + for command in commands: + if isinstance(command, list): + flat_list.extend(command) + else: + flat_list.append(command) + return flat_list + + +def map_params_to_obj(module): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + obj.append(item.copy()) + else: + obj.append( + { + "name": module.params["name"], + "mode": module.params["mode"], + "access_vlan": module.params["access_vlan"], + "native_vlan": module.params["native_vlan"], + "trunk_vlans": module.params["trunk_vlans"], + "trunk_allowed_vlans": module.params["trunk_allowed_vlans"], + "state": module.params["state"], + } + ) + return obj + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + name=dict(type="str", aliases=["interface"]), + mode=dict(choices=["access", "trunk"]), + access_vlan=dict(type="str"), + native_vlan=dict(type="str"), + trunk_vlans=dict(type="str"), + trunk_allowed_vlans=dict(type="str"), + state=dict( + choices=["absent", "present", "unconfigured"], default="present" + ), + ) + aggregate_spec = deepcopy(element_spec) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec) + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=[ + ["access_vlan", "trunk_vlans"], + ["access_vlan", "native_vlan"], + ["access_vlan", "trunk_allowed_vlans"], + ], + supports_check_mode=True, + ) + warnings = list() + commands = [] + result = {"changed": False, "warnings": warnings} + want = map_params_to_obj(module) + for w in want: + name = w["name"] + mode = w["mode"] + access_vlan = w["access_vlan"] + state = w["state"] + trunk_vlans = w["trunk_vlans"] + native_vlan = w["native_vlan"] + trunk_allowed_vlans = w["trunk_allowed_vlans"] + args = dict( + name=name, + mode=mode, + access_vlan=access_vlan, + native_vlan=native_vlan, + trunk_vlans=trunk_vlans, + trunk_allowed_vlans=trunk_allowed_vlans, + ) + proposed = dict((k, v) for k, v in args.items() if v is not None) + name = name.lower() + if mode == "access" and state == "present" and not access_vlan: + module.fail_json( + msg="access_vlan param is required when mode=access && state=present" + ) + if mode == "trunk" and access_vlan: + module.fail_json( + msg="access_vlan param not supported when using mode=trunk" + ) + if not is_switchport(name, module): + module.fail_json( + msg="""Ensure interface is configured to be a L2 +port first before using this module. You can use +the ios_interface module for this.""" + ) + if interface_is_portchannel(name, module): + module.fail_json( + msg="""Cannot change L2 config on physical +port because it is in a portchannel. +You should update the portchannel config.""" + ) + # existing will never be null for Eth intfs as there is always a default + existing = get_switchport(name, module) + # Safeguard check + # If there isn't an existing, something is wrong per previous comment + if not existing: + module.fail_json( + msg="Make sure you are using the FULL interface name" + ) + if trunk_vlans or trunk_allowed_vlans: + if trunk_vlans: + trunk_vlans_list = vlan_range_to_list(trunk_vlans) + elif trunk_allowed_vlans: + trunk_vlans_list = vlan_range_to_list(trunk_allowed_vlans) + proposed["allowed"] = True + existing_trunks_list = vlan_range_to_list(existing["trunk_vlans"]) + existing["trunk_vlans_list"] = existing_trunks_list + proposed["trunk_vlans_list"] = trunk_vlans_list + current_vlans = get_list_of_vlans(module) + if state == "present": + if access_vlan and access_vlan not in current_vlans: + module.fail_json( + msg="""You are trying to configure a VLAN on an interface that +does not exist on the switch yet!""", + vlan=access_vlan, + ) + elif native_vlan and native_vlan not in current_vlans: + module.fail_json( + msg="""You are trying to configure a VLAN on an interface that +does not exist on the switch yet!""", + vlan=native_vlan, + ) + else: + command = get_switchport_config_commands( + name, existing, proposed, module + ) + commands.append(command) + elif state == "unconfigured": + is_default = is_switchport_default(existing) + if not is_default: + command = default_switchport_config(name) + commands.append(command) + elif state == "absent": + command = remove_switchport_config_commands( + name, existing, proposed, module + ) + commands.append(command) + if trunk_vlans or trunk_allowed_vlans: + existing.pop("trunk_vlans_list") + proposed.pop("trunk_vlans_list") + cmds = flatten_list(commands) + if cmds: + if module.check_mode: + module.exit_json(changed=True, commands=cmds) + else: + result["changed"] = True + load_config(module, cmds) + if "configure" in cmds: + cmds.pop(0) + result["commands"] = cmds + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py new file mode 100644 index 00000000..08b208d4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py @@ -0,0 +1,560 @@ +#!/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/>. +# +""" +The module file for ios_l2_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_l2_interfaces +short_description: L2 interfaces resource module +description: This module provides declarative management of Layer-2 interface on Cisco + IOS devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of Layer-2 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + type: str + required: true + access: + description: + - Switchport mode access command to configure the interface as a layer 2 access. + type: dict + suboptions: + vlan: + description: + - Configure given VLAN in access port. It's used as the access VLAN ID. + type: int + voice: + description: + - Switchport mode voice command to configure the interface with a voice vlan. + type: dict + suboptions: + vlan: + description: + - Configure given voice VLAN on access port. It's used as the voice VLAN + ID. + type: int + trunk: + description: + - Switchport mode trunk command to configure the interface as a Layer 2 trunk. + Note The encapsulation is always set to dot1q. + type: dict + suboptions: + allowed_vlans: + description: + - List of allowed VLANs in a given trunk port. These are the only VLANs + that will be configured on the trunk. + type: list + elements: str + native_vlan: + description: + - Native VLAN to be configured in trunk port. It's used as the trunk native + VLAN ID. + type: int + encapsulation: + description: + - Trunking encapsulation when interface is in trunking mode. + choices: + - dot1q + - isl + - negotiate + type: str + pruning_vlans: + description: + - Pruning VLAN to be configured in trunk port. It's used as the trunk + pruning VLAN ID. + type: list + elements: str + mode: + description: + - Mode in which interface needs to be configured. + - An interface whose trunk encapsulation is "Auto" can not be configured to + "trunk" mode. + type: str + choices: + - access + - trunk + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show running-config | section ^interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + +""" + +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# media-type rj45 +# negotiation auto + +- name: Merge provided configuration with device configuration + cisco.ios.ios_l2_interfaces: + config: + - name: GigabitEthernet0/1 + mode: access + access: + vlan: 10 + voice: + vlan: 40 + - name: GigabitEthernet0/2 + mode: trunk + trunk: + allowed_vlans: 10-20,40 + native_vlan: 20 + pruning_vlans: 10,20 + encapsulation: dot1q + state: merged + +# After state: +# ------------ +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport access vlan 10 +# switchport voice vlan 40 +# switchport mode access +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport trunk allowed vlan 10-20,40 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 20 +# switchport trunk pruning vlan 10,20 +# switchport mode trunk +# media-type rj45 +# negotiation auto + +# Using replaced + +# Before state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport access vlan 20 +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# media-type rj45 +# negotiation auto + +- name: Replaces device configuration of listed l2 interfaces with provided configuration + cisco.ios.ios_l2_interfaces: + config: + - name: GigabitEthernet0/2 + trunk: + allowed_vlans: 20-25,40 + native_vlan: 20 + pruning_vlans: 10 + encapsulation: isl + state: replaced + +# After state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport access vlan 20 +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport trunk allowed vlan 20-25,40 +# switchport trunk encapsulation isl +# switchport trunk native vlan 20 +# switchport trunk pruning vlan 10 +# media-type rj45 +# negotiation auto + +# Using overridden + +# Before state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 20 +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 20 +# media-type rj45 +# negotiation auto + +- name: Override device configuration of all l2 interfaces with provided configuration + cisco.ios.ios_l2_interfaces: + config: + - name: GigabitEthernet0/2 + access: + vlan: 20 + voice: + vlan: 40 + state: overridden + +# After state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# switchport voice vlan 40 +# media-type rj45 +# negotiation auto + +# Using Deleted + +# Before state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport access vlan 20 +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# switchport trunk allowed vlan 20-40,60,80 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 10 +# switchport trunk pruning vlan 10 +# media-type rj45 +# negotiation auto + +- name: Delete IOS L2 interfaces as in given arguments + cisco.ios.ios_l2_interfaces: + config: + - name: GigabitEthernet0/1 + state: deleted + +# After state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# switchport trunk allowed vlan 20-40,60,80 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 10 +# switchport trunk pruning vlan 10 +# media-type rj45 +# negotiation auto + + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured resource module attributes from each configured interface)" + +# Before state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# switchport access vlan 20 +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# switchport access vlan 20 +# switchport trunk allowed vlan 20-40,60,80 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 10 +# switchport trunk pruning vlan 10 +# media-type rj45 +# negotiation auto + +- name: Delete IOS L2 interfaces as in given arguments + cisco.ios.ios_l2_interfaces: + state: deleted + +# After state: +# ------------- +# +# viosl2#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# negotiation auto +# interface GigabitEthernet0/2 +# description This is test +# media-type rj45 +# negotiation auto + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# switchport access vlan 10 +# interface GigabitEthernet0/2 +# switchport trunk allowed vlan 10-20,40 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 10 +# switchport trunk pruning vlan 10,20 +# switchport mode trunk + +- name: Gather listed l2 interfaces with provided configurations + cisco.ios.ios_l2_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "name": "GigabitEthernet0/0" +# }, +# { +# "access": { +# "vlan": 10 +# }, +# "name": "GigabitEthernet0/1" +# }, +# { +# "mode": "trunk", +# "name": "GigabitEthernet0/2", +# "trunk": { +# "allowed_vlans": [ +# "10-20", +# "40" +# ], +# "encapsulation": "dot1q", +# "native_vlan": 10, +# "pruning_vlans": [ +# "10", +# "20" +# ] +# } +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# switchport access vlan 10 +# interface GigabitEthernet0/2 +# switchport trunk allowed vlan 10-20,40 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 10 +# switchport trunk pruning vlan 10,20 +# switchport mode trunk + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_l2_interfaces: + config: + - name: GigabitEthernet0/1 + access: + vlan: 30 + - name: GigabitEthernet0/2 + trunk: + allowed_vlans: 10-20,40 + native_vlan: 20 + pruning_vlans: 10,20 + encapsulation: dot1q + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "switchport access vlan 30", +# "interface GigabitEthernet0/2", +# "switchport trunk encapsulation dot1q", +# "switchport trunk native vlan 20", +# "switchport trunk allowed vlan 10-20,40", +# "switchport trunk pruning vlan 10,20" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# switchport mode access +# switchport access vlan 30 +# interface GigabitEthernet0/2 +# switchport trunk allowed vlan 15-20,40 +# switchport trunk encapsulation dot1q +# switchport trunk native vlan 20 +# switchport trunk pruning vlan 10,20 + +- name: Parse the commands for provided configuration + cisco.ios.ios_l2_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "access": { +# "vlan": 30 +# }, +# "mode": "access", +# "name": "GigabitEthernet0/1" +# }, +# { +# "name": "GigabitEthernet0/2", +# "trunk": { +# "allowed_vlans": [ +# "15-20", +# "40" +# ], +# "encapsulation": "dot1q", +# "native_vlan": 20, +# "pruning_vlans": [ +# "10", +# "20" +# ] +# } +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/1', 'switchport access vlan 20'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import ( + L2_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.l2_interfaces.l2_interfaces import ( + L2_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=L2_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = L2_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py new file mode 100644 index 00000000..2a2b10a5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py @@ -0,0 +1,382 @@ +#!/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: ios_l3_interface +author: Ganesh Nalawade (@ganeshrn) +short_description: (deprecated, removed after 2022-06-01) Manage Layer-3 interfaces + on Cisco IOS network devices. +description: +- This module provides declarative management of Layer-3 interfaces on IOS network + devices. +version_added: 1.0.0 +deprecated: + alternative: ios_l3_interfaces + why: Newer and updated modules released with more functionality in Ansible 2.9 + removed_at_date: '2022-06-01' +notes: +- Tested against IOS 15.2 +options: + name: + description: + - Name of the Layer-3 interface to be configured eg. GigabitEthernet0/2 + type: str + ipv4: + description: + - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option. + The address format is <ipv4 address>/<mask>, the mask is number in range 0-32 + eg. 192.168.0.1/24 + type: str + ipv6: + description: + - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option. + The address format is <ipv6 address>/<mask>, the mask is number in range 0-128 + eg. fd5d:12c9:2201:1::1/64 + type: str + aggregate: + description: + - List of Layer-3 interfaces definitions. Each of the entry in aggregate list + should define name of interface C(name) and a optional C(ipv4) or C(ipv6) address. + type: list + elements: dict + suboptions: + name: + description: + - Name of the Layer-3 interface to be configured eg. GigabitEthernet0/2 + type: str + required: true + ipv4: + description: + - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option. + The address format is <ipv4 address>/<mask>, the mask is number in range 0-32 + eg. 192.168.0.1/24 + type: str + ipv6: + description: + - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option. + The address format is <ipv6 address>/<mask>, the mask is number in range 0-128 + eg. fd5d:12c9:2201:1::1/64 + type: str + state: + description: + - State of the Layer-3 interface configuration. It indicates if the configuration + should be present or absent on remote device. + type: str + choices: + - present + - absent + state: + description: + - State of the Layer-3 interface configuration. It indicates if the configuration + should be present or absent on remote device. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: +- cisco.ios.ios + + +""" +EXAMPLES = """ +- name: Remove GigabitEthernet0/3 IPv4 and IPv6 address + cisco.ios.ios_l3_interface: + name: GigabitEthernet0/3 + state: absent +- name: Set GigabitEthernet0/3 IPv4 address + cisco.ios.ios_l3_interface: + name: GigabitEthernet0/3 + ipv4: 192.168.0.1/24 +- name: Set GigabitEthernet0/3 IPv6 address + cisco.ios.ios_l3_interface: + name: GigabitEthernet0/3 + ipv6: fd5d:12c9:2201:1::1/64 +- name: Set GigabitEthernet0/3 in dhcp + cisco.ios.ios_l3_interface: + name: GigabitEthernet0/3 + ipv4: dhcp + ipv6: dhcp +- name: Set interface Vlan1 (SVI) IPv4 address + cisco.ios.ios_l3_interface: + name: Vlan1 + ipv4: 192.168.0.5/24 +- name: Set IP addresses on aggregate + cisco.ios.ios_l3_interface: + aggregate: + - name: GigabitEthernet0/3 + ipv4: 192.168.2.10/24 + - name: GigabitEthernet0/3 + ipv4: 192.168.3.10/24 + ipv6: fd5d:12c9:2201:1::1/64 +- name: Remove IP addresses on aggregate + cisco.ios.ios_l3_interface: + aggregate: + - name: GigabitEthernet0/3 + ipv4: 192.168.2.10/24 + - name: GigabitEthernet0/3 + ipv4: 192.168.3.10/24 + ipv6: fd5d:12c9:2201:1::1/64 + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always, except for the platforms that use Netconf transport to manage the device. + type: list + sample: + - interface GigabitEthernet0/2 + - ip address 192.168.0.1 255.255.255.0 + - ipv6 address fd5d:12c9:2201:1::1/64 +""" +import re +from copy import deepcopy +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + is_netmask, + is_masklen, + to_netmask, + to_masklen, +) + + +def validate_ipv4(value, module): + if value: + address = value.split("/") + if len(address) != 2: + module.fail_json( + msg="address format is <ipv4 address>/<mask>, got invalid format %s" + % value + ) + if not is_masklen(address[1]): + module.fail_json( + msg="invalid value for mask: %s, mask should be in range 0-32" + % address[1] + ) + + +def validate_ipv6(value, module): + if value: + address = value.split("/") + if len(address) != 2: + module.fail_json( + msg="address format is <ipv6 address>/<mask>, got invalid format %s" + % value + ) + elif not 0 <= int(address[1]) <= 128: + module.fail_json( + msg="invalid value for mask: %s, mask should be in range 0-128" + % address[1] + ) + + +def validate_param_values(module, obj, param=None): + if param is None: + param = module.params + for key in obj: + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if callable(validator): + validator(param.get(key), module) + + +def parse_config_argument(configobj, name, arg=None): + cfg = configobj["interface %s" % name] + cfg = "\n".join(cfg.children) + values = [] + matches = re.finditer("%s (.+)$" % arg, cfg, re.M) + for match in matches: + match_str = match.group(1).strip() + if arg == "ipv6 address": + values.append(match_str) + else: + values = match_str + break + return values or None + + +def search_obj_in_list(name, lst): + for o in lst: + if o["name"] == name: + return o + return None + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + for w in want: + name = w["name"] + ipv4 = w["ipv4"] + ipv6 = w["ipv6"] + state = w["state"] + interface = "interface " + name + commands.append(interface) + obj_in_have = search_obj_in_list(name, have) + if state == "absent" and obj_in_have: + if obj_in_have["ipv4"]: + if ipv4: + address = ipv4.split("/") + if len(address) == 2: + ipv4 = "{0} {1}".format( + address[0], to_netmask(address[1]) + ) + commands.append("no ip address {0}".format(ipv4)) + else: + commands.append("no ip address") + if obj_in_have["ipv6"]: + if ipv6: + commands.append("no ipv6 address {0}".format(ipv6)) + else: + commands.append("no ipv6 address") + if "dhcp" in obj_in_have["ipv6"]: + commands.append("no ipv6 address dhcp") + elif state == "present": + if ipv4: + if ( + obj_in_have is None + or obj_in_have.get("ipv4") is None + or ipv4 != obj_in_have["ipv4"] + ): + address = ipv4.split("/") + if len(address) == 2: + ipv4 = "{0} {1}".format( + address[0], to_netmask(address[1]) + ) + commands.append("ip address {0}".format(ipv4)) + if ipv6: + if ( + obj_in_have is None + or obj_in_have.get("ipv6") is None + or ipv6.lower() + not in [addr.lower() for addr in obj_in_have["ipv6"]] + ): + commands.append("ipv6 address {0}".format(ipv6)) + if commands[-1] == interface: + commands.pop(-1) + return commands + + +def map_config_to_obj(module): + config = get_config(module) + configobj = NetworkConfig(indent=1, contents=config) + match = re.findall("^interface (\\S+)", config, re.M) + if not match: + return list() + instances = list() + for item in set(match): + ipv4 = parse_config_argument(configobj, item, "ip address") + if ipv4: + address = ipv4.strip().split(" ") + if len(address) == 2 and is_netmask(address[1]): + ipv4 = "{0}/{1}".format( + address[0], to_text(to_masklen(address[1])) + ) + obj = { + "name": item, + "ipv4": ipv4, + "ipv6": parse_config_argument(configobj, item, "ipv6 address"), + "state": "present", + } + instances.append(obj) + return instances + + +def map_params_to_obj(module): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + validate_param_values(module, item, item) + obj.append(item.copy()) + else: + obj.append( + { + "name": module.params["name"], + "ipv4": module.params["ipv4"], + "ipv6": module.params["ipv6"], + "state": module.params["state"], + } + ) + validate_param_values(module, obj) + return obj + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + name=dict(), + ipv4=dict(), + ipv6=dict(), + state=dict(default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["name"] = dict(required=True) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec) + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + required_one_of = [["name", "aggregate"]] + mutually_exclusive = [["name", "aggregate"]] + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have), module) + result["commands"] = commands + if commands: + if not module.check_mode: + resp = load_config(module, commands) + warnings.extend(out for out in resp if out) + result["changed"] = True + if warnings: + result["warnings"] = warnings + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py new file mode 100644 index 00000000..0ea1bb3a --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py @@ -0,0 +1,605 @@ +#!/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/>. +# +""" +The module file for ios_l3_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_l3_interfaces +short_description: L3 interfaces resource module +description: +- This module provides declarative management of Layer-3 interface on Cisco IOS devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of Layer-3 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + type: str + required: true + ipv4: + description: + - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option. + The address format is <ipv4 address>/<mask>, the mask is number in range + 0-32 eg. 192.168.0.1/24. + type: list + elements: dict + suboptions: + address: + description: + - Configures the IPv4 address for Interface. + type: str + secondary: + description: + - Configures the IP address as a secondary address. + type: bool + dhcp_client: + description: + - Configures and specifies client-id to use over DHCP ip. Note, This option + shall work only when dhcp is configured as IP. + - GigabitEthernet interface number + type: int + dhcp_hostname: + description: + - Configures and specifies value for hostname option over DHCP ip. Note, + This option shall work only when dhcp is configured as IP. + type: str + ipv6: + description: + - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option. + - The address format is <ipv6 address>/<mask>, the mask is number in range + 0-128 eg. fd5d:12c9:2201:1::1/64 + type: list + elements: dict + suboptions: + address: + description: + - Configures the IPv6 address for Interface. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device + by executing the command B(show running-config | section ^interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command + I(show running-config | section ^interface) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# ip address 10.1.1.1 255.255.255.0 +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# no ip address +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 + +- name: Merge provided configuration with device configuration + cisco.ios.ios_l3_interfaces: + config: + - name: GigabitEthernet0/1 + ipv4: + - address: 192.168.0.1/24 + secondary: true + - name: GigabitEthernet0/2 + ipv4: + - address: 192.168.0.2/24 + - name: GigabitEthernet0/3 + ipv6: + - address: fd5d:12c9:2201:1::1/64 + - name: GigabitEthernet0/3.100 + ipv4: + - address: 192.168.0.3/24 + state: merged + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# ip address 10.1.1.1 255.255.255.0 +# ip address 192.168.0.1 255.255.255.0 secondary +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# ip address 192.168.0.2 255.255.255.0 +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ipv6 address FD5D:12C9:2201:1::1/64 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.3 255.255.255.0 + +# Using replaced +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# ip address 10.1.1.1 255.255.255.0 +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# no ip address +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ip address 192.168.2.0 255.255.255.0 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.2 255.255.255.0 + +- name: Replaces device configuration of listed interfaces with provided configuration + cisco.ios.ios_l3_interfaces: + config: + - name: GigabitEthernet0/2 + ipv4: + - address: 192.168.2.0/24 + - name: GigabitEthernet0/3 + ipv4: + - address: dhcp + dhcp_client: 2 + dhcp_hostname: test.com + - name: GigabitEthernet0/3.100 + ipv4: + - address: 192.168.0.3/24 + secondary: true + state: replaced + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# ip address 10.1.1.1 255.255.255.0 +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# ip address 192.168.2.1 255.255.255.0 +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ip address dhcp client-id GigabitEthernet0/2 hostname test.com +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.2 255.255.255.0 +# ip address 192.168.0.3 255.255.255.0 secondary + +# Using overridden +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# ip address 10.1.1.1 255.255.255.0 +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# ip address 192.168.2.1 255.255.255.0 +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ipv6 address FD5D:12C9:2201:1::1/64 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.2 255.255.255.0 + +- name: Override device configuration of all interfaces with provided configuration + cisco.ios.ios_l3_interfaces: + config: + - name: GigabitEthernet0/2 + ipv4: + - address: 192.168.0.1/24 + - name: GigabitEthernet0/3.100 + ipv6: + - address: autoconfig + state: overridden + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# description Configured by Ansible +# no ip address +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description This is test +# ip address 192.168.0.1 255.255.255.0 +# duplex auto +# speed 1000 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ipv6 address autoconfig + +# Using Deleted +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# ip address 192.0.2.10 255.255.255.0 +# shutdown +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# ip address 192.168.1.0 255.255.255.0 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ip address 192.168.0.1 255.255.255.0 +# shutdown +# duplex full +# speed 10 +# ipv6 address FD5D:12C9:2201:1::1/64 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.2 255.255.255.0 + +- name: "Delete attributes of given interfaces (NOTE: This won't delete the interface sitself)" + cisco.ios.ios_l3_interfaces: + config: + - name: GigabitEthernet0/2 + - name: GigabitEthernet0/3.100 + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# shutdown +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ip address 192.168.0.1 255.255.255.0 +# shutdown +# duplex full +# speed 10 +# ipv6 address FD5D:12C9:2201:1::1/64 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured L3 resource module attributes from each configured interface)" + +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# ip address 192.0.2.10 255.255.255.0 +# shutdown +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# ip address 192.168.1.0 255.255.255.0 +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# ip address 192.168.0.1 255.255.255.0 +# shutdown +# duplex full +# speed 10 +# ipv6 address FD5D:12C9:2201:1::1/64 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 +# ip address 192.168.0.2 255.255.255.0 + +- name: "Delete L3 attributes of ALL interfaces together (NOTE: This won't delete the interface itself)" + cisco.ios.ios_l3_interfaces: + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface GigabitEthernet0/1 +# no ip address +# shutdown +# duplex auto +# speed auto +# interface GigabitEthernet0/2 +# description Configured by Ansible Network +# no ip address +# interface GigabitEthernet0/3 +# description Configured by Ansible Network +# shutdown +# duplex full +# speed 10 +# interface GigabitEthernet0/3.100 +# encapsulation dot1Q 20 + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# ip address 203.0.113.27 255.255.255.0 +# interface GigabitEthernet0/2 +# ip address 192.0.2.1 255.255.255.0 secondary +# ip address 192.0.2.2 255.255.255.0 +# ipv6 address 2001:DB8:0:3::/64 + +- name: Gather listed l3 interfaces with provided configurations + cisco.ios.ios_l3_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "ipv4": [ +# { +# "address": "203.0.113.27 255.255.255.0" +# } +# ], +# "name": "GigabitEthernet0/1" +# }, +# { +# "ipv4": [ +# { +# "address": "192.0.2.1 255.255.255.0", +# "secondary": true +# }, +# { +# "address": "192.0.2.2 255.255.255.0" +# } +# ], +# "ipv6": [ +# { +# "address": "2001:db8:0:3::/64" +# } +# ], +# "name": "GigabitEthernet0/2" +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^interface +# interface GigabitEthernet0/1 +# ip address 203.0.113.27 255.255.255.0 +# interface GigabitEthernet0/2 +# ip address 192.0.2.1 255.255.255.0 secondary +# ip address 192.0.2.2 255.255.255.0 +# ipv6 address 2001:DB8:0:3::/64 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_l3_interfaces: + config: + - name: GigabitEthernet0/1 + ipv4: + - address: dhcp + dhcp_client: 0 + dhcp_hostname: test.com + - name: GigabitEthernet0/2 + ipv4: + - address: 198.51.100.1/24 + secondary: true + - address: 198.51.100.2/24 + ipv6: + - address: 2001:db8:0:3::/64 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "ip address dhcp client-id GigabitEthernet 0/0 hostname test.com", +# "interface GigabitEthernet0/2", +# "ip address 198.51.100.1 255.255.255.0 secondary", +# "ip address 198.51.100.2 255.255.255.0", +# "ipv6 address 2001:db8:0:3::/64" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# ip address dhcp client-id +# GigabitEthernet 0/0 hostname test.com +# interface GigabitEthernet0/2 +# ip address 198.51.100.1 255.255.255.0 +# secondary ip address 198.51.100.2 255.255.255.0 +# ipv6 address 2001:db8:0:3::/64 + +- name: Parse the commands for provided configuration + cisco.ios.ios_l3_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "ipv4": [ +# { +# "address": "dhcp", +# "dhcp_client": 0, +# "dhcp_hostname": "test.com" +# } +# ], +# "name": "GigabitEthernet0/1" +# }, +# { +# "ipv4": [ +# { +# "address": "198.51.100.1 255.255.255.0", +# "secondary": true +# }, +# { +# "address": "198.51.100.2 255.255.255.0" +# } +# ], +# "ipv6": [ +# { +# "address": "2001:db8:0:3::/64" +# } +# ], +# "name": "GigabitEthernet0/2" +# } +# ] + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/1', 'ip address 192.168.0.2 255.255.255.0'] +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import ( + L3_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.l3_interfaces.l3_interfaces import ( + L3_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=L3_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = L3_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py new file mode 100644 index 00000000..71884ab0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py @@ -0,0 +1,273 @@ +#!/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/>. +# +""" +The module file for ios_lacp +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_lacp +short_description: LACP resource module +description: This module provides declarative management of Global LACP on Cisco IOS + network devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: The provided configurations. + type: dict + suboptions: + system: + description: This option sets the default system parameters for LACP. + type: dict + suboptions: + priority: + description: + - LACP priority for the system. + - Refer to vendor documentation for valid values. + type: int + required: true + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show lacp sys-id). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - deleted + - rendered + - parsed + - gathered + default: merged +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vios#show lacp sys-id +# 32768, 5e00.0000.8000 + +- name: Merge provided configuration with device configuration + cisco.ios.ios_lacp: + config: + system: + priority: 123 + state: merged + +# After state: +# ------------ +# +# vios#show lacp sys-id +# 123, 5e00.0000.8000 + +# Using replaced +# +# Before state: +# ------------- +# +# vios#show lacp sys-id +# 500, 5e00.0000.8000 + +- name: Replaces Global LACP configuration + cisco.ios.ios_lacp: + config: + system: + priority: 123 + state: replaced + +# After state: +# ------------ +# +# vios#show lacp sys-id +# 123, 5e00.0000.8000 + +# Using Deleted +# +# Before state: +# ------------- +# +# vios#show lacp sys-id +# 500, 5e00.0000.8000 + +- name: Delete Global LACP attribute + cisco.ios.ios_lacp: + state: deleted + +# After state: +# ------------- +# +# vios#show lacp sys-id +# 32768, 5e00.0000.8000 + +# Using Gathered + +# Before state: +# ------------- +# +# vios#show lacp sys-id +# 123, 5e00.0000.8000 + +- name: Gather listed LACP with provided configurations + cisco.ios.ios_lacp: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": { +# "system": { +# "priority": 500 +# } +# } + +# After state: +# ------------ +# +# vios#show lacp sys-id +# 123, 5e00.0000.8000 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_lacp: + config: + system: + priority: 123 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "lacp system-priority 10" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# lacp system-priority 123 + +- name: Parse the commands for provided configuration + cisco.ios.ios_lacp: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": { +# "system": { +# "priority": 123 +# } +# } + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['lacp system-priority 10'] +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp.lacp import ( + LacpArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lacp.lacp import ( + Lacp, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=LacpArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Lacp(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py new file mode 100644 index 00000000..7bf4092a --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py @@ -0,0 +1,508 @@ +#!/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/>. +# +""" +The module file for ios_lacp_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_lacp_interfaces +short_description: LACP interfaces resource module +description: This module provides declarative management of LACP on Cisco IOS network + devices lacp_interfaces. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of LACP lacp_interfaces option + type: list + elements: dict + suboptions: + name: + description: + - Name of the Interface for configuring LACP. + type: str + required: true + port_priority: + description: + - LACP priority on this interface. + - Refer to vendor documentation for valid port values. + type: int + fast_switchover: + description: + - LACP fast switchover supported on this port channel. + type: bool + max_bundle: + description: + - LACP maximum number of ports to bundle in this port channel. + - Refer to vendor documentation for valid port values. + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show running-config | section ^interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown + +- name: Merge provided configuration with device configuration + cisco.ios.ios_lacp_interfaces: + config: + - name: GigabitEthernet0/1 + port_priority: 10 + - name: GigabitEthernet0/2 + port_priority: 20 + - name: GigabitEthernet0/3 + port_priority: 30 + - name: Port-channel10 + fast_switchover: true + max_bundle: 5 + state: merged + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# lacp max-bundle 5 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +# Using overridden +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +- name: Override device configuration of all lacp_interfaces with provided configuration + cisco.ios.ios_lacp_interfaces: + config: + - name: GigabitEthernet0/1 + port_priority: 20 + - name: Port-channel10 + max_bundle: 2 + state: overridden + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp max-bundle 2 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown + +# Using replaced +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp max-bundle 5 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +- name: Replaces device configuration of listed lacp_interfaces with provided configuration + cisco.ios.ios_lacp_interfaces: + config: + - name: GigabitEthernet0/3 + port_priority: 40 + - name: Port-channel10 + fast_switchover: true + max_bundle: 2 + state: replaced + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# lacp max-bundle 2 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 40 + +# Using Deleted +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# flowcontrol receive on +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +- name: "Delete LACP attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lacp_interfaces: + config: + - name: GigabitEthernet0/1 + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +# Using Deleted without any config passed +# "(NOTE: This will delete all of configured LLDP module attributes)" +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# interface Port-channel20 +# lacp max-bundle 2 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# shutdown +# lacp port-priority 20 +# interface GigabitEthernet0/3 +# shutdown +# lacp port-priority 30 + +- name: "Delete LACP attributes for all configured interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lacp_interfaces: + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# lacp max-bundle 2 +# interface Port-channel40 +# lacp max-bundle 5 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# lacp port-priority 30 +# interface GigabitEthernet0/2 +# lacp port-priority 20 + +- name: Gather listed LACP interfaces with provided configurations + cisco.ios.ios_lacp_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "fast_switchover": true, +# "max_bundle": 2, +# "name": "Port-channel10" +# }, +# { +# "max_bundle": 5, +# "name": "Port-channel40" +# }, +# { +# "name": "GigabitEthernet0/0" +# }, +# { +# "name": "GigabitEthernet0/1", +# "port_priority": 30 +# }, +# { +# "name": "GigabitEthernet0/2", +# "port_priority": 20 +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^interface +# interface Port-channel10 +# lacp fast-switchover +# lacp max-bundle 2 +# interface Port-channel40 +# lacp max-bundle 5 +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# lacp port-priority 30 +# interface GigabitEthernet0/2 +# lacp port-priority 20 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_lacp_interfaces: + config: + - name: GigabitEthernet0/1 + port_priority: 10 + - name: GigabitEthernet0/2 + port_priority: 20 + - name: Port-channel10 + fast_switchover: true + max_bundle: 2 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "lacp port-priority 10", +# "interface GigabitEthernet0/2", +# "lacp port-priority 20", +# "interface Port-channel10", +# "lacp max-bundle 2", +# "lacp fast-switchover" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# lacp port-priority 10 +# interface GigabitEthernet0/2 +# lacp port-priority 20 +# interface Port-channel10 +# lacp max-bundle 2 fast-switchover + +- name: Parse the commands for provided configuration + cisco.ios.ios_lacp_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "name": "GigabitEthernet0/1", +# "port_priority": 10 +# }, +# { +# "name": "GigabitEthernet0/2", +# "port_priority": 20 +# }, +# { +# "fast_switchover": true, +# "max_bundle": 2, +# "name": "Port-channel10" +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface GigabitEthernet 0/1', 'lacp port-priority 30'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import ( + Lacp_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lacp_interfaces.lacp_interfaces import ( + Lacp_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Lacp_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Lacp_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py new file mode 100644 index 00000000..679925ea --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py @@ -0,0 +1,534 @@ +#!/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/>. +# +""" +The module file for ios_l3_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_lag_interfaces +short_description: LAG interfaces resource module +description: This module manages properties of Link Aggregation Group on Cisco IOS + devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A list of link aggregation group configurations. + type: list + elements: dict + suboptions: + name: + description: + - ID of Ethernet Channel of interfaces. + - Refer to vendor documentation for valid port values. + type: str + required: true + members: + description: + - Interface options for the link aggregation group. + type: list + elements: dict + suboptions: + member: + description: + - Interface member of the link aggregation group. + type: str + mode: + description: + - Etherchannel Mode of the interface for link aggregation. + - On mode has to be quoted as 'on' or else pyyaml will convert + to True before it gets to Ansible. + type: str + required: true + choices: + - auto + - 'on' + - desirable + - active + - passive + link: + description: + - Assign a link identifier used for load-balancing. + - Refer to vendor documentation for valid values. + - NOTE, parameter only supported on Cisco IOS XE platform. + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device + by executing the command B(show running-config | section ^interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - parsed + - gathered + default: merged +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown +# interface GigabitEthernet0/4 +# shutdown + +- name: Merge provided configuration with device configuration + cisco.ios.ios_lag_interfaces: + config: + - name: 10 + members: + - member: GigabitEthernet0/1 + mode: auto + - member: GigabitEthernet0/2 + mode: auto + - name: 20 + members: + - member: GigabitEthernet0/3 + mode: on + - name: 30 + members: + - member: GigabitEthernet0/4 + mode: active + state: merged + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +# Using overridden +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +- name: Override device configuration of all interfaces with provided configuration + cisco.ios.ios_lag_interfaces: + config: + - name: 20 + members: + - member: GigabitEthernet0/2 + mode: auto + - member: GigabitEthernet0/3 + mode: auto + state: overridden + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# channel-group 20 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode auto +# interface GigabitEthernet0/4 +# shutdown + +# Using replaced +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +- name: Replaces device configuration of listed interfaces with provided configuration + cisco.ios.ios_lag_interfaces: + config: + - name: 40 + members: + - member: GigabitEthernet0/3 + mode: auto + state: replaced + +# After state: +# ------------ +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface Port-channel40 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 40 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +# Using Deleted +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +- name: "Delete LAG attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lag_interfaces: + config: + - name: 10 + - name: 20 + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured LLDP module attributes)" + +# +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/2 +# shutdown +# channel-group 10 mode auto +# interface GigabitEthernet0/3 +# shutdown +# channel-group 20 mode on +# interface GigabitEthernet0/4 +# shutdown +# channel-group 30 mode active + +- name: "Delete all configured LAG attributes for interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lag_interfaces: + state: deleted + +# After state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel10 +# interface Port-channel20 +# interface Port-channel30 +# interface GigabitEthernet0/1 +# shutdown +# interface GigabitEthernet0/2 +# shutdown +# interface GigabitEthernet0/3 +# shutdown +# interface GigabitEthernet0/4 +# shutdown + +# Using Gathered + +# Before state: +# ------------- +# +# vios#show running-config | section ^interface +# interface Port-channel11 +# interface Port-channel22 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 11 mode active +# interface GigabitEthernet0/2 +# shutdown +# channel-group 22 mode active + +- name: Gather listed LAG interfaces with provided configurations + cisco.ios.ios_lag_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "members": [ +# { +# "member": "GigabitEthernet0/1", +# "mode": "active" +# } +# ], +# "name": "Port-channel11" +# }, +# { +# "members": [ +# { +# "member": "GigabitEthernet0/2", +# "mode": "active" +# } +# ], +# "name": "Port-channel22" +# } +# ] + +# After state: +# ------------ +# +# vios#sh running-config | section ^interface +# interface Port-channel11 +# interface Port-channel22 +# interface GigabitEthernet0/1 +# shutdown +# channel-group 11 mode active +# interface GigabitEthernet0/2 +# shutdown +# channel-group 22 mode active + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_lag_interfaces: + config: + - name: Port-channel11 + members: + - member: GigabitEthernet0/1 + mode: active + - name: Port-channel22 + members: + - member: GigabitEthernet0/2 + mode: passive + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "channel-group 11 mode active", +# "interface GigabitEthernet0/2", +# "channel-group 22 mode passive", +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/1 +# channel-group 11 mode active +# interface GigabitEthernet0/2 +# channel-group 22 mode passive + +- name: Parse the commands for provided configuration + cisco.ios.ios_lag_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "members": [ +# { +# "member": "GigabitEthernet0/1", +# "mode": "active" +# } +# ], +# "name": "Port-channel11" +# }, +# { +# "members": [ +# { +# "member": "GigabitEthernet0/2", +# "mode": "passive" +# } +# ], +# "name": "Port-channel22" +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/1', 'channel-group 1 mode active'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import ( + Lag_interfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lag_interfaces.lag_interfaces import ( + Lag_interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Lag_interfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Lag_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py new file mode 100644 index 00000000..ebf934d8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py @@ -0,0 +1,363 @@ +#!/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 = r""" +module: ios_linkagg +author: Trishna Guha (@trishnaguha) +short_description: Manage link aggregation groups on Cisco IOS network devices +description: +- This module provides declarative management of link aggregation groups on Cisco + IOS network devices. +version_added: 1.0.0 +notes: +- Tested against IOS 15.2 +options: + group: + description: + - Channel-group number for the port-channel Link aggregation group. Range 1-255. + type: int + mode: + description: + - Mode of the link aggregation group. + - On mode has to be quoted as 'on' or else pyyaml will convert + to True before it gets to Ansible. + choices: + - active + - 'on' + - passive + - auto + - desirable + type: str + members: + description: + - List of members of the link aggregation group. + type: list + elements: str + aggregate: + description: List of link aggregation definitions. + type: list + elements: dict + suboptions: + group: + description: + - Channel-group number for the port-channel Link aggregation group. Range 1-255. + type: str + required: true + mode: + description: + - Mode of the link aggregation group. + - On mode has to be quoted as 'on' or else pyyaml will convert + to True before it gets to Ansible. + choices: + - active + - 'on' + - passive + - auto + - desirable + type: str + members: + description: + - List of members of the link aggregation group. + type: list + elements: str + state: + description: + - State of the link aggregation group. + choices: + - present + - absent + type: str + state: + description: + - State of the link aggregation group. + default: present + choices: + - present + - absent + type: str + purge: + description: + - Purge links not defined in the I(aggregate) parameter. + default: false + type: bool +extends_documentation_fragment: +- cisco.ios.ios +""" +EXAMPLES = """ +- name: create link aggregation group + cisco.ios.ios_linkagg: + group: 10 + state: present + +- name: delete link aggregation group + cisco.ios.ios_linkagg: + group: 10 + state: absent + +- name: set link aggregation group to members + cisco.ios.ios_linkagg: + group: 200 + mode: active + members: + - GigabitEthernet0/0 + - GigabitEthernet0/1 + +- name: remove link aggregation group from GigabitEthernet0/0 + cisco.ios.ios_linkagg: + group: 200 + mode: active + members: + - GigabitEthernet0/1 + +- name: Create aggregate of linkagg definitions + cisco.ios.ios_linkagg: + aggregate: + - {group: 3, mode: on, members: [GigabitEthernet0/1]} + - {group: 100, mode: passive, members: [GigabitEthernet0/2]} +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always, except for the platforms that use Netconf transport to manage the device. + type: list + sample: + - interface port-channel 30 + - interface GigabitEthernet0/3 + - channel-group 30 mode on + - no interface port-channel 30 +""" +import re +from copy import deepcopy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + CustomNetworkConfig, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def search_obj_in_list(group, lst): + for o in lst: + if o["group"] == group: + return o + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + purge = module.params["purge"] + for w in want: + group = w["group"] + mode = w["mode"] + members = w.get("members") or [] + state = w["state"] + del w["state"] + obj_in_have = search_obj_in_list(group, have) + if state == "absent": + if obj_in_have: + commands.append("no interface port-channel {0}".format(group)) + elif state == "present": + cmd = ["interface port-channel {0}".format(group), "end"] + if not obj_in_have: + if not group: + module.fail_json(msg="group is a required option") + commands.extend(cmd) + if members: + for m in members: + commands.append("interface {0}".format(m)) + commands.append( + "channel-group {0} mode {1}".format(group, mode) + ) + elif members: + if "members" not in obj_in_have.keys(): + for m in members: + commands.extend(cmd) + commands.append("interface {0}".format(m)) + commands.append( + "channel-group {0} mode {1}".format(group, mode) + ) + elif set(members) != set(obj_in_have["members"]): + missing_members = list( + set(members) - set(obj_in_have["members"]) + ) + for m in missing_members: + commands.extend(cmd) + commands.append("interface {0}".format(m)) + commands.append( + "channel-group {0} mode {1}".format(group, mode) + ) + superfluous_members = list( + set(obj_in_have["members"]) - set(members) + ) + for m in superfluous_members: + commands.extend(cmd) + commands.append("interface {0}".format(m)) + commands.append( + "no channel-group {0} mode {1}".format(group, mode) + ) + if purge: + for h in have: + obj_in_want = search_obj_in_list(h["group"], want) + if not obj_in_want: + commands.append( + "no interface port-channel {0}".format(h["group"]) + ) + return commands + + +def map_params_to_obj(module): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + d = item.copy() + d["group"] = str(d["group"]) + obj.append(d) + else: + obj.append( + { + "group": str(module.params["group"]), + "mode": module.params["mode"], + "members": module.params["members"], + "state": module.params["state"], + } + ) + return obj + + +def parse_mode(module, config, group, member): + mode = None + netcfg = CustomNetworkConfig(indent=1, contents=config) + parents = ["interface {0}".format(member)] + body = netcfg.get_section(parents) + match_int = re.findall("interface {0}\\n".format(member), body, re.M) + if match_int: + match = re.search( + "channel-group {0} mode (\\S+)".format(group), body, re.M + ) + if match: + mode = match.group(1) + return mode + + +def parse_members(module, config, group): + members = [] + for line in config.strip().split("!"): + l = line.strip() + if l.startswith("interface"): + match_group = re.findall( + "channel-group {0} mode".format(group), l, re.M + ) + if match_group: + match = re.search("interface (\\S+)", l, re.M) + if match: + members.append(match.group(1)) + return members + + +def get_channel(module, config, group): + match = re.findall("^interface (\\S+)", config, re.M) + if not match: + return {} + channel = {} + for item in set(match): + member = item + channel["mode"] = parse_mode(module, config, group, member) + channel["members"] = parse_members(module, config, group) + return channel + + +def map_config_to_obj(module): + objs = list() + config = get_config(module) + for line in config.split("\n"): + l = line.strip() + match = re.search("interface Port-channel(\\S+)", l, re.M) + if match: + obj = {} + group = match.group(1) + obj["group"] = group + obj.update(get_channel(module, config, group)) + objs.append(obj) + return objs + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + group=dict(type="int"), + mode=dict(choices=["active", "on", "passive", "auto", "desirable"]), + members=dict(type="list", elements="str"), + state=dict(default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["group"] = dict(required=True) + required_one_of = [["group", "aggregate"]] + required_together = [["members", "mode"]] + mutually_exclusive = [["group", "aggregate"]] + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict( + type="list", + elements="dict", + options=aggregate_spec, + required_together=required_together, + ), + purge=dict(default=False, type="bool"), + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + required_together=required_together, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have), module) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py new file mode 100644 index 00000000..7b6d48e6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py @@ -0,0 +1,113 @@ +#!/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: ios_lldp +author: Ganesh Nalawade (@ganeshrn) +short_description: Manage LLDP configuration on Cisco IOS network devices. +description: +- This module provides declarative management of LLDP service on Cisco IOS network + devices. +version_added: 1.0.0 +notes: +- Tested against IOS 15.2 +options: + state: + description: + - State of the LLDP configuration. If value is I(present) lldp will be enabled + else if it is I(absent) it will be disabled. + default: present + choices: + - present + - absent + - enabled + - disabled + type: str +extends_documentation_fragment: +- cisco.ios.ios +""" +EXAMPLES = """ +- name: Enable LLDP service + cisco.ios.ios_lldp: + state: present + +- name: Disable LLDP service + cisco.ios.ios_lldp: + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always, except for the platforms that use Netconf transport to manage the device. + type: list + sample: + - lldp run +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + load_config, + run_commands, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def has_lldp(module): + output = run_commands(module, ["show lldp"]) + is_lldp_enable = False + if len(output) > 0 and "LLDP is not enabled" not in output[0]: + is_lldp_enable = True + return is_lldp_enable + + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + state=dict( + default="present", + choices=["present", "absent", "enabled", "disabled"], + ) + ) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + HAS_LLDP = has_lldp(module) + commands = [] + if module.params["state"] == "absent" and HAS_LLDP: + commands.append("no lldp run") + elif module.params["state"] == "present" and not HAS_LLDP: + commands.append("lldp run") + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py new file mode 100644 index 00000000..77f65a05 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py @@ -0,0 +1,356 @@ +#!/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/>. +# +""" +The module file for ios_lldp_global +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_lldp_global +short_description: LLDP resource module +description: This module configures and manages the Link Layer Discovery Protocol(LLDP) + attributes on IOS platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of LLDP options + type: dict + suboptions: + holdtime: + description: + - LLDP holdtime (in sec) to be sent in packets. + - Refer to vendor documentation for valid values. + type: int + reinit: + description: + - Specify the delay (in secs) for LLDP to initialize. + - Refer to vendor documentation for valid values. + - NOTE, if LLDP reinit is configured with a starting value, idempotency won't + be maintained as the Cisco device doesn't record the starting reinit configured + value. As such, Ansible cannot verify if the respective starting reinit + value is already configured or not from the device side. If you try to apply + starting reinit value in every play run, Ansible will show changed as True. + For any other reinit value, idempotency will be maintained since any other + reinit value is recorded in the Cisco device. + type: int + enabled: + description: + - Enable LLDP + type: bool + timer: + description: + - Specify the rate at which LLDP packets are sent (in sec). + - Refer to vendor documentation for valid values. + type: int + tlv_select: + description: + - Selection of LLDP TLVs i.e. type-length-value to send + - NOTE, if tlv-select is configured idempotency won't be maintained as Cisco + device doesn't record configured tlv-select options. As such, Ansible cannot + verify if the respective tlv-select options is already configured or not + from the device side. If you try to apply tlv-select option in every play + run, Ansible will show changed as True. + type: dict + suboptions: + four_wire_power_management: + description: + - Cisco 4-wire Power via MDI TLV + type: bool + mac_phy_cfg: + description: + - IEEE 802.3 MAC/Phy Configuration/status TLV + type: bool + management_address: + description: + - Management Address TLV + type: bool + port_description: + description: + - Port Description TLV + type: bool + port_vlan: + description: + - Port VLAN ID TLV + type: bool + power_management: + description: + - IEEE 802.3 DTE Power via MDI TLV + type: bool + system_capabilities: + description: + - System Capabilities TLV + type: bool + system_description: + description: + - System Description TLV + type: bool + system_name: + description: + - System Name TLV + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device + by executing the command B(show running-config | section ^lldp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - deleted + - rendered + - gathered + - parsed + default: merged + + +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# vios#sh running-config | section ^lldp +# vios1# + + +- name: Merge provided configuration with device configuration + cisco.ios.ios_lldp_global: + config: + holdtime: 10 + enabled: true + reinit: 3 + timer: 10 + state: merged + +# After state: +# ------------ +# vios#sh running-config | section ^lldp +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + + +# Using replaced + +# Before state: +# ------------- +# vios#sh running-config | section ^lldp +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + + +- name: Replaces LLDP device configuration with provided configuration + cisco.ios.ios_lldp_global: + config: + holdtime: 20 + reinit: 5 + state: replaced + +# After state: +# ------------- +# vios#sh running-config | section ^lldp +# lldp holdtime 20 +# lldp reinit 5 + + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured LLDP module attributes)" + +# Before state: +# ------------- +# vios#sh running-config | section ^lldp +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + + +- name: Delete LLDP attributes + cisco.ios.ios_lldp_global: + state: deleted + +# After state: +# ------------- +# vios#sh running-config | section ^lldp +# vios1# + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh running-config | section ^lldp +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + +- name: Gather listed interfaces with provided configurations + cisco.ios.ios_lldp_global: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": { +# "enabled": true, +# "holdtime": 10, +# "reinit": 3, +# "timer": 10 +# } + +# After state: +# ------------ +# +# vios#sh running-config | section ^lldp +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + +# Using Rendered +- name: Render the commands for provided configuration + cisco.ios.ios_lldp_global: + config: + holdtime: 10 + enabled: true + reinit: 3 + timer: 10 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "lldp holdtime 10", +# "lldp run", +# "lldp timer 10", +# "lldp reinit 3" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# lldp timer 10 +# lldp holdtime 10 +# lldp reinit 3 +# lldp run + +- name: Parse the commands for provided configuration + cisco.ios.ios_lldp_global: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": { +# "enabled": true, +# "holdtime": 10, +# "reinit": 3, +# "timer": 10 +# } + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: dict + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: dict + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['lldp holdtime 10', 'lldp run', 'lldp timer 10'] +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_global.lldp_global import ( + Lldp_globalArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lldp_global.lldp_global import ( + Lldp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Lldp_globalArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Lldp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py new file mode 100644 index 00000000..32629d09 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py @@ -0,0 +1,666 @@ +#!/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/>. +# +""" +The module file for ios_lldp_interfaces +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_lldp_interfaces +short_description: LLDP interfaces resource module +description: This module manages link layer discovery protocol (LLDP) attributes of + interfaces on Cisco IOS devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of LLDP options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + type: str + required: true + receive: + description: + - Enable LLDP reception on interface. + type: bool + transmit: + description: + - Enable LLDP transmission on interface. + type: bool + med_tlv_select: + description: + - Selection of LLDP MED TLVs to send + - NOTE, if med-tlv-select is configured idempotency won't be maintained as + Cisco device doesn't record configured med-tlv-select options. As such, + Ansible cannot verify if the respective med-tlv-select options is already + configured or not from the device side. If you try to apply med-tlv-select + option in every play run, Ansible will show changed as True. + type: dict + suboptions: + inventory_management: + description: + - LLDP MED Inventory Management TLV + type: bool + tlv_select: + description: + - Selection of LLDP type-length-value i.e. TLVs to send + - NOTE, if tlv-select is configured idempotency won't be maintained as Cisco + device doesn't record configured tlv-select options. As such, Ansible cannot + verify if the respective tlv-select options is already configured or not + from the device side. If you try to apply tlv-select option in every play + run, Ansible will show changed as True. + type: dict + suboptions: + power_management: + description: + - IEEE 802.3 DTE Power via MDI TLV + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(sh lldp interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# + +- name: Merge provided configuration with device configuration + cisco.ios.ios_lldp_interfaces: + config: + - name: GigabitEthernet0/1 + receive: true + transmit: true + - name: GigabitEthernet0/2 + receive: true + - name: GigabitEthernet0/3 + transmit: true + state: merged + +# After state: +# ------------ +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: enabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# + +# Using overridden +# +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +- name: Override device configuration of all lldp_interfaces with provided configuration + cisco.ios.ios_lldp_interfaces: + config: + - name: GigabitEthernet0/2 + receive: true + transmit: true + state: overridden + +# After state: +# ------------ +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +# Using replaced +# +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# + +- name: Replaces device configuration of listed lldp_interfaces with provided configuration + cisco.ios.ios_lldp_interfaces: + config: + - name: GigabitEthernet0/2 + receive: true + transmit: true + - name: GigabitEthernet0/3 + receive: true + state: replaced + +# After state: +# ------------ +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: disabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# + +# Using Deleted +# +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +- name: "Delete LLDP attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lldp_interfaces: + config: + - name: GigabitEthernet0/1 + state: deleted + +# After state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# + +# Using Deleted without any config passed +# "(NOTE: This will delete all of configured LLDP module attributes)" +# +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +- name: "Delete LLDP attributes for all configured interfaces (Note: This won't delete the interface itself)" + cisco.ios.ios_lldp_interfaces: + state: deleted + +# After state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: INIT +# +# GigabitEthernet0/3: +# Tx: disabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +# Using Gathered + +# Before state: +# ------------- +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +- name: Gather listed LLDP interfaces with provided configurations + cisco.ios.ios_lldp_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "name": "GigabitEthernet0/0", +# "receive": true, +# "transmit": true +# }, +# { +# "name": "GigabitEthernet0/1", +# "receive": true, +# "transmit": true +# }, +# { +# "name": "GigabitEthernet0/2", +# "receive": true, +# "transmit": true +# } +# ] + +# After state: +# ------------ +# +# vios#sh lldp interface +# GigabitEthernet0/0: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +# GigabitEthernet0/2: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_lldp_interfaces: + config: + - name: GigabitEthernet0/0 + receive: true + transmit: true + - name: GigabitEthernet0/1 + receive: true + transmit: true + - name: GigabitEthernet0/2 + receive: true + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/0", +# "lldp receive", +# "lldp transmit", +# "interface GigabitEthernet0/1", +# "lldp receive", +# "lldp transmit", +# "interface GigabitEthernet0/2", +# "lldp receive" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# GigabitEthernet0/0: +# Tx: enabled +# Rx: disabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/1: +# Tx: enabled +# Rx: enabled +# Tx state: IDLE +# Rx state: WAIT FOR FRAME +# +# GigabitEthernet0/2: +# Tx: disabled +# Rx: enabled +# Tx state: IDLE +# Rx state: INIT + +- name: Parse the commands for provided configuration + cisco.ios.ios_lldp_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "name": "GigabitEthernet0/0", +# "receive": false, +# "transmit": true +# }, +# { +# "name": "GigabitEthernet0/1", +# "receive": true, +# "transmit": true +# }, +# { +# "name": "GigabitEthernet0/2", +# "receive": true, +# "transmit": false +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface GigabitEthernet 0/1', 'lldp transmit', 'lldp receive'] +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import ( + Lldp_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lldp_interfaces.lldp_interfaces import ( + Lldp_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Lldp_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Lldp_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py new file mode 100644 index 00000000..0d1046a1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py @@ -0,0 +1,511 @@ +#!/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: ios_logging +author: Trishna Guha (@trishnaguha) +short_description: Manage logging on network devices +description: +- This module provides declarative management of logging on Cisco Ios devices. +version_added: 1.0.0 +notes: +- Tested against IOS 15.6 +options: + dest: + description: + - Destination of the logs. + - On dest has to be quoted as 'on' or else pyyaml will convert + to True before it gets to Ansible. + choices: + - 'on' + - host + - console + - monitor + - buffered + - trap + type: str + name: + description: + - The hostname or IP address of the destination. + - Required when I(dest=host). + type: str + size: + description: + - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes. + type: int + facility: + description: + - Set logging facility. + type: str + level: + description: + - Set logging severity levels. + default: debugging + choices: + - emergencies + - alerts + - critical + - errors + - warnings + - notifications + - informational + - debugging + type: str + aggregate: + description: List of logging definitions. + type: list + elements: dict + suboptions: + dest: + description: + - Destination of the logs. + - On dest has to be quoted as 'on' or else pyyaml will convert + to True before it gets to Ansible. + choices: + - 'on' + - host + - console + - monitor + - buffered + - trap + type: str + name: + description: + - The hostname or IP address of the destination. + - Required when I(dest=host). + type: str + size: + description: + - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes. + type: int + facility: + description: + - Set logging facility. + type: str + level: + description: + - Set logging severity levels. + type: str + choices: + - emergencies + - alerts + - critical + - errors + - warnings + - notifications + - informational + - debugging + state: + description: + - State of the logging configuration. + choices: + - present + - absent + type: str + state: + description: + - State of the logging configuration. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: +- cisco.ios.ios +""" +EXAMPLES = """ +- name: configure host logging + cisco.ios.ios_logging: + dest: host + name: 172.16.0.1 + state: present + +- name: remove host logging configuration + cisco.ios.ios_logging: + dest: host + name: 172.16.0.1 + state: absent + +- name: configure console logging level and facility + cisco.ios.ios_logging: + dest: console + facility: local7 + level: debugging + state: present + +- name: enable logging to all + cisco.ios.ios_logging: + dest: on + +- name: configure buffer size + cisco.ios.ios_logging: + dest: buffered + size: 5000 + +- name: Configure logging using aggregate + cisco.ios.ios_logging: + aggregate: + - {dest: console, level: notifications} + - {dest: buffered, size: 9000} + +- name: remove logging using aggregate + cisco.ios.ios_logging: + aggregate: + - {dest: console, level: notifications} + - {dest: buffered, size: 9000} + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - logging facility local7 + - logging host 172.16.0.1 +""" +import re +from copy import deepcopy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, + validate_ip_address, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_capabilities, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def validate_size(value, module): + if value: + if not int(4096) <= int(value) <= int(4294967295): + module.fail_json(msg="size must be between 4096 and 4294967295") + else: + return value + + +def map_obj_to_commands(updates, module, os_version): + dest_group = "console", "monitor", "buffered", "on", "trap" + commands = list() + want, have = updates + for w in want: + dest = w["dest"] + name = w["name"] + size = w["size"] + facility = w["facility"] + level = w["level"] + state = w["state"] + del w["state"] + if facility: + w["dest"] = "facility" + if state == "absent" and w in have: + if dest: + if dest == "host": + if "12." in os_version: + commands.append("no logging {0}".format(name)) + else: + commands.append("no logging host {0}".format(name)) + elif dest in dest_group: + commands.append("no logging {0}".format(dest)) + else: + module.fail_json( + msg="dest must be among console, monitor, buffered, host, on, trap" + ) + if facility: + commands.append("no logging facility {0}".format(facility)) + if state == "present" and w not in have: + if facility: + present = False + for entry in have: + if ( + entry["dest"] == "facility" + and entry["facility"] == facility + ): + present = True + if not present: + commands.append("logging facility {0}".format(facility)) + if dest == "host": + if "12." in os_version: + commands.append("logging {0}".format(name)) + else: + commands.append("logging host {0}".format(name)) + elif dest == "on": + commands.append("logging on") + elif dest == "buffered" and size: + present = False + for entry in have: + if ( + entry["dest"] == "buffered" + and entry["size"] == size + and entry["level"] == level + ): + present = True + if not present: + if level and level != "debugging": + commands.append( + "logging buffered {0} {1}".format(size, level) + ) + else: + commands.append("logging buffered {0}".format(size)) + elif dest: + dest_cmd = "logging {0}".format(dest) + if level: + dest_cmd += " {0}".format(level) + commands.append(dest_cmd) + return commands + + +def parse_facility(line, dest): + facility = None + if dest == "facility": + match = re.search("logging facility (\\S+)", line, re.M) + if match: + facility = match.group(1) + return facility + + +def parse_size(line, dest): + size = None + if dest == "buffered": + match = re.search( + "logging buffered(?: (\\d+))?(?: [a-z]+)?", line, re.M + ) + if match: + if match.group(1) is not None: + size = match.group(1) + else: + size = "4096" + return size + + +def parse_name(line, dest): + if dest == "host": + match = re.search("logging host (\\S+)", line, re.M) + if match: + name = match.group(1) + else: + name = None + return name + + +def parse_level(line, dest): + level_group = ( + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", + ) + if dest == "host": + level = "debugging" + else: + if dest == "buffered": + match = re.search( + "logging buffered(?: \\d+)?(?: ([a-z]+))?", line, re.M + ) + else: + match = re.search("logging {0} (\\S+)".format(dest), line, re.M) + if match and match.group(1) in level_group: + level = match.group(1) + else: + level = "debugging" + return level + + +def map_config_to_obj(module): + obj = [] + dest_group = ( + "console", + "host", + "monitor", + "buffered", + "on", + "facility", + "trap", + ) + data = get_config(module, flags=["| include logging"]) + for line in data.split("\n"): + match = re.search("^logging (\\S+)", line, re.M) + if match: + if match.group(1) in dest_group: + dest = match.group(1) + obj.append( + { + "dest": dest, + "name": parse_name(line, dest), + "size": parse_size(line, dest), + "facility": parse_facility(line, dest), + "level": parse_level(line, dest), + } + ) + elif validate_ip_address(match.group(1)): + dest = "host" + obj.append( + { + "dest": dest, + "name": match.group(1), + "size": parse_size(line, dest), + "facility": parse_facility(line, dest), + "level": parse_level(line, dest), + } + ) + else: + ip_match = re.search( + "\\d+\\.\\d+\\.\\d+\\.\\d+", match.group(1), re.M + ) + if ip_match: + dest = "host" + obj.append( + { + "dest": dest, + "name": match.group(1), + "size": parse_size(line, dest), + "facility": parse_facility(line, dest), + "level": parse_level(line, dest), + } + ) + return obj + + +def map_params_to_obj(module, required_if=None): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + module._check_required_if(required_if, item) + d = item.copy() + if d["dest"] != "host": + d["name"] = None + if d["dest"] == "buffered": + if "size" in d: + d["size"] = str(validate_size(d["size"], module)) + elif "size" not in d: + d["size"] = str(4096) + else: + pass + if d["dest"] != "buffered": + d["size"] = None + obj.append(d) + else: + if module.params["dest"] != "host": + module.params["name"] = None + if module.params["dest"] == "buffered": + if not module.params["size"]: + module.params["size"] = str(4096) + else: + module.params["size"] = None + if module.params["size"] is None: + obj.append( + { + "dest": module.params["dest"], + "name": module.params["name"], + "size": module.params["size"], + "facility": module.params["facility"], + "level": module.params["level"], + "state": module.params["state"], + } + ) + else: + obj.append( + { + "dest": module.params["dest"], + "name": module.params["name"], + "size": str(validate_size(module.params["size"], module)), + "facility": module.params["facility"], + "level": module.params["level"], + "state": module.params["state"], + } + ) + return obj + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + dest=dict( + type="str", + choices=["on", "host", "console", "monitor", "buffered", "trap"], + ), + name=dict(type="str"), + size=dict(type="int"), + facility=dict(type="str"), + level=dict( + type="str", + default="debugging", + choices=[ + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", + ], + ), + state=dict(default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec) + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + required_if = [("dest", "host", ["name"])] + module = AnsibleModule( + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + device_info = get_capabilities(module) + os_version = device_info["device_info"]["network_os_version"] + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module, required_if=required_if) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have), module, os_version) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py new file mode 100644 index 00000000..8f8e0da4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py @@ -0,0 +1,326 @@ +#!/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: ios_ntp +extends_documentation_fragment: +- cisco.ios.ios +short_description: Manages core NTP configuration. +description: +- Manages core NTP configuration. +version_added: 1.0.0 +author: +- Federico Olivieri (@Federico87) +options: + server: + description: + - Network address of NTP server. + type: str + source_int: + description: + - Source interface for NTP packets. + type: str + acl: + description: + - ACL for peer/server access restricition. + type: str + logging: + description: + - Enable NTP logs. Data type boolean. + type: bool + default: false + auth: + description: + - Enable NTP authentication. Data type boolean. + type: bool + default: false + auth_key: + description: + - md5 NTP authentication key of tye 7. + type: str + key_id: + description: + - auth_key id. Data type string + type: str + state: + description: + - Manage the state of the resource. + default: present + choices: + - present + - absent + type: str +""" +EXAMPLES = """ +# Set new NTP server and source interface +- cisco.ios.ios_ntp: + server: 10.0.255.10 + source_int: Loopback0 + logging: false + state: present + +# Remove NTP ACL and logging +- cisco.ios.ios_ntp: + acl: NTP_ACL + logging: true + state: absent + +# Set NTP authentication +- cisco.ios.ios_ntp: + key_id: 10 + auth_key: 15435A030726242723273C21181319000A + auth: true + state: present + +# Set new NTP configuration +- cisco.ios.ios_ntp: + server: 10.0.255.10 + source_int: Loopback0 + acl: NTP_ACL + logging: true + key_id: 10 + auth_key: 15435A030726242723273C21181319000A + auth: true + state: present +""" +RETURN = """ +commands: + description: command sent to the device + returned: always + type: list + sample: ["no ntp server 10.0.255.10", "no ntp source Loopback0"] +""" +import re +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def parse_server(line, dest): + if dest == "server": + match = re.search( + "(ntp server )(\\d+\\.\\d+\\.\\d+\\.\\d+)", line, re.M + ) + if match: + server = match.group(2) + return server + + +def parse_source_int(line, dest): + if dest == "source": + match = re.search("(ntp source )(\\S+)", line, re.M) + if match: + source = match.group(2) + return source + + +def parse_acl(line, dest): + if dest == "access-group": + match = re.search( + "ntp access-group (?:peer|serve)(?:\\s+)(\\S+)", line, re.M + ) + if match: + acl = match.group(1) + return acl + + +def parse_logging(line, dest): + if dest == "logging": + logging = dest + return logging + + +def parse_auth_key(line, dest): + if dest == "authentication-key": + match = re.search( + "(ntp authentication-key \\d+ md5 )(\\w+)", line, re.M + ) + if match: + auth_key = match.group(2) + return auth_key + + +def parse_key_id(line, dest): + if dest == "trusted-key": + match = re.search("(ntp trusted-key )(\\d+)", line, re.M) + if match: + auth_key = match.group(2) + return auth_key + + +def parse_auth(dest): + if dest == "authenticate": + return dest + + +def map_config_to_obj(module): + obj_dict = {} + obj = [] + server_list = [] + config = get_config(module, flags=["| include ntp"]) + for line in config.splitlines(): + match = re.search("ntp (\\S+)", line, re.M) + if match: + dest = match.group(1) + server = parse_server(line, dest) + source_int = parse_source_int(line, dest) + acl = parse_acl(line, dest) + logging = parse_logging(line, dest) + auth = parse_auth(dest) + auth_key = parse_auth_key(line, dest) + key_id = parse_key_id(line, dest) + if server: + server_list.append(server) + if source_int: + obj_dict["source_int"] = source_int + if acl: + obj_dict["acl"] = acl + if logging: + obj_dict["logging"] = True + if auth: + obj_dict["auth"] = True + if auth_key: + obj_dict["auth_key"] = auth_key + if key_id: + obj_dict["key_id"] = key_id + obj_dict["server"] = server_list + obj.append(obj_dict) + return obj + + +def map_params_to_obj(module): + obj = [] + obj.append( + { + "state": module.params["state"], + "server": module.params["server"], + "source_int": module.params["source_int"], + "logging": module.params["logging"], + "acl": module.params["acl"], + "auth": module.params["auth"], + "auth_key": module.params["auth_key"], + "key_id": module.params["key_id"], + } + ) + return obj + + +def map_obj_to_commands(want, have, module): + commands = list() + server_have = have[0].get("server", None) + source_int_have = have[0].get("source_int", None) + acl_have = have[0].get("acl", None) + logging_have = have[0].get("logging", None) + auth_have = have[0].get("auth", None) + auth_key_have = have[0].get("auth_key", None) + key_id_have = have[0].get("key_id", None) + for w in want: + server = w["server"] + source_int = w["source_int"] + acl = w["acl"] + logging = w["logging"] + state = w["state"] + auth = w["auth"] + auth_key = w["auth_key"] + key_id = w["key_id"] + if state == "absent": + if server_have and server in server_have: + commands.append("no ntp server {0}".format(server)) + if source_int and source_int_have: + commands.append("no ntp source {0}".format(source_int)) + if acl and acl_have: + commands.append("no ntp access-group peer {0}".format(acl)) + if logging is True and logging_have: + commands.append("no ntp logging") + if auth is True and auth_have: + commands.append("no ntp authenticate") + if key_id and key_id_have: + commands.append("no ntp trusted-key {0}".format(key_id)) + if auth_key and auth_key_have: + if key_id and key_id_have: + commands.append( + "no ntp authentication-key {0} md5 {1} 7".format( + key_id, auth_key + ) + ) + elif state == "present": + if server is not None and server not in server_have: + commands.append("ntp server {0}".format(server)) + if source_int is not None and source_int != source_int_have: + commands.append("ntp source {0}".format(source_int)) + if acl is not None and acl != acl_have: + commands.append("ntp access-group peer {0}".format(acl)) + if ( + logging is not None + and logging != logging_have + and logging is not False + ): + commands.append("ntp logging") + if auth is not None and auth != auth_have and auth is not False: + commands.append("ntp authenticate") + if key_id is not None and key_id != key_id_have: + commands.append("ntp trusted-key {0}".format(key_id)) + if auth_key is not None and auth_key != auth_key_have: + if key_id is not None: + commands.append( + "ntp authentication-key {0} md5 {1} 7".format( + key_id, auth_key + ) + ) + return commands + + +def main(): + argument_spec = dict( + server=dict(), + source_int=dict(), + acl=dict(), + logging=dict(type="bool", default=False), + auth=dict(type="bool", default=False), + auth_key=dict(), + key_id=dict(), + state=dict(choices=["absent", "present"], default="present"), + ) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + result = {"changed": False} + warnings = list() + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands(want, have, module) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py new file mode 100644 index 00000000..b5bdc775 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py @@ -0,0 +1,1101 @@ +#!/usr/bin/python +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for ios_ospf_interfaces +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_ospf_interfaces +short_description: OSPF_Interfaces resource module +description: This module configures and manages the Open Shortest Path First (OSPF) + version 2 on IOS platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of OSPF interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, + i.e. GigabitEthernet0/1. + type: str + required: true + address_family: + description: + - OSPF interfaces settings on the interfaces in address-family + context. + type: list + elements: dict + suboptions: + afi: + description: + - Address Family Identifier (AFI) for OSPF interfaces settings + on the interfaces. + type: str + choices: + - ipv4 + - ipv6 + required: true + process: + description: OSPF interfaces process config + type: dict + suboptions: + id: + description: + - Address Family Identifier (AFI) for OSPF interfaces settings + on the interfaces. Please refer vendor documentation of Valid + values. + type: int + area_id: + description: + - OSPF interfaces area ID as a decimal value. Please + refer vendor documentation of Valid values. + - OSPF interfaces area ID in IP address format(e.g. + A.B.C.D) + type: str + secondaries: + description: + - Include or exclude secondary IP addresses. + - Valid only with IPv4 config + type: bool + instance_id: + description: + - Set the OSPF instance based on ID + - Valid only with IPv6 OSPF config + type: int + adjacency: + description: Adjacency staggering + type: bool + authentication: + description: Enable authentication + type: dict + suboptions: + key_chain: + description: Use a key-chain for cryptographic + authentication keys + type: str + message_digest: + description: Use message-digest authentication + type: bool + 'null': + description: Use no authentication + type: bool + bfd: + description: + - BFD configuration commands + - Enable/Disable BFD on this interface + type: bool + cost: + description: Interface cost + type: dict + suboptions: + interface_cost: + description: Interface cost or Route cost of this interface + type: int + dynamic_cost: + description: + - Specify dynamic cost options + - Valid only with IPv6 OSPF config + type: dict + suboptions: + default: + description: Specify default link metric value + type: int + hysteresis: + description: Specify hysteresis value for LSA dampening + type: dict + suboptions: + percent: + description: Specify hysteresis percent changed. + Please refer vendor documentation of Valid values. + type: int + threshold: + description: Specify hysteresis threshold value. + Please refer vendor documentation of Valid values. + type: int + weight: + description: Specify weight to be placed on individual + metrics + type: dict + suboptions: + l2_factor: + description: + - Specify weight to be given to L2-factor metric + - Percentage weight of L2-factor metric. Please refer + vendor documentation of Valid values. + type: int + latency: + description: + - Specify weight to be given to latency metric. + - Percentage weight of latency metric. Please refer + vendor documentation of Valid values. + type: int + oc: + description: + - Specify weight to be given to cdr/mdr for oc + - Give 100 percent weightage for current data rate(0 + for maxdatarate) + type: bool + resources: + description: + - Specify weight to be given to resources metric + - Percentage weight of resources metric. Please refer + vendor documentation of Valid values. + type: int + throughput: + description: + - Specify weight to be given to throughput metric + - Percentage weight of throughput metric. Please refer + vendor documentation of Valid values. + type: int + database_filter: + description: Filter OSPF LSA during synchronization and flooding + type: bool + dead_interval: + description: Interval after which a neighbor is declared dead + type: dict + suboptions: + time: + description: time in seconds + type: int + minimal: + description: + - Set to 1 second and set multiplier for Hellos + - Number of Hellos sent within 1 second. Please refer + vendor documentation of Valid values. + - Valid only with IP OSPF config + type: int + demand_circuit: + description: OSPF Demand Circuit, enable or disable + the demand circuit' + type: dict + suboptions: + enable: + description: Enable Demand Circuit + type: bool + ignore: + description: Ignore demand circuit auto-negotiation requests + type: bool + disable: + description: + - Disable demand circuit on this interface + - Valid only with IPv6 OSPF config + type: bool + flood_reduction: + description: OSPF Flood Reduction + type: bool + hello_interval: + description: + - Time between HELLO packets + - Please refer vendor documentation of Valid values. + type: int + lls: + description: + - Link-local Signaling (LLS) support + - Valid only with IP OSPF config + type: bool + manet: + description: + - Mobile Adhoc Networking options + - MANET Peering options + - Valid only with IPv6 OSPF config + type: dict + suboptions: + cost: + description: Redundant path cost improvement required to peer + type: dict + suboptions: + percent: + description: Relative incremental path cost. + Please refer vendor documentation of Valid values. + type: int + threshold: + description: Absolute incremental path cost. + Please refer vendor documentation of Valid values. + type: int + link_metrics: + description: Redundant path cost improvement required to peer + type: dict + suboptions: + set: + description: Enable link-metrics + type: bool + cost_threshold: + description: Minimum link cost threshold. + Please refer vendor documentation of Valid values. + type: int + mtu_ignore: + description: Ignores the MTU in DBD packets + type: bool + multi_area: + description: + - Set the OSPF multi-area ID + - Valid only with IP OSPF config + type: dict + suboptions: + id: + description: + - OSPF multi-area ID as a decimal value. Please refer vendor + documentation of Valid values. + - OSPF multi-area ID in IP address format(e.g. A.B.C.D) + type: int + cost: + description: Interface cost + type: int + neighbor: + description: + - OSPF neighbor link-local IPv6 address (X:X:X:X::X) + - Valid only with IPv6 OSPF config + type: dict + suboptions: + address: + description: Neighbor link-local IPv6 address + type: str + cost: + description: OSPF cost for point-to-multipoint neighbor + type: int + database_filter: + description: Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor + type: bool + poll_interval: + description: OSPF dead-router polling interval + type: int + priority: + description: OSPF priority of non-broadcast neighbor + type: int + network: + description: Network type + type: dict + suboptions: + broadcast: + description: Specify OSPF broadcast multi-access network + type: bool + manet: + description: + - Specify MANET OSPF interface type + - Valid only with IPv6 OSPF config + type: bool + non_broadcast: + description: Specify OSPF NBMA network + type: bool + point_to_multipoint: + description: Specify OSPF point-to-multipoint network + type: bool + point_to_point: + description: Specify OSPF point-to-point network + type: bool + prefix_suppression: + description: Enable/Disable OSPF prefix suppression + type: bool + priority: + description: Router priority. Please refer vendor documentation + of Valid values. + type: int + resync_timeout: + description: Interval after which adjacency is reset if oob-resync + is not started. Please refer vendor documentation of Valid values. + type: int + retransmit_interval: + description: Time between retransmitting lost link state + advertisements. Please refer vendor documentation of Valid values. + type: int + shutdown: + description: Set OSPF protocol's state to disable under + current interface + type: bool + transmit_delay: + description: Link state transmit delay. + Please refer vendor documentation of Valid values. + type: int + ttl_security: + description: + - TTL security check + - Valid only with IPV4 OSPF config + type: dict + suboptions: + set: + description: Enable TTL Security on all interfaces + type: bool + hops: + description: + - Maximum number of IP hops allowed + - Please refer vendor documentation of Valid values. + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS + device by executing the command B(sh running-config | section + ^interface). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any + change on the device. + - The state I(rendered) will transform the configuration in C(config) + option to platform specific CLI commands which will be returned in the + I(rendered) key within the result. For state I(rendered) active + connection to remote host is not required. + - The state I(gathered) will fetch the running configuration from device + and transform it into structured data in the format as per the resource + module argspec and the value is returned in the I(gathered) key within + the result. + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into JSON format as per the resource module + parameters and the value is returned in the I(parsed) key within the + result. The value of C(running_config) option should be the same format + as the output of command I(show running-config | include ip route|ipv6 + route) executed on device. For state I(parsed) active connection to + remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged + +""" +EXAMPLES = """ + +# Using deleted + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ipv6 ospf 55 area 105 +# ipv6 ospf priority 20 +# ipv6 ospf transmit-delay 30 +# ipv6 ospf adjacency stagger disable +# interface GigabitEthernet0/2 +# ip ospf priority 40 +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf 10 area 20 +# ip ospf cost 30 + +- name: Delete provided OSPF Interface config + cisco.ios.ios_ospf_interfaces: + config: + - name: GigabitEthernet0/1 + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "interface GigabitEthernet0/1", +# "no ipv6 ospf 55 area 105", +# "no ipv6 ospf adjacency stagger disable", +# "no ipv6 ospf priority 20", +# "no ipv6 ospf transmit-delay 30" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# interface GigabitEthernet0/2 +# ip ospf priority 40 +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf 10 area 20 +# ip ospf cost 30 + +# Using deleted without any config passed (NOTE: This will delete all OSPF Interfaces configuration from device) + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ipv6 ospf 55 area 105 +# ipv6 ospf priority 20 +# ipv6 ospf transmit-delay 30 +# ipv6 ospf adjacency stagger disable +# interface GigabitEthernet0/2 +# ip ospf priority 40 +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf 10 area 20 +# ip ospf cost 30 + +- name: Delete all OSPF config from interfaces + cisco.ios.ios_ospf_interfaces: + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "interface GigabitEthernet0/2", +# "no ip ospf 10 area 20", +# "no ip ospf adjacency stagger disable", +# "no ip ospf cost 30", +# "no ip ospf priority 40", +# "no ip ospf ttl-security hops 50", +# "interface GigabitEthernet0/1", +# "no ipv6 ospf 55 area 105", +# "no ipv6 ospf adjacency stagger disable", +# "no ipv6 ospf priority 20", +# "no ipv6 ospf transmit-delay 30" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# interface GigabitEthernet0/2 + +# Using merged + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# router-ios# + +- name: Merge provided OSPF Interfaces configuration + cisco.ios.ios_ospf_interfaces: + config: + - name: GigabitEthernet0/1 + address_family: + - afi: ipv4 + process: + id: 10 + area_id: 30 + adjacency: true + bfd: true + cost: + interface_cost: 5 + dead_interval: + time: 5 + demand_circuit: + ignore: true + network: + broadcast: true + priority: 25 + resync_timeout: 10 + shutdown: true + ttl_security: + hops: 50 + - afi: ipv6 + process: + id: 35 + area_id: 45 + adjacency: true + database_filter: true + manet: + link_metrics: + cost_threshold: 10 + priority: 55 + transmit_delay: 45 + state: merged + +# Commands Fired: +# --------------- +# +# "commands": [ +# "interface GigabitEthernet0/1", +# "ip ospf 10 area 30", +# "ip ospf adjacency stagger disable", +# "ip ospf bfd", +# "ip ospf cost 5", +# "ip ospf dead-interval 5", +# "ip ospf demand-circuit ignore", +# "ip ospf network broadcast", +# "ip ospf priority 25", +# "ip ospf resync-timeout 10", +# "ip ospf shutdown", +# "ip ospf ttl-security hops 50", +# "ipv6 ospf 35 area 45", +# "ipv6 ospf adjacency stagger disable", +# "ipv6 ospf database-filter all out", +# "ipv6 ospf manet peering link-metrics 10", +# "ipv6 ospf priority 55", +# "ipv6 ospf transmit-delay 45" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 + +# Using overridden + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 + +- name: Override provided OSPF Interfaces configuration + cisco.ios.ios_ospf_interfaces: + config: + - name: GigabitEthernet0/1 + address_family: + - afi: ipv6 + process: + id: 55 + area_id: 105 + adjacency: true + priority: 20 + transmit_delay: 30 + - name: GigabitEthernet0/2 + address_family: + - afi: ipv4 + process: + id: 10 + area_id: 20 + adjacency: true + cost: + interface_cost: 30 + priority: 40 + ttl_security: + hops: 50 + state: overridden + +# Commands Fired: +# --------------- +# +# "commands": [ +# "interface GigabitEthernet0/2", +# "ip ospf 10 area 20", +# "ip ospf adjacency stagger disable", +# "ip ospf cost 30", +# "ip ospf priority 40", +# "ip ospf ttl-security hops 50", +# "interface GigabitEthernet0/1", +# "ipv6 ospf 55 area 105", +# "no ipv6 ospf database-filter all out", +# "no ipv6 ospf manet peering link-metrics 10", +# "ipv6 ospf priority 20", +# "ipv6 ospf transmit-delay 30", +# "no ip ospf 10 area 30", +# "no ip ospf adjacency stagger disable", +# "no ip ospf bfd", +# "no ip ospf cost 5", +# "no ip ospf dead-interval 5", +# "no ip ospf demand-circuit ignore", +# "no ip ospf network broadcast", +# "no ip ospf priority 25", +# "no ip ospf resync-timeout 10", +# "no ip ospf shutdown", +# "no ip ospf ttl-security hops 50" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ipv6 ospf 55 area 105 +# ipv6 ospf priority 20 +# ipv6 ospf transmit-delay 30 +# ipv6 ospf adjacency stagger disable +# interface GigabitEthernet0/2 +# ip ospf priority 40 +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf 10 area 20 +# ip ospf cost 30 + +# Using replaced + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 + +- name: Replaced provided OSPF Interfaces configuration + cisco.ios.ios_ospf_interfaces: + config: + - name: GigabitEthernet0/2 + address_family: + - afi: ipv6 + process: + id: 55 + area_id: 105 + adjacency: true + priority: 20 + transmit_delay: 30 + state: replaced + +# Commands Fired: +# --------------- +# "commands": [ +# "interface GigabitEthernet0/2", +# "ipv6 ospf 55 area 105", +# "ipv6 ospf adjacency stagger disable", +# "ipv6 ospf priority 20", +# "ipv6 ospf transmit-delay 30" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 +# ipv6 ospf 55 area 105 +# ipv6 ospf priority 20 +# ipv6 ospf transmit-delay 30 +# ipv6 ospf adjacency stagger disable + +# Using Gathered + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 + +- name: Gather OSPF Interfaces provided configurations + cisco.ios.ios_ospf_interfaces: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "name": "GigabitEthernet0/2" +# }, +# { +# "address_family": [ +# { +# "adjacency": true, +# "afi": "ipv4", +# "bfd": true, +# "cost": { +# "interface_cost": 5 +# }, +# "dead_interval": { +# "time": 5 +# }, +# "demand_circuit": { +# "ignore": true +# }, +# "network": { +# "broadcast": true +# }, +# "priority": 25, +# "process": { +# "area_id": "30", +# "id": 10 +# }, +# "resync_timeout": 10, +# "shutdown": true, +# "ttl_security": { +# "hops": 50 +# } +# }, +# { +# "adjacency": true, +# "afi": "ipv6", +# "database_filter": true, +# "manet": { +# "link_metrics": { +# "cost_threshold": 10 +# } +# }, +# "priority": 55, +# "process": { +# "area_id": "45", +# "id": 35 +# }, +# "transmit_delay": 45 +# } +# ], +# "name": "GigabitEthernet0/1" +# }, +# { +# "name": "GigabitEthernet0/0" +# } +# ] + +# After state: +# ------------ +# +# router-ios#sh running-config | section ^interface +# interface GigabitEthernet0/0 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/2 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_ospf_interfaces: + config: + - name: GigabitEthernet0/1 + address_family: + - afi: ipv4 + process: + id: 10 + area_id: 30 + adjacency: true + bfd: true + cost: + interface_cost: 5 + dead_interval: + time: 5 + demand_circuit: + ignore: true + network: + broadcast: true + priority: 25 + resync_timeout: 10 + shutdown: true + ttl_security: + hops: 50 + - afi: ipv6 + process: + id: 35 + area_id: 45 + adjacency: true + database_filter: true + manet: + link_metrics: + cost_threshold: 10 + priority: 55 + transmit_delay: 45 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "interface GigabitEthernet0/1", +# "ip ospf 10 area 30", +# "ip ospf adjacency stagger disable", +# "ip ospf bfd", +# "ip ospf cost 5", +# "ip ospf dead-interval 5", +# "ip ospf demand-circuit ignore", +# "ip ospf network broadcast", +# "ip ospf priority 25", +# "ip ospf resync-timeout 10", +# "ip ospf shutdown", +# "ip ospf ttl-security hops 50", +# "ipv6 ospf 35 area 45", +# "ipv6 ospf adjacency stagger disable", +# "ipv6 ospf database-filter all out", +# "ipv6 ospf manet peering link-metrics 10", +# "ipv6 ospf priority 55", +# "ipv6 ospf transmit-delay 45" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# interface GigabitEthernet0/2 +# interface GigabitEthernet0/1 +# ip ospf network broadcast +# ip ospf resync-timeout 10 +# ip ospf dead-interval 5 +# ip ospf priority 25 +# ip ospf demand-circuit ignore +# ip ospf bfd +# ip ospf adjacency stagger disable +# ip ospf ttl-security hops 50 +# ip ospf shutdown +# ip ospf 10 area 30 +# ip ospf cost 5 +# ipv6 ospf 35 area 45 +# ipv6 ospf priority 55 +# ipv6 ospf transmit-delay 45 +# ipv6 ospf database-filter all out +# ipv6 ospf adjacency stagger disable +# ipv6 ospf manet peering link-metrics 10 +# interface GigabitEthernet0/0 + +- name: Parse the provided configuration with the exisiting running configuration + cisco.ios.ios_ospf_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# }, +# { +# "name": "GigabitEthernet0/2" +# }, +# { +# "address_family": [ +# { +# "adjacency": true, +# "afi": "ipv4", +# "bfd": true, +# "cost": { +# "interface_cost": 5 +# }, +# "dead_interval": { +# "time": 5 +# }, +# "demand_circuit": { +# "ignore": true +# }, +# "network": { +# "broadcast": true +# }, +# "priority": 25, +# "process": { +# "area_id": "30", +# "id": 10 +# }, +# "resync_timeout": 10, +# "shutdown": true, +# "ttl_security": { +# "hops": 50 +# } +# }, +# { +# "adjacency": true, +# "afi": "ipv6", +# "database_filter": true, +# "manet": { +# "link_metrics": { +# "cost_threshold": 10 +# } +# }, +# "priority": 55, +# "process": { +# "area_id": "45", +# "id": 35 +# }, +# "transmit_delay": 45 +# } +# ], +# "name": "GigabitEthernet0/1" +# }, +# { +# "name": "GigabitEthernet0/0" +# } +# ] + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +after: + description: The resulting configuration model invocation. + returned: when changed + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface GigabitEthernet0/1', 'ip ospf 10 area 30', 'ip ospf cost 5', 'ip ospf priority 25'] +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospf_interfaces.ospf_interfaces import ( + Ospf_InterfacesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospf_interfaces.ospf_interfaces import ( + Ospf_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Ospf_InterfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Ospf_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py new file mode 100644 index 00000000..6a435b43 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py @@ -0,0 +1,1691 @@ +#!/usr/bin/python +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for ios_ospfv2 +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_ospfv2 +short_description: OSPFv2 resource module +description: This module configures and manages the Open Shortest Path First (OSPF) + version 2 on IOS platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of OSPF options. + type: dict + suboptions: + processes: + description: + - List of OSPF instance configurations. + type: list + elements: dict + suboptions: + process_id: + description: Process ID + required: true + type: int + vrf: + description: Specify parameters for a VPN Routing/Forwarding instance + type: str + address_family: + description: Router Address Family configuration mode + type: dict + suboptions: + default: + description: Set a command to its defaults + type: bool + snmp_context: + description: + - Modify snmp parameters + - Configure SNMP context name + type: str + topology: + description: Associate the routing protocol to a topology instance + type: dict + suboptions: + name: + description: Routing topology instance name + type: str + base: + description: Entering router topology sub mode + type: bool + tid: + description: + - Configuring the routing protocol topology tid + - Note, please refer vendor documentation for valid values + type: bool + adjacency: + description: To configure control adjacency formation + type: dict + suboptions: + min_adjacency: + description: + - Initial number of adjacencies allowed to be forming in an area + - Please refer vendor documentation for valid values + type: int + max_adjacency: + description: + - Maximum number of adjacencies allowed to be forming + - Please refer vendor documentation for valid values + type: int + none: + description: No initial + type: bool + areas: + description: OSPF area parameters + type: list + elements: dict + suboptions: + area_id: + description: + - OSPF area ID as a decimal value. Please refer vendor documentation + of Valid values. + - OSPF area ID in IP address format(e.g. A.B.C.D) + type: str + authentication: + description: Area authentication + type: dict + suboptions: + enable: + description: Enable area authentication + type: bool + message_digest: + description: Use IPsec authentication + type: bool + capability: + description: + - Enable area specific capability + - Enable exclusion of links from base topology + type: bool + default_cost: + description: + - Set the summary default-cost of a NSSA/stub area + - Stub's advertised external route metric + - Note, please refer vendor documentation for respective valid values + type: int + filter_list: + description: Filter networks between OSPF areas + type: list + elements: dict + suboptions: + name: + description: Name of an IP prefix-list + type: str + direction: + description: The direction to apply on the filter networks sent to and from this area. + type: str + choices: ['in', 'out'] + required: true + nssa: + description: Specify a NSSA area + type: dict + suboptions: + set: + description: Enable a NSSA area + type: bool + default_information_originate: + description: Originate Type 7 default into NSSA area + type: dict + suboptions: + metric: + description: OSPF default metric + type: int + metric_type: + description: + - OSPF metric type for default routes + - OSPF Link State type + type: int + choices: [1, 2] + nssa_only: + description: Limit default advertisement to this NSSA area + type: bool + no_ext_capability: + description: Do not send domain specific capabilities into NSSA + type: bool + no_redistribution: + description: No redistribution into this NSSA area + type: bool + no_summary: + description: Do not send summary LSA into NSSA + type: bool + translate: + description: + - Translate LSA + - Always translate LSAs on this ABR + - Suppress forwarding address in translated LSAs + type: str + choices: ['always', 'suppress-fa'] + ranges: + description: Summarize routes matching address/mask (border routers only) + type: list + elements: dict + suboptions: + address: + description: IP address to match + type: str + netmask: + description: IP mask for address + type: str + advertise: + description: + - Advertise this range (default) + - Since, advertise when enabled is not shown in running-config + idempotency won't be maintained for the play in the second or + next run of the play. + type: bool + cost: + description: User specified metric for this range + type: int + not_advertise: + description: DoNotAdvertise this range + type: bool + sham_link: + description: Define a sham link and its parameters + type: dict + suboptions: + source: + description: IP addr associated with sham-link source (A.B.C.D) + type: str + destination: + description: IP addr associated with sham-link destination (A.B.C.D) + type: str + cost: + description: + - Associate a cost with the sham-link + - Cost of the sham-link + - Note, please refer vendor documentation for respective valid values + type: int + ttl_security: + description: + - TTL security check + - Maximum number of IP hops allowed + type: int + stub: + description: + - Specify a stub area + - Backbone can not be configured as stub area + type: dict + suboptions: + set: + description: Enable a stub area + type: bool + no_ext_capability: + description: Do not send domain specific capabilities into stub area + type: bool + no_summary: + description: Do not send summary LSA into stub area + type: bool + auto_cost: + description: Calculate OSPF interface cost according to bandwidth + type: dict + suboptions: + set: + description: Enable OSPF auto-cost + type: bool + reference_bandwidth: + description: + - Use reference bandwidth method to assign OSPF cost + - Note, refer vendor documentation for respective valid values + type: int + bfd: + description: + - BFD configuration commands + - Enable BFD on all interfaces + type: bool + capability: + description: Enable specific OSPF feature + type: dict + suboptions: + lls: + description: Link-local Signaling (LLS) support + type: bool + opaque: + description: Opaque LSA + type: bool + transit: + description: Transit Area + type: bool + vrf_lite: + description: Do not perform PE specific checks + type: bool + compatible: + description: OSPF router compatibility list + type: dict + suboptions: + rfc1583: + description: compatible with RFC 1583 + type: bool + rfc1587: + description: compatible with RFC 1587 + type: bool + rfc5243: + description: supports DBD exchange optimization + type: bool + default_information: + description: Control distribution of default information + type: dict + suboptions: + originate: + description: Distribute a default route + type: bool + always: + description: Always advertise default route + type: bool + metric: + description: + - OSPF default metric + - Note, refer vendor documentation for respective valid values + type: int + metric_type: + description: + - OSPF metric type for default routes + - Note, please refer vendor documentation for respective valid range + type: int + route_map: + description: Route-map reference name + type: str + default_metric: + description: Set metric of redistributed routes + type: int + discard_route: + description: Enable or disable discard-route installation + type: dict + suboptions: + set: + description: Enable discard-route installation + type: bool + external: + description: + - Discard route for redistributed summarised routes + - Administrative distance for redistributed summarised routes + - Note, please refer vendor documentation for respective valid range + type: int + internal: + description: + - Discard route for summarised internal routes + - Administrative distance for summarised internal routes + - Note, please refer vendor documentation for respective valid range + type: int + distance: + description: Define an administrative distance + type: dict + suboptions: + admin_distance: + description: OSPF Administrative distance + type: dict + suboptions: + distance: + description: Administrative distance + type: int + address: + description: IP Source address + type: str + wildcard_bits: + description: Wildcard bits + type: str + acl: + description: Access-list name/number + type: str + ospf: + description: OSPF distance + type: dict + suboptions: + external: + description: External type 5 and type 7 routes + type: int + inter_area: + description: Inter-area routes + type: int + intra_area: + description: Intra-area routes + type: int + distribute_list: + description: Filter networks in routing updates + type: dict + suboptions: + acls: + description: IP access list + type: list + elements: dict + suboptions: + name: + description: IP access list name/number + type: str + required: true + direction: + description: Filter incoming and outgoing routing updates. + type: str + required: true + choices: ['in', 'out'] + interface: + description: + - Interface configuration (GigabitEthernet A/B) + - Valid with incoming traffic + type: str + protocol: + description: + - Protocol config (bgp 1). + - Valid with outgoing traffic + type: str + prefix: + description: Filter prefixes in routing updates + type: dict + suboptions: + name: + description: Name of an IP prefix-list + type: str + required: true + gateway_name: + description: Gateway name for filtering incoming updates based on gateway + type: str + direction: + description: Filter incoming and outgoing routing updates. + type: str + required: true + choices: ['in', 'out'] + interface: + description: + - Interface configuration (GigabitEthernet A/B) + - Valid with incoming traffic + type: str + protocol: + description: + - Protocol config (bgp 1). + - Valid with outgoing traffic + type: str + route_map: + description: Filter prefixes in routing updates + type: dict + suboptions: + name: + description: Route-map name + type: str + required: true + domain_id: + description: OSPF domain-id + type: dict + suboptions: + ip_address: + description: IP address + type: dict + suboptions: + address: + description: OSPF domain ID in IP address format + type: str + secondary: + description: Secondary Domain-ID + type: bool + 'null': + description: Null Domain-ID + type: bool + domain_tag: + description: + - OSPF domain-tag which is OSPF domain tag - 32-bit value + - Note, please refer vendor documentation for respective valid range + type: int + event_log: + description: Event Logging + type: dict + suboptions: + enable: + description: Enable event Logging + type: bool + one_shot: + description: Disable Logging When Log Buffer Becomes Full + type: bool + pause: + description: Pause Event Logging + type: bool + size: + description: + - Maximum Number of Events Stored in the Event Log + - Note, refer vendor documentation for respective valid values + type: int + help: + description: Description of the interactive help system + type: bool + ignore: + description: + - Do not complain about specific event + - Do not complain upon receiving LSA of the specified type, MOSPF Type 6 LSA + type: bool + interface_id: + description: + - Source of the interface ID + - SNMP MIB ifIndex + type: bool + ispf: + description: Enable incremental SPF computation + type: bool + limit: + description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions + type: dict + suboptions: + dc: + description: Demand circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + non_dc: + description: Non-demand-circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + local_rib_criteria: + description: Enable or disable usage of local RIB as route criteria + type: dict + suboptions: + enable: + description: Enable usage of local RIB as route criteria + type: bool + forwarding_address: + description: Local RIB used to validate external/NSSA forwarding addresses + type: bool + inter_area_summary: + description: Local RIB used as criteria for inter-area summaries + type: bool + nssa_translation: + description: Local RIB used as criteria for NSSA translation + type: bool + log_adjacency_changes: + description: Log changes in adjacency state + type: dict + suboptions: + set: + description: Log changes in adjacency state + type: bool + detail: + description: Log all state changes + type: bool + max_lsa: + description: Maximum number of non self-generated LSAs to accept + type: dict + suboptions: + number: + description: + - Maximum number of non self-generated LSAs to accept + - Note, refer vendor documentation for respective valid values + type: int + threshold_value: + description: + - Threshold value (%) at which to generate a warning msg + - Note, refer vendor documentation for respective valid values + type: int + ignore_count: + description: + - Maximum number of times adjacencies can be suppressed + - Note, refer vendor documentation for respective valid values + type: int + ignore_time: + description: + - Number of minutes during which all adjacencies are suppressed + - Note, refer vendor documentation for respective valid values + type: int + reset_time: + description: + - Number of minutes after which ignore-count is reset to zero + - Note, refer vendor documentation for respective valid values + type: int + warning_only: + description: Only give a warning message when limit is exceeded + type: bool + max_metric: + description: Set maximum metric + type: dict + suboptions: + router_lsa: + description: Maximum metric in self-originated router-LSAs + type: bool + required: true + external_lsa: + description: + - Override external-lsa metric with max-metric value + - Overriding metric in external-LSAs + - Note, refer vendor documentation for respective valid values + type: int + include_stub: + description: Set maximum metric for stub links in router-LSAs + type: bool + on_startup: + description: Set maximum metric temporarily after reboot + type: dict + suboptions: + time: + description: + - Time, in seconds, router-LSAs are originated with max-metric + - Note, please refer vendor documentation for respective valid range + type: int + wait_for_bgp: + description: Let BGP decide when to originate router-LSA with normal metric + type: bool + summary_lsa: + description: + - Override summary-lsa metric with max-metric value + - Note, please refer vendor documentation for respective valid range + type: int + maximum_paths: + description: + - Forward packets over multiple paths + - Number of paths + type: int + mpls: + description: Configure MPLS routing protocol parameters + type: dict + suboptions: + ldp: + description: routing protocol commands for MPLS LDP + type: dict + suboptions: + autoconfig: + description: routing protocol commands for MPLS LDP + type: dict + suboptions: + set: + description: Configure LDP automatic configuration and set the config + type: bool + area: + description: Configure an OSPF area to run MPLS LDP + type: str + sync: + description: Configure LDP-IGP Synchronization + type: bool + traffic_eng: + description: Let BGP decide when to originate router-LSA with normal metric + type: dict + suboptions: + area: + description: + - Configure an ospf area to run MPLS Traffic Engineering + - OSPF area ID as a decimal value or in IP address format + type: str + autoroute_exclude: + description: + - MPLS TE autoroute exclude + - Filter prefixes based on name of an IP prefix-list + type: str + interface: + description: MPLS TE interface configuration for this OSPF process + type: dict + suboptions: + interface_type: + description: TE Interface configuration (GigabitEthernet A/B) + type: str + area: + description: + - Advertise MPLS TE information for this interface into area + - OSPF area ID as a decimal value + type: int + mesh_group: + description: Traffic Engineering Mesh-Group advertisement + type: dict + suboptions: + id: + description: Mesh Group Id + type: int + interface: + description: Interface configuration (GigabitEthernet A/B) + type: str + area: + description: configure flooding scope as area + type: str + multicast_intact: + description: MPLS TE and PIM interaction + type: bool + router_id_interface: + description: Router Interface configuration (GigabitEthernet A/B) + type: str + neighbor: + description: Specify a neighbor router + type: dict + suboptions: + address: + description: Neighbor address (A.B.C.D) + type: str + cost: + description: + - OSPF cost for point-to-multipoint neighbor metric + - Note, please refer vendor documentation for respective valid range + type: int + database_filter: + description: + - Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor + - Filter all outgoing LSA + type: bool + poll_interval: + description: OSPF dead-router polling interval of non-broadcast neighbor in Seconds + type: int + priority: + description: OSPF priority of non-broadcast neighbor priority + type: int + network: + description: Enable routing on an IP network + type: list + elements: dict + suboptions: + address: + description: Network number + type: str + wildcard_bits: + description: OSPF wild card bits + type: str + area: + description: Set the OSPF area ID + type: str + nsf: + description: Non-stop forwarding + type: dict + suboptions: + cisco: + description: Cisco Non-stop forwarding + type: dict + suboptions: + helper: + description: helper support + type: bool + disable: + description: disable helper support + type: bool + ietf: + description: IETF graceful restart + type: dict + suboptions: + helper: + description: helper support + type: bool + disable: + description: disable helper support + type: bool + strict_lsa_checking: + description: enable helper strict LSA checking + type: bool + passive_interface: + description: + - Suppress routing updates on an interface (GigabitEthernet A/B) + - Interface name with respective interface number + type: str + prefix_suppression: + description: Enable prefix suppression + type: bool + priority: + description: + - OSPF topology priority + - Note, refer vendor documentation for respective valid values + type: int + queue_depth: + description: Hello/Router process queue depth + type: dict + suboptions: + hello: + description: OSPF Hello process queue depth + type: dict + suboptions: + max_packets: + description: maximum number of packets in the queue + type: int + unlimited: + description: Unlimited queue depth + type: bool + update: + description: OSPF Router process queue depth + type: dict + suboptions: + max_packets: + description: maximum number of packets in the queue + type: int + unlimited: + description: Unlimited queue depth + type: bool + router_id: + description: + - Router-id address for this OSPF process + - OSPF router-id in IP address format (A.B.C.D) + type: str + shutdown: + description: Shutdown the router process + type: bool + summary_address: + description: Configure IP address summaries + type: dict + suboptions: + address: + description: IP summary address + type: str + mask: + description: IP Summary mask + type: str + not_advertise: + description: Do not advertise or translate + type: bool + nssa_only: + description: Limit summary to NSSA areas + type: bool + tag: + description: Set tag + type: int + timers: + description: Adjust routing timers + type: dict + suboptions: + lsa: + description: + - OSPF LSA timers, arrival timer + - The minimum interval in milliseconds between accepting the same LSA + - Note, refer vendor documentation for respective valid values + type: int + pacing: + description: OSPF pacing timers + type: dict + suboptions: + flood: + description: + - OSPF flood pacing timer + - The minimum interval in msec to pace limit flooding on interface + - Note, refer vendor documentation for respective valid values + type: int + lsa_group: + description: + - OSPF LSA group pacing timer + - Interval in sec between group of LSA being refreshed or maxaged + - Note, refer vendor documentation for respective valid values + type: int + retransmission: + description: + - OSPF retransmission pacing timer + - The minimum interval in msec between neighbor retransmissions + - Note, refer vendor documentation for respective valid values + type: int + throttle: + description: OSPF throttle timers + type: dict + suboptions: + lsa: + description: OSPF LSA throttle timers + type: dict + suboptions: + first_delay: + description: + - Delay to generate first occurrence of LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + min_delay: + description: + - Minimum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + spf: + description: OSPF SPF throttle timers + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: dict + suboptions: + receive_delay: + description: + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + between_delay: + description: + - Delay between first and second SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum wait time in milliseconds for SPF calculations + - Note, refer vendor documentation for respective valid values + type: int + traffic_share: + description: + - How to compute traffic share over alternate paths + - All traffic shared among min metric paths + - Use different interfaces for equal-cost paths + type: bool + ttl_security: + description: TTL security check + type: dict + suboptions: + set: + description: Enable TTL Security on all interfaces + type: bool + hops: + description: + - Maximum number of IP hops allowed + - Note, refer vendor documentation for respective valid values + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS + device by executing the command B(sh running-config | section ^router ospf). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + +""" +EXAMPLES = """ + +# Using deleted + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +- name: Delete provided OSPF V2 processes + cisco.ios.ios_ospfv2: + config: + processes: + - process_id: 1 + - process_id: 200 + vrf: blue + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospf 1" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in + +# Using deleted without any config passed (NOTE: This will delete all OSPFV2 configuration from device) + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +- name: Delete all OSPF processes + cisco.ios.ios_ospfv2: + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospf 200 vrf blue", +# "no router ospf 1" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospf +# router-ios# + +# Using merged + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router-ios# + +- name: Merge provided OSPF V2 configuration + cisco.ios.ios_ospfv2: + config: + processes: + - process_id: 1 + max_metric: + router_lsa: true + on_startup: + time: 110 + areas: + - area_id: '5' + capability: true + authentication: + enable: true + - area_id: '10' + authentication: + message_digest: true + nssa: + default_information_originate: + metric: 10 + translate: suppress-fa + default_cost: 10 + filter_list: + - name: test_prefix_in + direction: in + - name: test_prefix_out + direction: out + network: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + area: 5 + default_information: + originate: true + - process_id: 200 + vrf: blue + domain_id: + ip_address: + address: 192.0.3.1 + max_metric: + router_lsa: true + on_startup: + time: 100 + auto_cost: + reference_bandwidth: 4 + areas: + - area_id: '10' + capability: true + distribute_list: + acls: + - name: 10 + direction: out + - name: 123 + direction: in + state: merged + +# Commands Fired: +# --------------- +# +# "commands": [ +# "router ospf 200 vrf blue", +# "auto-cost reference-bandwidth 4", +# "distribute-list 10 out", +# "distribute-list 123 in", +# "domain-id 192.0.3.1", +# "max-metric router-lsa on-startup 100", +# "area 10 capability default-exclusion", +# "router ospf 1", +# "default-information originate", +# "max-metric router-lsa on-startup 110", +# "network 198.51.100.0 0.0.0.255 area 5", +# "area 10 authentication message-digest", +# "area 10 default-cost 10", +# "area 10 nssa translate type7 suppress-fa", +# "area 10 nssa default-information-originate metric 10", +# "area 10 filter-list prefix test_prefix_out out", +# "area 10 filter-list prefix test_prefix_in in", +# "area 5 authentication", +# "area 5 capability default-exclusion" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +# Using overridden + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +- name: Override provided OSPF V2 configuration + cisco.ios.ios_ospfv2: + config: + processes: + - process_id: 200 + vrf: blue + domain_id: + ip_address: + address: 192.0.4.1 + max_metric: + router_lsa: true + on_startup: + time: 200 + maximum_paths: 15 + ttl_security: + hops: 7 + areas: + - area_id: '10' + default_cost: 10 + authentication: + message_digest: true + - process_id: 100 + vrf: ospf_vrf + domain_id: + ip_address: + address: 192.0.5.1 + auto_cost: + reference_bandwidth: 5 + areas: + - area_id: '5' + authentication: + message_digest: true + nssa: + default_information_originate: + metric: 10 + translate: suppress-fa + state: overridden + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospf 1", +# "router ospf 100 vrf ospf_vrf", +# "auto-cost reference-bandwidth 5", +# "domain-id 192.0.5.1", +# "area 5 authentication message-digest", +# "area 5 nssa translate type7 suppress-fa", +# "area 5 nssa default-information-originate metric 10", +# "router ospf 200 vrf blue", +# "no auto-cost reference-bandwidth 4", +# "no distribute-list 10 out", +# "no distribute-list 123 in", +# "domain-id 192.0.4.1", +# "max-metric router-lsa on-startup 200", +# "maximum-paths 15", +# "ttl-security all-interfaces hops 7", +# "area 10 authentication message-digest", +# "no area 10 capability default-exclusion", +# "area 10 default-cost 10" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.4.1 +# max-metric router-lsa on-startup 200 +# ttl-security all-interfaces hops 7 +# area 10 authentication message-digest +# area 10 default-cost 10 +# maximum-paths 15 +# router ospf 100 vrf ospf_vrf +# domain-id 192.0.5.1 +# auto-cost reference-bandwidth 5 +# area 5 authentication message-digest +# area 5 nssa default-information-originate metric 10 +# area 5 nssa translate type7 suppress-fa + +# Using replaced + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +- name: Replaced provided OSPF V2 configuration + cisco.ios.ios_ospfv2: + config: + processes: + - process_id: 200 + vrf: blue + domain_id: + ip_address: + address: 192.0.4.1 + max_metric: + router_lsa: true + on_startup: + time: 200 + maximum_paths: 15 + ttl_security: + hops: 7 + areas: + - area_id: '10' + default_cost: 10 + authentication: + message_digest: true + - process_id: 100 + vrf: ospf_vrf + domain_id: + ip_address: + address: 192.0.5.1 + auto_cost: + reference_bandwidth: 5 + areas: + - area_id: '5' + authentication: + message_digest: true + nssa: + default_information_originate: + metric: 10 + translate: suppress-fa + state: replaced + +# Commands Fired: +# --------------- +# "commands": [ +# "router ospf 100 vrf ospf_vrf", +# "auto-cost reference-bandwidth 5", +# "domain-id 192.0.5.1", +# "area 5 authentication message-digest", +# "area 5 nssa translate type7 suppress-fa", +# "area 5 nssa default-information-originate metric 10", +# "router ospf 200 vrf blue", +# "no auto-cost reference-bandwidth 4", +# "no distribute-list 10 out", +# "no distribute-list 123 in", +# "domain-id 192.0.4.1", +# "max-metric router-lsa on-startup 200", +# "maximum-paths 15", +# "ttl-security all-interfaces hops 7", +# "area 10 authentication message-digest", +# "no area 10 capability default-exclusion", +# "area 10 default-cost 10" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.4.1 +# max-metric router-lsa on-startup 200 +# ttl-security all-interfaces hops 7 +# area 10 authentication message-digest +# area 10 default-cost 10 +# maximum-paths 15 +# router ospf 100 vrf ospf_vrf +# domain-id 192.0.5.1 +# auto-cost reference-bandwidth 5 +# area 5 authentication message-digest +# area 5 nssa default-information-originate metric 10 +# area 5 nssa translate type7 suppress-fa +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 5 capability default-exclusion +# area 5 authentication +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_in in +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +# Using Gathered + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +- name: Gather OSPFV2 provided configurations + cisco.ios.ios_ospfv2: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "5", +# "authentication": { +# "enable": true +# }, +# "capability": true +# }, +# { +# "area_id": "10", +# "authentication": { +# "message_digest": true +# }, +# "default_cost": 10, +# "filter_list": [ +# { +# "direction": "in", +# "name": "test_prefix_in" +# }, +# { +# "direction": "out", +# "name": "test_prefix_out" +# } +# ], +# "nssa": { +# "default_information_originate": { +# "metric": 10 +# }, +# "translate": "suppress-fa" +# } +# } +# ], +# "default_information": { +# "originate": true +# }, +# "max_metric": { +# "on_startup": { +# "time": 110 +# }, +# "router_lsa": true +# }, +# "network": { +# "address": "198.51.100.0", +# "area": "5", +# "wildcard_bits": "0.0.0.255" +# }, +# "process_id": 1 +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "capability": true +# } +# ], +# "auto_cost": { +# "reference_bandwidth": 4 +# }, +# "distribute_list": { +# "acls": [ +# { +# "direction": "out", +# "name": "10" +# }, +# { +# "direction": "in", +# "name": "123" +# } +# ] +# }, +# "domain_id": { +# "ip_address": { +# "address": "192.0.3.1" +# } +# }, +# "max_metric": { +# "on_startup": { +# "time": 100 +# }, +# "router_lsa": true +# }, +# "process_id": 200, +# "vrf": "blue" +# } +# ] +# } + +# After state: +# ------------ +# +# router-ios#sh running-config | section ^router ospf +# router ospf 200 vrf blue +# domain-id 192.0.3.1 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# area 10 capability default-exclusion +# distribute-list 10 out +# distribute-list 123 in +# router ospf 1 +# max-metric router-lsa on-startup 110 +# area 10 authentication message-digest +# area 10 nssa default-information-originate metric 10 +# area 10 nssa translate type7 suppress-fa +# area 10 default-cost 10 +# area 10 filter-list prefix test_prefix_out out +# network 198.51.100.0 0.0.0.255 area 5 +# default-information originate + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_ospfv2: + config: + processes: + - process_id: 1 + max_metric: + router_lsa: true + on_startup: + time: 110 + areas: + - area_id: '5' + capability: true + authentication: + enable: true + - area_id: '10' + authentication: + message_digest: true + nssa: + default_information_originate: + metric: 10 + translate: suppress-fa + default_cost: 10 + filter_list: + - name: test_prefix_in + direction: in + - name: test_prefix_out + direction: out + network: + address: 198.51.100.0 + wildcard_bits: 0.0.0.255 + area: 5 + default_information: + originate: true + - process_id: 200 + vrf: blue + domain_id: + ip_address: + address: 192.0.3.1 + max_metric: + router_lsa: true + on_startup: + time: 100 + auto_cost: + reference_bandwidth: 4 + areas: + - area_id: '10' + capability: true + distribute_list: + acls: + - name: 10 + direction: out + - name: 123 + direction: in + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "router ospf 200 vrf blue", +# "auto-cost reference-bandwidth 4", +# "distribute-list 10 out", +# "distribute-list 123 in", +# "domain-id 192.0.3.1", +# "max-metric router-lsa on-startup 100", +# "area 10 capability default-exclusion", +# "router ospf 1", +# "default-information originate", +# "max-metric router-lsa on-startup 110", +# "network 198.51.100.0 0.0.0.255 area 5", +# "area 10 authentication message-digest", +# "area 10 default-cost 10", +# "area 10 nssa translate type7 suppress-fa", +# "area 10 nssa default-information-originate metric 10", +# "area 10 filter-list prefix test_prefix_out out", +# "area 10 filter-list prefix test_prefix_in in", +# "area 5 authentication", +# "area 5 capability default-exclusion" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# router ospf 100 +# auto-cost reference-bandwidth 5 +# domain-id 192.0.5.1 +# area 5 authentication message-digest +# area 5 nssa translate type7 suppress-fa +# area 5 nssa default-information-originate metric 10 + +- name: Parse the provided configuration with the exisiting running configuration + cisco.ios.ios_ospfv2: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "5", +# "authentication": { +# "message_digest": true +# }, +# "nssa": { +# "default_information_originate": { +# "metric": 10 +# }, +# "translate": "suppress-fa" +# } +# } +# ], +# "auto_cost": { +# "reference_bandwidth": 5 +# }, +# "domain_id": { +# "ip_address": { +# "address": "192.0.5.1" +# } +# }, +# "process_id": 100 +# } +# ] +# } + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +after: + description: The resulting configuration model invocation. + returned: when changed + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['router ospf 200 vrf blue', 'auto-cost reference-bandwidth 5', 'domain-id 192.0.4.1'] +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv2.ospfv2 import ( + Ospfv2Args, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv2.ospfv2 import ( + Ospfv2, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Ospfv2Args.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Ospfv2(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py new file mode 100644 index 00000000..f566a2e2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py @@ -0,0 +1,1974 @@ +#!/usr/bin/python +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for ios_ospfv3 +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: ios_ospfv3 +short_description: OSPFv3 resource module +description: This module configures and manages the Open Shortest Path First (OSPF) + version 3 on IOS platforms. +version_added: 1.1.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A list of configurations for ospfv3. + type: dict + suboptions: + processes: + description: List of OSPF instance configurations. + type: list + elements: dict + suboptions: + process_id: + description: Process ID + required: true + type: int + address_family: + description: Enter Address Family command mode + type: list + elements: dict + suboptions: + afi: + description: Enter Address Family command mode + type: str + choices: + - ipv4 + - ipv6 + unicast: + description: Address Family modifier + type: bool + vrf: + description: Specify parameters for a VPN Routing/Forwarding instance + type: str + adjacency: + description: Control adjacency formation + type: dict + suboptions: + min_adjacency: + description: + - Initial number of adjacencies allowed to be forming in an area + - Please refer vendor documentation for valid values + type: int + none: + description: No initial + type: bool + max_adjacency: + description: + - Maximum number of adjacencies allowed to be forming + - Please refer vendor documentation for valid values + type: int + disable: + description: Disable adjacency staggering + type: bool + areas: + description: OSPF area parameters + type: list + elements: dict + suboptions: + area_id: + description: + - OSPF area ID as a decimal value. Please refer vendor documentation + of Valid values. + - OSPF area ID in IP address format(e.g. A.B.C.D) + type: str + authentication: + description: Authentication parameters + type: dict + suboptions: + key_chain: + description: Use a key-chain for cryptographic authentication keys + type: str + 'null': + description: Use no authentication + type: bool + default_cost: + description: + - Set the summary default-cost of a NSSA/stub area + - Stub's advertised external route metric + - Note, please refer vendor documentation for respective valid values + type: int + filter_list: + description: Filter networks between OSPFv3 areas + type: list + elements: dict + suboptions: + name: + description: Name of an IP prefix-list + type: str + direction: + description: The direction to apply on the filter networks sent to and from this area. + type: str + choices: ['in', 'out'] + required: True + normal: + description: Specify a normal area type + type: bool + nssa: + description: Specify a NSSA area + type: dict + suboptions: + set: + description: Enable a NSSA area + type: bool + default_information_originate: + description: Originate Type 7 default into NSSA area + type: dict + suboptions: + metric: + description: OSPF default metric + type: int + metric_type: + description: + - OSPF metric type for default routes + - OSPF Link State type + type: int + choices: [1, 2] + nssa_only: + description: Limit default advertisement to this NSSA area + type: bool + no_redistribution: + description: No redistribution into this NSSA area + type: bool + no_summary: + description: Do not send summary LSA into NSSA + type: bool + translate: + description: + - Translate LSA + - Always translate LSAs on this ABR + - Suppress forwarding address in translated LSAs + type: str + choices: ['always', 'suppress-fa'] + ranges: + description: Summarize routes matching address/mask (border routers only) + type: list + elements: dict + suboptions: + address: + description: IP address to match + type: str + netmask: + description: IP mask for address + type: str + advertise: + description: + - Advertise this range (default) + - Since, advertise when enabled is not shown in running-config + idempotency won't be maintained for the play in the second or + next run of the play. + type: bool + cost: + description: User specified metric for this range + type: int + not_advertise: + description: DoNotAdvertise this range + type: bool + sham_link: + description: Define a sham link and its parameters + type: dict + suboptions: + source: + description: IPv6 address associated with sham-link source (X:X:X:X::X) + type: str + destination: + description: IPv6 address associated with sham-link destination (X:X:X:X::X) + type: str + authentication: + description: Authentication parameters + type: dict + suboptions: + key_chain: + description: Use a key-chain for cryptographic authentication keys + type: str + 'null': + description: Use no authentication + type: bool + cost: + description: + - Associate a cost with the sham-link + - Cost of the sham-link + type: int + ttl_security: + description: + - TTL security check + - maximum number of hops allowed + type: int + stub: + description: + - Specify a stub area + - Backbone can not be configured as stub area + type: dict + suboptions: + set: + description: Enable a stub area + type: bool + no_summary: + description: Do not send summary LSA into stub area + type: bool + authentication: + description: + - Authentication parameters + - Authentication operation mode + type: dict + suboptions: + deployment: + description: Deployment mode of operation + type: bool + normal: + description: Normal mode of operation + type: bool + auto_cost: + description: Calculate OSPF interface cost according to bandwidth + type: dict + suboptions: + set: + description: Enable OSPF auto-cost + type: bool + reference_bandwidth: + description: + - Use reference bandwidth method to assign OSPF cost + - Note, refer vendor documentation for respective valid values + type: int + bfd: + description: BFD configuration commands + type: dict + suboptions: + all_interfaces: + description: Enable BFD on all interfaces + type: bool + disable: + description: Disable BFD on all interfaces + type: bool + capability: + description: + - Enable a specific feature + - Do not perform PE specific checks + type: bool + compatible: + description: OSPFv3 router compatibility list + type: dict + suboptions: + rfc1583: + description: compatible with RFC 1583 + type: bool + rfc1587: + description: compatible with RFC 1587 + type: bool + rfc5243: + description: supports DBD exchange optimization + type: bool + default_information: + description: Control distribution of default information + type: dict + suboptions: + originate: + description: Distribute a default route + type: bool + always: + description: Always advertise default route + type: bool + metric: + description: + - OSPF default metric + - Note, refer vendor documentation for respective valid values + type: int + metric_type: + description: + - OSPF metric type for default routes + - Note, please refer vendor documentation for respective valid range + type: int + route_map: + description: Route-map reference name + type: str + default_metric: + description: Set metric of redistributed routes + type: int + discard_route: + description: Enable or disable discard-route installation + type: dict + suboptions: + sham_link: + description: Discard route for sham-link routes + type: bool + external: + description: Discard route for summarised redistributed routes + type: bool + internal: + description: Discard route for summarised inter-area routes + type: bool + distance: + description: + - Define an administrative distance + - Note, please refer vendor documentation for respective valid range + type: int + distribute_list: + description: Filter networks in routing updates + type: dict + suboptions: + acls: + description: IP access list + type: list + elements: dict + suboptions: + name: + description: IP access list name/number + type: str + required: true + direction: + description: Filter incoming and outgoing routing updates. + type: str + required: true + choices: ['in', 'out'] + interface: + description: + - Interface configuration (GigabitEthernet A/B) + - Valid with incoming traffic + type: str + protocol: + description: + - Protocol config (bgp 1). + - Valid with outgoing traffic + type: str + prefix: + description: Filter prefixes in routing updates + type: dict + suboptions: + name: + description: Name of an IP prefix-list + type: str + required: true + gateway_name: + description: Gateway name for filtering incoming updates based on gateway + type: str + direction: + description: Filter incoming and outgoing routing updates. + type: str + required: true + choices: ['in', 'out'] + interface: + description: + - Interface configuration (GigabitEthernet A/B) + - Valid with incoming traffic + type: str + protocol: + description: + - Protocol config (bgp 1). + - Valid with outgoing traffic + type: str + route_map: + description: Filter prefixes in routing updates + type: dict + suboptions: + name: + description: Route-map name + type: str + required: true + event_log: + description: Event Logging + type: dict + suboptions: + enable: + description: Enable event Logging + type: bool + one_shot: + description: Disable Logging When Log Buffer Becomes Full + type: bool + pause: + description: Pause Event Logging + type: bool + size: + description: + - Maximum Number of Events Stored in the Event Log + - Note, refer vendor documentation for respective valid values + type: int + graceful_restart: + description: + - Graceful-restart options + - helper support + type: dict + suboptions: + enable: + description: helper support enabled + type: bool + disable: + description: disable helper support + type: bool + strict_lsa_checking: + description: enable helper strict LSA checking + type: bool + interface_id: + description: Source of the interface ID + type: dict + suboptions: + ios_if_index: + description: IOS interface number + type: bool + snmp_if_index: + description: SNMP MIB ifIndex + type: bool + limit: + description: Limit a specific OSPF feature + type: dict + suboptions: + dc: + description: Demand circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + non_dc: + description: Non-demand-circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + local_rib_criteria: + description: Enable or disable usage of local RIB as route criteria + type: dict + suboptions: + enable: + description: Enable usage of local RIB as route criteria + type: bool + forwarding_address: + description: Local RIB used to validate external/NSSA forwarding addresses + type: bool + inter_area_summary: + description: Local RIB used as criteria for inter-area summaries + type: bool + nssa_translation: + description: Local RIB used as criteria for NSSA translation + type: bool + log_adjacency_changes: + description: Log changes in adjacency state + type: dict + suboptions: + set: + description: Log changes in adjacency state + type: bool + detail: + description: Log all state changes + type: bool + manet: + description: Specify MANET OSPF parameters + type: dict + suboptions: + cache: + description: Specify MANET cache sizes + type: dict + suboptions: + acknowledgement: + description: + - Specify MANET acknowledgement cache size + - Maximum number of acknowledgements in cache + type: int + update: + description: + - Specify MANET LSA cache size + - Maximum number of LSAs in cache + type: int + hello: + description: Unicast Hellos rather than multicast + type: dict + suboptions: + multicast: + description: Multicast Hello requests and responses rather than unicast + type: bool + unicast: + description: Unicast Hello requests and responses rather than multicast + type: bool + peering: + description: MANET OSPF Smart Peering + type: dict + suboptions: + set: + description: Enable selective peering + type: bool + disable: + description: Disable selective peering + type: bool + per_interface: + description: Select peers per interface rather than per node + type: bool + redundancy: + description: + - Redundant paths + - Number of redundant OSPF paths + type: int + willingness: + description: Specify and Relay willingness value + type: int + max_lsa: + description: Maximum number of non self-generated LSAs to accept + type: dict + suboptions: + number: + description: + - Maximum number of non self-generated LSAs to accept + - Note, refer vendor documentation for respective valid values + type: int + threshold_value: + description: + - Threshold value (%) at which to generate a warning msg + - Note, refer vendor documentation for respective valid values + type: int + ignore_count: + description: + - Maximum number of times adjacencies can be suppressed + - Note, refer vendor documentation for respective valid values + type: int + ignore_time: + description: + - Number of minutes during which all adjacencies are suppressed + - Note, refer vendor documentation for respective valid values + type: int + reset_time: + description: + - Number of minutes after which ignore-count is reset to zero + - Note, refer vendor documentation for respective valid values + type: int + warning_only: + description: Only give a warning message when limit is exceeded + type: bool + max_metric: + description: + - Set maximum metric + - Maximum metric in self-originated router-LSAs + type: dict + suboptions: + disable: + description: disable maximum metric in self-originated router-LSAs + type: bool + external_lsa: + description: + - Override external-lsa metric with max-metric value + - Overriding metric in external-LSAs + - Note, refer vendor documentation for respective valid values + type: int + inter_area_lsas: + description: + - Override inter-area-lsas metric with max-metric value + - Overriding metric in inter-area-LSAs + - Note, refer vendor documentation for respective valid values + type: int + on_startup: + description: Set maximum metric temporarily after reboot + type: dict + suboptions: + time: + description: + - Time, in seconds, router-LSAs are originated with max-metric + - Note, please refer vendor documentation for respective valid range + type: int + wait_for_bgp: + description: Let BGP decide when to originate router-LSA with normal metric + type: bool + stub_prefix_lsa: + description: Set maximum metric for stub links in prefix LSAs + type: bool + maximum_paths: + description: + - Forward packets over multiple paths + - Number of paths + type: int + passive_interface: + description: Suppress routing updates on an interface + type: str + prefix_suppression: + description: Prefix suppression + type: dict + suboptions: + enable: + description: Enable prefix suppression + type: bool + disable: + description: Disable prefix suppression + type: bool + queue_depth: + description: Hello/Router process queue depth + type: dict + suboptions: + hello: + description: OSPF Hello process queue depth + type: dict + suboptions: + max_packets: + description: maximum number of packets in the queue + type: int + unlimited: + description: Unlimited queue depth + type: bool + update: + description: OSPF Router process queue depth + type: dict + suboptions: + max_packets: + description: maximum number of packets in the queue + type: int + unlimited: + description: Unlimited queue depth + type: bool + router_id: + description: + - Router-id address for this OSPF process + - OSPF router-id in IP address format (A.B.C.D) + type: str + shutdown: + description: Shutdown the router process + type: dict + suboptions: + enable: + description: Shutdown the router process + type: bool + disable: + description: Disable Shutdown + type: bool + summary_prefix: + description: Configure IP address summaries + type: dict + suboptions: + address: + description: + - IP summary address (A.B.C.D) + - IP prefix <network>/<length> (A.B.C.D/nn) + type: str + mask: + description: IP Summary mask + type: str + not_advertise: + description: Do not advertise or translate + type: bool + nssa_only: + description: Limit summary to NSSA areas + type: bool + tag: + description: Set tag + type: int + timers: + description: Adjust routing timers + type: dict + suboptions: + lsa: + description: + - OSPF LSA timers, arrival timer + - The minimum interval in milliseconds between accepting the same LSA + - Note, refer vendor documentation for respective valid values + type: int + manet: + description: OSPF MANET timers + type: dict + suboptions: + cache: + description: Specify MANET cache sizes + type: dict + suboptions: + acknowledgement: + description: Specify MANET acknowledgement cache size + type: int + redundancy: + description: Specify MANET LSA cache size + type: int + hello: + description: + - Unicast Hellos rather than multicast + - Unicast Hello requests and responses rather than multicast + type: bool + peering: + description: MANET OSPF Smart Peering + type: dict + suboptions: + set: + description: Enable selective peering + type: bool + per_interface: + description: Select peers per interface rather than per node + type: bool + redundancy: + description: + - Redundant paths + - Number of redundant OSPF paths + type: int + willingness: + description: Specify and Relay willingness value + type: int + pacing: + description: OSPF pacing timers + type: dict + suboptions: + flood: + description: + - OSPF flood pacing timer + - The minimum interval in msec to pace limit flooding on interface + - Note, refer vendor documentation for respective valid values + type: int + lsa_group: + description: + - OSPF LSA group pacing timer + - Interval in sec between group of LSA being refreshed or maxaged + - Note, refer vendor documentation for respective valid values + type: int + retransmission: + description: + - OSPF retransmission pacing timer + - The minimum interval in msec between neighbor retransmissions + - Note, refer vendor documentation for respective valid values + type: int + throttle: + description: OSPF throttle timers + type: dict + suboptions: + lsa: + description: OSPF LSA throttle timers + type: dict + suboptions: + first_delay: + description: + - Delay to generate first occurrence of LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + min_delay: + description: + - Minimum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + spf: + description: OSPF SPF throttle timers + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: dict + suboptions: + receive_delay: + description: + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + between_delay: + description: + - Delay between first and second SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum wait time in milliseconds for SPF calculations + - Note, refer vendor documentation for respective valid values + type: int + adjacency: + description: Control adjacency formation + type: dict + suboptions: + min_adjacency: + description: + - Initial number of adjacencies allowed to be forming in an area + - Please refer vendor documentation for valid values + type: int + max_adjacency: + description: + - Maximum number of adjacencies allowed to be forming + - Please refer vendor documentation for valid values + type: int + none: + description: No initial + type: bool + areas: + description: OSPF area parameters + type: list + elements: dict + suboptions: + area_id: + description: + - OSPF area ID as a decimal value. Please refer vendor documentation + of Valid values. + - OSPF area ID in IP address format(e.g. A.B.C.D) + type: str + authentication: + description: Authentication parameters + type: dict + suboptions: + key_chain: + description: Use a key-chain for cryptographic authentication keys + type: str + ipsec: + description: Use IPsec authentication + type: dict + suboptions: + spi: + description: Set the SPI (Security Parameters Index) + type: int + md5: + description: Use MD5 authentication + type: int + sha1: + description: Use SHA-1 authentication + type: int + hex_string: + description: SHA-1 key (40 chars) + type: str + default_cost: + description: + - Set the summary default-cost of a NSSA/stub area + - Stub's advertised external route metric + - Note, please refer vendor documentation for respective valid values + type: int + nssa: + description: Specify a NSSA area + type: dict + suboptions: + set: + description: Enable a NSSA area + type: bool + default_information_originate: + description: Originate Type 7 default into NSSA area + type: dict + suboptions: + metric: + description: OSPF default metric + type: int + metric_type: + description: + - OSPF metric type for default routes + - OSPF Link State type + type: int + choices: [1, 2] + nssa_only: + description: Limit default advertisement to this NSSA area + type: bool + no_redistribution: + description: No redistribution into this NSSA area + type: bool + no_summary: + description: Do not send summary LSA into NSSA + type: bool + translate: + description: + - Translate LSA + - Always translate LSAs on this ABR + - Suppress forwarding address in translated LSAs + type: str + choices: ['always', 'suppress-fa'] + stub: + description: + - Specify a stub area + - Backbone can not be configured as stub area + type: dict + suboptions: + set: + description: Enable a stub area + type: bool + no_summary: + description: Do not send summary LSA into stub area + type: bool + authentication: + description: + - Authentication parameter mode + - Deployment mode of operation + type: bool + auto_cost: + description: Calculate OSPF interface cost according to bandwidth + type: dict + suboptions: + set: + description: Enable OSPF auto-cost + type: bool + reference_bandwidth: + description: + - Use reference bandwidth method to assign OSPF cost + - Note, refer vendor documentation for respective valid values + type: int + bfd: + description: + - BFD configuration commands + - Enable BFD on all interfaces + type: bool + compatible: + description: OSPFv3 router compatibility list + type: dict + suboptions: + rfc1583: + description: compatible with RFC 1583 + type: bool + rfc1587: + description: compatible with RFC 1587 + type: bool + rfc5243: + description: supports DBD exchange optimization + type: bool + event_log: + description: Event Logging + type: dict + suboptions: + enable: + description: Enable event Logging + type: bool + one_shot: + description: Disable Logging When Log Buffer Becomes Full + type: bool + pause: + description: Pause Event Logging + type: bool + size: + description: + - Maximum Number of Events Stored in the Event Log + - Note, refer vendor documentation for respective valid values + type: int + graceful_restart: + description: Graceful-restart options for helper support + type: dict + suboptions: + disable: + description: disable helper support + type: bool + strict_lsa_checking: + description: enable helper strict LSA checking + type: bool + help: + description: Description of the interactive help system + type: bool + interface_id: + description: + - Source of the interface ID + - SNMP MIB ifIndex + type: bool + limit: + description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions + type: dict + suboptions: + dc: + description: Demand circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + non_dc: + description: Non-demand-circuit retransmissions + type: dict + suboptions: + number: + description: The maximum number of retransmissions + type: int + disable: + description: Disble the feature + type: bool + local_rib_criteria: + description: Enable or disable usage of local RIB as route criteria + type: dict + suboptions: + enable: + description: Enable usage of local RIB as route criteria + type: bool + forwarding_address: + description: Local RIB used to validate external/NSSA forwarding addresses + type: bool + inter_area_summary: + description: Local RIB used as criteria for inter-area summaries + type: bool + nssa_translation: + description: Local RIB used as criteria for NSSA translation + type: bool + log_adjacency_changes: + description: Log changes in adjacency state + type: dict + suboptions: + set: + description: Log changes in adjacency state + type: bool + detail: + description: Log all state changes + type: bool + manet: + description: Specify MANET OSPF parameters + type: dict + suboptions: + cache: + description: Specify MANET cache sizes + type: dict + suboptions: + acknowledgement: + description: Specify MANET acknowledgement cache size + type: int + redundancy: + description: Specify MANET LSA cache size + type: int + hello: + description: + - Unicast Hellos rather than multicast + - Unicast Hello requests and responses rather than multicast + type: bool + peering: + description: MANET OSPF Smart Peering + type: dict + suboptions: + set: + description: Enable selective peering + type: bool + per_interface: + description: Select peers per interface rather than per node + type: bool + redundancy: + description: + - Redundant paths + - Number of redundant OSPF paths + type: int + willingness: + description: Specify and Relay willingness value + type: int + max_lsa: + description: Maximum number of non self-generated LSAs to accept + type: dict + suboptions: + number: + description: + - Maximum number of non self-generated LSAs to accept + - Note, refer vendor documentation for respective valid values + type: int + threshold_value: + description: + - Threshold value (%) at which to generate a warning msg + - Note, refer vendor documentation for respective valid values + type: int + ignore_count: + description: + - Maximum number of times adjacencies can be suppressed + - Note, refer vendor documentation for respective valid values + type: int + ignore_time: + description: + - Number of minutes during which all adjacencies are suppressed + - Note, refer vendor documentation for respective valid values + type: int + reset_time: + description: + - Number of minutes after which ignore-count is reset to zero + - Note, refer vendor documentation for respective valid values + type: int + warning_only: + description: Only give a warning message when limit is exceeded + type: bool + max_metric: + description: Set maximum metric + type: dict + suboptions: + router_lsa: + description: Maximum metric in self-originated router-LSAs + type: bool + required: true + external_lsa: + description: + - Override external-lsa metric with max-metric value + - Overriding metric in external-LSAs + - Note, refer vendor documentation for respective valid values + type: int + include_stub: + description: Set maximum metric for stub links in router-LSAs + type: bool + on_startup: + description: Set maximum metric temporarily after reboot + type: dict + suboptions: + time: + description: + - Time, in seconds, router-LSAs are originated with max-metric + - Note, please refer vendor documentation for respective valid range + type: int + wait_for_bgp: + description: Let BGP decide when to originate router-LSA with normal metric + type: bool + summary_lsa: + description: + - Override summary-lsa metric with max-metric value + - Note, please refer vendor documentation for respective valid range + type: int + passive_interface: + description: Suppress routing updates on an interface + type: str + prefix_suppression: + description: Enable prefix suppression + type: bool + queue_depth: + description: Hello/Router process queue depth + type: dict + suboptions: + hello: + description: OSPF Hello process queue depth + type: dict + suboptions: + max_packets: + description: maximum number of packets in the queue + type: int + unlimited: + description: Unlimited queue depth + type: bool + router_id: + description: + - Router-id address for this OSPF process + - OSPF router-id in IP address format (A.B.C.D) + type: str + shutdown: + description: Shutdown the router process + type: bool + timers: + description: Adjust routing timers + type: dict + suboptions: + lsa: + description: + - OSPF LSA timers, arrival timer + - The minimum interval in milliseconds between accepting the same LSA + - Note, refer vendor documentation for respective valid values + type: int + manet: + description: OSPF MANET timers + type: dict + suboptions: + cache: + description: Specify MANET cache sizes + type: dict + suboptions: + acknowledgement: + description: Specify MANET acknowledgement cache size + type: int + redundancy: + description: Specify MANET LSA cache size + type: int + hello: + description: + - Unicast Hellos rather than multicast + - Unicast Hello requests and responses rather than multicast + type: bool + peering: + description: MANET OSPF Smart Peering + type: dict + suboptions: + set: + description: Enable selective peering + type: bool + per_interface: + description: Select peers per interface rather than per node + type: bool + redundancy: + description: + - Redundant paths + - Number of redundant OSPF paths + type: int + willingness: + description: Specify and Relay willingness value + type: int + pacing: + description: OSPF pacing timers + type: dict + suboptions: + flood: + description: + - OSPF flood pacing timer + - The minimum interval in msec to pace limit flooding on interface + - Note, refer vendor documentation for respective valid values + type: int + lsa_group: + description: + - OSPF LSA group pacing timer + - Interval in sec between group of LSA being refreshed or maxaged + - Note, refer vendor documentation for respective valid values + type: int + retransmission: + description: + - OSPF retransmission pacing timer + - The minimum interval in msec between neighbor retransmissions + - Note, refer vendor documentation for respective valid values + type: int + throttle: + description: OSPF throttle timers + type: dict + suboptions: + lsa: + description: OSPF LSA throttle timers + type: dict + suboptions: + first_delay: + description: + - Delay to generate first occurrence of LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + min_delay: + description: + - Minimum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum delay between originating the same LSA in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + spf: + description: OSPF SPF throttle timers + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: dict + suboptions: + receive_delay: + description: + - Delay between receiving a change to SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + between_delay: + description: + - Delay between first and second SPF calculation in milliseconds + - Note, refer vendor documentation for respective valid values + type: int + max_delay: + description: + - Maximum wait time in milliseconds for SPF calculations + - Note, refer vendor documentation for respective valid values + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(sh running-config | section ^router ospfv3). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + +""" +EXAMPLES = """ + +# Using deleted + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Delete provided OSPF V3 processes + cisco.ios.ios_ospfv3: + config: + processes: + - process_id: 1 + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospfv3 1" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +# Using deleted without any config passed (NOTE: This will delete all OSPFV3 configuration from device) + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Delete all OSPF processes + cisco.ios.ios_ospfv3: + state: deleted + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospfv3 200", +# "no router ospfv3 1" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospfv3 +# router-ios# + +# Using merged + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router-ios# + +- name: Merge provided OSPFV3 configuration + cisco.ios.ios_ospfv3: + config: + processes: + - process_id: 1 + max_metric: + router_lsa: true + on_startup: + time: 110 + address_family: + - afi: ipv4 + unicast: true + vrf: blue + adjacency: + min_adjacency: 50 + max_adjacency: 50 + areas: + - area_id: 25 + nssa: + default_information_originate: + metric: 25 + nssa_only: true + areas: + - area_id: "10" + nssa: + default_information_originate: + metric: 10 + timers: + throttle: + lsa: + first_delay: 12 + min_delay: 14 + max_delay: 16 + - process_id: 200 + address_family: + - afi: ipv4 + unicast: true + adjacency: + min_adjacency: 200 + max_adjacency: 200 + max_metric: + router_lsa: true + on_startup: + time: 100 + auto_cost: + reference_bandwidth: 4 + state: merged + +# Commands Fired: +# --------------- +# +# "commands": [ +# "router ospfv3 1", +# "max-metric router-lsa on-startup 110", +# "area 10 nssa default-information-originate metric 10", +# "address-family ipv4 unicast vrf blue", +# "adjacency stagger 50 50", +# "area 25 nssa default-information-originate metric 25 nssa-only", +# "exit-address-family", +# "router ospfv3 200", +# "auto-cost reference-bandwidth 4", +# "max-metric router-lsa on-startup 100", +# "address-family ipv4 unicast", +# "adjacency stagger 200 200", +# "exit-address-family" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +# Using overridden + +# Before state: +# ------------- +# +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Override provided OSPFV3 configuration + cisco.ios.ios_ospfv3: + config: + processes: + - process_id: 200 + max_metric: + router_lsa: true + on_startup: + time: 200 + address_family: + - afi: ipv4 + unicast: true + adjacency: + min_adjacency: 50 + max_adjacency: 50 + areas: + - area_id: 200 + nssa: + default_information_originate: + metric: 200 + nssa_only: true + areas: + - area_id: "10" + nssa: + default_information_originate: + metric: 10 + state: overridden + +# Commands Fired: +# --------------- +# +# "commands": [ +# "no router ospfv3 1", +# "router ospfv3 200", +# "no auto-cost reference-bandwidth 4", +# "max-metric router-lsa on-startup 200", +# "area 10 nssa default-information-originate metric 10", +# "address-family ipv4 unicast", +# "adjacency stagger 50 50", +# "area 200 nssa default-information-originate metric 200 nssa-only", +# "exit-address-family" +# ] + +# After state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 200 +# max-metric router-lsa on-startup 200 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast +# adjacency stagger 50 50 +# area 200 nssa default-information-originate metric 200 nssa-only +# exit-address-family + +# Using replaced + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Replaced provided OSPFV3 configuration + cisco.ios.ios_ospfv3: + config: + processes: + - process_id: 200 + max_metric: + router_lsa: true + on_startup: + time: 200 + address_family: + - afi: ipv4 + unicast: true + adjacency: + min_adjacency: 50 + max_adjacency: 50 + areas: + - area_id: 200 + nssa: + default_information_originate: + metric: 200 + nssa_only: true + areas: + - area_id: "10" + nssa: + default_information_originate: + metric: 10 + state: replaced + +# Commands Fired: +# --------------- +# "commands": [ +# "router ospfv3 200", +# "no auto-cost reference-bandwidth 4", +# "max-metric router-lsa on-startup 200", +# "area 10 nssa default-information-originate metric 10", +# "address-family ipv4 unicast", +# "adjacency stagger 50 50", +# "area 200 nssa default-information-originate metric 200 nssa-only", +# "exit-address-family" +# ] + +# After state: +# ------------- +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 200 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast +# adjacency stagger 50 50 +# area 200 nssa default-information-originate metric 200 nssa-only +# exit-address-family + +# Using Gathered + +# Before state: +# ------------- +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Gather OSPFV3 provided configurations + cisco.ios.ios_ospfv3: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": { +# "processes": [ +# { +# "address_family": [ +# { +# "adjacency": { +# "max_adjacency": 50, +# "min_adjacency": 50 +# }, +# "afi": "ipv4", +# "areas": [ +# { +# "area_id": "25", +# "nssa": { +# "default_information_originate": { +# "metric": 25, +# "nssa_only": true +# } +# } +# } +# ], +# "unicast": true, +# "vrf": "blue" +# } +# ], +# "areas": [ +# { +# "area_id": "10", +# "nssa": { +# "default_information_originate": { +# "metric": 10 +# } +# } +# } +# ], +# "max_metric": { +# "on_startup": { +# "time": 110 +# }, +# "router_lsa": true +# }, +# "process_id": 1 +# }, +# { +# "address_family": [ +# { +# "adjacency": { +# "max_adjacency": 200, +# "min_adjacency": 200 +# }, +# "afi": "ipv4", +# "unicast": true +# } +# ], +# "auto_cost": { +# "reference_bandwidth": 4 +# }, +# "max_metric": { +# "on_startup": { +# "time": 100 +# }, +# "router_lsa": true +# }, +# "process_id": 200 +# } +# ] +# } + +# After state: +# ------------ +# +# router-ios#sh running-config | section ^router ospfv3 +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_ospfv3: + config: + processes: + - process_id: 1 + max_metric: + router_lsa: true + on_startup: + time: 110 + address_family: + - afi: ipv4 + unicast: true + vrf: blue + adjacency: + min_adjacency: 50 + max_adjacency: 50 + areas: + - area_id: 25 + nssa: + default_information_originate: + metric: 25 + nssa_only: true + areas: + - area_id: "10" + nssa: + default_information_originate: + metric: 10 + timers: + throttle: + lsa: + first_delay: 12 + min_delay: 14 + max_delay: 16 + - process_id: 200 + address_family: + - afi: ipv4 + unicast: true + adjacency: + min_adjacency: 200 + max_adjacency: 200 + max_metric: + router_lsa: true + on_startup: + time: 100 + auto_cost: + reference_bandwidth: 4 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "router ospfv3 1", +# "max-metric router-lsa on-startup 110", +# "area 10 nssa default-information-originate metric 10", +# "address-family ipv4 unicast vrf blue", +# "adjacency stagger 50 50", +# "area 25 nssa default-information-originate metric 25 nssa-only", +# "exit-address-family", +# "router ospfv3 200", +# "auto-cost reference-bandwidth 4", +# "max-metric router-lsa on-startup 100", +# "address-family ipv4 unicast", +# "adjacency stagger 200 200", +# "exit-address-family" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# router ospfv3 1 +# max-metric router-lsa on-startup 110 +# area 10 nssa default-information-originate metric 10 +# ! +# address-family ipv4 unicast vrf blue +# adjacency stagger 50 50 +# area 25 nssa default-information-originate metric 25 nssa-only +# exit-address-family +# router ospfv3 200 +# max-metric router-lsa on-startup 100 +# auto-cost reference-bandwidth 4 +# ! +# address-family ipv4 unicast +# adjacency stagger 200 200 +# exit-address-family + +- name: Parse the provided configuration with the exisiting running configuration + cisco.ios.ios_ospfv3: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": { +# "processes": [ +# { +# "address_family": [ +# { +# "adjacency": { +# "max_adjacency": 50, +# "min_adjacency": 50 +# }, +# "afi": "ipv4", +# "areas": [ +# { +# "area_id": "25", +# "nssa": { +# "default_information_originate": { +# "metric": 25, +# "nssa_only": true +# } +# } +# } +# ], +# "unicast": true, +# "vrf": "blue" +# } +# ], +# "areas": [ +# { +# "area_id": "10", +# "nssa": { +# "default_information_originate": { +# "metric": 10 +# } +# } +# } +# ], +# "max_metric": { +# "on_startup": { +# "time": 110 +# }, +# "router_lsa": true +# }, +# "process_id": 1 +# } +# ] +# } + +""" + +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +after: + description: The resulting configuration model invocation. + returned: when changed + sample: > + The configuration returned will always be in the same format + of the parameters above. + type: dict +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['router ospfv3 1', 'address-family ipv4 unicast vrf blue', 'adjacency stagger 50 50'] +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv3.ospfv3 import ( + Ospfv3Args, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv3.ospfv3 import ( + Ospfv3, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Ospfv3Args.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Ospfv3(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py new file mode 100644 index 00000000..b67edc57 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py @@ -0,0 +1,242 @@ +#!/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: ios_ping +short_description: Tests reachability using ping from Cisco IOS network devices +description: +- Tests reachability using ping from switch to a remote destination. +- For a general purpose network module, see the M(net_ping) module. +- For Windows targets, use the M(win_ping) module instead. +- For targets running Python, use the M(ping) module instead. +version_added: 1.0.0 +author: +- Jacob McGill (@jmcgill298) +extends_documentation_fragment: +- cisco.ios.ios +options: + count: + description: + - Number of packets to send. + type: int + dest: + description: + - The IP Address or hostname (resolvable by switch) of the remote node. + required: true + type: str + df_bit: + description: + - Set the DF bit. + default: false + type: bool + size: + description: + - Size of packets to send. + type: int + source: + description: + - The source IP Address. + type: str + state: + description: + - Determines if the expected result is success or fail. + choices: + - absent + - present + default: present + type: str + vrf: + description: + - The VRF to use for forwarding. + type: str +notes: +- For a general purpose network module, see the M(net_ping) module. +- For Windows targets, use the M(win_ping) module instead. +- For targets running Python, use the M(ping) module instead. +""" +EXAMPLES = """ +- name: Test reachability to 10.10.10.10 using default vrf + cisco.ios.ios_ping: + dest: 10.10.10.10 + +- name: Test reachability to 10.20.20.20 using prod vrf + cisco.ios.ios_ping: + dest: 10.20.20.20 + vrf: prod + +- name: Test unreachability to 10.30.30.30 using default vrf + cisco.ios.ios_ping: + dest: 10.30.30.30 + state: absent + +- name: Test reachability to 10.40.40.40 using prod vrf and setting count and source + cisco.ios.ios_ping: + dest: 10.40.40.40 + source: loopback0 + vrf: prod + count: 20 + +- name: Test reachability to 10.50.50.50 using df-bit and size + cisco.ios.ios_ping: + dest: 10.50.50.50 + df_bit: true + size: 1400 +""" +RETURN = """ +commands: + description: Show the command sent. + returned: always + type: list + sample: ["ping vrf prod 10.40.40.40 count 20 source loopback0"] +packet_loss: + description: Percentage of packets lost. + returned: always + type: str + sample: "0%" +packets_rx: + description: Packets successfully received. + returned: always + type: int + sample: 20 +packets_tx: + description: Packets successfully transmitted. + returned: always + type: int + sample: 20 +rtt: + description: Show RTT stats. + returned: always + type: dict + sample: {"avg": 2, "max": 8, "min": 1} +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + run_commands, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +import re + + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + count=dict(type="int"), + dest=dict(type="str", required=True), + df_bit=dict(type="bool", default=False), + size=dict(type="int"), + source=dict(type="str"), + state=dict( + type="str", choices=["absent", "present"], default="present" + ), + vrf=dict(type="str"), + ) + argument_spec.update(ios_argument_spec) + module = AnsibleModule(argument_spec=argument_spec) + count = module.params["count"] + dest = module.params["dest"] + df_bit = module.params["df_bit"] + size = module.params["size"] + source = module.params["source"] + vrf = module.params["vrf"] + warnings = list() + results = {} + if warnings: + results["warnings"] = warnings + results["commands"] = [build_ping(dest, count, source, vrf, size, df_bit)] + ping_results = run_commands(module, commands=results["commands"]) + ping_results_list = ping_results[0].split("\n") + stats = "" + for line in ping_results_list: + if line.startswith("Success"): + stats = line + success, rx, tx, rtt = parse_ping(stats) + loss = abs(100 - int(success)) + results["packet_loss"] = str(loss) + "%" + results["packets_rx"] = int(rx) + results["packets_tx"] = int(tx) + # Convert rtt values to int + for k, v in rtt.items(): + if rtt[k] is not None: + rtt[k] = int(v) + results["rtt"] = rtt + validate_results(module, loss, results) + module.exit_json(**results) + + +def build_ping( + dest, count=None, source=None, vrf=None, size=None, df_bit=False +): + """ + Function to build the command to send to the terminal for the switch + to execute. All args come from the module's unique params. + """ + if vrf is not None: + cmd = "ping vrf {0} {1}".format(vrf, dest) + else: + cmd = "ping {0}".format(dest) + if count is not None: + cmd += " repeat {0}".format(str(count)) + if size is not None: + cmd += " size {0}".format(size) + if df_bit: + cmd += " df-bit" + if source is not None: + cmd += " source {0}".format(source) + return cmd + + +def parse_ping(ping_stats): + """ + Function used to parse the statistical information from the ping response. + Example: "Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/8 ms" + Returns the percent of packet loss, received packets, transmitted packets, and RTT dict. + """ + rate_re = re.compile( + "^\\w+\\s+\\w+\\s+\\w+\\s+(?P<pct>\\d+)\\s+\\w+\\s+\\((?P<rx>\\d+)/(?P<tx>\\d+)\\)" + ) + rtt_re = re.compile( + ".*,\\s+\\S+\\s+\\S+\\s+=\\s+(?P<min>\\d+)/(?P<avg>\\d+)/(?P<max>\\d+)\\s+\\w+\\s*$|.*\\s*$" + ) + rate = rate_re.match(ping_stats) + rtt = rtt_re.match(ping_stats) + return ( + rate.group("pct"), + rate.group("rx"), + rate.group("tx"), + rtt.groupdict(), + ) + + +def validate_results(module, loss, results): + """ + This function is used to validate whether the ping results were unexpected per "state" param. + """ + state = module.params["state"] + if state == "present" and loss == 100: + module.fail_json(msg="Ping failed unexpectedly", **results) + elif state == "absent" and loss < 100: + module.fail_json(msg="Ping succeeded unexpectedly", **results) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py new file mode 100644 index 00000000..a3b5a957 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py @@ -0,0 +1,372 @@ +#!/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: ios_static_route +author: Ricardo Carrillo Cruz (@rcarrillocruz) +short_description: (deprecated, removed after 2022-06-01) Manage static IP routes + on Cisco IOS network devices +description: +- This module provides declarative management of static IP routes on Cisco IOS network + devices. +version_added: 1.0.0 +deprecated: + alternative: ios_static_routes + why: Newer and updated modules released with more functionality. + removed_at_date: '2022-06-01' +notes: +- Tested against IOS 15.6 +options: + prefix: + description: + - Network prefix of the static route. + type: str + mask: + description: + - Network prefix mask of the static route. + type: str + next_hop: + description: + - Next hop IP of the static route. + type: str + vrf: + description: + - VRF of the static route. + type: str + interface: + description: + - Interface of the static route. + type: str + name: + description: + - Name of the static route + type: str + aliases: + - description + admin_distance: + description: + - Admin distance of the static route. + type: str + tag: + description: + - Set tag of the static route. + type: str + track: + description: + - Tracked item to depend on for the static route. + type: str + aggregate: + description: List of static route definitions. + type: list + elements: dict + suboptions: + prefix: + description: + - Network prefix of the static route. + type: str + required: true + mask: + description: + - Network prefix mask of the static route. + type: str + next_hop: + description: + - Next hop IP of the static route. + type: str + vrf: + description: + - VRF of the static route. + type: str + interface: + description: + - Interface of the static route. + type: str + name: + description: + - Name of the static route + aliases: + - description + type: str + admin_distance: + description: + - Admin distance of the static route. + type: str + tag: + description: + - Set tag of the static route. + type: str + track: + description: + - Tracked item to depend on for the static route. + type: str + state: + description: + - State of the static route configuration. + choices: + - present + - absent + type: str + state: + description: + - State of the static route configuration. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: +- cisco.ios.ios +""" +EXAMPLES = """ +- name: configure static route + cisco.ios.ios_static_route: + prefix: 192.168.2.0 + mask: 255.255.255.0 + next_hop: 10.0.0.1 + +- name: configure black hole in vrf blue depending on tracked item 10 + cisco.ios.ios_static_route: + prefix: 192.168.2.0 + mask: 255.255.255.0 + vrf: blue + interface: null0 + track: 10 + +- name: configure ultimate route with name and tag + cisco.ios.ios_static_route: + prefix: 192.168.2.0 + mask: 255.255.255.0 + interface: GigabitEthernet1 + name: hello world + tag: 100 + +- name: remove configuration + cisco.ios.ios_static_route: + prefix: 192.168.2.0 + mask: 255.255.255.0 + next_hop: 10.0.0.1 + state: absent + +- name: Add static route aggregates + cisco.ios.ios_static_route: + aggregate: + - {prefix: 172.16.32.0, mask: 255.255.255.0, next_hop: 10.0.0.8} + - {prefix: 172.16.33.0, mask: 255.255.255.0, next_hop: 10.0.0.8} + +- name: Remove static route aggregates + cisco.ios.ios_static_route: + aggregate: + - {prefix: 172.16.32.0, mask: 255.255.255.0, next_hop: 10.0.0.8} + - {prefix: 172.16.33.0, mask: 255.255.255.0, next_hop: 10.0.0.8} + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - ip route 192.168.2.0 255.255.255.0 10.0.0.1 +""" +from copy import deepcopy +from re import findall +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, + validate_ip_address, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def map_obj_to_commands(want, have): + commands = list() + for w in want: + state = w["state"] + del w["state"] + # Try to match an existing config with the desired config + for h in have: + # Try to match an existing config with the desired config + if not w.get("admin_distance") and h.get("admin_distance"): + del h["admin_distance"] + diff = list(set(w.items()) ^ set(h.items())) + if not diff: + break + # Try to match an existing config with the desired config + if ( + len(diff) == 2 + and diff[0][0] == diff[1][0] == "name" + and (not w["name"] or h["name"].startswith(w["name"])) + ): + break + # If no matches found, clear `h` + else: + h = None + command = "ip route" + prefix = w["prefix"] + mask = w["mask"] + vrf = w.get("vrf") + if vrf: + command = " ".join((command, "vrf", vrf, prefix, mask)) + else: + command = " ".join((command, prefix, mask)) + for key in [ + "interface", + "next_hop", + "admin_distance", + "tag", + "name", + "track", + ]: + if w.get(key): + if key == "name" and len(w.get(key).split()) > 1: + command = " ".join((command, key, '"%s"' % w.get(key))) + elif key in ("name", "tag", "track"): + command = " ".join((command, key, w.get(key))) + else: + command = " ".join((command, w.get(key))) + if state == "absent" and h: + commands.append("no %s" % command) + elif state == "present" and not h: + commands.append(command) + return commands + + +def map_config_to_obj(module): + obj = [] + out = get_config(module, flags="| include ip route") + for line in out.splitlines(): + # Split by whitespace but do not split quotes, needed for name parameter + splitted_line = findall('[^"\\s]\\S*|".+?"', line) + if splitted_line[2] == "vrf": + route = {"vrf": splitted_line[3]} + del splitted_line[:4] # Removes the words ip route vrf vrf_name + else: + route = {} + del splitted_line[:2] # Removes the words ip route + prefix = splitted_line[0] + mask = splitted_line[1] + route.update({"prefix": prefix, "mask": mask, "admin_distance": "1"}) + next_word = None + for word in splitted_line[2:]: + if next_word: + route[next_word] = word.strip('"') + next_word = None + elif validate_ip_address(word): + route.update(next_hop=word) + elif word.isdigit(): + route.update(admin_distance=word) + elif word in ("tag", "name", "track"): + next_word = word + else: + route.update(interface=word) + obj.append(route) + return obj + + +def map_params_to_obj(module, required_together=None): + keys = [ + "prefix", + "mask", + "state", + "next_hop", + "vrf", + "interface", + "name", + "admin_distance", + "track", + "tag", + ] + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + route = item.copy() + for key in keys: + if route.get(key) is None: + route[key] = module.params.get(key) + route = dict((k, v) for k, v in route.items() if v is not None) + module._check_required_together(required_together, route) + obj.append(route) + else: + module._check_required_together(required_together, module.params) + route = dict() + for key in keys: + if module.params.get(key) is not None: + route[key] = module.params.get(key) + obj.append(route) + return obj + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + prefix=dict(type="str"), + mask=dict(type="str"), + next_hop=dict(type="str"), + vrf=dict(type="str"), + interface=dict(type="str"), + name=dict(type="str", aliases=["description"]), + admin_distance=dict(type="str"), + track=dict(type="str"), + tag=dict(type="str"), + state=dict(default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["prefix"] = dict(required=True) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec) + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + required_one_of = [["aggregate", "prefix"]] + required_together = [["prefix", "mask"]] + mutually_exclusive = [["aggregate", "prefix"]] + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module, required_together=required_together) + have = map_config_to_obj(module) + commands = map_obj_to_commands(want, have) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py new file mode 100644 index 00000000..f8115095 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py @@ -0,0 +1,692 @@ +#!/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/>. +# +""" +The module file for ios_static_routes +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_static_routes +short_description: Static routes resource module +description: This module configures and manages the static routes on IOS platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSv Version 15.2 on VIRL. +options: + config: + description: A dictionary of static route options + type: list + elements: dict + suboptions: + vrf: + description: + - IP VPN Routing/Forwarding instance name. + - NOTE, In case of IPV4/IPV6 VRF routing table should pre-exist before configuring. + - NOTE, if the vrf information is not provided then the routes shall be configured + under global vrf. + type: str + address_families: + elements: dict + description: + - Address family to use for the static routes + type: list + suboptions: + afi: + description: + - Top level address family indicator. + required: true + type: str + choices: + - ipv4 + - ipv6 + routes: + description: Configuring static route + type: list + elements: dict + suboptions: + dest: + description: Destination prefix with its subnet mask + type: str + required: true + topology: + description: + - Configure static route for a Topology Routing/Forwarding instance + - NOTE, VRF and Topology can be used together only with Multicast + and Topology should pre-exist before it can be used + type: str + next_hops: + description: + - next hop address or interface + type: list + elements: dict + suboptions: + forward_router_address: + description: Forwarding router's address + type: str + interface: + description: Interface for directly connected static routes + type: str + dhcp: + description: Default gateway obtained from DHCP + type: bool + distance_metric: + description: Distance metric for this route + type: int + global: + description: Next hop address is global + type: bool + name: + description: Specify name of the next hop + type: str + multicast: + description: multicast route + type: bool + permanent: + description: permanent route + type: bool + tag: + description: + - Set tag for this route + - Refer to vendor documentation for valid values. + type: int + track: + description: + - Install route depending on tracked item with tracked object + number. + - Tracking does not support multicast + - Refer to vendor documentation for valid values. + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS + device by executing the command B(show running-config | include ip route|ipv6 route). + - The state I(parsed) reads the configuration from C(running_config) + option and transforms it into Ansible structured data as per the + resource module's argspec and the value is then returned in the + I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route + +- name: Merge provided configuration with device configuration + cisco.ios.ios_static_routes: + config: + - vrf: blue + address_families: + - afi: ipv4 + routes: + - dest: 192.0.2.0/24 + next_hops: + - forward_router_address: 192.0.2.1 + name: merged_blue + tag: 50 + track: 150 + - address_families: + - afi: ipv4 + routes: + - dest: 198.51.100.0/24 + next_hops: + - forward_router_address: 198.51.101.1 + name: merged_route_1 + distance_metric: 110 + tag: 40 + multicast: true + - forward_router_address: 198.51.101.2 + name: merged_route_2 + distance_metric: 30 + - forward_router_address: 198.51.101.3 + name: merged_route_3 + - afi: ipv6 + routes: + - dest: 2001:DB8:0:3::/64 + next_hops: + - forward_router_address: 2001:DB8:0:3::2 + name: merged_v6 + tag: 105 + state: merged + +# Commands fired: +# --------------- +# ip route vrf blue 192.0.2.0 255.255.255.0 10.0.0.8 name merged_blue track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name merged_route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name merged_v6 tag 105 + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name merged_route_1 multicast +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6 + +# Using replaced + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Replace provided configuration with device configuration + cisco.ios.ios_static_routes: + config: + - address_families: + - afi: ipv4 + routes: + - dest: 198.51.100.0/24 + next_hops: + - forward_router_address: 198.51.101.1 + name: replaced_route + distance_metric: 175 + tag: 70 + multicast: true + state: replaced + +# Commands fired: +# --------------- +# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 name replaced_route track 150 tag 70 + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 name replaced_route track 150 tag 70 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6 + +# Using overridden + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Override provided configuration with device configuration + cisco.ios.ios_static_routes: + config: + - vrf: blue + address_families: + - afi: ipv4 + routes: + - dest: 192.0.2.0/24 + next_hops: + - forward_router_address: 192.0.2.1 + name: override_vrf + tag: 50 + track: 150 + state: overridden + +# Commands fired: +# --------------- +# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 198.51.101.8 name test_vrf track 150 tag 50 +# no ipv6 route FD5D:12C9:2201:1::/64 FD5D:12C9:2202::2 name test_v6 tag 105 +# ip route vrf blue 192.0.2.0 255.255.255.0 198.51.101.4 name override_vrf track 150 tag 50 + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name override_vrf track 150 + +# Using Deleted + +# Example 1: +# ---------- +# To delete the exact static routes, with all the static routes explicitly mentioned in want + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Delete provided configuration from the device configuration + cisco.ios.ios_static_routes: + config: + - vrf: ansible_temp_vrf + address_families: + - afi: ipv4 + routes: + - dest: 192.0.2.0/24 + next_hops: + - forward_router_address: 192.0.2.1 + name: test_vrf + tag: 50 + track: 150 + - address_families: + - afi: ipv4 + routes: + - dest: 198.51.100.0/24 + next_hops: + - forward_router_address: 198.51.101.1 + name: route_1 + distance_metric: 110 + tag: 40 + multicast: true + - forward_router_address: 198.51.101.2 + name: route_2 + distance_metric: 30 + - forward_router_address: 198.51.101.3 + name: route_3 + - afi: ipv6 + routes: + - dest: 2001:DB8:0:3::/64 + next_hops: + - forward_router_address: 2001:DB8:0:3::2 + name: test_v6 + tag: 105 + state: deleted + +# Commands fired: +# --------------- +# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 198.51.101.8 name test_vrf track 150 tag 50 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# no ipv6 route FD5D:12C9:2201:1::/64 FD5D:12C9:2202::2 name test_v6 tag 105 + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route + +# Example 2: +# ---------- +# To delete the destination specific static routes + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Delete provided configuration from the device configuration + cisco.ios.ios_static_routes: + config: + - address_families: + - afi: ipv4 + routes: + - dest: 198.51.100.0/24 + state: deleted + +# Commands fired: +# --------------- +# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6 + + +# Example 3: +# ---------- +# To delete the vrf specific static routes + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Delete provided configuration from the device configuration + cisco.ios.ios_static_routes: + config: + - vrf: ansible_temp_vrf + state: deleted + +# Commands fired: +# --------------- +# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured resource module attributes from each configured interface)" + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Delete ALL configured IOS static routes + cisco.ios.ios_static_routes: + state: deleted + +# Commands fired: +# --------------- +# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast +# no ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6 + +# After state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# + +# Using gathered + +# Before state: +# ------------- +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +- name: Gather listed static routes with provided configurations + cisco.ios.ios_static_routes: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "192.0.2.0/24", +# "next_hops": [ +# { +# "forward_router_address": "192.0.2.1", +# "name": "test_vrf", +# "tag": 50, +# "track": 150 +# } +# ] +# } +# ] +# } +# ], +# "vrf": "ansible_temp_vrf" +# }, +# { +# "address_families": [ +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2001:DB8:0:3::/64", +# "next_hops": [ +# { +# "forward_router_address": "2001:DB8:0:3::2", +# "name": "test_v6", +# "tag": 105 +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "198.51.100.0/24", +# "next_hops": [ +# { +# "distance_metric": 110, +# "forward_router_address": "198.51.101.1", +# "multicast": true, +# "name": "route_1", +# "tag": 40 +# }, +# { +# "distance_metric": 30, +# "forward_router_address": "198.51.101.2", +# "name": "route_2" +# }, +# { +# "forward_router_address": "198.51.101.3", +# "name": "route_3" +# } +# ] +# } +# ] +# } +# ] +# } +# ] + +# After state: +# ------------ +# +# vios#show running-config | include ip route|ipv6 route +# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50 +# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40 +# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2 +# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3 +# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105 + +# Using rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_static_routes: + config: + - vrf: ansible_temp_vrf + address_families: + - afi: ipv4 + routes: + - dest: 192.0.2.0/24 + next_hops: + - forward_router_address: 192.0.2.1 + name: test_vrf + tag: 50 + track: 150 + - address_families: + - afi: ipv4 + routes: + - dest: 198.51.100.0/24 + next_hops: + - forward_router_address: 198.51.101.1 + name: route_1 + distance_metric: 110 + tag: 40 + multicast: true + - forward_router_address: 198.51.101.2 + name: route_2 + distance_metric: 30 + - forward_router_address: 198.51.101.3 + name: route_3 + - afi: ipv6 + routes: + - dest: 2001:DB8:0:3::/64 + next_hops: + - forward_router_address: 2001:DB8:0:3::2 + name: test_v6 + tag: 105 + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50", +# "ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40", +# "ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2", +# "ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3", +# "ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105" +# ] +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['ip route vrf test 172.31.10.0 255.255.255.0 10.10.10.2 name new_test multicast'] +rendered: + description: The set of CLI commands generated from the value in C(config) option + returned: When C(state) is I(rendered) + type: list + sample: ['interface Ethernet1/1', 'mtu 1800'] +gathered: + description: + - The configuration as structured data transformed for the running configuration + fetched from remote host + returned: When C(state) is I(gathered) + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +parsed: + description: + - The configuration as structured data transformed for the value of + C(running_config) option + returned: When C(state) is I(parsed) + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.static_routes.static_routes import ( + Static_RoutesArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.static_routes.static_routes import ( + Static_Routes, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Static_RoutesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + result = Static_Routes(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py new file mode 100644 index 00000000..208270bc --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py @@ -0,0 +1,382 @@ +#!/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: ios_system +author: Peter Sprygada (@privateip) +short_description: Manage the system attributes on Cisco IOS devices +description: +- This module provides declarative management of node system attributes on Cisco IOS + devices. It provides an option to configure host system parameters or remove those + parameters from the device active configuration. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +options: + hostname: + description: + - Configure the device hostname parameter. This option takes an ASCII string value. + type: str + domain_name: + description: + - Configure the IP domain name on the remote device to the provided value. Value + should be in the dotted name form and will be appended to the C(hostname) to + create a fully-qualified domain name. + type: list + elements: raw + domain_search: + description: + - Provides the list of domain suffixes to append to the hostname for the purpose + of doing name resolution. This argument accepts a list of names and will be + reconciled with the current active configuration on the running node. + type: list + elements: raw + lookup_source: + description: + - Provides one or more source interfaces to use for performing DNS lookups. The + interface provided in C(lookup_source) must be a valid interface configured + on the device. + type: str + lookup_enabled: + description: + - Administrative control for enabling or disabling DNS lookups. When this argument + is set to True, lookups are performed and when it is set to False, lookups are + not performed. + type: bool + name_servers: + description: + - List of DNS name servers by IP address to use to perform name resolution lookups. This + argument accepts either a list of DNS servers See examples. + type: list + elements: raw + state: + description: + - State of the configuration values in the device's current active configuration. When + set to I(present), the values should be configured in the device active configuration + and when set to I(absent) the values should not be in the device active configuration + default: present + choices: + - present + - absent + type: str +""" +EXAMPLES = """ +- name: configure hostname and domain name + cisco.ios.ios_system: + hostname: ios01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - cisco.com + +- name: remove configuration + cisco.ios.ios_system: + state: absent + +- name: configure DNS lookup sources + cisco.ios.ios_system: + lookup_source: MgmtEth0/0/CPU0/0 + lookup_enabled: yes + +- name: configure name servers + cisco.ios.ios_system: + name_servers: + - 8.8.8.8 + - 8.8.4.4 +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - hostname ios01 + - ip domain name test.example.com +""" +import re +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + ComplexList, +) + +_CONFIGURED_VRFS = None + + +def has_vrf(module, vrf): + global _CONFIGURED_VRFS + if _CONFIGURED_VRFS is not None: + return vrf in _CONFIGURED_VRFS + config = get_config(module) + _CONFIGURED_VRFS = re.findall("vrf definition (\\S+)", config) + return vrf in _CONFIGURED_VRFS + + +def requires_vrf(module, vrf): + if not has_vrf(module, vrf): + module.fail_json(msg="vrf %s is not configured" % vrf) + + +def diff_list(want, have): + adds = [w for w in want if w not in have] + removes = [h for h in have if h not in want] + return adds, removes + + +def map_obj_to_commands(want, have, module): + commands = list() + state = module.params["state"] + + def needs_update(x): + return want.get(x) is not None and want.get(x) != have.get(x) + + if state == "absent": + if have["hostname"] != "Router": + commands.append("no hostname") + if have["lookup_source"]: + commands.append( + "no ip domain lookup source-interface %s" + % have["lookup_source"] + ) + if have["lookup_enabled"] is False: + commands.append("ip domain lookup") + vrfs = set() + for item in have["domain_name"]: + if item["vrf"] and item["vrf"] not in vrfs: + vrfs.add(item["vrf"]) + commands.append("no ip domain name vrf %s" % item["vrf"]) + elif None not in vrfs: + vrfs.add(None) + commands.append("no ip domain name") + vrfs = set() + for item in have["domain_search"]: + if item["vrf"] and item["vrf"] not in vrfs: + vrfs.add(item["vrf"]) + commands.append("no ip domain list vrf %s" % item["vrf"]) + elif None not in vrfs: + vrfs.add(None) + commands.append("no ip domain list") + vrfs = set() + for item in have["name_servers"]: + if item["vrf"] and item["vrf"] not in vrfs: + vrfs.add(item["vrf"]) + commands.append("no ip name-server vrf %s" % item["vrf"]) + elif None not in vrfs: + vrfs.add(None) + commands.append("no ip name-server") + elif state == "present": + if needs_update("hostname"): + commands.append("hostname %s" % want["hostname"]) + if needs_update("lookup_source"): + commands.append( + "ip domain lookup source-interface %s" % want["lookup_source"] + ) + if needs_update("lookup_enabled"): + cmd = "ip domain lookup" + if want["lookup_enabled"] is False: + cmd = "no %s" % cmd + commands.append(cmd) + if want["domain_name"]: + adds, removes = diff_list(want["domain_name"], have["domain_name"]) + for item in removes: + if item["vrf"]: + commands.append( + "no ip domain name vrf %s %s" + % (item["vrf"], item["name"]) + ) + else: + commands.append("no ip domain name %s" % item["name"]) + for item in adds: + if item["vrf"]: + requires_vrf(module, item["vrf"]) + commands.append( + "ip domain name vrf %s %s" + % (item["vrf"], item["name"]) + ) + else: + commands.append("ip domain name %s" % item["name"]) + if want["domain_search"]: + adds, removes = diff_list( + want["domain_search"], have["domain_search"] + ) + for item in removes: + if item["vrf"]: + commands.append( + "no ip domain list vrf %s %s" + % (item["vrf"], item["name"]) + ) + else: + commands.append("no ip domain list %s" % item["name"]) + for item in adds: + if item["vrf"]: + requires_vrf(module, item["vrf"]) + commands.append( + "ip domain list vrf %s %s" + % (item["vrf"], item["name"]) + ) + else: + commands.append("ip domain list %s" % item["name"]) + if want["name_servers"]: + adds, removes = diff_list( + want["name_servers"], have["name_servers"] + ) + for item in removes: + if item["vrf"]: + commands.append( + "no ip name-server vrf %s %s" + % (item["vrf"], item["server"]) + ) + else: + commands.append("no ip name-server %s" % item["server"]) + for item in adds: + if item["vrf"]: + requires_vrf(module, item["vrf"]) + commands.append( + "ip name-server vrf %s %s" + % (item["vrf"], item["server"]) + ) + else: + commands.append("ip name-server %s" % item["server"]) + return commands + + +def parse_hostname(config): + match = re.search("^hostname (\\S+)", config, re.M) + return match.group(1) + + +def parse_domain_name(config): + match = re.findall( + "^ip domain[- ]name (?:vrf (\\S+) )*(\\S+)", config, re.M + ) + matches = list() + for vrf, name in match: + if not vrf: + vrf = None + matches.append({"name": name, "vrf": vrf}) + return matches + + +def parse_domain_search(config): + match = re.findall( + "^ip domain[- ]list (?:vrf (\\S+) )*(\\S+)", config, re.M + ) + matches = list() + for vrf, name in match: + if not vrf: + vrf = None + matches.append({"name": name, "vrf": vrf}) + return matches + + +def parse_name_servers(config): + match = re.findall("^ip name-server (?:vrf (\\S+) )*(.*)", config, re.M) + matches = list() + for vrf, servers in match: + if not vrf: + vrf = None + for server in servers.split(): + matches.append({"server": server, "vrf": vrf}) + return matches + + +def parse_lookup_source(config): + match = re.search( + "ip domain[- ]lookup source-interface (\\S+)", config, re.M + ) + if match: + return match.group(1) + + +def map_config_to_obj(module): + config = get_config(module) + return { + "hostname": parse_hostname(config), + "domain_name": parse_domain_name(config), + "domain_search": parse_domain_search(config), + "lookup_source": parse_lookup_source(config), + "lookup_enabled": "no ip domain lookup" not in config + and "no ip domain-lookup" not in config, + "name_servers": parse_name_servers(config), + } + + +def map_params_to_obj(module): + obj = { + "hostname": module.params["hostname"], + "lookup_source": module.params["lookup_source"], + "lookup_enabled": module.params["lookup_enabled"], + } + domain_name = ComplexList(dict(name=dict(key=True), vrf=dict()), module) + domain_search = ComplexList(dict(name=dict(key=True), vrf=dict()), module) + name_servers = ComplexList(dict(server=dict(key=True), vrf=dict()), module) + for arg, cast in [ + ("domain_name", domain_name), + ("domain_search", domain_search), + ("name_servers", name_servers), + ]: + if module.params[arg]: + obj[arg] = cast(module.params[arg]) + else: + obj[arg] = None + return obj + + +def main(): + """ Main entry point for Ansible module execution + """ + argument_spec = dict( + hostname=dict(), + domain_name=dict(type="list", elements="raw"), + domain_search=dict(type="list", elements="raw"), + name_servers=dict(type="list", elements="raw"), + lookup_source=dict(), + lookup_enabled=dict(type="bool"), + state=dict(choices=["present", "absent"], default="present"), + ) + argument_spec.update(ios_argument_spec) + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + result = {"changed": False} + warnings = list() + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands(want, have, module) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py new file mode 100644 index 00000000..8c94ef96 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py @@ -0,0 +1,616 @@ +#!/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: ios_user +author: Trishna Guha (@trishnaguha) +short_description: Manage the aggregate of local users on Cisco IOS device +description: +- This module provides declarative management of the local usernames configured on + network devices. It allows playbooks to manage either individual usernames or the + aggregate of usernames in the current running config. It also supports purging usernames + from the configuration that are not explicitly defined. +version_added: 1.0.0 +notes: +- Tested against IOS 15.6 +options: + aggregate: + description: + - The set of username objects to be configured on the remote Cisco IOS device. + The list entries can either be the username or a hash of username and properties. + This argument is mutually exclusive with the C(name) argument. + aliases: + - users + - collection + type: list + elements: dict + suboptions: + name: + description: + - The username to be configured on the Cisco IOS device. This argument accepts + a string value and is mutually exclusive with the C(aggregate) argument. Please + note that this option is not same as C(provider username). + type: str + required: true + configured_password: + description: + - The password to be configured on the Cisco IOS device. The password needs to + be provided in clear and it will be encrypted on the device. Please note that + this option is not same as C(provider password). + type: str + update_password: + description: + - Since passwords are encrypted in the device running config, this argument will + instruct the module when to change the password. When set to C(always), the + password will always be updated in the device and when set to C(on_create) the + password will be updated only if the username is created. + choices: + - on_create + - always + type: str + password_type: + description: + - This argument determines whether a 'password' or 'secret' will be configured. + choices: + - secret + - password + type: str + hashed_password: + description: + - This option allows configuring hashed passwords on Cisco IOS devices. + type: dict + suboptions: + type: + description: + - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.) + - For this to work, the device needs to support the desired hash type + type: int + required: true + value: + description: + - The actual hashed password to be configured on the device + required: true + type: str + privilege: + description: + - The C(privilege) argument configures the privilege level of the user when logged + into the system. This argument accepts integer values in the range of 1 to 15. + type: int + view: + description: + - Configures the view for the username in the device running configuration. The + argument accepts a string value defining the view name. This argument does not + check if the view has been configured on the device. + aliases: + - role + type: str + sshkey: + description: + - Specifies one or more SSH public key(s) to configure for the given username. + - This argument accepts a valid SSH key value. + type: list + elements: str + nopassword: + description: + - Defines the username without assigning a password. This will allow the user + to login to the system without being authenticated by a password. + type: bool + state: + description: + - Configures the state of the username definition as it relates to the device + operational configuration. When set to I(present), the username(s) should be + configured in the device active configuration and when set to I(absent) the + username(s) should not be in the device active configuration + choices: + - present + - absent + type: str + name: + description: + - The username to be configured on the Cisco IOS device. This argument accepts + a string value and is mutually exclusive with the C(aggregate) argument. Please + note that this option is not same as C(provider username). + type: str + configured_password: + description: + - The password to be configured on the Cisco IOS device. The password needs to + be provided in clear and it will be encrypted on the device. Please note that + this option is not same as C(provider password). + type: str + update_password: + description: + - Since passwords are encrypted in the device running config, this argument will + instruct the module when to change the password. When set to C(always), the + password will always be updated in the device and when set to C(on_create) the + password will be updated only if the username is created. + default: always + choices: + - on_create + - always + type: str + password_type: + description: + - This argument determines whether a 'password' or 'secret' will be configured. + default: secret + choices: + - secret + - password + type: str + hashed_password: + description: + - This option allows configuring hashed passwords on Cisco IOS devices. + type: dict + suboptions: + type: + description: + - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.) + - For this to work, the device needs to support the desired hash type + type: int + required: true + value: + description: + - The actual hashed password to be configured on the device + required: true + type: str + privilege: + description: + - The C(privilege) argument configures the privilege level of the user when logged + into the system. This argument accepts integer values in the range of 1 to 15. + type: int + view: + description: + - Configures the view for the username in the device running configuration. The + argument accepts a string value defining the view name. This argument does not + check if the view has been configured on the device. + aliases: + - role + type: str + sshkey: + description: + - Specifies one or more SSH public key(s) to configure for the given username. + - This argument accepts a valid SSH key value. + type: list + elements: str + nopassword: + description: + - Defines the username without assigning a password. This will allow the user + to login to the system without being authenticated by a password. + type: bool + purge: + description: + - Instructs the module to consider the resource definition absolute. It will remove + any previously configured usernames on the device with the exception of the + `admin` user (the current defined set of users). + type: bool + default: false + state: + description: + - Configures the state of the username definition as it relates to the device + operational configuration. When set to I(present), the username(s) should be + configured in the device active configuration and when set to I(absent) the + username(s) should not be in the device active configuration + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: +- cisco.ios.ios +""" +EXAMPLES = """ +- name: create a new user + cisco.ios.ios_user: + name: ansible + nopassword: true + sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + state: present + +- name: create a new user with multiple keys + cisco.ios.ios_user: + name: ansible + sshkey: + - "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + - "{{ lookup('file', '~/path/to/public_key') }}" + state: present + +- name: remove all users except admin + cisco.ios.ios_user: + purge: yes + +- name: remove all users except admin and these listed users + cisco.ios.ios_user: + aggregate: + - name: testuser1 + - name: testuser2 + - name: testuser3 + purge: yes + +- name: set multiple users to privilege level 15 + cisco.ios.ios_user: + aggregate: + - name: netop + - name: netend + privilege: 15 + state: present + +- name: set user view/role + cisco.ios.ios_user: + name: netop + view: network-operator + state: present + +- name: Change Password for User netop + cisco.ios.ios_user: + name: netop + configured_password: '{{ new_password }}' + update_password: always + state: present + +- name: Aggregate of users + cisco.ios.ios_user: + aggregate: + - name: ansibletest2 + - name: ansibletest3 + view: network-admin + +- name: Add a user specifying password type + cisco.ios.ios_user: + name: ansibletest4 + configured_password: '{{ new_password }}' + password_type: password + +- name: Add a user with MD5 hashed password + cisco.ios.ios_user: + name: ansibletest5 + hashed_password: + type: 5 + value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/ + +- name: Delete users with aggregate + cisco.ios.ios_user: + aggregate: + - name: ansibletest1 + - name: ansibletest2 + - name: ansibletest3 + state: absent +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - username ansible secret password + - username admin secret admin +""" +import base64 +import hashlib +import re +from copy import deepcopy +from functools import partial +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + get_config, + load_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible.module_utils.six import iteritems + + +def validate_privilege(value, module): + if value and not 1 <= value <= 15: + module.fail_json( + msg="privilege must be between 1 and 15, got %s" % value + ) + + +def user_del_cmd(username): + return { + "command": "no username %s" % username, + "prompt": "This operation will remove all username related configurations with same name", + "answer": "y", + "newline": False, + } + + +def sshkey_fingerprint(sshkey): + # IOS will accept a MD5 fingerprint of the public key + # and is easier to configure in a single line + # we calculate this fingerprint here + if not sshkey: + return None + if " " in sshkey: + # ssh-rsa AAA...== comment + keyparts = sshkey.split(" ") + keyparts[1] = ( + hashlib.md5(base64.b64decode(keyparts[1])).hexdigest().upper() + ) + return " ".join(keyparts) + else: + # just the key, assume rsa type + return ( + "ssh-rsa %s" + % hashlib.md5(base64.b64decode(sshkey)).hexdigest().upper() + ) + + +def map_obj_to_commands(updates, module): + commands = list() + update_password = module.params["update_password"] + password_type = module.params["password_type"] + + def needs_update(want, have, x): + return want.get(x) and want.get(x) != have.get(x) + + def add(command, want, x): + command.append("username %s %s" % (want["name"], x)) + + def add_hashed_password(command, want, x): + command.append( + "username %s secret %s %s" + % (want["name"], x.get("type"), x.get("value")) + ) + + def add_ssh(command, want, x=None): + command.append("ip ssh pubkey-chain") + if x: + command.append("username %s" % want["name"]) + for item in x: + command.append("key-hash %s" % item) + command.append("exit") + else: + command.append("no username %s" % want["name"]) + command.append("exit") + + for update in updates: + want, have = update + if want["state"] == "absent": + if have["sshkey"]: + add_ssh(commands, want) + else: + commands.append(user_del_cmd(want["name"])) + if needs_update(want, have, "view"): + add(commands, want, "view %s" % want["view"]) + if needs_update(want, have, "privilege"): + add(commands, want, "privilege %s" % want["privilege"]) + if needs_update(want, have, "sshkey"): + add_ssh(commands, want, want["sshkey"]) + if needs_update(want, have, "configured_password"): + if update_password == "always" or not have: + if have and password_type != have["password_type"]: + module.fail_json( + msg="Can not have both a user password and a user secret." + + " Please choose one or the other." + ) + add( + commands, + want, + "%s %s" % (password_type, want["configured_password"]), + ) + if needs_update(want, have, "hashed_password"): + add_hashed_password(commands, want, want["hashed_password"]) + if needs_update(want, have, "nopassword"): + if want["nopassword"]: + add(commands, want, "nopassword") + else: + add(commands, want, user_del_cmd(want["name"])) + return commands + + +def parse_view(data): + match = re.search("view (\\S+)", data, re.M) + if match: + return match.group(1) + + +def parse_sshkey(data, user): + sshregex = "username %s(\\n\\s+key-hash .+$)+" % user + sshcfg = re.search(sshregex, data, re.M) + key_list = [] + if sshcfg: + match = re.findall( + "key-hash (\\S+ \\S+(?: .+)?)$", sshcfg.group(), re.M + ) + if match: + key_list = match + return key_list + + +def parse_privilege(data): + match = re.search("privilege (\\S+)", data, re.M) + if match: + return int(match.group(1)) + + +def parse_password_type(data): + type = None + if data and data.split()[-3] in ["password", "secret"]: + type = data.split()[-3] + return type + + +def map_config_to_obj(module): + data = get_config(module, flags=["| section username"]) + match = re.findall("(?:^(?:u|\\s{2}u))sername (\\S+)", data, re.M) + if not match: + return list() + instances = list() + for user in set(match): + regex = "username %s .+$" % user + cfg = re.findall(regex, data, re.M) + cfg = "\n".join(cfg) + obj = { + "name": user, + "state": "present", + "nopassword": "nopassword" in cfg, + "configured_password": None, + "hashed_password": None, + "password_type": parse_password_type(cfg), + "sshkey": parse_sshkey(data, user), + "privilege": parse_privilege(cfg), + "view": parse_view(cfg), + } + instances.append(obj) + return instances + + +def get_param_value(key, item, module): + # if key doesn't exist in the item, get it from module.params + if not item.get(key): + value = module.params[key] + # if key does exist, do a type check on it to validate it + else: + value_type = module.argument_spec[key].get("type", "str") + type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] + type_checker(item[key]) + value = item[key] + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if all((value, validator)): + validator(value, module) + return value + + +def map_params_to_obj(module): + users = module.params["aggregate"] + if not users: + if not module.params["name"] and module.params["purge"]: + return list() + elif not module.params["name"]: + module.fail_json(msg="username is required") + else: + aggregate = [{"name": module.params["name"]}] + else: + aggregate = list() + for item in users: + if not isinstance(item, dict): + aggregate.append({"name": item}) + elif "name" not in item: + module.fail_json(msg="name is required") + else: + aggregate.append(item) + objects = list() + for item in aggregate: + get_value = partial(get_param_value, item=item, module=module) + item["configured_password"] = get_value("configured_password") + item["hashed_password"] = get_value("hashed_password") + item["nopassword"] = get_value("nopassword") + item["privilege"] = get_value("privilege") + item["view"] = get_value("view") + item["sshkey"] = render_key_list(get_value("sshkey")) + item["state"] = get_value("state") + objects.append(item) + return objects + + +def render_key_list(ssh_keys): + key_list = [] + if ssh_keys: + for item in ssh_keys: + key_list.append(sshkey_fingerprint(item)) + return key_list + + +def update_objects(want, have): + updates = list() + for entry in want: + item = next((i for i in have if i["name"] == entry["name"]), None) + if all((item is None, entry["state"] == "present")): + updates.append((entry, {})) + elif item: + for key, value in iteritems(entry): + if value and value != item[key]: + updates.append((entry, item)) + return updates + + +def main(): + """ main entry point for module execution + """ + hashed_password_spec = dict( + type=dict(type="int", required=True), + value=dict(no_log=True, required=True), + ) + element_spec = dict( + name=dict(), + configured_password=dict(no_log=True), + hashed_password=dict( + no_log=True, type="dict", options=hashed_password_spec + ), + nopassword=dict(type="bool"), + update_password=dict( + default="always", choices=["on_create", "always"] + ), + password_type=dict(default="secret", choices=["secret", "password"]), + privilege=dict(type="int"), + view=dict(aliases=["role"]), + sshkey=dict(type="list", elements="str"), + state=dict(default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["name"] = dict(required=True) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict( + type="list", + elements="dict", + options=aggregate_spec, + aliases=["users", "collection"], + ), + purge=dict(type="bool", default=False), + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + mutually_exclusive = [ + ("name", "aggregate"), + ("nopassword", "hashed_password", "configured_password"), + ] + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False, "warnings": warnings} + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands(update_objects(want, have), module) + if module.params["purge"]: + want_users = [x["name"] for x in want] + have_users = [x["name"] for x in have] + for item in set(have_users).difference(want_users): + if item != "admin": + commands.append(user_del_cmd(item)) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py new file mode 100644 index 00000000..f18f3027 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py @@ -0,0 +1,416 @@ +#!/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: ios_vlan +author: Trishna Guha (@trishnaguha) +short_description: (deprecated, removed after 2022-06-01) Manage VLANs on IOS network + devices +description: +- This module provides declarative management of VLANs on Cisco IOS network devices. +version_added: 1.0.0 +deprecated: + alternative: ios_vlans + why: Newer and updated modules released with more functionality in Ansible 2.9 + removed_at_date: '2022-06-01' +notes: +- Tested against IOS 15.2 +options: + name: + description: + - Name of the VLAN. + type: str + vlan_id: + description: + - ID of the VLAN. Range 1-4094. + type: int + interfaces: + description: + - List of interfaces that should be associated to the VLAN. + type: list + elements: str + associated_interfaces: + description: + - This is a intent option and checks the operational state of the for given vlan + C(name) for associated interfaces. If the value in the C(associated_interfaces) + does not match with the operational state of vlan interfaces on device it will + result in failure. + type: list + elements: str + delay: + description: + - Delay the play should wait to check for declarative intent params values. + default: 10 + type: int + aggregate: + description: List of VLANs definitions. + type: list + elements: dict + suboptions: + name: + description: + - Name of the VLAN. + type: str + vlan_id: + description: + - ID of the VLAN. Range 1-4094. + required: true + type: str + interfaces: + description: + - List of interfaces that should be associated to the VLAN. + type: list + elements: str + associated_interfaces: + description: + - This is a intent option and checks the operational state of the for given vlan + C(name) for associated interfaces. If the value in the C(associated_interfaces) + does not match with the operational state of vlan interfaces on device it will + result in failure. + type: list + elements: str + delay: + description: + - Delay the play should wait to check for declarative intent params values. + type: int + state: + description: + - State of the VLAN configuration. + type: str + choices: + - present + - absent + - active + - suspend + purge: + description: + - Purge VLANs not defined in the I(aggregate) parameter. + default: false + type: bool + state: + description: + - State of the VLAN configuration. + default: present + choices: + - present + - absent + - active + - suspend + type: str +extends_documentation_fragment: +- cisco.ios.ios + + +""" +EXAMPLES = """ +- name: Create vlan + cisco.ios.ios_vlan: + vlan_id: 100 + name: test-vlan + state: present + +- name: Add interfaces to VLAN + cisco.ios.ios_vlan: + vlan_id: 100 + interfaces: + - GigabitEthernet0/0 + - GigabitEthernet0/1 + +- name: Check if interfaces is assigned to VLAN + cisco.ios.ios_vlan: + vlan_id: 100 + associated_interfaces: + - GigabitEthernet0/0 + - GigabitEthernet0/1 + +- name: Delete vlan + cisco.ios.ios_vlan: + vlan_id: 100 + state: absent + +- name: Add vlan using aggregate + cisco.ios.ios_vlan: + aggregate: + - {vlan_id: 100, name: test-vlan, interfaces: [GigabitEthernet0/1, GigabitEthernet0/2], + delay: 15, state: suspend} + - {vlan_id: 101, name: test-vlan, interfaces: GigabitEthernet0/3} + +- name: Move interfaces to a different VLAN + cisco.ios.ios_vlan: + vlan_id: 102 + interfaces: + - GigabitEthernet0/0 + - GigabitEthernet0/1 +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - vlan 100 + - name test-vlan +""" +import re +import time +from copy import deepcopy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + load_config, + run_commands, + normalize_interface, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) + + +def search_obj_in_list(vlan_id, lst): + for o in lst: + if o["vlan_id"] == vlan_id: + return o + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + purge = module.params["purge"] + for w in want: + vlan_id = w["vlan_id"] + name = w["name"] + interfaces = w["interfaces"] + state = w["state"] + obj_in_have = search_obj_in_list(vlan_id, have) + if state == "absent": + if obj_in_have: + commands.append("no vlan {0}".format(vlan_id)) + elif state == "present": + if not obj_in_have: + commands.append("vlan {0}".format(vlan_id)) + if name: + commands.append("name {0}".format(name)) + if interfaces: + for i in interfaces: + commands.append("interface {0}".format(i)) + commands.append("switchport mode access") + commands.append( + "switchport access vlan {0}".format(vlan_id) + ) + else: + if name: + if name != obj_in_have["name"]: + commands.append("vlan {0}".format(vlan_id)) + commands.append("name {0}".format(name)) + if interfaces: + if not obj_in_have["interfaces"]: + for i in interfaces: + commands.append("vlan {0}".format(vlan_id)) + commands.append("interface {0}".format(i)) + commands.append("switchport mode access") + commands.append( + "switchport access vlan {0}".format(vlan_id) + ) + elif set(interfaces) != set(obj_in_have["interfaces"]): + missing_interfaces = list( + set(interfaces) - set(obj_in_have["interfaces"]) + ) + for i in missing_interfaces: + commands.append("vlan {0}".format(vlan_id)) + commands.append("interface {0}".format(i)) + commands.append("switchport mode access") + commands.append( + "switchport access vlan {0}".format(vlan_id) + ) + superfluous_interfaces = list( + set(obj_in_have["interfaces"]) - set(interfaces) + ) + for i in superfluous_interfaces: + commands.append("vlan {0}".format(vlan_id)) + commands.append("interface {0}".format(i)) + commands.append("switchport mode access") + commands.append( + "no switchport access vlan {0}".format(vlan_id) + ) + else: + commands.append("vlan {0}".format(vlan_id)) + if name: + commands.append("name {0}".format(name)) + commands.append("state {0}".format(state)) + if purge: + for h in have: + obj_in_want = search_obj_in_list(h["vlan_id"], want) + if not obj_in_want and h["vlan_id"] != "1": + commands.append("no vlan {0}".format(h["vlan_id"])) + return commands + + +def map_params_to_obj(module): + obj = [] + aggregate = module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = module.params[key] + d = item.copy() + d["vlan_id"] = str(d["vlan_id"]) + obj.append(d) + else: + obj.append( + { + "vlan_id": str(module.params["vlan_id"]), + "name": module.params["name"], + "interfaces": module.params["interfaces"], + "associated_interfaces": module.params[ + "associated_interfaces" + ], + "state": module.params["state"], + } + ) + return obj + + +def parse_to_logical_rows(out): + started_yielding = False + cur_row = [] + for l in out.splitlines()[2:]: + if not l: + """Skip empty lines.""" + continue + if "0" < l[0] <= "9": + """Line starting with a number.""" + if started_yielding: + yield cur_row + cur_row = [] # Reset it to hold a next chunk + started_yielding = True + cur_row.append(l) + yield cur_row + + +def map_ports_str_to_list(ports_str): + return list( + filter( + bool, + (normalize_interface(p.strip()) for p in ports_str.split(", ")), + ) + ) + + +def parse_to_obj(logical_rows): + first_row = logical_rows[0] + rest_rows = logical_rows[1:] + obj = re.match( + "(?P<vlan_id>\\d+)\\s+(?P<name>[^\\s]+)\\s+(?P<state>[^\\s]+)\\s*(?P<interfaces>.*)", + first_row, + ).groupdict() + if obj["state"] == "suspended": + obj["state"] = "suspend" + obj["interfaces"] = map_ports_str_to_list(obj["interfaces"]) + obj["interfaces"].extend( + prts_r for prts in rest_rows for prts_r in map_ports_str_to_list(prts) + ) + return obj + + +def parse_vlan_brief(vlan_out): + return [parse_to_obj(r) for r in parse_to_logical_rows(vlan_out)] + + +def map_config_to_obj(module): + return parse_vlan_brief(run_commands(module, ["show vlan brief"])[0]) + + +def check_declarative_intent_params(want, module, result): + have = None + is_delay = False + for w in want: + if w.get("associated_interfaces") is None: + continue + if result["changed"] and not is_delay: + time.sleep(module.params["delay"]) + is_delay = True + if have is None: + have = map_config_to_obj(module) + for i in w["associated_interfaces"]: + obj_in_have = search_obj_in_list(w["vlan_id"], have) + if ( + obj_in_have + and "interfaces" in obj_in_have + and i not in obj_in_have["interfaces"] + ): + module.fail_json( + msg="Interface %s not configured on vlan %s" + % (i, w["vlan_id"]) + ) + + +def main(): + """ main entry point for module execution + """ + element_spec = dict( + vlan_id=dict(type="int"), + name=dict(), + interfaces=dict(type="list", elements="str"), + associated_interfaces=dict(type="list", elements="str"), + delay=dict(default=10, type="int"), + state=dict( + default="present", + choices=["present", "absent", "active", "suspend"], + ), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["vlan_id"] = dict(required=True) + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec), + purge=dict(default=False, type="bool"), + ) + argument_spec.update(element_spec) + argument_spec.update(ios_argument_spec) + required_one_of = [["vlan_id", "aggregate"]] + mutually_exclusive = [["vlan_id", "aggregate"]] + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + warnings = list() + result = {"changed": False} + if warnings: + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have), module) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + check_declarative_intent_params(want, module, result) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py new file mode 100644 index 00000000..d215a62e --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py @@ -0,0 +1,748 @@ +#!/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/>. +# +""" +The module file for ios_vlans +""" +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +DOCUMENTATION = """ +module: ios_vlans +short_description: VLANs resource module +description: This module provides declarative management of VLANs on Cisco IOS network + devices. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco IOSl2 device with Version 15.2 on VIRL. +options: + config: + description: A dictionary of VLANs options + type: list + elements: dict + suboptions: + name: + description: + - Ascii name of the VLAN. + - NOTE, I(name) should not be named/appended with I(default) as it is reserved + for device default vlans. + type: str + vlan_id: + description: + - ID of the VLAN. Range 1-4094 + type: int + required: true + mtu: + description: + - VLAN Maximum Transmission Unit. + - Refer to vendor documentation for valid values. + type: int + state: + description: + - Operational state of the VLAN + type: str + choices: + - active + - suspend + remote_span: + description: + - Configure as Remote SPAN VLAN + type: bool + shutdown: + description: + - Shutdown VLAN switching. + type: str + choices: + - enabled + - disabled + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device + by executing the command B(show vlan). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command I(show running-config + | include ip route|ipv6 route) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 + +- name: Merge provided configuration with device configuration + cisco.ios.ios_vlans: + config: + - name: Vlan_10 + vlan_id: 10 + state: active + shutdown: disabled + remote_span: 10 + - name: Vlan_20 + vlan_id: 20 + mtu: 610 + state: active + shutdown: enabled + - name: Vlan_30 + vlan_id: 30 + state: suspend + shutdown: enabled + state: merged + +# After state: +# ------------ +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +# Using overridden + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +- name: Override device configuration of all VLANs with provided configuration + cisco.ios.ios_vlans: + config: + - name: Vlan_10 + vlan_id: 10 + mtu: 1000 + state: overridden + +# After state: +# ------------ +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 10 Vlan_10 active +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 10 enet 100010 1000 - - - - - 0 0 + +# Using replaced + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +- name: Replaces device configuration of listed VLANs with provided configuration + cisco.ios.ios_vlans: + config: + - vlan_id: 20 + name: Test_VLAN20 + mtu: 700 + shutdown: disabled + - vlan_id: 30 + name: Test_VLAN30 + mtu: 1000 + state: replaced + +# After state: +# ------------ +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 Test_VLAN20 active +# 30 Test_VLAN30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 700 - - - - - 0 0 +# 30 enet 100030 1000 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +# Using deleted + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +- name: Delete attributes of given VLANs + cisco.ios.ios_vlans: + config: + - vlan_id: 10 + - vlan_id: 20 + state: deleted + +# After state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured vlans attributes)" + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +- name: Delete attributes of ALL VLANs + cisco.ios.ios_vlans: + state: deleted + +# After state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 + +# Using Gathered + +# Before state: +# ------------- +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +- name: Gather listed vlans with provided configurations + cisco.ios.ios_vlans: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "mtu": 1500, +# "name": "default", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 1 +# }, +# { +# "mtu": 1500, +# "name": "VLAN0010", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 10 +# }, +# { +# "mtu": 1500, +# "name": "VLAN0020", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 20 +# }, +# { +# "mtu": 1500, +# "name": "VLAN0030", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 30 +# }, +# { +# "mtu": 1500, +# "name": "fddi-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1002 +# }, +# { +# "mtu": 1500, +# "name": "token-ring-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1003 +# }, +# { +# "mtu": 1500, +# "name": "fddinet-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1004 +# }, +# { +# "mtu": 1500, +# "name": "trnet-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1005 +# } +# ] + +# After state: +# ------------ +# +# vios_l2#show vlan +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 610 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 10 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.ios.ios_vlans: + config: + - name: Vlan_10 + vlan_id: 10 + state: active + shutdown: disabled + remote_span: 10 + - name: Vlan_20 + vlan_id: 20 + mtu: 610 + state: active + shutdown: enabled + - name: Vlan_30 + vlan_id: 30 + state: suspend + shutdown: enabled + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "vlan 10", +# "name Vlan_10", +# "state active", +# "remote-span", +# "no shutdown", +# "vlan 20", +# "name Vlan_20", +# "state active", +# "mtu 610", +# "shutdown", +# "vlan 30", +# "name Vlan_30", +# "state suspend", +# "shutdown" +# ] + +# Using Parsed + +# File: parsed.cfg +# ---------------- +# +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 10 vlan_10 active +# 20 vlan_20 act/lshut +# 30 vlan_30 sus/lshut +# 1002 fddi-default act/unsup +# 1003 token-ring-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trnet-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 10 enet 100010 1500 - - - - - 0 0 +# 20 enet 100020 1500 - - - - - 0 0 +# 30 enet 100030 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 tr 101003 1500 - - - - - 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trnet 101005 1500 - - - ibm - 0 0 + +- name: Parse the commands for provided configuration + cisco.ios.ios_vlans: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "mtu": 1500, +# "name": "default", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 1 +# }, +# { +# "mtu": 1500, +# "name": "vlan_10", +# "shutdown": "disabled", +# "state": "active", +# "vlan_id": 10 +# }, +# { +# "mtu": 1500, +# "name": "vlan_20", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 20 +# }, +# { +# "mtu": 1500, +# "name": "vlan_30", +# "shutdown": "enabled", +# "state": "suspend", +# "vlan_id": 30 +# }, +# { +# "mtu": 1500, +# "name": "fddi-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1002 +# }, +# { +# "mtu": 1500, +# "name": "token-ring-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1003 +# }, +# { +# "mtu": 1500, +# "name": "fddinet-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1004 +# }, +# { +# "mtu": 1500, +# "name": "trnet-default", +# "shutdown": "enabled", +# "state": "active", +# "vlan_id": 1005 +# } +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['vlan 20', 'name vlan_20', 'mtu 600', 'remote-span'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vlans.vlans import ( + VlansArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.vlans.vlans import ( + Vlans, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=VlansArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = Vlans(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py new file mode 100644 index 00000000..b86df5a0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py @@ -0,0 +1,750 @@ +#!/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: ios_vrf +author: Peter Sprygada (@privateip) +short_description: Manage the collection of VRF definitions on Cisco IOS devices +description: +- This module provides declarative management of VRF definitions on Cisco IOS devices. It + allows playbooks to manage individual or the entire VRF collection. It also supports + purging VRF definitions from the configuration that are not explicitly defined. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.ios.ios +notes: +- Tested against IOS 15.6 +options: + vrfs: + description: + - The set of VRF definition objects to be configured on the remote IOS device. Ths + list entries can either be the VRF name or a hash of VRF definitions and attributes. This + argument is mutually exclusive with the C(name) argument. + type: list + elements: raw + name: + description: + - The name of the VRF definition to be managed on the remote IOS device. The + VRF definition name is an ASCII string name used to uniquely identify the VRF. This + argument is mutually exclusive with the C(vrfs) argument + type: str + description: + description: + - Provides a short description of the VRF definition in the current active configuration. The + VRF definition value accepts alphanumeric characters used to provide additional + information about the VRF. + type: str + rd: + description: + - The router-distinguisher value uniquely identifies the VRF to routing processes + on the remote IOS system. The RD value takes the form of C(A:B) where C(A) + and C(B) are both numeric values. + type: str + interfaces: + description: + - Identifies the set of interfaces that should be configured in the VRF. Interfaces + must be routed interfaces in order to be placed into a VRF. + type: list + elements: str + associated_interfaces: + description: + - This is a intent option and checks the operational state of the for given vrf + C(name) for associated interfaces. If the value in the C(associated_interfaces) + does not match with the operational state of vrf interfaces on device it will + result in failure. + type: list + elements: str + delay: + description: + - Time in seconds to wait before checking for the operational state on remote + device. + default: 10 + type: int + purge: + description: + - Instructs the module to consider the VRF definition absolute. It will remove + any previously configured VRFs on the device. + default: false + type: bool + state: + description: + - Configures the state of the VRF definition as it relates to the device operational + configuration. When set to I(present), the VRF should be configured in the + device active configuration and when set to I(absent) the VRF should not be + in the device active configuration + default: present + choices: + - present + - absent + type: str + route_both: + description: + - Adds an export and import list of extended route target communities to the VRF. + type: list + elements: str + route_export: + description: + - Adds an export list of extended route target communities to the VRF. + type: list + elements: str + route_import: + description: + - Adds an import list of extended route target communities to the VRF. + type: list + elements: str + route_both_ipv4: + description: + - Adds an export and import list of extended route target communities in address-family + configuration submode to the VRF. + type: list + elements: str + route_export_ipv4: + description: + - Adds an export list of extended route target communities in address-family configuration + submode to the VRF. + type: list + elements: str + route_import_ipv4: + description: + - Adds an import list of extended route target communities in address-family configuration + submode to the VRF. + type: list + elements: str + route_both_ipv6: + description: + - Adds an export and import list of extended route target communities in address-family + configuration submode to the VRF. + type: list + elements: str + route_export_ipv6: + description: + - Adds an export list of extended route target communities in address-family configuration + submode to the VRF. + type: list + elements: str + route_import_ipv6: + description: + - Adds an import list of extended route target communities in address-family configuration + submode to the VRF. + type: list + elements: str +""" +EXAMPLES = """ +- name: configure a vrf named management + cisco.ios.ios_vrf: + name: management + description: oob mgmt vrf + interfaces: + - Management1 + +- name: remove a vrf named test + cisco.ios.ios_vrf: + name: test + state: absent + +- name: configure set of VRFs and purge any others + cisco.ios.ios_vrf: + vrfs: + - red + - blue + - green + purge: yes + +- name: Creates a list of import RTs for the VRF with the same parameters + cisco.ios.ios_vrf: + name: test_import + rd: 1:100 + route_import: + - 1:100 + - 3:100 + +- name: Creates a list of import RTs in address-family configuration submode for the + VRF with the same parameters + cisco.ios.ios_vrf: + name: test_import_ipv4 + rd: 1:100 + route_import_ipv4: + - 1:100 + - 3:100 + +- name: Creates a list of import RTs in address-family configuration submode for the + VRF with the same parameters + cisco.ios.ios_vrf: + name: test_import_ipv6 + rd: 1:100 + route_import_ipv6: + - 1:100 + - 3:100 + +- name: Creates a list of export RTs for the VRF with the same parameters + cisco.ios.ios_vrf: + name: test_export + rd: 1:100 + route_export: + - 1:100 + - 3:100 + +- name: Creates a list of export RTs in address-family configuration submode for the + VRF with the same parameters + cisco.ios.ios_vrf: + name: test_export_ipv4 + rd: 1:100 + route_export_ipv4: + - 1:100 + - 3:100 + +- name: Creates a list of export RTs in address-family configuration submode for the + VRF with the same parameters + cisco.ios.ios_vrf: + name: test_export_ipv6 + rd: 1:100 + route_export_ipv6: + - 1:100 + - 3:100 + +- name: Creates a list of import and export route targets for the VRF with the same + parameters + cisco.ios.ios_vrf: + name: test_both + rd: 1:100 + route_both: + - 1:100 + - 3:100 + +- name: Creates a list of import and export route targets in address-family configuration + submode for the VRF with the same parameters + cisco.ios.ios_vrf: + name: test_both_ipv4 + rd: 1:100 + route_both_ipv4: + - 1:100 + - 3:100 + +- name: Creates a list of import and export route targets in address-family configuration + submode for the VRF with the same parameters + cisco.ios.ios_vrf: + name: test_both_ipv6 + rd: 1:100 + route_both_ipv6: + - 1:100 + - 3:100 +""" +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - vrf definition ansible + - description management vrf + - rd: 1:100 +start: + description: The time the job started + returned: always + type: str + sample: "2016-11-16 10:38:15.126146" +end: + description: The time the job ended + returned: always + type: str + sample: "2016-11-16 10:38:25.595612" +delta: + description: The time elapsed to perform all operations + returned: always + type: str + sample: "0:00:10.469466\" +""" +import re +import time +from functools import partial +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import exec_command +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + load_config, + get_config, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import ( + ios_argument_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, +) +from ansible.module_utils.six import iteritems + + +def get_interface_type(interface): + if interface.upper().startswith("ET"): + return "ethernet" + elif interface.upper().startswith("VL"): + return "svi" + elif interface.upper().startswith("LO"): + return "loopback" + elif interface.upper().startswith("MG"): + return "management" + elif interface.upper().startswith("MA"): + return "management" + elif interface.upper().startswith("PO"): + return "portchannel" + elif interface.upper().startswith("NV"): + return "nve" + else: + return "unknown" + + +def add_command_to_vrf(name, cmd, commands): + if "vrf definition %s" % name not in commands: + commands.extend(["vrf definition %s" % name]) + commands.append(cmd) + + +def map_obj_to_commands(updates, module): + commands = list() + for update in updates: + want, have = update + + def needs_update(want, have, x): + if isinstance(want.get(x), list) and isinstance(have.get(x), list): + return ( + want.get(x) + and want.get(x) != have.get(x) + and not all(elem in have.get(x) for elem in want.get(x)) + ) + return want.get(x) and want.get(x) != have.get(x) + + if want["state"] == "absent": + commands.append("no vrf definition %s" % want["name"]) + continue + if not have.get("state"): + commands.extend(["vrf definition %s" % want["name"]]) + ipv6 = ( + len( + [ + k + for k, v in module.params.items() + if (k.endswith("_ipv6") or k.endswith("_both")) and v + ] + ) + != 0 + ) + ipv4 = ( + len( + [ + k + for k, v in module.params.items() + if (k.endswith("_ipv4") or k.endswith("_both")) and v + ] + ) + != 0 + ) + if ipv4: + commands.extend(["address-family ipv4", "exit"]) + if ipv6: + commands.extend(["address-family ipv6", "exit"]) + if needs_update(want, have, "description"): + cmd = "description %s" % want["description"] + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "rd"): + cmd = "rd %s" % want["rd"] + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_import"): + for route in want["route_import"]: + cmd = "route-target import %s" % route + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_export"): + for route in want["route_export"]: + cmd = "route-target export %s" % route + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_import_ipv4"): + cmd = "address-family ipv4" + add_command_to_vrf(want["name"], cmd, commands) + for route in want["route_import_ipv4"]: + cmd = "route-target import %s" % route + add_command_to_vrf(want["name"], cmd, commands) + cmd = "exit-address-family" + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_export_ipv4"): + cmd = "address-family ipv4" + add_command_to_vrf(want["name"], cmd, commands) + for route in want["route_export_ipv4"]: + cmd = "route-target export %s" % route + add_command_to_vrf(want["name"], cmd, commands) + cmd = "exit-address-family" + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_import_ipv6"): + cmd = "address-family ipv6" + add_command_to_vrf(want["name"], cmd, commands) + for route in want["route_import_ipv6"]: + cmd = "route-target import %s" % route + add_command_to_vrf(want["name"], cmd, commands) + cmd = "exit-address-family" + add_command_to_vrf(want["name"], cmd, commands) + if needs_update(want, have, "route_export_ipv6"): + cmd = "address-family ipv6" + add_command_to_vrf(want["name"], cmd, commands) + for route in want["route_export_ipv6"]: + cmd = "route-target export %s" % route + add_command_to_vrf(want["name"], cmd, commands) + cmd = "exit-address-family" + add_command_to_vrf(want["name"], cmd, commands) + if want["interfaces"] is not None: + for intf in set(have.get("interfaces", [])).difference( + want["interfaces"] + ): + commands.extend( + [ + "interface %s" % intf, + "no vrf forwarding %s" % want["name"], + ] + ) + for intf in set(want["interfaces"]).difference( + have.get("interfaces", []) + ): + cfg = get_config(module) + configobj = NetworkConfig(indent=1, contents=cfg) + children = configobj["interface %s" % intf].children + intf_config = "\n".join(children) + commands.extend( + ["interface %s" % intf, "vrf forwarding %s" % want["name"]] + ) + match = re.search("ip address .+", intf_config, re.M) + if match: + commands.append(match.group()) + return commands + + +def parse_description(configobj, name): + cfg = configobj["vrf definition %s" % name] + cfg = "\n".join(cfg.children) + match = re.search("description (.+)$", cfg, re.M) + if match: + return match.group(1) + + +def parse_rd(configobj, name): + cfg = configobj["vrf definition %s" % name] + cfg = "\n".join(cfg.children) + match = re.search("rd (.+)$", cfg, re.M) + if match: + return match.group(1) + + +def parse_interfaces(configobj): + vrf_cfg = "vrf forwarding" + interfaces = dict() + for intf in set(re.findall("^interface .+", str(configobj), re.M)): + for line in configobj[intf].children: + if vrf_cfg in line: + try: + interfaces[line.split()[-1]].append(intf.split(" ")[1]) + except KeyError: + interfaces[line.split()[-1]] = [intf.split(" ")[1]] + return interfaces + + +def parse_import(configobj, name): + cfg = configobj["vrf definition %s" % name] + cfg = "\n".join(cfg.children) + matches = re.findall("route-target\\s+import\\s+(.+)", cfg, re.M) + return matches + + +def parse_export(configobj, name): + cfg = configobj["vrf definition %s" % name] + cfg = "\n".join(cfg.children) + matches = re.findall("route-target\\s+export\\s+(.+)", cfg, re.M) + return matches + + +def parse_both(configobj, name, address_family="global"): + rd_pattern = re.compile("(?P<rd>.+:.+)") + matches = list() + export_match = None + import_match = None + if address_family == "global": + export_match = parse_export(configobj, name) + import_match = parse_import(configobj, name) + elif address_family == "ipv4": + export_match = parse_export_ipv4(configobj, name) + import_match = parse_import_ipv4(configobj, name) + elif address_family == "ipv6": + export_match = parse_export_ipv6(configobj, name) + import_match = parse_import_ipv6(configobj, name) + if import_match and export_match: + for ex in export_match: + exrd = rd_pattern.search(ex) + exrd = exrd.groupdict().get("rd") + for im in import_match: + imrd = rd_pattern.search(im) + imrd = imrd.groupdict().get("rd") + if exrd == imrd: + matches.extend([exrd]) if exrd not in matches else None + matches.extend([imrd]) if imrd not in matches else None + return matches + + +def parse_import_ipv4(configobj, name): + cfg = configobj["vrf definition %s" % name] + try: + subcfg = cfg["address-family ipv4"] + subcfg = "\n".join(subcfg.children) + matches = re.findall("route-target\\s+import\\s+(.+)", subcfg, re.M) + return matches + except KeyError: + pass + + +def parse_export_ipv4(configobj, name): + cfg = configobj["vrf definition %s" % name] + try: + subcfg = cfg["address-family ipv4"] + subcfg = "\n".join(subcfg.children) + matches = re.findall("route-target\\s+export\\s+(.+)", subcfg, re.M) + return matches + except KeyError: + pass + + +def parse_import_ipv6(configobj, name): + cfg = configobj["vrf definition %s" % name] + try: + subcfg = cfg["address-family ipv6"] + subcfg = "\n".join(subcfg.children) + matches = re.findall("route-target\\s+import\\s+(.+)", subcfg, re.M) + return matches + except KeyError: + pass + + +def parse_export_ipv6(configobj, name): + cfg = configobj["vrf definition %s" % name] + try: + subcfg = cfg["address-family ipv6"] + subcfg = "\n".join(subcfg.children) + matches = re.findall("route-target\\s+export\\s+(.+)", subcfg, re.M) + return matches + except KeyError: + pass + + +def map_config_to_obj(module): + config = get_config(module) + configobj = NetworkConfig(indent=1, contents=config) + match = re.findall("^vrf definition (\\S+)", config, re.M) + if not match: + return list() + instances = list() + interfaces = parse_interfaces(configobj) + for item in set(match): + obj = { + "name": item, + "state": "present", + "description": parse_description(configobj, item), + "rd": parse_rd(configobj, item), + "interfaces": interfaces.get(item), + "route_import": parse_import(configobj, item), + "route_export": parse_export(configobj, item), + "route_both": parse_both(configobj, item), + "route_import_ipv4": parse_import_ipv4(configobj, item), + "route_export_ipv4": parse_export_ipv4(configobj, item), + "route_both_ipv4": parse_both( + configobj, item, address_family="ipv4" + ), + "route_import_ipv6": parse_import_ipv6(configobj, item), + "route_export_ipv6": parse_export_ipv6(configobj, item), + "route_both_ipv6": parse_both( + configobj, item, address_family="ipv6" + ), + } + instances.append(obj) + return instances + + +def get_param_value(key, item, module): + # if key doesn't exist in the item, get it from module.params + if not item.get(key): + value = module.params[key] + # if key does exist, do a type check on it to validate it + else: + value_type = module.argument_spec[key].get("type", "str") + type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] + type_checker(item[key]) + value = item[key] + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if validator: + validator(value, module) + return value + + +def map_params_to_obj(module): + vrfs = module.params.get("vrfs") + if not vrfs: + if not module.params["name"] and module.params["purge"]: + return list() + elif not module.params["name"]: + module.fail_json(msg="name is required") + collection = [{"name": module.params["name"]}] + else: + collection = list() + for item in vrfs: + if not isinstance(item, dict): + collection.append({"name": item}) + elif "name" not in item: + module.fail_json(msg="name is required") + else: + collection.append(item) + objects = list() + for item in collection: + get_value = partial(get_param_value, item=item, module=module) + item["description"] = get_value("description") + item["rd"] = get_value("rd") + item["interfaces"] = get_value("interfaces") + item["state"] = get_value("state") + item["route_import"] = get_value("route_import") + item["route_export"] = get_value("route_export") + item["route_both"] = get_value("route_both") + item["route_import_ipv4"] = get_value("route_import_ipv4") + item["route_export_ipv4"] = get_value("route_export_ipv4") + item["route_both_ipv4"] = get_value("route_both_ipv4") + item["route_import_ipv6"] = get_value("route_import_ipv6") + item["route_export_ipv6"] = get_value("route_export_ipv6") + item["route_both_ipv6"] = get_value("route_both_ipv6") + both_addresses_family = ["", "_ipv6", "_ipv4"] + for address_family in both_addresses_family: + if item["route_both%s" % address_family]: + if not item["route_export%s" % address_family]: + item["route_export%s" % address_family] = list() + if not item["route_import%s" % address_family]: + item["route_import%s" % address_family] = list() + item["route_export%s" % address_family].extend( + get_value("route_both%s" % address_family) + ) + item["route_import%s" % address_family].extend( + get_value("route_both%s" % address_family) + ) + item["associated_interfaces"] = get_value("associated_interfaces") + objects.append(item) + return objects + + +def update_objects(want, have): + updates = list() + for entry in want: + item = next((i for i in have if i["name"] == entry["name"]), None) + if all((item is None, entry["state"] == "present")): + updates.append((entry, {})) + else: + for key, value in iteritems(entry): + if value: + try: + if isinstance(value, list): + if sorted(value) != sorted(item[key]): + if (entry, item) not in updates: + updates.append((entry, item)) + elif value != item[key]: + if (entry, item) not in updates: + updates.append((entry, item)) + except TypeError: + pass + return updates + + +def check_declarative_intent_params(want, module, result): + if module.params["associated_interfaces"]: + if result["changed"]: + time.sleep(module.params["delay"]) + name = module.params["name"] + rc, out, err = exec_command( + module, "show vrf | include {0}".format(name) + ) + if rc == 0: + data = out.strip().split() + if not data: + return + vrf = data[0] + interface = data[-1] + for w in want: + if w["name"] == vrf: + if w.get("associated_interfaces") is None: + continue + for i in w["associated_interfaces"]: + if get_interface_type(i) is not get_interface_type( + interface + ): + module.fail_json( + msg="Interface %s not configured on vrf %s" + % (interface, name) + ) + + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + vrfs=dict(type="list", elements="raw"), + name=dict(), + description=dict(), + rd=dict(), + route_export=dict(type="list", elements="str"), + route_import=dict(type="list", elements="str"), + route_both=dict(type="list", elements="str"), + route_export_ipv4=dict(type="list", elements="str"), + route_import_ipv4=dict(type="list", elements="str"), + route_both_ipv4=dict(type="list", elements="str"), + route_export_ipv6=dict(type="list", elements="str"), + route_import_ipv6=dict(type="list", elements="str"), + route_both_ipv6=dict(type="list", elements="str"), + interfaces=dict(type="list", elements="str"), + associated_interfaces=dict(type="list", elements="str"), + delay=dict(default=10, type="int"), + purge=dict(type="bool", default=False), + state=dict(default="present", choices=["present", "absent"]), + ) + argument_spec.update(ios_argument_spec) + mutually_exclusive = [("name", "vrfs")] + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = {"changed": False} + warnings = list() + result["warnings"] = warnings + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands(update_objects(want, have), module) + if module.params["purge"]: + want_vrfs = [x["name"] for x in want] + have_vrfs = [x["name"] for x in have] + for item in set(have_vrfs).difference(want_vrfs): + cmd = "no vrf definition %s" % item + if cmd not in commands: + commands.append(cmd) + result["commands"] = commands + if commands: + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + check_declarative_intent_params(want, module, result) + module.exit_json(**result) + + +if __name__ == "__main__": + main() |