diff options
Diffstat (limited to 'ansible_collections/cisco/ios/plugins/modules')
13 files changed, 1047 insertions, 962 deletions
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_acls.py b/ansible_collections/cisco/ios/plugins/modules/ios_acls.py index f81e0e7ab..4636ecb5d 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_acls.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_acls.py @@ -471,6 +471,11 @@ options: - Remarks entry used as the only key in as the list option will produce non ace specific remarks, these remarks would be pushed at the end of all the aces for an acl. + - Remarks is treated a block, for every single remarks updated for + an ace all the remarks are negated and added back to maintain the + order of remarks mentioned. + - As the appliance deletes all the remarks once the ace is updated, + the set of remarks would be re-applied that is an expected behavior. elements: str type: list sequence: @@ -1944,6 +1949,347 @@ EXAMPLES = """ # 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 +# Using overridden - example remarks specific on multiple sequence + +# Before state: +# ------------- +# +# vios#show running-config | section access-list +# ip access-list extended TEST +# 10 remark FIRST REMARK BEFORE SEQUENCE 10 +# 10 remark ============ +# 10 remark REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE +# 20 remark FIRST REMARK BEFORE SEQUENCE 20 +# 20 remark ============ +# 20 remark ALLOW HOST FROM SEQUENCE 20 +# 20 permit ip host 1.1.1.1 any +# 30 remark FIRST REMARK BEFORE SEQUENCE 30 +# 30 remark ============ +# 30 remark ALLOW HOST FROM SEQUENCE 30 +# 30 permit ip host 2.2.2.2 any +# 40 remark FIRST REMARK BEFORE SEQUENCE 40 +# 40 remark ============ +# 40 remark ALLOW NEW HOST FROM SEQUENCE 40 +# 40 permit ip host 3.3.3.3 any +# remark Remark not specific to sequence +# remark ============ +# remark End Remarks +# ip access-list extended test_acl +# 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 +# ip access-list extended 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 +# ip access-list extended 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 +# ipv6 access-list R1_TRAFFIC +# sequence 10 deny tcp any eq www any eq telnet ack dscp af11 + +- name: Override remarks and ace configurations + cisco.ios.ios_acls: + config: + - afi: ipv4 + acls: + - name: TEST + acl_type: extended + aces: + - sequence: 10 + remarks: + - "FIRST REMARK BEFORE SEQUENCE 10" + - "============" + - "REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE" + grant: permit + protocol: ip + source: + host: 1.1.1.1 + destination: + any: true + - sequence: 20 + remarks: + - "FIRST REMARK BEFORE SEQUENCE 20" + - "============" + - "ALLOW HOST FROM SEQUENCE 20" + grant: permit + protocol: ip + source: + host: 192.168.0.1 + destination: + any: true + - sequence: 30 + remarks: + - "FIRST REMARK BEFORE SEQUENCE 30" + - "============" + - "ALLOW HOST FROM SEQUENCE 30 updated" + grant: permit + protocol: ip + source: + host: 2.2.2.2 + destination: + any: true + - sequence: 40 + remarks: + - "FIRST REMARK BEFORE SEQUENCE 40" + - "============" + - "ALLOW NEW HOST FROM SEQUENCE 40" + grant: permit + protocol: ip + source: + host: 3.3.3.3 + destination: + any: true + - remarks: + - "Remark not specific to sequence" + - "============" + - "End Remarks 1" + state: overridden + +# Task Output +# ----------- +# +# before: +# - acls: +# - aces: +# - destination: +# address: 192.0.3.0 +# wildcard_bits: 0.0.0.255 +# dscp: ef +# grant: deny +# protocol: icmp +# 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: tcp +# 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: tcp +# 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: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 20 +# - ============ +# - ALLOW HOST FROM SEQUENCE 20 +# sequence: 20 +# source: +# host: 1.1.1.1 +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 30 +# - ============ +# - ALLOW HOST FROM SEQUENCE 30 +# sequence: 30 +# source: +# host: 2.2.2.2 +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 40 +# - ============ +# - ALLOW NEW HOST FROM SEQUENCE 40 +# sequence: 40 +# source: +# host: 3.3.3.3 +# - remarks: +# - FIRST REMARK BEFORE SEQUENCE 10 +# - ============ +# - REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE +# sequence: 10 +# - remarks: +# - Remark not specific to sequence +# - ============ +# - End Remarks +# acl_type: extended +# name: TEST +# - aces: +# - destination: +# address: 192.0.3.0 +# port_protocol: +# eq: www +# wildcard_bits: 0.0.0.255 +# grant: deny +# option: +# traceroute: true +# protocol: tcp +# 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: tcp +# protocol_options: +# tcp: +# ack: true +# sequence: 10 +# source: +# any: true +# port_protocol: +# eq: www +# name: R1_TRAFFIC +# afi: ipv6 +# commands: +# - no ipv6 access-list R1_TRAFFIC +# - ip access-list extended TEST +# - no 10 # removes all remarks and ace entry for sequence 10 +# - no 20 permit ip host 1.1.1.1 any # removing the ace automatically removes the remarks +# - no 30 remark # just remove remarks for sequence 30 +# - no remark # remove all remarks at end of acl, that has no sequence +# - 10 remark FIRST REMARK BEFORE SEQUENCE 10 +# - 10 remark ============ +# - 10 remark REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE +# - 10 permit ip host 1.1.1.1 any +# - 20 remark FIRST REMARK BEFORE SEQUENCE 20 +# - 20 remark ============ +# - 20 remark ALLOW HOST FROM SEQUENCE 20 +# - 20 permit ip host 192.168.0.1 any +# - 30 remark FIRST REMARK BEFORE SEQUENCE 30 +# - 30 remark ============ +# - 30 remark ALLOW HOST FROM SEQUENCE 30 updated +# - remark Remark not specific to sequence +# - remark ============ +# - remark End Remarks 1 +# - no ip access-list extended 110 +# - no ip access-list extended 123 +# - no ip access-list extended test_acl +# after: +# - acls: +# - aces: +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 10 +# - ============ +# - REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE +# sequence: 10 +# source: +# host: 1.1.1.1 +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 20 +# - ============ +# - ALLOW HOST FROM SEQUENCE 20 +# sequence: 20 +# source: +# host: 192.168.0.1 +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 30 +# - ============ +# - ALLOW HOST FROM SEQUENCE 30 updated +# sequence: 30 +# source: +# host: 2.2.2.2 +# - destination: +# any: true +# grant: permit +# protocol: ip +# remarks: +# - FIRST REMARK BEFORE SEQUENCE 40 +# - ============ +# - ALLOW NEW HOST FROM SEQUENCE 40 +# sequence: 40 +# source: +# host: 3.3.3.3 +# - remarks: +# - Remark not specific to sequence +# - ============ +# - End Remarks 1 +# acl_type: extended +# name: TEST +# afi: ipv4 + +# After state: +# ------------- +# +# foo#show running-config | section access-list +# ip access-list extended TEST +# 10 remark FIRST REMARK BEFORE SEQUENCE 10 +# 10 remark ============ +# 10 remark REMARKS FOR SEQUENCE 10 NO FOLLOWING ACE +# 10 permit ip host 1.1.1.1 any +# 20 remark FIRST REMARK BEFORE SEQUENCE 20 +# 20 remark ============ +# 20 remark ALLOW HOST FROM SEQUENCE 20 +# 20 permit ip host 192.168.0.1 any +# 30 remark FIRST REMARK BEFORE SEQUENCE 30 +# 30 remark ============ +# 30 remark ALLOW HOST FROM SEQUENCE 30 updated +# 30 permit ip host 2.2.2.2 any +# 40 remark FIRST REMARK BEFORE SEQUENCE 40 +# 40 remark ============ +# 40 remark ALLOW NEW HOST FROM SEQUENCE 40 +# 40 permit ip host 3.3.3.3 any +# remark Remark not specific to sequence +# remark ============ +# remark End Remarks 1 # Using deleted - delete ACL(s) diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py deleted file mode 100644 index b01f99428..000000000 --- a/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py +++ /dev/null @@ -1,504 +0,0 @@ -#!/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: Module to configure BGP protocol settings. -description: - - This module provides configuration management of global BGP parameters on devices - running Cisco IOS -version_added: 1.0.0 -deprecated: - alternative: ios_bgp_global - why: Newer and updated modules released with more functionality - removed_at_date: "2023-08-24" -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: true - maximum_prefix: 250 - advertisement_interval: 120 - - neighbor: 192.0.2.15 - activate: true - 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.cli.config.bgp.process import ( - REDISTRIBUTE_PROTOCOLS, -) -from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.module import ( - NetworkModule, -) - - -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/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py index 14589f20f..e9f770631 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py @@ -22,7 +22,7 @@ author: - Sagar Paul (@KB-perByte) - Sumit Jaiswal (@justjais) notes: - - Tested against Cisco IOSXE Version 17.3 on CML. + - Tested against Cisco IOS-XE Version 17.3 on CML. - This module works with connection C(network_cli). See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html) - The module examples uses callback plugin (stdout_callback = yaml) to generate task diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py index 9aa33c87c..55ab21341 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py @@ -22,7 +22,7 @@ author: - Sumit Jaiswal (@justjais) - Sagar Paul (@KB-perByte) notes: - - Tested against Cisco IOSXE Version 17.3 on CML. + - Tested against Cisco IOS-XE Version 17.3 on CML. - This module works with connection C(network_cli). See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html) - The module examples uses callback plugin (stdout_callback = yaml) to generate task @@ -274,6 +274,22 @@ options: - Set the bgp consistency checker - Please refer vendor documentation for valid values type: int + default: + description: Configure BGP defaults + type: dict + suboptions: + ipv4_unicast: + description: Activate ipv4-unicast for a peer by default + type: bool + default: true + route_target: + description: Control behavior based on Route-Target attributes + type: dict + suboptions: + filter: + description: Control automatic VPN Route-Target filtering + type: bool + default: true dampening: description: Enable route-flap dampening type: dict @@ -1795,8 +1811,6 @@ options: template: description: - Enter template command mode - - This option is DEPRECATED as is not valid within the scope of module, - this attribute will be removed after 2024-06-01. type: dict suboptions: peer_policy: @@ -1883,6 +1897,10 @@ EXAMPLES = """ reuse_route_val: 1 suppress_route_val: 1 max_suppress: 1 + default: + ipv4_unicast: false + route_target: + filter: true graceful_shutdown: neighbors: time: 50 @@ -1926,6 +1944,7 @@ EXAMPLES = """ # - timers bgp 100 200 150 # - bgp advertise-best-external # - bgp bestpath compare-routerid +# - no bgp default ipv4-unicast # - bgp dampening 1 1 1 1 # - bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 # - bgp log-neighbor-changes @@ -1948,6 +1967,10 @@ EXAMPLES = """ # penalty_half_time: 1 # reuse_route_val: 1 # suppress_route_val: 1 +# default: +# ipv4_unicast: false +# route_target: +# filter: true # graceful_shutdown: # community: '100' # local_preference: 100 @@ -1987,6 +2010,7 @@ EXAMPLES = """ # # vios#sh running-config | section ^router bgp # router bgp 65000 +# no bgp default ipv4-unicast # bgp log-neighbor-changes # bgp nopeerup-delay post-boot 10 # bgp graceful-shutdown all neighbors 50 local-preference 100 community 100 @@ -2059,6 +2083,10 @@ EXAMPLES = """ # penalty_half_time: 1 # reuse_route_val: 1 # suppress_route_val: 1 +# default: +# ipv4_unicast: true +# route_target: +# filter: true # graceful_shutdown: # community: '100' # local_preference: 100 @@ -2106,6 +2134,10 @@ EXAMPLES = """ # bestpath_options: # med: # confed: true +# default: +# ipv4_unicast: true +# route_target: +# filter: true # log_neighbor_changes: true # nopeerup_delay_options: # cold_boot: 20 @@ -2172,6 +2204,10 @@ EXAMPLES = """ # penalty_half_time: 1 # reuse_route_val: 1 # suppress_route_val: 1 +# default: +# ipv4_unicast: true +# route_target: +# filter: true # graceful_shutdown: # community: '100' # local_preference: 100 @@ -2247,6 +2283,10 @@ EXAMPLES = """ # penalty_half_time: 1 # reuse_route_val: 1 # suppress_route_val: 1 +# default: +# ipv4_unicast: true +# route_target: +# filter: true # graceful_shutdown: # community: '100' # local_preference: 100 @@ -2318,6 +2358,10 @@ EXAMPLES = """ # advertise_best_external: true # bestpath_options: # compare_routerid: true +# default: +# ipv4_unicast: true +# route_target: +# filter: true # dampening: # max_suppress: 1 # penalty_half_time: 1 @@ -2394,6 +2438,10 @@ EXAMPLES = """ # penalty_half_time: 1 # reuse_route_val: 1 # suppress_route_val: 1 +# default: +# ipv4_unicast: true +# route_target: +# filter: true # graceful_shutdown: # community: '100' # local_preference: 100 diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_evpn_evi.py b/ansible_collections/cisco/ios/plugins/modules/ios_evpn_evi.py index c2b8b330e..2b232e3f1 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_evpn_evi.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_evpn_evi.py @@ -21,7 +21,7 @@ description: This module provides declarative management of L2VPN EVPN EVI on Ci version_added: 5.3.0 author: Padmini Priyadarshini Sivaraj (@PadminiSivaraj) notes: - - Tested against Cisco IOS device with Version 17.13.01 on Cat9k on CML. + - Tested against Cisco IOS-XE device with Version 17.13.01 on Cat9k on CML. - This module works with connection C(network_cli). See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html) options: diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_evpn_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_evpn_global.py index 0ffe52b90..9070df49d 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_evpn_global.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_evpn_global.py @@ -21,7 +21,7 @@ description: This module provides declarative management of L2VPN EVPN on Cisco version_added: 5.3.0 author: Padmini Priyadarshini Sivaraj (@PadminiSivaraj) notes: - - Tested against Cisco IOS device with Version 17.13.01 on Cat9k on CML. + - Tested against Cisco IOS-XE device with Version 17.13.01 on Cat9k on CML. - This module works with connection C(network_cli). See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html) options: diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py index 0f6924124..f8bf73f80 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py @@ -40,6 +40,14 @@ options: - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. type: str required: true + autostate: + description: + - Enable autostate determination for VLAN. + type: bool + mac_address: + description: + - Manually set interface MAC address. + type: str ipv4: description: - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option. @@ -87,6 +95,19 @@ options: pool: description: IP Address auto-configured from a local DHCP pool. type: str + source_interface: + description: Enable IP processing without an explicit address + type: dict + suboptions: + name: + description: Interface name + type: str + poll: + description: Enable IP connected host polling + type: bool + point_to_point: + description: Enable point-to-point connection + type: bool ipv6: description: - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option. @@ -119,6 +140,9 @@ options: rapid_commit: description: Enable Rapid-Commit. type: bool + enable: + description: Enable IPv6 on interface + type: bool anycast: description: Configure as an anycast type: bool @@ -229,6 +253,13 @@ EXAMPLES = """ - name: GigabitEthernet3.100 ipv4: - address: 192.168.0.3/24 + - name: Vlan901 + autostate: false + ipv4: + - source_interface: + name: Loopback1 + ipv6: + - enable: true state: merged # Task Output @@ -253,6 +284,10 @@ EXAMPLES = """ # - ipv6 address fd5d:12c9:2201:1::1/64 # - interface GigabitEthernet3.100 # - ip address 192.168.0.3 255.255.255.0 +# - interface Vlan901 +# - ip unnumbered Loopback1 +# - ipv6 enable +# - no autostate # after: # - ipv4: # - dhcp: @@ -269,6 +304,13 @@ EXAMPLES = """ # - address: 192.168.0.3/24 # - name: GigabitEthernet4 # - name: Loopback999 +# ipv4: +# - source_interface: +# name: Loopback1 +# ipv6: +# - enable: true +# autostate: false +# - name: Vlan901 # After state: # ------------ @@ -299,6 +341,11 @@ EXAMPLES = """ # no ip address # shutdown # negotiation auto +# interface Vlan901 +# ip unnumbered Loopback1 +# ipv6 enable +# no autostate + # Using replaced diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py b/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py index 4572afe42..01267865f 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py @@ -265,11 +265,11 @@ def parse_mode(module, config, group, member): 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) + lineStrip = line.strip() + if lineStrip.startswith("interface"): + match_group = re.findall("channel-group {0} mode".format(group), lineStrip, re.M) if match_group: - match = re.search("interface (\\S+)", l, re.M) + match = re.search("interface (\\S+)", lineStrip, re.M) if match: members.append(match.group(1)) return members @@ -291,8 +291,8 @@ 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) + lStrip = line.strip() + match = re.search("interface Port-channel(\\S+)", lStrip, re.M) if match: obj = {} group = match.group(1) diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py b/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py deleted file mode 100644 index 065054411..000000000 --- a/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py +++ /dev/null @@ -1,357 +0,0 @@ -#!/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: (deprecated, removed after 2024-01-01) Manages core NTP configuration. -description: - - Manages core NTP configuration. -version_added: 1.0.0 -deprecated: - alternative: ios_ntp_global - why: Updated module released with more functionality. - removed_at_date: "2024-01-01" -author: - - Federico Olivieri (@Federico87) - - Joanie Sylvain (@JoanieAda) -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 - vrf: - description: - - VRF configuration for NTP servers - type: str -""" - -EXAMPLES = """ -# Set new NTP server and source interface -- name: Example ntp play - cisco.ios.ios_ntp: - server: 10.0.255.10 - source_int: Loopback0 - logging: false - state: present - -# Remove NTP ACL and logging -- name: Example ntp play absent - cisco.ios.ios_ntp: - acl: NTP_ACL - logging: true - state: absent - -# Set NTP authentication -- name: Example ntp play auth - cisco.ios.ios_ntp: - key_id: 10 - auth_key: 15435A030726242723273C21181319000A - auth: true - state: present - -# Set new NTP configuration -- name: Example ntp play auth - cisco.ios.ios_ntp: - server: 10.0.255.10 - source_int: Loopback0 - acl: NTP_ACL - logging: true - vrf: mgmt - 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, -) - - -def parse_server(line, dest): - if dest == "server": - vrf, server = None, None - match = re.search( - "(ntp\\sserver\\s)(vrf\\s\\w+\\s)?(\\d+\\.\\d+\\.\\d+\\.\\d+)", - line, - re.M, - ) - - if match and match.group(2) and match.group(3): - vrf = match.group(2) - server = match.group(3) - return vrf, server - - if match and match.group(3): - server = match.group(3) - return vrf, server - - -def parse_source_int(line, dest): - if dest == "source": - match = re.search("(ntp\\ssource\\s)(\\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\\saccess-group\\s(?: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\\sauthentication-key\\s\\d+\\smd5\\s)(\\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\\strusted-key\\s)(\\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 = dict() - obj = list() - server_list = list() - config = get_config(module, flags=["| include ntp"]) - for line in config.splitlines(): - match = re.search("ntp\\s(\\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: - if server[0] is None: - server_list.append((server[0], server[1])) - else: - server_list.append((server[0].split()[1], server[1])) - 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 = list() - - 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"], - "vrf": module.params["vrf"], - }, - ) - - 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"] - vrf = w["vrf"] - if vrf == "": - vrf = None - - if state == "absent": - if server_have and (vrf, server) in server_have: - if vrf is not None: - commands.append("no ntp server vrf {0} {1}".format(vrf, server)) - else: - 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 (vrf, server) not in server_have: - if vrf is not None: - commands.append("ntp server vrf {0} {1}".format(vrf, server)) - else: - 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(no_log=True), - key_id=dict(), - state=dict(choices=["absent", "present"], default="present"), - vrf=dict(), - ) - 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/ansible_collections/cisco/ios/plugins/modules/ios_user.py b/ansible_collections/cisco/ios/plugins/modules/ios_user.py index 50f2f3455..931ed0e71 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_user.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_user.py @@ -220,6 +220,17 @@ extends_documentation_fragment: """ EXAMPLES = """ +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username testuser privilege 15 password 0 password + +# Present state create a new user play: +# ------------------------------------- + - name: Create a new user cisco.ios.ios_user: name: ansible @@ -227,6 +238,37 @@ EXAMPLES = """ sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: present +# Task Output +# ----------- + +# commands: +# - ip ssh pubkey-chain +# - username ansible +# - key-hash ssh-rsa 2ABB27BBC33ED53EF7D55037952ABB27 test@fedora +# - exit +# - exit +# - username ansible nopassword + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username testuser privilege 15 password 0 password +# username ansible nopassword +# username ansible +# key-hash ssh-rsa 2ABB27BBC33ED53EF7D55037952ABB27 test@fedora + +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username testuser privilege 15 password 0 password + +# Present state create a new user with multiple keys play: +# -------------------------------------------------------- + - name: Create a new user with multiple keys cisco.ios.ios_user: name: ansible @@ -235,18 +277,109 @@ EXAMPLES = """ - "{{ lookup('file', '~/path/to/public_key') }}" state: present +# Task Output +# ----------- + +# commands: +# - ip ssh pubkey-chain +# - username ansible +# - key-hash ssh-rsa 2ABB27BBC33ED53EF7D55037952ABB27 test@fedora +# - key-hash ssh-rsa 1985673DCF7FA9A0F374BB97DC2ABB27 test@fedora +# - exit +# - exit + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username testuser privilege 15 password 0 password +# username ansible +# key-hash ssh-rsa 2ABB27BBC33ED53EF7D55037952ABB27 test@fedora +# key-hash ssh-rsa 1985673DCF7FA9A0F374BB97DC2ABB27 test@fedora + +# Using Purge: true + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username testuser privilege 15 password 0 password +# username ansible nopassword +# username ansible +# key-hash ssh-rsa 2ABB27BBC33ED53EF7D55037952ABB27 test@fedora + +# Purge all users except admin play: +# ---------------------------------- + - name: Remove all users except admin cisco.ios.ios_user: purge: true +# Task Output +# ----------- + +# commands: +# - no username testuser +# - no username ansible +# - ip ssh pubkey-chain +# - no username ansible +# - exit + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password + +# Using Purge: true + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username testuser privilege 15 password 0 password1 +# username testuser1 privilege 15 password 0 password2 +# username ansible nopassword + +# Purge all users except admin and these listed users play: +# --------------------------------------------------------- + - name: Remove all users except admin and these listed users cisco.ios.ios_user: aggregate: + - name: testuser - name: testuser1 - - name: testuser2 - - name: testuser3 purge: true +# Task Output +# ----------- + +# commands: +# - no username ansible + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password +# username testuser privilege 15 password 0 password1 +# username testuser1 privilege 15 password 0 password2 + +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username netop password 0 password1 +# username netend password 0 password2 + +# Present state set multiple users to privilege level 15 play: +# ------------------------------------------------------------ + - name: Set multiple users to privilege level 15 cisco.ios.ios_user: aggregate: @@ -255,38 +388,135 @@ EXAMPLES = """ privilege: 15 state: present -- name: Set user view/role - cisco.ios.ios_user: - name: netop - view: network-operator - state: present +# Task Output +# ----------- + +# commands: +# - username netop privilege 15 +# - username netend privilege 15 + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password +# username netop privilege 15 password 0 password1 +# username netend privilege 15 password 0 password2 + +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username netop privilege 15 password 0 oldpassword + +# Present state Change Password for User netop play: +# -------------------------------------------- - name: Change Password for User netop cisco.ios.ios_user: name: netop - configured_password: "{{ new_password }}" + configured_password: "newpassword" + password_type: password update_password: always state: present -- name: Aggregate of users +# Task Output +# ----------- + +# commands: +# - username netop password newpassword + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password +# username netop privilege 15 password 0 newpassword + +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username netop privilege 15 password 0 password +# username netend privilege 15 password 0 password + +# Present state set user view/role for users play: +# -------------------------------------------- + +- name: Set user view/role for users cisco.ios.ios_user: aggregate: - - name: ansibletest2 - - name: ansibletest3 + - name: netop + - name: netend view: network-admin + state: present -- name: Add a user specifying password type - cisco.ios.ios_user: - name: ansibletest4 - configured_password: "{{ new_password }}" - password_type: password +# Task Output +# ----------- + +# commands: +# - username netop view network-admin +# - username netend view network-admin + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password +# username netop privilege 15 view network-admin password 0 password +# username netend privilege 15 view network-admin password 0 password + +# Using state: present + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password + +# Present state create a new user with hashed password play: +# -------------------------------------------------------------- -- name: Add a user with MD5 hashed password +- name: Create a new user with hashed password cisco.ios.ios_user: name: ansibletest5 hashed_password: - type: 5 - value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/ + type: 9 + value: "thiswillbereplacedwithhashedpassword" + state: present + +# Task Output +# ----------- + +# commands: +# - username ansibletest5 secret 9 thiswillbereplacedwithhashedpassword + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password +# username ansibletest5 secret 9 thiswillbereplacedwithhashedpassword + +# Using state: absent + +# Before state: +# ------------- + +# router-ios#show running-config | section ^username +# username admin privilege 15 password 0 password +# username ansibletest1 password 0 password +# username ansibletest2 secret 9 thiswillbereplacedwithhashedpassword +# username ansibletest3 password 5 thistoowillbereplacedwithhashedpassword + +# Absent state remove multiple users play: +# ---------------------------------------- - name: Delete users with aggregate cisco.ios.ios_user: @@ -295,6 +525,20 @@ EXAMPLES = """ - name: ansibletest2 - name: ansibletest3 state: absent + +# Task Output +# ----------- + +# commands: +# - no username ansibletest1 +# - no username ansibletest2 +# - no username ansibletest3 + +# After state: +# ------------ + +# router-ios#show running-config | section username +# username admin privilege 15 password 0 password """ RETURN = """ @@ -339,6 +583,18 @@ def user_del_cmd(username): } +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") + + def sshkey_fingerprint(sshkey): # IOS will accept a MD5 fingerprint of the public key # and is easier to configure in a single line @@ -366,19 +622,10 @@ def map_obj_to_commands(updates, module): 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") + def add_hashed_password(command, want, x, password_type): + command.append( + "username %s %s %s %s" % (want["name"], password_type, x.get("type"), x.get("value")), + ) for update in updates: want, have = update @@ -402,7 +649,7 @@ def map_obj_to_commands(updates, module): ) 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"]) + add_hashed_password(commands, want, want["hashed_password"], password_type) if needs_update(want, have, "nopassword"): if want["nopassword"]: add(commands, want, "nopassword") @@ -451,6 +698,7 @@ def map_config_to_obj(module): regex = "username %s .+$" % user cfg = re.findall(regex, data, re.M) cfg = "\n".join(cfg) + ssh_key_list = parse_sshkey(data, user) obj = { "name": user, "state": "present", @@ -458,7 +706,9 @@ def map_config_to_obj(module): "configured_password": None, "hashed_password": None, "password_type": parse_password_type(cfg), - "sshkey": parse_sshkey(data, user), + "sshkey": ssh_key_list, + "is_only_ssh_user": False if cfg.strip() and ssh_key_list else True, + "is_only_normal_user": True if cfg.strip() and ssh_key_list == [] else False, "privilege": parse_privilege(cfg), "view": parse_view(cfg), } @@ -536,6 +786,14 @@ def update_objects(want, have): return updates +def find_set_difference(list1, list2, key): + want_users = [x[key] for x in list1] + have_users = [x[key] for x in list2] + setdifference = set(have_users).difference(want_users) + result = [item for item in list2 if item[key] in setdifference] + return result + + def main(): """main entry point for module execution""" hashed_password_spec = dict( @@ -581,13 +839,19 @@ def main(): 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)) + setdifference = find_set_difference(want, have, "name") + for item in setdifference: + if item["name"] != "admin": + if item["is_only_ssh_user"]: + add_ssh(commands, item) + if item["is_only_normal_user"]: + commands.append(user_del_cmd(item["name"])) + if item["is_only_normal_user"] is False and item["is_only_ssh_user"] is False: + add_ssh(commands, item) + commands.append(user_del_cmd(item["name"])) result["commands"] = commands if commands: if not module.check_mode: diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py b/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py index 1dd3228ce..de9a0212a 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py @@ -30,9 +30,12 @@ description: This module provides declarative management of VLANs on Cisco IOS network devices. version_added: 1.0.0 -author: Sumit Jaiswal (@justjais) +author: + - Sumit Jaiswal (@justjais) + - Sagar Paul (@KB-perByte) + - Padmini Priyadarshini Sivaraj (@PadminiSivaraj) notes: - - Tested against Cisco IOSl2 device with Version 15.2 on VIRL. + - Tested against Cisco IOS-XE device with Version 17.13.01 on Cat9k on CML. - Starting from v2.5.0, this module will fail when run against Cisco IOS devices that do not support VLANs. The offline states (C(rendered) and C(parsed)) will work as expected. - This module works with connection C(network_cli). @@ -118,10 +121,6 @@ options: 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 - configuration: - description: - When set to true, deals with vlan configuration CLIs - type: bool state: description: - The state the configuration should be left in @@ -137,8 +136,8 @@ options: - 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 + option should be the same format as the output of commands I(show vlan) and I(show + running-config | sec ^vlan configuration .+) executed on device. For state I(parsed) active connection to remote host is not required. type: str choices: @@ -148,6 +147,7 @@ options: - deleted - rendered - gathered + - purged - parsed default: merged """ @@ -224,7 +224,7 @@ EXAMPLES = """ # ------------------------------------------------------------------------------ # 10 -# Using merged (configuration: True) +# Using merged # Before state: # ------------- @@ -246,7 +246,6 @@ EXAMPLES = """ - vlan_id: 901 member: vni: 50901 - configuration: true state: merged # After state: @@ -325,7 +324,7 @@ EXAMPLES = """ # 1005 trnet 101005 1500 - - - ibm - 0 0 -# Using overridden (configuration: True) +# Using overridden # Before state: # ------------- @@ -351,7 +350,6 @@ EXAMPLES = """ member: vni: 10101 evi: 101 - configuration: true state: overridden # After state: @@ -523,7 +521,7 @@ EXAMPLES = """ # 1004 fdnet 101004 1500 - - - ieee - 0 0 # 1005 trnet 101005 1500 - - - ibm - 0 0 -# Using deleted (configuration: True) +# Using deleted # Before state: # ------------- @@ -542,13 +540,13 @@ EXAMPLES = """ cisco.ios.ios_vlans: config: - vlan_id: 101 - configuration: true state: deleted # After state: # ------------- # # Leaf-01#show run nve | sec ^vlan configuration +# vlan configuration 101 # vlan configuration 102 # member evpn-instance 102 vni 10102 # vlan configuration 201 @@ -613,7 +611,7 @@ EXAMPLES = """ # 1004 fdnet 101004 1500 - - - ieee - 0 0 # 1005 trnet 101005 1500 - - - ibm - 0 0 -# Using Deleted without any config passed (configuration: True) +# Using Deleted without any config passed # "(NOTE: This will delete all of configured vlans attributes)" # Before state: @@ -633,7 +631,6 @@ EXAMPLES = """ - name: Delete attributes of ALL VLANs cisco.ios.ios_vlans: - configuration: true state: deleted # After state: @@ -647,7 +644,7 @@ EXAMPLES = """ # no vlan configuration 901 # no vlan configuration 902 -# Using Gathered (configuration: True) +# Using gathered, vlan configuration only # Before state: # ------------- @@ -666,8 +663,6 @@ EXAMPLES = """ - name: Gather listed vlans with provided configurations cisco.ios.ios_vlans: - config: - configuration: true state: gathered # Module Execution Result: @@ -757,9 +752,9 @@ EXAMPLES = """ # "shutdown" # ] -# Using Rendered (configuration: True) +# Using Rendered -- name: Render the commands for provided configuration +- name: Render the commands for provided configuration cisco.ios.ios_vlans: config: - vlan_id: 101 @@ -876,7 +871,7 @@ EXAMPLES = """ # } # ] -# Using Parsed (configuration: True) +# Using Parsed Vlan configuration only # File: parsed.cfg # ---------------- @@ -891,7 +886,6 @@ EXAMPLES = """ - name: Parse the commands for provided configuration cisco.ios.ios_vlans: running_config: "{{ lookup('file', './parsed.cfg') }}" - configuration: true state: parsed # Module Execution Result: @@ -919,29 +913,177 @@ EXAMPLES = """ # "vlan_id": 901 # } # ] + +# Using Parsed, Vlan and vlan configuration + +# File: parsed.cfg +# ---------------- +# +# VLAN Name Status Ports +# ---- -------------------------------- --------- ------------------------------- +# 1 default active Gi0/1, Gi0/2 +# 101 RemoteIsInMyName act/unsup Fa0/1, Fa0/4, Fa0/5, Fa0/6, Fa0/7, Fa0/8, Fa0/9, Fa0/10, Fa0/11, Fa0/12 +# Fa0/13, Fa0/14, Fa0/15, Fa0/16, Fa0/17, Fa0/18, Fa0/19, Fa0/20, Fa0/21 +# Fa0/22, Fa0/23, Fa0/24, Fa0/25, Fa0/26, Fa0/27, Fa0/28, Fa0/29, Fa0/30 +# Fa0/31, Fa0/32, Fa0/33, Fa0/34, Fa0/35, Fa0/36, Fa0/37, Fa0/38, Fa0/39 +# Fa0/40, Fa0/41, Fa0/42, Fa0/43, Fa0/44, Fa0/45, Fa0/46, Fa0/47, Fa0/48 +# 150 VLAN0150 active +# 888 a_very_long_vlan_name_a_very_long_vlan_name +# active +# 1002 fddi-default act/unsup +# 1003 trcrf-default act/unsup +# 1004 fddinet-default act/unsup +# 1005 trbrf-default act/unsup +# +# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 +# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ +# 1 enet 100001 1500 - - - - - 0 0 +# 101 enet 100101 610 - - - - - 0 0 +# 150 enet 100150 1500 - - - - - 0 0 +# 888 enet 100888 1500 - - - - - 0 0 +# 1002 fddi 101002 1500 - - - - - 0 0 +# 1003 trcrf 101003 4472 1005 3276 - - srb 0 0 +# 1004 fdnet 101004 1500 - - - ieee - 0 0 +# 1005 trbrf 101005 4472 - - 15 ibm - 0 0 +# +# +# VLAN AREHops STEHops Backup CRF +# ---- ------- ------- ---------- +# 1003 7 7 off +# +# Remote SPAN VLANs +# ------------------------------------------------------------------------------ +# 150 +# +# Primary Secondary Type Ports +# ------- --------- ----------------- ------------------------------------------ +# +# vlan configuration 101 +# member evpn-instance 101 vni 10101 +# vlan configuration 102 +# member evpn-instance 102 vni 10102 +# vlan configuration 901 +# member vni 50901 + +- name: Parse the commands for provided configuration + cisco.ios.ios_vlans: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "name": "default", +# "vlan_id": 1, +# "state": "active", +# "shutdown": "disabled", +# "mtu": 1500, +# }, +# { +# "name": "RemoteIsInMyName", +# "vlan_id": 101, +# "state": "active", +# "shutdown": "enabled", +# "mtu": 610, +# "member": {"evi": 101, "vni": 10101}, +# }, +# { +# "name": "VLAN0150", +# "vlan_id": 150, +# "state": "active", +# "shutdown": "disabled", +# "mtu": 1500, +# "remote_span": True, +# }, +# { +# "name": "a_very_long_vlan_name_a_very_long_vlan_name", +# "vlan_id": 888, +# "state": "active", +# "shutdown": "disabled", +# "mtu": 1500, +# }, +# { +# "name": "fddi-default", +# "vlan_id": 1002, +# "state": "active", +# "shutdown": "enabled", +# "mtu": 1500, +# }, +# { +# "name": "trcrf-default", +# "vlan_id": 1003, +# "state": "active", +# "shutdown": "enabled", +# "mtu": 4472, +# }, +# { +# "name": "fddinet-default", +# "vlan_id": 1004, +# "state": "active", +# "shutdown": "enabled", +# "mtu": 1500, +# }, +# { +# "name": "trbrf-default", +# "vlan_id": 1005, +# "state": "active", +# "shutdown": "enabled", +# "mtu": 4472, +# }, +# {"vlan_id": 102, "member": {"evi": 102, "vni": 10102}}, +# {"vlan_id": 901, "member": {"vni": 50901}}, +# ] """ RETURN = """ before: - description: The configuration as structured data prior to module invocation. - returned: always - type: list + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict sample: > - The configuration returned will always be in the same format - of the parameters above. + This output will always be in the same format as the + module argspec. after: - description: The configuration as structured data after module completion. + description: The resulting configuration after module execution. returned: when changed - type: list + type: dict sample: > - The configuration returned will always be in the same format - of the parameters above. + This output will always be in the same format as the + module argspec. commands: description: The set of commands pushed to the remote device. - returned: always + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - vlan configuration 202 + - state active + - remote-span +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) type: list - sample: ['vlan 20', 'name vlan_20', 'mtu 600', 'remote-span'] + sample: + - vlan configuration 202 + - member evpn-instance 202 vni 10202 + - vlan 200 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. """ + from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vlans.vlans import ( @@ -966,19 +1108,17 @@ def main(): :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, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "purged", ["config"]], + ["state", "parsed", ["running_config"]], + ], supports_check_mode=True, ) diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py b/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py index 27c6641eb..ff6814ba1 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py @@ -58,6 +58,61 @@ options: description: - The list of address families with MDT parameters to be configured on the remote IOS device. type: list + suboptions: + afi: + description: Address family identifier. + type: str + choices: + ["ipv4", "ipv6"] + mdt: + description: MDT parameters. + type: dict + suboptions: + auto_discovery: + description: Auto-discovery parameters. + type: dict + suboptions: + vxlan: + description: Vxlan parameters. + type: dict + suboptions: + enable: + description: Enable VXLAN. + type: bool + inter_as: + description: Enable inter-as. + type: bool + default: + description: Parameters for default option. + type: dict + suboptions: + vxlan_mcast_group: + description: VXLAN multicast group value. + type: str + data: + description: Parameters for data option. + type: dict + suboptions: + vxlan_mcast_group: + description: VXLAN multicast group value. + type: str + threshold: + description: Threshold value. + type: int + overlay: + description: Parameters for overlay option. + type: dict + suboptions: + use_bgp: + description: parameters for BGP option. + type: dict + suboptions: + enable: + description: Enable use BGP. + type: bool + spt_only: + description: Enable SPT only. + type: bool elements: dict rd: description: @@ -832,12 +887,58 @@ def check_declarative_intent_params(want, module, result): def main(): """main entry point for module execution""" + address_family_spec = dict( + afi=dict(type="str", choices=["ipv4", "ipv6"]), + mdt=dict( + type="dict", + options=dict( + overlay=dict( + type="dict", + options=dict( + use_bgp=dict( + type="dict", + options=dict( + enable=dict(type="bool"), + spt_only=dict(type="bool"), + ), + ), + ), + ), + auto_discovery=dict( + type="dict", + options=dict( + vxlan=dict( + type="dict", + options=dict( + enable=dict(type="bool"), + inter_as=dict(type="bool"), + ), + ), + ), + ), + default=dict( + type="dict", + options=dict( + vxlan_mcast_group=dict(type="str"), + ), + ), + data=dict( + type="dict", + options=dict( + vxlan_mcast_group=dict(type="str"), + threshold=dict(type="int"), + ), + ), + ), + ), + ) + argument_spec = dict( vrfs=dict(type="list", elements="raw"), - name=dict(), - description=dict(), - address_family=dict(type="list", elements="dict"), - rd=dict(), + name=dict(type="str"), + description=dict(type="str"), + address_family=dict(type="list", elements="dict", options=address_family_spec), + rd=dict(type="str"), route_export=dict(type="list", elements="str"), route_import=dict(type="list", elements="str"), route_both=dict(type="list", elements="str"), diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_vxlan_vtep.py b/ansible_collections/cisco/ios/plugins/modules/ios_vxlan_vtep.py index b2c5933e7..3cf933b13 100644 --- a/ansible_collections/cisco/ios/plugins/modules/ios_vxlan_vtep.py +++ b/ansible_collections/cisco/ios/plugins/modules/ios_vxlan_vtep.py @@ -21,7 +21,7 @@ description: This module provides declarative management of VXLAN VTEP interface version_added: 5.3.0 author: Padmini Priyadarshini Sivaraj (@PadminiSivaraj) notes: - - Tested against Cisco IOS device with Version 17.13.01 on Cat9k on CML. + - Tested against Cisco IOS-XE device with Version 17.13.01 on Cat9k on CML. - This module works with connection C(network_cli). See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html) options: |