diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/arista/eos/plugins/modules | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/arista/eos/plugins/modules')
35 files changed, 24220 insertions, 0 deletions
diff --git a/ansible_collections/arista/eos/plugins/modules/__init__.py b/ansible_collections/arista/eos/plugins/modules/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/__init__.py diff --git a/ansible_collections/arista/eos/plugins/modules/eos_acl_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_acl_interfaces.py new file mode 100644 index 000000000..e609a7c09 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_acl_interfaces.py @@ -0,0 +1,423 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_acl_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_acl_interfaces +short_description: ACL interfaces resource module +description: +- This module manages adding and removing Access Control Lists (ACLs) from interfaces + on devices running EOS software. +version_added: 1.0.0 +author: GomathiSelvi S (@GomathiselviS) +options: + config: + description: A dictionary of ACL options for interfaces. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier for the interface. + type: str + required: true + access_groups: + type: list + elements: dict + description: + - Specifies ACLs attached to the interfaces. + suboptions: + afi: + description: + - Specifies the AFI for the ACL(s) to be configured on this interface. + type: str + choices: + - ipv4 + - ipv6 + required: true + acls: + type: list + description: + - Specifies the ACLs for the provided AFI. + 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. + type: str + choices: + - in + - out + required: true + 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. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + +""" +EXAMPLES = """ +# Using Merged + +# Before state: +# ------------- +# +# eos#sh running-config | include interface|access-group +# interface Ethernet1 +# interface Ethernet2 +# interface Ethernet3 + +- name: Merge module attributes of given access-groups + arista.eos.eos_acl_interfaces: + config: + - name: Ethernet2 + access_groups: + - afi: ipv4 + acls: + name: acl01 + direction: in + - afi: ipv6 + acls: + name: acl03 + direction: out + state: merged + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 + + +# Using Replaced + +# Before state: +# ------------- +# +# eos#sh running-config | include interface|access-group +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 +# ip access-group acl01 in + +- name: Replace module attributes of given access-groups + arista.eos.eos_acl_interfaces: + config: + - name: Ethernet2 + access_groups: + - afi: ipv4 + acls: + name: acl01 + direction: out + state: replaced + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# no ip access-group acl01 in +# no ipv6 access-group acl03 out +# ip access-group acl01 out + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 out +# interface Ethernet3 +# ip access-group acl01 in + + +# Using Overridden + +# Before state: +# ------------- +# +# eos#sh running-config | include interface|access-group +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 +# ip access-group acl01 in + +- name: Override module attributes of given access-groups + arista.eos.eos_acl_interfaces: + config: + - name: Ethernet2 + access_groups: + - afi: ipv4 + acls: + name: acl01 + direction: out + state: overridden + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# no ip access-group acl01 in +# no ipv6 access-group acl03 out +# ip access-group acl01 out +# interface Ethernet3 +# no ip access-group acl01 in + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 out +# interface Ethernet3 + + +# Using Deleted + +# Before state: +# ------------- +# +# eos#sh running-config | include interface|access-group +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 +# ip access-group acl01 out + +- name: Delete module attributes of given access-groups + arista.eos.eos_acl_interfaces: + config: + - name: Ethernet2 + access_groups: + - afi: ipv4 + acls: + name: acl01 + direction: in + - afi: ipv6 + acls: + name: acl03 + direction: out + state: deleted + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# no ip access-group acl01 in +# no ipv6 access-group acl03 out + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# interface Ethernet3 +# ip access-group acl01 out + + +# Before state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 +# ip access-group acl01 out + +- name: Delete module attributes of given access-groups from ALL Interfaces + arista.eos.eos_acl_interfaces: + config: + state: deleted + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# no ip access-group acl01 in +# no ipv6 access-group acl03 out +# interface Ethernet3 +# no ip access-group acl01 out + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# interface Ethernet3 + +# Before state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# ipv6 access-group acl03 out +# interface Ethernet3 +# ip access-group acl01 out + +- name: Delete acls under afi + arista.eos.eos_acl_interfaces: + config: + - name: Ethernet3 + access_groups: + - afi: ipv4 + - name: Ethernet2 + access_groups: + - afi: ipv6 + state: deleted + +# Commands Fired: +# --------------- +# +# interface Ethernet2 +# no ipv6 access-group acl03 out +# interface Ethernet3 +# no ip access-group acl01 out + +# After state: +# ------------- +# +# eos#sh running-config | include interface| access-group +# interface Loopback888 +# interface Ethernet1 +# interface Ethernet2 +# ip access-group acl01 in +# interface Ethernet3 + + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The resulting configuration model invocation. + 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 Ethernet2 + - ip access-group acl01 in + - ipv6 access-group acl03 out + - interface Ethernet3 + - ip access-group acl01 out +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.acl_interfaces.acl_interfaces import ( + Acl_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.acl_interfaces.acl_interfaces import ( + Acl_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Acl_interfacesArgs.argument_spec, + supports_check_mode=True, + ) + + result = Acl_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_acls.py b/ansible_collections/arista/eos/plugins/modules/eos_acls.py new file mode 100644 index 000000000..95c961d5a --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_acls.py @@ -0,0 +1,904 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_acls +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_acls +short_description: ACLs resource module +description: This module manages the IP access-list attributes of Arista EOS interfaces. +version_added: 1.0.0 +author: Gomathiselvi S (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +options: + config: + description: A dictionary of IP access-list options + type: list + elements: dict + suboptions: + afi: + description: + - The Address Family Indicator (AFI) for the Access Control Lists (ACL). + type: str + required: true + choices: + - ipv4 + - ipv6 + acls: + description: + - A list of Access Control Lists (ACL). + type: list + elements: dict + suboptions: + standard: + description: standard access-list or not + type: bool + name: + description: Name of the acl-list + type: str + required: true + aces: + description: Filtering data + type: list + elements: dict + suboptions: + sequence: + description: sequence number for the ordered list of rules + type: int + remark: + description: Specify a comment + type: str + fragment_rules: + description: Add fragment rules + type: bool + grant: + description: Action to be applied on the rule + type: str + choices: + - permit + - deny + line: + description: For fact gathering, any ACE that is not fully parsed, + while show up as a value of this attribute. + type: str + aliases: + - ace + protocol: + description: + - Specify the protocol to match. + - Refer to vendor documentation for valid values. + type: str + vlan: + description: Vlan options + type: str + protocol_options: + description: All the possible sub options for the protocol chosen. + type: dict + suboptions: + tcp: + description: Options for tcp protocol. + type: dict + suboptions: + flags: + 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 + icmp: + description: + - Internet Control Message Protocol settings. + 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 requests + type: bool + message_code: + description: ICMP message code + type: int + message_type: + description: ICMP message type + type: int + 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 + message_num: + description: icmp msg type number. + type: int + icmpv6: + description: Options for icmpv6. + type: dict + suboptions: + address_unreachable: + description: address unreachable + type: bool + beyond_scope: + description: beyond_scope + type: bool + echo_reply: + description: echo_reply + type: bool + echo_request: + description: echo reques + type: bool + erroneous_header: + description: erroneous header + type: bool + fragment_reassembly_exceeded: + description: fragment_reassembly_exceeded + type: bool + hop_limit_exceeded: + description: hop limit exceeded + type: bool + neighbor_advertisement: + description: neighbor advertisement + type: bool + neighbor_solicitation: + description: neighbor_solicitation + type: bool + no_admin: + description: no admin + type: bool + no_route: + description: no route + type: bool + packet_too_big: + description: packet too big + type: bool + parameter_problem: + description: parameter problem + type: bool + port_unreachable: + description: port unreachable + type: bool + redirect_message: + description: redirect message + type: bool + reject_route: + description: reject route + type: bool + router_advertisement: + description: router_advertisement + type: bool + router_solicitation: + description: router_solicitation + type: bool + source_address_failed: + description: source_address_failed + type: bool + source_routing_error: + description: source_routing_error + type: bool + time_exceeded: + description: time_exceeded + type: bool + unreachable: + description: unreachable + type: bool + unrecognized_ipv6_option: + description: unrecognized_ipv6_option + type: bool + unrecognized_next_header: + description: unrecognized_next_header + type: bool + ip: + description: Internet Protocol. + type: dict + suboptions: + nexthop_group: + description: Nexthop-group name. + type: str + ipv6: + description: Internet V6 Protocol. + type: dict + suboptions: + nexthop_group: + description: Nexthop-group name. + type: str + source: + description: The packet's source address + type: dict + suboptions: + address: + description: dotted decimal notation of IP address + type: str + wildcard_bits: + description: Source wildcard bits + type: str + subnet_address: + description: A subnet address + type: str + host: + description: Host IP address + type: str + any: + description: Rule matches all source addresses + type: bool + port_protocol: + description: Specify source port/protocoli, along with operator. + (comes with tcp/udp). + type: dict + destination: + description: The packet's destination address + type: dict + suboptions: + address: + description: dotted decimal notation of IP address + type: str + wildcard_bits: + description: Source wildcard bits + type: str + subnet_address: + description: A subnet address + type: str + host: + description: Host IP address + type: str + any: + description: Rule matches all source addresses + type: bool + port_protocol: + description: Specify dest port/protocol, along with operator . + (comes with tcp/udp). + type: dict + ttl: + description: Compares the TTL (time-to-live) value in the packet to + a specified value + type: dict + suboptions: + eq: + description: Match a single TTL value + type: int + lt: + description: Match TTL lesser than this number + type: int + gt: + description: Match TTL greater than this number + type: int + neq: + description: Match TTL not equal to this value + type: int + fragments: + description: Match non-head fragment packets + type: bool + log: + description: Log matches against this rule + type: bool + tracked: + description: Match packets in existing ICMP/UDP/TCP connections + type: bool + hop_limit: + description: Hop limit value. + type: dict + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device by + executing the command B(show running-config | section 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: + description: + - The state the configuration should be left in. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged + +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 40 permit ip any any +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + +- name: Merge provided configuration with device configuration + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + aces: + - sequence: 35 + grant: deny + protocol: ospf + source: + subnet_address: 20.0.0.0/8 + destination: + any: true + state: merged + +# After state: +# ------------ +# +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 35 deny ospf 20.0.0.0/8 any +# 40 permit ip any any +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + +# Using merged + +# Before state: +# ------------- +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 40 permit ip any any +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + +- name: Merge to update the given configuration with an existing ace + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + aces: + - sequence: 35 + log: true + ttl: + eq: 33 + state: merged + +# After state: +# ------------ +# +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 35 deny ospf 20.0.0.0/8 any ttl eq 33 log +# 40 permit ip any any +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + +# Using replaced + +# Before state: +# ------------- +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 40 permit ip any any +# ! +# ip access-list test3 +# 10 permit ip 35.33.0.0/16 any log +# ! +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + + + +- name: Replace device configuration with provided configuration + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + aces: + - sequence: 35 + grant: permit + protocol: ospf + source: + subnet_address: 20.0.0.0/8 + destination: + any: true + state: replaced + +# After state: +# ------------ +# +# show running-config | section access-list +# ip access-list test1 +# 35 permit ospf 20.0.0.0/8 any +# ! +# ip access-list test3 +# 10 permit ip 35.33.0.0/16 any log +# ! +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + + +# Using overridden + +# Before state: +# ------------- +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 40 permit ip any any +# ! +# ip access-list test3 +# 10 permit ip 35.33.0.0/16 any log +# ! +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + + + +- name: override device configuration with provided configuration + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + aces: + - sequence: 35 + grant: permit + protocol: ospf + source: + subnet_address: 20.0.0.0/8 + destination: + any: true + state: overridden + +# After state: +# ------------ +# +# show running-config | section access-list +# ip access-list test1 +# 35 permit ospf 20.0.0.0/8 any +# ! + +# Using deleted: + +# Before state: +# ------------- +# show running-config | section access-list +# ip access-list test1 +# 10 permit ip 10.10.10.0/24 any ttl eq 200 +# 20 permit ip 10.30.10.0/24 host 10.20.10.1 +# 30 deny tcp host 10.10.20.1 eq finger www any syn log +# 40 permit ip any any +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + +# ! + +- name: Delete provided configuration + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + state: deleted + +# After state: +# ------------ +# +# show running-config | section access-list + +# ipv6 access-list test2 +# 10 deny icmpv6 any any reject-route hop-limit eq 20 + + +# using gathered + +# ip access-list test1 +# 35 deny ospf 20.0.0.0/8 any +# ip access-list test2 +# 40 permit vlan 55 0xE2 icmpv6 any any log + +- name: Gather the existing configuration + arista.eos.eos_acls: + state: gathered + +# returns: + + +# arista.eos.eos_acls: +# config: +# - afi: "ipv4" +# acls: +# - name: test1 +# aces: +# - sequence: 35 +# grant: "deny" +# protocol: "ospf" +# source: +# subnet_address: 20.0.0.0/8 +# destination: +# any: true +# - afi: "ipv6" +# acls: +# - name: test2 +# aces: +# - sequence: 40 +# grant: "permit" +# vlan: "55 0xE2" +# protocol: "icmpv6" +# log: true +# source: +# any: true +# destination: +# any: true + + +# using rendered + +- name: Delete provided configuration + arista.eos.eos_acls: + config: + - afi: ipv4 + acls: + - name: test1 + aces: + - sequence: 35 + grant: deny + protocol: ospf + source: + subnet_address: 20.0.0.0/8 + destination: + any: true + - afi: ipv6 + acls: + - name: test2 + aces: + - sequence: 40 + grant: permit + vlan: 55 0xE2 + protocol: icmpv6 + log: true + source: + any: true + destination: + any: true + state: rendered + +# returns: + +# ip access-list test1 +# 35 deny ospf 20.0.0.0/8 any +# ip access-list test2 +# 40 permit vlan 55 0xE2 icmpv6 any any log + + +# Using Parsed + +# parsed_acls.cfg + +# ipv6 access-list standard test2 +# 10 permit any log +# ! +# ip access-list test1 +# 35 deny ospf 20.0.0.0/8 any +# 45 remark Run by ansible +# 55 permit tcp any any +# ! + +- name: parse configs + arista.eos.eos_acls: + running_config: "{{ lookup('file', './parsed_acls.cfg') }}" + state: parsed + +# returns +# "parsed": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "any": true +# }, +# "grant": "deny", +# "protocol": "ospf", +# "sequence": 35, +# "source": { +# "subnet_address": "20.0.0.0/8" +# } +# }, +# { +# "remark": "Run by ansible", +# "sequence": 45 +# }, +# { +# "destination": { +# "any": true +# }, +# "grant": "permit", +# "protocol": "tcp", +# "sequence": 55, +# "source": { +# "any": true +# } +# } +# ], +# "name": "test1" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "aces": [ +# { +# "grant": "permit", +# "log": true, +# "sequence": 10, +# "source": { +# "any": true +# } +# } +# ], +# "name": "test2", +# "standard": true +# } +# ], +# "afi": "ipv6" +# } +# ] + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The resulting configuration model invocation. + 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: + - ipv6 access-list standard test2 + - 10 permit any log + - ip access-list test1 + - 35 deny ospf 20.0.0.0/8 any + - 45 remark Run by ansible + - 55 permit tcp any any +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.acls.acls import ( + AclsArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Acls(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_banner.py b/ansible_collections/arista/eos/plugins/modules/eos_banner.py new file mode 100644 index 000000000..19a187c4c --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_banner.py @@ -0,0 +1,199 @@ +#!/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: eos_banner +author: Peter Sprygada (@privateip) +short_description: Manage multiline banners on Arista EOS devices +description: +- This will configure both login and motd banners on remote devices running Arista + EOS. It allows playbooks to add or remote banner text from the active running configuration. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +options: + banner: + description: + - Specifies which banner that should be configured on the remote device. + required: true + choices: + - login + - motd + type: str + text: + description: + - The banner text that should be present in the remote device running configuration. This + argument accepts a multiline string. 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 + arista.eos.eos_banner: + banner: login + text: | + this is my login banner + that contains a multiline + string + state: present + +- name: remove the motd banner + arista.eos.eos_banner: + banner: motd + state: absent +""" + +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 + - EOF +session_name: + description: The EOS config session name used to load the configuration + returned: if changes + type: str + sample: ansible_1479315771 +""" +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import string_types + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + load_config, + run_commands, +) + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + state = module.params["state"] + + if state == "absent" and have.get("text"): + if isinstance(have["text"], string_types): + commands.append("no banner %s" % module.params["banner"]) + elif have["text"].get("loginBanner") or have["text"].get("motd"): + commands.append({"cmd": "no banner %s" % module.params["banner"]}) + + elif state == "present": + if isinstance(have["text"], string_types): + if want["text"] != have["text"]: + commands.append("banner %s" % module.params["banner"]) + commands.extend(want["text"].strip().split("\n")) + commands.append("EOF") + else: + have_text = have["text"].get("loginBanner") or have["text"].get( + "motd", + ) + if have_text: + have_text = have_text.strip() + + if to_text(want["text"]) != have_text or not have_text: + # For EAPI we need to construct a dict with cmd/input + # key/values for the banner + commands.append( + { + "cmd": "banner %s" % module.params["banner"], + "input": want["text"].strip("\n"), + }, + ) + + return commands + + +def map_config_to_obj(module): + output = run_commands(module, ["show banner %s" % module.params["banner"]]) + obj = {"banner": module.params["banner"], "state": "absent"} + if output: + obj["text"] = output[0] + obj["state"] = "present" + return obj + + +def map_params_to_obj(module): + text = module.params["text"] + if text: + text = to_text(text).strip() + + 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"]), + text=dict(), + state=dict(default="present", choices=["present", "absent"]), + ) + + 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: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_bgp.py b/ansible_collections/arista/eos/plugins/modules/eos_bgp.py new file mode 100644 index 000000000..a9d01d60a --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_bgp.py @@ -0,0 +1,469 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_bgp +author: Nilashish Chakraborty (@NilashishC) +short_description: (deprecated, removed after 2023-01-29) Configure global BGP protocol settings on Arista EOS. +description: +- This module provides configuration management of global BGP parameters on Arista + EOS devices. +version_added: 1.0.0 +deprecated: + alternative: eos_bgp_global + why: Updated module released with more functionality. + removed_at_date: '2023-01-01' +notes: +- Tested against Arista EOS 4.24.6F +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 + 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 + 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 3600. + type: int + required: true + holdtime: + description: + - Interval (in seconds) after not receiving a keepalive message that + device declares a peer dead. + - The range is from 3 to 7200. + - Setting this value to 0 will not send keep-alives (hold forever). + type: int + required: true + route_reflector_client: + description: + - Specify a neighbor as a route reflector client. + type: int + remove_private_as: + description: + - Remove the private AS number from outbound updates. + type: bool + enabled: + description: + - Administratively shutdown or enable a neighbor. + type: bool + maximum_prefix: + description: + - Maximum number of prefixes to accept from this peer. + - The range is from 0 to 4294967294. + type: int + redistribute: + description: + - Specifies the redistribute information from another routing protocol. + type: list + elements: dict + suboptions: + protocol: + description: + - Specifies the protocol for configuring redistribute information. + required: true + type: str + choices: [ospf, ospfv3, static, connected, rip, isis] + 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 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. + type: str + choices: + - ipv4 + - ipv6 + required: true + redistribute: + description: + - Specifies the redistribute information from another routing protocol. + type: list + elements: dict + suboptions: + protocol: + description: + - Specifies the protocol for configuring redistribute information. + required: true + type: str + choices: + - ospfv3 + - ospf + - isis + - static + - connected + - rip + 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 + activate: + description: + - Enable the Address Family for this Neighbor. + type: bool + default_originate: + description: + - Originate default route to this neighbor. + type: bool + graceful_restart: + description: + - Enable/disable graceful restart mode for this neighbor. + type: bool + weight: + description: + - Assign weight for routes learnt from this neighbor. + - The range is from 0 to 65535 + type: int + 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. + type: str + default: merge + choices: + - merge + - replace + - override + - delete +""" + +EXAMPLES = """ +- name: configure global bgp as 64496 + arista.eos.eos_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 + - 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: isis + route_map: RMAP_1 + operation: merge +- name: Configure BGP neighbors + arista.eos.eos_bgp: + config: + bgp_as: 64496 + neighbors: + - neighbor: 192.0.2.10 + remote_as: 64496 + description: IBGP_NBR_1 + ebgp_multihop: 100 + timers: + keepalive: 300 + 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 + arista.eos.eos_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 + arista.eos.eos_bgp: + config: + bgp_as: 64496 + address_family: + - afi: ipv4 + neighbors: + - neighbor: 203.0.113.10 + activate: yes + default_originate: true + - neighbor: 192.0.2.15 + activate: yes + graceful_restart: true + operation: merge +- name: remove bgp as 64496 from config + arista.eos.eos_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 + - 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 isis route-map RMAP_1 + - exit-address-family +""" +from ansible.module_utils._text import to_text + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.providers.cli.config.bgp.process import ( + REDISTRIBUTE_PROTOCOLS, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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=list(REDISTRIBUTE_PROTOCOLS), required=True), + "route_map": dict(), + } + + timer_spec = { + "keepalive": dict(type="int", required=True), + "holdtime": dict(type="int", required=True), + } + + neighbor_spec = { + "neighbor": dict(required=True), + "remote_as": dict(type="int", required=True), + "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(), + "maximum_prefix": dict(type="int"), + "route_reflector_client": dict(type="int"), + "remove_private_as": dict(type="bool"), + } + + af_neighbor_spec = { + "neighbor": dict(required=True), + "activate": dict(type="bool"), + "default_originate": dict(type="bool"), + "graceful_restart": dict(type="bool"), + "weight": dict(type="int"), + } + + address_family_spec = { + "afi": dict(choices=["ipv4", "ipv6"], required=True), + "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, + ), + "redistribute": dict( + type="list", + elements="dict", + options=redistribute_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 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/arista/eos/plugins/modules/eos_bgp_address_family.py b/ansible_collections/arista/eos/plugins/modules/eos_bgp_address_family.py new file mode 100644 index 000000000..67aaabef7 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_bgp_address_family.py @@ -0,0 +1,1351 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 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 eos_bgp_address_family +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_bgp_address_family +short_description: Manages BGP address family resource module +description: This module configures and manages the attributes of BGP AF on Arista + EOS platforms. +version_added: 1.4.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: Configurations for BGP address family. + type: dict + suboptions: + as_number: + description: Autonomous system number. + type: str + address_family: &address_family + description: Enable address family and enter its config mode + type: list + elements: dict + suboptions: + afi: + description: address family. + type: str + choices: ['ipv4', 'ipv6', 'evpn'] + safi: + description: Address family type for ipv4. + type: str + choices: ['labeled-unicast', 'multicast'] + bgp_params: + description: BGP parameters. + type: dict + suboptions: + additional_paths: + description: BGP additional-paths commands + type: str + choices: ['install', 'send', 'receive'] + next_hop_address_family: + description: Next-hop address-family configuration + type: str + choices: ['ipv6'] + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + redistribute_internal: + description: Redistribute internal BGP routes. + type: bool + route: + description: Configure route-map for route installation. + type: str + graceful_restart: + description: Enable graceful restart mode. + type: bool + neighbor: + description: Configure routing for a network. + type: list + elements: dict + suboptions: + peer: + type: str + description: Neighbor address/ peer group name. + activate: + description: Activate neighbor in the address family. + type: bool + additional_paths: + description: BGP additional-paths commands. + type: str + choices: ['send', 'receive'] + default_originate: + description: Originate default route to this neighbor. + type: dict + suboptions: + route_map: + description: Route map reference. + type: str + always: + description: Always originate default route to this neighbor. + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: bool + next_hop_address_family: + description: Next-hop address-family configuration + type: str + choices: ['ipv6'] + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + prefix_list: + description: Prefix list reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound prefix-list. + type: str + choices: ['in', 'out'] + name: + description: prefix list name. + type: str + route_map: + description: Route map reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound route-map. + type: str + choices: ['in', 'out'] + name: + description: Route map name. + type: str + weight: + description: Weight to assign. + type: int + encapsulation: + description: Default transport encapsulation for neighbor. Applicable for evpn address-family. + type: dict + suboptions: + transport: + description: MPLS/VXLAN transport. + type: str + choices: ['mpls', 'vxlan'] + source_interface: + description: Source interface to update BGP next hop address. Applicable for mpls transport. + type: str + network: + description: configure routing for network. + type: list + elements: dict + suboptions: + route_map: + description: Route map reference. + type: str + address: + description: network address. + type: str + redistribute: + description: Redistribute routes in to BGP. + type: list + elements: dict + suboptions: + protocol: + description: Routes to be redistributed. + type: str + choices: ['isis', 'ospfv3', 'dhcp'] + route_map: + description: Route map reference. + type: str + isis_level: + description: Applicable for isis routes. Specify isis route level. + type: str + choices: ['level-1', 'level-2', 'level-1-2'] + ospf_route: + description: ospf route options. + type: str + choices: ['internal', 'external', 'nssa_external_1', 'nssa_external_2'] + route_target: + description: Route target. + type: dict + suboptions: + action: + description: Route action. + type: str + choices: ['both', 'import', 'export'] + type: + description: Type of address fmaily + type: str + choices: ['evpn', 'vpn-ipv4', 'vpn-ipv6'] + aliases: ['mode'] + route_map: + description: Name of a route map. + type: str + target: + description: Route Target. + type: str + imported_route: + description: Export routes imported from the same Afi/Safi + type: bool + vrf: + description: name of the VRF in which BGP will be configured. + 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 EOS device by + executing the command B(show running-config | section 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: + description: + - The state the configuration should be left in. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged + +""" + +EXAMPLES = """ + +# Using merged + +# Before state + +# veos(config)#show running-config | section bgp +# veos(config)# + + - name: Merge provided configuration with device configuration + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv4" + redistribute: + - protocol: "ospfv3" + ospf_route: "external" + network: + - address: "1.1.1.0/24" + - address: "1.5.1.0/24" + route_map: "MAP01" + - afi: "ipv6" + bgp_params: + additional_paths: "receive" + neighbor: + - peer: "peer2" + default_originate: + always: True + - afi: "ipv6" + redistribute: + - protocol: "isis" + isis_level: "level-2" + route_target: + mode: "export" + target: "33:11" + vrf: "vrft" + state: merged + +# After state: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# bgp additional-paths receive +# neighbor peer2 activate +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv6 +# route-target export 33:11 +# redistribute isis level-2 +# veos(config-router-bgp)# + +# Module Execution: + +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# } +# ], +# "route_target": { +# "mode": "export", +# "target": "33:11" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "router bgp 10", +# "address-family ipv4", +# "redistribute ospfv3 match external", +# "network 1.1.1.0/24", +# "network 1.5.1.0/24 route-map MAP01", +# "exit", +# "address-family ipv6", +# "neighbor peer2 default-originate always", +# "bgp additional-paths receive", +# "exit", +# "vrf vrft", +# "address-family ipv6", +# "redistribute isis level-2", +# "route-target export 33:11", +# "exit", +# "exit" +# ], + +# Using replaced: + +# Before State: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# bgp additional-paths receive +# neighbor peer2 activate +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv6 +# route-target export 33:11 +# redistribute isis level-2 +# veos(config-router-bgp)# +# + + - name: Replace + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv6" + vrf: "vrft" + redistribute: + - protocol: "ospfv3" + ospf_route: "external" + - afi: "ipv6" + redistribute: + - protocol: "isis" + isis_level: "level-2" + state: replaced + +# After State: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# neighbor peer2 default-originate always +# redistribute isis level-2 +# ! +# vrf vrft +# address-family ipv6 +# redistribute ospfv3 match external +# veos(config-router-bgp)# +# +# +# # Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "neighbor": [ +# { +# "activate": true, +# "peer": "1.1.1.1" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ], +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "neighbor": [ +# { +# "activate": true, +# "peer": "1.1.1.1" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "activate": true, +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# } +# ], +# "route_target": { +# "mode": "export", +# "target": "33:11" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "changed": true, +# "commands": [ +# "router bgp 10", +# "vrf vrft", +# "address-family ipv6", +# "redistribute ospfv3 match external", +# "no redistribute isis level-2", +# "no route-target export 33:11", +# "exit", +# "exit", +# "address-family ipv6", +# "redistribute isis level-2", +# "no neighbor peer2 activate", +# "no bgp additional-paths receive", +# "exit" +# ], + +# Using overridden (overriding af at global context): +# Before state: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# neighbor peer2 default-originate always +# redistribute isis level-2 +# ! +# vrf vrft +# address-family ipv6 +# redistribute ospfv3 match external +# veos(config-router-bgp)# + + - name: Overridden + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv4" + bgp_params: + additional_paths: "receive" + neighbor: + - peer: "peer2" + default_originate: + always: True + state: overridden + +# After State: +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv6 +# redistribute ospfv3 match external +# veos(config-router-bgp)# +# +# Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ], +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "neighbor": [ +# { +# "activate": true, +# "peer": "1.1.1.1" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ], +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "changed": true, +# "commands": [ +# "router bgp 10", +# "address-family ipv4", +# "no redistribute ospfv3 match external", +# "no network 1.1.1.0/24", +# "no network 1.5.1.0/24 route-map MAP01", +# "neighbor peer2 default-originate always", +# "no neighbor 1.1.1.1 activate", +# "bgp additional-paths receive", +# "exit", +# "no address-family ipv6" +# ], + +# using Overridden (overridding af in vrf context): + +# Before State: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# no neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv6 +# route-target export 33:11 +# redistribute isis level-2 +# redistribute ospfv3 match external +# veos(config-router-bgp)# + + + - name: Overridden + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv4" + bgp_params: + additional_paths: "receive" + neighbor: + - peer: "peer2" + default_originate: + always: True + vrf: vrft + state: overridden + +# After State: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv4 +# bgp additional-paths receive +# veos(config-router-bgp)# +# +# Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# }, +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ], +# "route_target": { +# "mode": "export", +# "target": "33:11" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "changed": true, +# "commands": [ +# "router bgp 10", +# "vrf vrft", +# "address-family ipv4", +# "neighbor peer2 default-originate always", +# "bgp additional-paths receive", +# "exit", +# "exit", +# " vrf vrft", +# "no address-family ipv6" +# ], + +# Using Deleted: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# no neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# ! +# vrf vrft +# address-family ipv4 +# bgp additional-paths receive +# veos(config-router-bgp)# + + - name: Delete + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv6" + vrf: "vrft" + - afi: "ipv6" + state: deleted + +# After State: + +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# no neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# vrf vrft +# address-family ipv4 +# bgp additional-paths receive +# veos(config-router-bgp)# +# +# Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, + +# Using parsed: + +# parsed_bgp_address_family.cfg : + +# router bgp 10 +# neighbor n2 peer group +# neighbor n2 next-hop-unchanged +# neighbor n2 maximum-routes 12000 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# redistribute ospfv3 match external +# ! +# address-family ipv6 +# no bgp additional-paths receive +# neighbor n2 next-hop-unchanged +# redistribute isis level-2 +# ! +# vrf bgp_10 +# ip access-group acl01 +# ucmp fec threshold trigger 33 clear 22 warning-only +# ! +# address-family ipv4 +# route-target import 20:11 +# ! +# vrf vrft +# address-family ipv4 +# bgp additional-paths receive +# ! +# address-family ipv6 +# redistribute ospfv3 match external + + - name: parse configs + arista.eos.eos_bgp_address_family: + running_config: "{{ lookup('file', './parsed_bgp_address_family.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "neighbor": [ +# { +# "next_hop_unchanged": true, +# "peer": "n2" +# } +# ], +# "redistribute": [ +# { +# "isis_level": "level-2", +# "protocol": "isis" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "route_target": { +# "mode": "import", +# "target": "20:11" +# }, +# "vrf": "bgp_10" +# }, +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "vrf": "vrft" +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ], +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# } +# } + +# Using gathered: + +# Device config: +# veos(config-router-bgp)#show running-config | section bgp +# router bgp 10 +# neighbor peer2 peer group +# neighbor peer2 maximum-routes 12000 +# neighbor 1.1.1.1 maximum-routes 12000 +# ! +# address-family ipv4 +# bgp additional-paths receive +# neighbor peer2 default-originate always +# no neighbor 1.1.1.1 activate +# network 1.1.1.0/24 +# network 1.5.1.0/24 route-map MAP01 +# redistribute ospfv3 match external +# ! +# vrf vrft +# address-family ipv4 +# bgp additional-paths receive +# veos(config-router-bgp)# + + - name: gather configs + arista.eos.eos_bgp_address_family: + state: gathered + +# Module Execution: +# "gathered": { +# "address_family": [ +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "neighbor": [ +# { +# "default_originate": { +# "always": true +# }, +# "peer": "peer2" +# } +# ], +# "network": [ +# { +# "address": "1.1.1.0/24" +# }, +# { +# "address": "1.5.1.0/24", +# "route_map": "MAP01" +# } +# ], +# "redistribute": [ +# { +# "ospf_route": "external", +# "protocol": "ospfv3" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "bgp_params": { +# "additional_paths": "receive" +# }, +# "vrf": "vrft" +# } +# ], +# "as_number": "10" +# }, + +# using rendered: + + - name: Render + arista.eos.eos_bgp_address_family: + config: + as_number: "10" + address_family: + - afi: "ipv4" + redistribute: + - protocol: "ospfv3" + ospf_route: "external" + network: + - address: "1.1.1.0/24" + - address: "1.5.1.0/24" + route_map: "MAP01" + - afi: "ipv6" + bgp_params: + additional_paths: "receive" + neighbor: + - peer: "peer2" + default_originate: + always: True + - afi: "ipv6" + redistribute: + - protocol: "isis" + isis_level: "level-2" + route_target: + mode: "export" + target: "33:11" + vrf: "vrft" + + state: rendered + +# Module Execution: + +# "rendered": [ +# "router bgp 10", +# "address-family ipv4", +# "redistribute ospfv3 match external", +# "network 1.1.1.0/24", +# "network 1.5.1.0/24 route-map MAP01", +# "exit", +# "address-family ipv6", +# "neighbor peer2 default-originate always", +# "bgp additional-paths receive", +# "exit", +# "vrf vrft", +# "address-family ipv6", +# "redistribute isis level-2", +# "route-target export 33:11", +# "exit", +# "exit" +# ] +# + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.bgp_address_family.bgp_address_family import ( + Bgp_afArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.bgp_address_family.bgp_address_family import ( + Bgp_af, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_afArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Bgp_af(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_bgp_global.py b/ansible_collections/arista/eos/plugins/modules/eos_bgp_global.py new file mode 100644 index 000000000..06168db54 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_bgp_global.py @@ -0,0 +1,2353 @@ +#!/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 eos_bgp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_bgp_global +short_description: Manages BGP global resource module +description: This module configures and manages the attributes of BGP global on Arista + EOS platforms. +version_added: 1.4.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: A list of configurations for BGP global. + type: dict + suboptions: + as_number: + description: Autonomous system number. + type: str + aggregate_address: + description: Configure aggregate address. + type: list + elements: dict + suboptions: + address: + description: ipv4/ipv6 address prefix. + type: str + advertise_only: + description: Advertise without installing the generated blackhole route in + FIB. + type: bool + as_set: + description: Generate autonomous system set path information. + type: bool + attribute_map: + description: Name of the route map used to set the attribute of the + aggregate route. + type: str + match_map: + description: Name of the route map used to filter the contributors of the + aggregate route. + type: str + summary_only: + description: Filters all more-specific routes from updates. + type: bool + bgp_params: + description: BGP parameters. + type: dict + suboptions: + additional_paths: + description: BGP additional-paths commands + type: str + choices: ['install', 'send', 'receive'] + advertise_inactive: + description: Advertise BGP routes even if they are inactive in RIB. + type: bool + allowas_in: + description: Allow local-as in updates. + type: dict + suboptions: + set: + description: When True, it is set. + type: bool + count: + description: Number of local ASNs allowed in a BGP update. + type: int + always_compare_med: + description: BGP Always Compare MED + type: bool + asn: + description: AS Number notation. + type: str + choices: ['asdot', 'asplain'] + auto_local_addr: + description: Automatically determine the local address to be used + for the non-transport AF. + type: bool + bestpath: + description: Select the bestpath selection algorithim for BGP routes. + type: dict + suboptions: + as_path: + description: Select the bestpath selection based on as-path. + type: str + choices: ['ignore', 'multipath_relax'] + ecmp_fast: + description: Tie-break BGP paths in a ECMP group based on the order of arrival. + type: bool + med: + description: MED attribute + type: dict + suboptions: + confed: + description: MED Confed. + type: bool + missing_as_worst: + description: MED missing-as-worst. + type: bool + skip: + description: skip one of the tie breaking rules in the bestpath selection. + type: bool + tie_break: + description: Configure the tie-break option for BGP bestpath selection. + choices: ['cluster_list_length', 'router_id'] + type: str + client_to_client: + description: client to client configuration. + type: bool + cluster_id: + description: Cluster ID of this router acting as a route reflector. + type: str + confederation: + description: confederation. + type: dict + suboptions: + identifier: + description: Confederation identifier. + type: str + peers: + description: Confederation peers. + type: str + control_plane_filter: + description: Control plane filter for BGP. + type: bool + convergence: + description: Bgp convergence parameters. + type: dict + suboptions: + slow_peer: + description: Maximum amount of time to wait for slow peers to estabilsh session. + type: bool + time: + description: time in secs + type: int + default: + description: Default neighbor configuration commands. + type: str + choices: ['ipv4_unicast', 'ipv6_unicast'] + enforce_first_as: + description: Enforce the First AS for EBGP routes(default). + type: bool + host_routes: + description: BGP host routes configuration. + type: bool + labeled_unicast: + description: Labeled Unicast. + type: str + choices: ['ip', 'tunnel'] + listen: + description: BGP listen. + type: dict + suboptions: + limit: + description: Set limit on the number of dynamic BGP peers allowed. + type: int + range: + description: Subnet Range to be associated with the peer group. + type: dict + suboptions: + address: + description: Address prefix + type: str + peer_group: + description: Name of peer group. + type: dict + suboptions: + name: + description: name. + type: str + peer_filter: + description: Name of peer filter. + type: str + remote_as: + description: Neighbor AS number + type: str + log_neighbor_changes: + description: Log neighbor up/down events. + type: bool + missing_policy: + description: Missing policy override configuration commands. + type: dict + suboptions: + direction: + description: Missing policy direction options. + type: str + choices: ['in', 'out'] + action: + description: Missing policy action options. + type: str + choices: ['deny', 'permit', 'deny-in-out'] + monitoring: + description: Enable Bgp monitoring for all/specified stations. + type: bool + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + redistribute_internal: + description: Redistribute internal BGP routes. + type: bool + route: + description: Configure route-map for route installation. + type: str + route_reflector: + description: Configure route reflector options + type: dict + suboptions: + set: + description: When True route_reflector is set. + type: bool + preserve: + description: preserve route attributes, overwriting route-map changes + type: bool + transport: + description: Configure transport port for TCP session + type: int + default_metric: + description: Default metric. + type: int + distance: + description: Define an administrative distance. + type: dict + suboptions: + external: + description: distance for external routes. + type: int + internal: + description: distance for internal routes. + type: int + local: + description: distance for local routes. + type: int + graceful_restart: + description: Enable graceful restart mode. + type: dict + suboptions: + set: + description: When True, graceful restart is set. + type: bool + restart_time: + description: Set the max time needed to restart and come back up. + type: int + stalepath_time: + description: Set the max time to hold onto restarting peer stale paths. + type: int + graceful_restart_helper: + description: Enable graceful restart helper mode. + type: bool + access_group: + description: ip/ipv6 access list configuration. + type: list + elements: dict + suboptions: + afi: + description: Specify ip/ipv6. + type: str + choices: ['ipv4', 'ipv6'] + acl_name: + description: access list name. + type: str + direction: + description: direction of packets. + type: str + maximum_paths: + description: Maximum number of equal cost paths. + type: dict + suboptions: + max_equal_cost_paths: + description: Value for maximum number of equal cost paths. + type: int + max_installed_ecmp_paths: + description: Value for maximum number of installed ECMP routes. + type: int + monitoring: + description: BGP monitoring protocol configuration. + type: dict + suboptions: + port: + description: Configure the BGP monitoring protocol port number <1024-65535>. + type: int + received: + description: BGP monitoring protocol received route selection. + type: str + choices: ['post_policy', 'pre_policy'] + station: + description: BGP monitoring station configuration. + type: str + timestamp: + description: BGP monitoring protocol Per-Peer Header timestamp behavior. + type: str + choices: ['none', 'send_time'] + neighbor: + description: Configure routing for a network. + type: list + elements: dict + suboptions: + neighbor_address: + type: str + description: Neighbor address or peer group. + aliases: + - peer + additional_paths: + description: BGP additional-paths commands. + type: str + choices: ['send', 'receive'] + allowas_in: + description: Allow local-as in updates. + type: dict + suboptions: + set: + description: When True, it is set. + type: bool + count: + description: Number of local ASNs allowed in a BGP update. + type: int + auto_local_addr: + description: Automatically determine the local address to be used + for the non-transport AF. + type: bool + bfd: + description: Configure BFD fallover for this peer + type: str + choices: ['enable', 'c_bit'] + default_originate: + description: Originate default route to this neighbor. + type: dict + suboptions: + route_map: + description: Route map reference. + type: str + always: + description: Always originate default route to this neighbor. + type: bool + description: + description: Text describing the neighbor. + type: str + dont_capability_negotiate: + description: Donot perform Capability Negotiation with this + neighbor. + type: bool + ebgp_multihop: + description: Allow BGP connections to indirectly connected + external peers. + type: dict + suboptions: + ttl: + description: Time-to-live in the range 1-255 hops. + type: int + set: + description: If True, ttl is not set. + type: bool + enforce_first_as: + description: Enforce the First AS for EBGP routes(default). + type: bool + export_localpref: + description: Override localpref when exporting to an internal + peer. + type: int + fall_over: + description: Configure BFD protocol options for this peer. + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: bool + graceful_restart_helper: + description: Enable graceful restart helper mode. + type: bool + idle_restart_timer: + description: Neighbor idle restart timer. + type: int + import_localpref: + description: Override localpref when importing from an external + peer. + type: int + link_bandwidth: + description: Enable link bandwidth community for routes to this + peer. + type: dict + suboptions: + set: + description: If True, set link bandwidth + type: bool + auto: + description: Enable link bandwidth auto generation for routes from this peer. + type: bool + default: + description: Enable link bandwidth default generation for routes from this + peer. + type: str + update_delay: + description: Delay outbound route updates. + type: int + local_as: + description: Configure local AS number advertised to peer. + type: dict + suboptions: + as_number: + description: AS number. + type: str + fallback: + description: Prefer router AS Number over local AS Number. + type: bool + local_v6_addr: + description: The local IPv6 address of the neighbor in A:B:C:D:E:F:G:H format. + type: str + maximum_accepted_routes: + description: Maximum number of routes accepted from this peer. + type: dict + suboptions: + count: + description: Maximum number of accepted routes (0 means unlimited). + type: int + warning_limit: + description: Maximum number of accepted routes after which a warning is issued. + (0 means never warn) + type: int + maximum_received_routes: + description: Maximum number of routes received from this peer. + type: dict + suboptions: + count: + description: Maximum number of routes (0 means unlimited). + type: int + warning_limit: + description: Percentage of maximum-routes at which warning is to be issued. + type: dict + suboptions: + limit_count: + description: Number of routes at which to warn. + type: int + limit_percent: + description: Percentage of maximum number of routes at which to warn( 1-100). + type: int + warning_only: + description: Only warn, no restart, if max route limit exceeded. + type: bool + metric_out: + description: MED value to advertise to peer. + type: int + monitoring: + description: Enable BGP Monitoring Protocol for this peer. + type: bool + next_hop_self: + description: Always advertise this router address as the BGP + next hop + type: bool + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + next_hop_v6_address: + description: IPv6 next-hop address for the neighbor + type: str + out_delay: + description: Delay outbound route updates. + type: int + encryption_password: + description: Password to use in computation of MD5 hash. + type: dict + suboptions: + type: + description: Encryption type. + type: int + choices: [0, 7] + password: + description: password (up to 80 chars). + type: str + remote_as: + description: Neighbor Autonomous System. + type: str + remove_private_as: + description: Remove private AS number from updates to this peer. + type: dict + suboptions: + set: + description: If True, set remove_private_as. + type: bool + all: + description: Remove private AS number. + type: bool + replace_as: + description: Replace private AS number with local AS number. + type: bool + peer_group: + description: Name of the peer group. + type: str + + prefix_list: + description: Prefix list reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound prefix-list. + type: str + choices: ['in', 'out'] + name: + description: prefix list name. + type: str + route_map: + description: Route map reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound route-map. + type: str + choices: ['in', 'out'] + name: + description: Route map name. + type: str + route_reflector_client: + description: Configure peer as a route reflector client. + type: bool + route_to_peer: + description: Use routing table information to reach the peer. + type: bool + send_community: + description: Send community attribute to this neighbor. + type: dict + suboptions: + set: + description: Enable send-community + type: bool + community_attribute: + description: Type of community attributes to send to this neighbor. + type: str + sub_attribute: + description: Attribute to be sent to the neighbor. + type: str + choices: ['extended', 'link-bandwidth', 'standard'] + link_bandwidth_attribute: + description: cumulative/aggregate attribute to be sent. + type: str + choices: ['aggregate', 'divide'] + speed: + description: Reference link speed in bits/second + type: str + divide: + description: link-bandwidth divide attribute. + type: str + choices: ['equal', 'ratio'] + shutdown: + description: Administratively shut down this neighbor. + type: bool + soft_recognition: + description: Configure how to handle routes that fail import. + type: str + choices: ['all', 'None'] + timers: + description: Timers. + type: dict + suboptions: + keepalive: + description: Keep Alive Interval in secs. + type: int + holdtime: + description: Hold time in secs. + type: int + transport: + description: Configure transport options for TCP session. + type: dict + suboptions: + connection_mode: + description: Configure connection-mode for TCP session. + type: str + remote_port: + description: Configure BGP peer TCP port to connect to. + type: int + ttl: + description: BGP ttl security check + type: int + update_source: + description: Specify the local source interface for peer BGP + sessions. + type: str + weight: + description: Weight to assign. + type: int + aliases: + - neighbors + network: + description: Configure routing for a network. + type: list + elements: dict + suboptions: + address: + description: address prefix. + type: str + route_map: + description: Name of route map. + type: str + aliases: + - networks + redistribute: + description: Redistribute routes in to BGP. + type: list + elements: dict + suboptions: + protocol: + description: Routes to be redistributed. + type: str + choices: ['isis', 'ospfv3', 'ospf', 'attached-host', 'connected', 'rip', 'static'] + route_map: + description: Route map reference. + type: str + isis_level: + description: Applicable for isis routes. Specify isis route level. + type: str + choices: ['level-1', 'level-2', 'level-1-2'] + ospf_route: + description: ospf route options. + type: str + choices: ['internal', 'external', 'nssa_external_1', 'nssa_external_2'] + router_id: + description: Router id. + type: str + route_target: + description: Route target. + type: dict + suboptions: + action: + description: Route action. + type: str + choices: ['both', 'import', 'export'] + target: + description: Route Target. + type: str + shutdown: + description: When True, shut down BGP. + type: bool + timers: + description: Timers. + type: dict + suboptions: + keepalive: + description: Keep Alive Interval in secs. + type: int + holdtime: + description: Hold time in secs. + type: int + ucmp: + description: Configure unequal cost multipathing. + type: dict + suboptions: + fec: + description: Configure UCMP fec utilization threshold. + type: dict + suboptions: + trigger: + description: UCMP fec utilization too high threshold. + type: int + clear: + description: UCMP FEC utilization Clear thresholds. + type: int + link_bandwidth: + description: Configure link-bandwidth propagation delay. + type: dict + suboptions: + mode: + description: UCMP link bandwidth mode + type: str + choices: ['encoding_weighted', 'recursive'] + update_delay: + description: Link Bandwidth Advertisement delay. + type: int + mode: + description: UCMP mode. + type: dict + suboptions: + set: + description: If True, ucmp mode is set to 1. + type: bool + nexthops: + description: Value for total number UCMP nexthops. + type: int + update: + description: Configure BGP update generation. + type: dict + suboptions: + wait_for: + description: wait for options before converge or synchronize. + type: str + choices: ['wait_for_convergence', 'wait_install'] + batch_size: + description: batch size for FIB route acknowledgements. + type: int + vlan: + description: Configure MAC VRF BGP for single VLAN support. + type: int + vlan_aware_bundle: + description: Configure MAC VRF BGP for multiple VLAN support. + type: str + vrfs: + description: Configure BGP in a VRF. + type: list + elements: dict + suboptions: + vrf: + description: VRF name. + type: str + aggregate_address: + description: Configure aggregate address. + type: list + elements: dict + suboptions: + address: + description: ipv4/ipv6 address prefix. + type: str + advertise_only: + description: Advertise without installing the generated blackhole route in + FIB. + type: bool + as_set: + description: Generate autonomous system set path information. + type: bool + attribute_map: + description: Name of the route map used to set the attribute of the + aggregate route. + type: str + match_map: + description: Name of the route map used to filter the contributors of the + aggregate route. + type: str + summary_only: + description: Filters all more-specific routes from updates. + type: bool + bgp_params: + description: BGP parameters. + type: dict + suboptions: + additional_paths: + description: BGP additional-paths commands + type: str + choices: ['install', 'send', 'receive'] + advertise_inactive: + description: Advertise BGP routes even if they are inactive in RIB. + type: bool + allowas_in: + description: Allow local-as in updates. + type: dict + suboptions: + set: + description: When True, it is set. + type: bool + count: + description: Number of local ASNs allowed in a BGP update. + type: int + always_compare_med: + description: BGP Always Compare MED + type: bool + asn: + description: AS Number notation. + type: str + choices: ['asdot', 'asplain'] + auto_local_addr: + description: Automatically determine the local address to be used + for the non-transport AF. + type: bool + bestpath: + description: Select the bestpath selection algorithim for BGP routes. + type: dict + suboptions: + as_path: + description: Select the bestpath selection based on as-path. + type: str + choices: ['ignore', 'multipath_relax'] + ecmp_fast: + description: Tie-break BGP paths in a ECMP group based on the order of arrival. + type: bool + med: + description: MED attribute + type: dict + suboptions: + confed: + description: MED Confed. + type: bool + missing_as_worst: + description: MED missing-as-worst. + type: bool + skip: + description: skip one of the tie breaking rules in the bestpath selection. + type: bool + tie_break: + description: Configure the tie-break option for BGP bestpath selection. + choices: ['cluster_list_length', 'router_id'] + type: str + client_to_client: + description: client to client configuration. + type: bool + cluster_id: + description: Cluster ID of this router acting as a route reflector. + type: str + confederation: + description: confederation. + type: dict + suboptions: + identifier: + description: Confederation identifier. + type: str + peers: + description: Confederation peers. + type: str + control_plane_filter: + description: Control plane filter for BGP. + type: bool + convergence: + description: Bgp convergence parameters. + type: dict + suboptions: + slow_peer: + description: Maximum amount of time to wait for slow peers to estabilsh session. + type: bool + time: + description: time in secs + type: int + default: + description: Default neighbor configuration commands. + type: str + choices: ['ipv4_unicast', 'ipv6_unicast'] + enforce_first_as: + description: Enforce the First AS for EBGP routes(default). + type: bool + host_routes: + description: BGP host routes configuration. + type: bool + labeled_unicast: + description: Labeled Unicast. + type: str + choices: ['ip', 'tunnel'] + listen: + description: BGP listen. + type: dict + suboptions: + limit: + description: Set limit on the number of dynamic BGP peers allowed. + type: int + range: + description: Subnet Range to be associated with the peer group. + type: dict + suboptions: + address: + description: Address prefix + type: str + peer_group: + description: Name of peer group. + type: dict + suboptions: + name: + description: name. + type: str + peer_filter: + description: Name of peer filter. + type: str + remote_as: + description: Neighbor AS number + type: str + log_neighbor_changes: + description: Log neighbor up/down events. + type: bool + missing_policy: + description: Missing policy override configuration commands. + type: dict + suboptions: + direction: + description: Missing policy direction options. + type: str + choices: ['in', 'out'] + action: + description: Missing policy action options. + type: str + choices: ['deny', 'permit', 'deny-in-out'] + monitoring: + description: Enable Bgp monitoring for all/specified stations. + type: bool + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + redistribute_internal: + description: Redistribute internal BGP routes. + type: bool + route: + description: Configure route-map for route installation. + type: str + route_reflector: + description: Configure route reflector options + type: dict + suboptions: + set: + description: When True route_reflector is set. + type: bool + preserve: + description: preserve route attributes, overwriting route-map changes + type: bool + transport: + description: Configure transport port for TCP session + type: int + default_metric: + description: Default metric. + type: int + distance: + description: Define an administrative distance. + type: dict + suboptions: + external: + description: distance for external routes. + type: int + internal: + description: distance for internal routes. + type: int + local: + description: distance for local routes. + type: int + graceful_restart: + description: Enable graceful restart mode. + type: dict + suboptions: + set: + description: When True, graceful restart is set. + type: bool + restart_time: + description: Set the max time needed to restart and come back up. + type: int + stalepath_time: + description: Set the max time to hold onto restarting peer stale paths. + type: int + graceful_restart_helper: + description: Enable graceful restart helper mode. + type: bool + access_group: + description: ip/ipv6 access list configuration. + type: list + elements: dict + suboptions: + afi: + description: Specify ip/ipv6. + type: str + choices: ['ipv4', 'ipv6'] + acl_name: + description: access list name. + type: str + direction: + description: direction of packets. + type: str + maximum_paths: + description: Maximum number of equal cost paths. + type: dict + suboptions: + max_equal_cost_paths: + description: Value for maximum number of equal cost paths. + type: int + max_installed_ecmp_paths: + description: Value for maximum number of installed ECMP routes. + type: int + neighbor: + description: Configure routing for a network. + aliases: + - neighbors + type: list + elements: dict + suboptions: + neighbor_address: + type: str + description: Neighbor address or peer group. + aliases: ["peer"] + additional_paths: + description: BGP additional-paths commands. + type: str + choices: ['send', 'receive'] + allowas_in: + description: Allow local-as in updates. + type: dict + suboptions: + set: + description: When True, it is set. + type: bool + count: + description: Number of local ASNs allowed in a BGP update. + type: int + auto_local_addr: + description: Automatically determine the local address to be used + for the non-transport AF. + type: bool + bfd: + description: Configure BFD fallover for this peer + type: str + choices: ['enable', 'c_bit'] + default_originate: + description: Originate default route to this neighbor. + type: dict + suboptions: + route_map: + description: Route map reference. + type: str + always: + description: Always originate default route to this neighbor. + type: bool + description: + description: Text describing the neighbor. + type: str + dont_capability_negotiate: + description: Donot perform Capability Negotiation with this + neighbor. + type: bool + ebgp_multihop: + description: Allow BGP connections to indirectly connected + external peers. + type: dict + suboptions: + ttl: + description: Time-to-live in the range 1-255 hops. + type: int + set: + description: If True, ttl is not set. + type: bool + enforce_first_as: + description: Enforce the First AS for EBGP routes(default). + type: bool + export_localpref: + description: Override localpref when exporting to an internal + peer. + type: int + fall_over: + description: Configure BFD protocol options for this peer. + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: bool + graceful_restart_helper: + description: Enable graceful restart helper mode. + type: bool + idle_restart_timer: + description: Neighbor idle restart timer. + type: int + import_localpref: + description: Override localpref when importing from an external + peer. + type: int + link_bandwidth: + description: Enable link bandwidth community for routes to this + peer. + type: dict + suboptions: + set: + description: If True, set link bandwidth + type: bool + auto: + description: Enable link bandwidth auto generation for routes from this peer. + type: bool + default: + description: Enable link bandwidth default generation for routes from this + peer. + type: str + update_delay: + description: Delay outbound route updates. + type: int + local_as: + description: Configure local AS number advertised to peer. + type: dict + suboptions: + as_number: + description: AS number. + type: str + fallback: + description: Prefer router AS Number over local AS Number. + type: bool + local_v6_addr: + description: The local IPv6 address of the neighbor in A:B:C:D:E:F:G:H format. + type: str + maximum_accepted_routes: + description: Maximum number of routes accepted from this peer. + type: dict + suboptions: + count: + description: Maximum number of accepted routes (0 means unlimited). + type: int + warning_limit: + description: Maximum number of accepted routes after which a warning is issued. + (0 means never warn) + type: int + maximum_received_routes: + description: Maximum number of routes received from this peer. + type: dict + suboptions: + count: + description: Maximum number of routes (0 means unlimited). + type: int + warning_limit: + description: Percentage of maximum-routes at which warning is to be issued. + type: dict + suboptions: + limit_count: + description: Number of routes at which to warn. + type: int + limit_percent: + description: Percentage of maximum number of routes at which to warn( 1-100). + type: int + warning_only: + description: Only warn, no restart, if max route limit exceeded. + type: bool + metric_out: + description: MED value to advertise to peer. + type: int + monitoring: + description: Enable BGP Monitoring Protocol for this peer. + type: bool + next_hop_self: + description: Always advertise this router address as the BGP + next hop + type: bool + next_hop_unchanged: + description: Preserve original nexthop while advertising routes to + eBGP peers. + type: bool + next_hop_v6_address: + description: IPv6 next-hop address for the neighbor + type: str + out_delay: + description: Delay outbound route updates. + type: int + encryption_password: + description: Password to use in computation of MD5 hash. + type: dict + suboptions: + type: + description: Encryption type. + type: int + choices: [0, 7] + password: + description: password (up to 80 chars). + type: str + remote_as: + description: Neighbor Autonomous System. + type: str + remove_private_as: + description: Remove private AS number from updates to this peer. + type: dict + suboptions: + set: + description: If True, set remove_private_as. + type: bool + all: + description: Remove private AS number. + type: bool + replace_as: + description: Replace private AS number with local AS number. + type: bool + peer_group: + description: Name of the peer group. + type: str + + prefix_list: + description: Prefix list reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound prefix-list. + type: str + choices: ['in', 'out'] + name: + description: prefix list name. + type: str + route_map: + description: Route map reference. + type: dict + suboptions: + direction: + description: Configure an inbound/outbound route-map. + type: str + choices: ['in', 'out'] + name: + description: Route map name. + type: str + route_reflector_client: + description: Configure peer as a route reflector client. + type: bool + route_to_peer: + description: Use routing table information to reach the peer. + type: bool + send_community: + description: Send community attribute to this neighbor. + type: dict + suboptions: + community_attribute: + description: Type of community attributes to send to this neighbor. + type: str + sub_attribute: + description: Attribute to be sent to the neighbor. + type: str + choices: ['extended', 'link-bandwidth', 'standard'] + link_bandwidth_attribute: + description: cumulative/aggregate attribute to be sent. + type: str + choices: ['aggregate', 'divide'] + speed: + description: Reference link speed in bits/second + type: str + divide: + description: link-bandwidth divide attribute. + type: str + choices: ['equal', 'ratio'] + shutdown: + description: Administratively shut down this neighbor. + type: bool + soft_recognition: + description: Configure how to handle routes that fail import. + type: str + choices: ['all', 'None'] + timers: + description: Timers. + type: dict + suboptions: + keepalive: + description: Keep Alive Interval in secs. + type: int + holdtime: + description: Hold time in secs. + type: int + transport: + description: Configure transport options for TCP session. + type: dict + suboptions: + connection_mode: + description: Configure connection-mode for TCP session. + type: str + remote_port: + description: Configure BGP peer TCP port to connect to. + type: int + ttl: + description: BGP ttl security check + type: int + update_source: + description: Specify the local source interface for peer BGP + sessions. + type: str + weight: + description: Weight to assign. + type: int + network: + description: Configure routing for a network. + aliases: + - networks + type: list + elements: dict + suboptions: + address: + description: address prefix. + type: str + route_map: + description: Name of route map. + type: str + redistribute: + description: Redistribute routes in to BGP. + type: list + elements: dict + suboptions: + protocol: + description: Routes to be redistributed. + type: str + choices: ['isis', 'ospfv3', 'ospf', 'attached-host', 'connected', 'rip', 'static'] + route_map: + description: Route map reference. + type: str + isis_level: + description: Applicable for isis routes. Specify isis route level. + type: str + choices: ['level-1', 'level-2', 'level-1-2'] + ospf_route: + description: ospf route options. + type: str + choices: ['internal', 'external', 'nssa_external_1', 'nssa_external_2'] + route_target: + description: Route target. + type: dict + suboptions: + action: + description: Route action. + type: str + choices: ['both', 'import', 'export'] + type: + description: Type of address fmaily + type: str + choices: ['evpn', 'vpn-ipv4', 'vpn-ipv6'] + route_map: + description: Name of a route map. + type: str + target: + description: Route Target. + type: str + imported_route: + description: Export routes imported from the same Afi/Safi. + type: bool + router_id: + description: Router id. + type: str + shutdown: + description: When True, shut down BGP. + type: bool + timers: + description: Timers. + type: dict + suboptions: + keepalive: + description: Keep Alive Interval in secs. + type: int + holdtime: + description: Hold time in secs. + type: int + ucmp: + description: Configure unequal cost multipathing. + type: dict + suboptions: + fec: + description: Configure UCMP fec utilization threshold. + type: dict + suboptions: + trigger: + description: UCMP fec utilization too high threshold. + type: int + clear: + description: UCMP FEC utilization Clear thresholds. + type: int + link_bandwidth: + description: Configure link-bandwidth propagation delay. + type: dict + suboptions: + mode: + description: UCMP link bandwidth mode + type: str + choices: ['encoding_weighted', 'recursive', 'update_delay'] + update_delay: + description: Link Bandwidth Advertisement delay. + type: int + mode: + description: UCMP mode. + type: dict + suboptions: + set: + description: If True, ucmp mode is set to 1. + type: bool + nexthops: + description: Value for total number UCMP nexthops. + type: int + update: + description: Configure BGP update generation. + type: dict + suboptions: + wait_for: + description: wait for options before converge or synchronize. + type: str + choices: ['wait_for_convergence', 'wait_install'] + batch_size: + description: batch size for FIB route acknowledgements. + 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 EOS device by + executing the command B(show running-config | section 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: + description: + - The state the configuration should be left in. + - State I(purged) removes all the BGP configurations from the + target device. Use caution with this state.('no router bgp <x>') + - State I(deleted) only removes BGP attributes that this modules + manages and does not negate the BGP process completely. Thereby, preserving + address-family related configurations under BGP context. + - Running states I(deleted) and I(replaced) will result in an error if there + are address-family configuration lines present under vrf context that is + is to be removed. Please use the M(arista.eos.eos_bgp_address_family) + module for prior cleanup. + - Refer to examples for more details. + type: str + choices: [deleted, merged, purged, replaced, gathered, rendered, parsed] + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state + +# veos(config)#show running-config | section bgp +# veos(config)# + + - name: Merge provided configuration with device configuration + arista.eos.eos_bgp_global: + config: + as_number: "100" + bgp_params: + host_routes: True + convergence: + slow_peer: True + time: 6 + additional_paths: "send" + log_neighbor_changes: True + maximum_paths: + max_equal_cost_paths: 55 + aggregate_address: + - address: "1.2.1.0/24" + as_set: true + match_map: "match01" + - address: "5.2.1.0/24" + attribute_map: "attrmatch01" + advertise_only: true + redistribute: + - protocol: "static" + route_map: "map_static" + - protocol: "attached-host" + distance: + internal: 50 + neighbor: + - peer: "10.1.3.2" + allowas_in: + set: true + default_originate: + always: true + dont_capability_negotiate: true + export_localpref: 4000 + maximum_received_routes: + count: 500 + warning_limit: + limit_percent: 5 + next_hop_unchanged: true + prefix_list: + name: "prefix01" + direction: "out" + - neighbor_address: "peer1" + fall_over: true + link_bandwidth: + update_delay: 5 + monitoring: True + send_community: + community_attribute: "extended" + sub_attribute: "link-bandwidth" + link_bandwidth_attribute: "aggregate" + speed: "600" + vlan: 5 + state: merged + +# After State: +# veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# distance bgp 50 50 50 +# maximum-paths 55 +# bgp additional-paths send any +# neighbor peer1 peer group +# neighbor peer1 link-bandwidth update-delay 5 +# neighbor peer1 fall-over bfd +# neighbor peer1 monitoring +# neighbor peer1 send-community extended link-bandwidth aggregate 600 +# neighbor peer1 maximum-routes 12000 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! +# vlan 5 +# ! +# address-family ipv4 +# neighbor 10.1.3.2 prefix-list prefix01 out +# veos(config)# +# +# Module Execution: +# +# "after": { +# "aggregate_address": [ +# { +# "address": "1.2.1.0/24", +# "as_set": true, +# "match_map": "match01" +# }, +# { +# "address": "5.2.1.0/24", +# "advertise_only": true, +# "attribute_map": "attrmatch01" +# } +# ], +# "as_number": "100", +# "bgp_params": { +# "additional_paths": "send", +# "convergence": { +# "slow_peer": true, +# "time": 6 +# } +# }, +# "distance": { +# "external": 50, +# "internal": 50, +# "local": 50 +# }, +# "maximum_paths": { +# "max_equal_cost_paths": 55 +# }, +# "neighbor": [ +# { +# "fall_over": true, +# "link_bandwidth": { +# "set": true, +# "update_delay": 5 +# }, +# "maximum_received_routes": { +# "count": 12000 +# }, +# "monitoring": true, +# "peer": "peer1", +# "peer_group": "peer1", +# "send_community": { +# "community_attribute": "extended", +# "link_bandwidth_attribute": "aggregate", +# "speed": "600", +# "sub_attribute": "link-bandwidth" +# } +# }, +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "export_localpref": 4000, +# "maximum_received_routes": { +# "count": 500, +# "warning_limit": { +# "limit_percent": 5 +# } +# }, +# "next_hop_unchanged": true, +# "peer": "10.1.3.2" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map_static" +# }, +# { +# "protocol": "attached-host" +# } +# ], +# "vlan": 5 +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "router bgp 100", +# "neighbor 10.1.3.2 allowas-in", +# "neighbor 10.1.3.2 default-originate always", +# "neighbor 10.1.3.2 dont-capability-negotiate", +# "neighbor 10.1.3.2 export-localpref 4000", +# "neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent", +# "neighbor 10.1.3.2 next-hop-unchanged", +# "neighbor 10.1.3.2 prefix-list prefix01 out", +# "neighbor peer1 fall-over bfd", +# "neighbor peer1 link-bandwidth update-delay 5", +# "neighbor peer1 monitoring", +# "neighbor peer1 send-community extended link-bandwidth aggregate 600", +# "redistribute static route-map map_static", +# "redistribute attached-host", +# "aggregate-address 1.2.1.0/24 as-set match-map match01", +# "aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only", +# "bgp host-routes fib direct-install", +# "bgp convergence slow-peer time 6", +# "bgp additional-paths send any", +# "bgp log-neighbor-changes", +# "maximum-paths 55", +# "distance bgp 50", +# "vlan 5" +# ], + +# Using replaced: + +# Before state: +# veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# distance bgp 50 50 50 +# maximum-paths 55 +# bgp additional-paths send any +# neighbor peer1 peer group +# neighbor peer1 link-bandwidth update-delay 5 +# neighbor peer1 fall-over bfd +# neighbor peer1 monitoring +# neighbor peer1 send-community extended link-bandwidth aggregate 600 +# neighbor peer1 maximum-routes 12000 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! +# vlan 5 +# ! +# address-family ipv4 +# neighbor 10.1.3.2 prefix-list prefix01 out +# ! +# vrf vrf01 +# route-target import 54:11 +# neighbor 12.1.3.2 dont-capability-negotiate +# neighbor 12.1.3.2 allowas-in 3 +# neighbor 12.1.3.2 default-originate always +# neighbor 12.1.3.2 maximum-routes 12000 +# veos(config)# + + - name: replace provided configuration with device configuration + arista.eos.eos_bgp_global: + config: + as_number: "100" + bgp_params: + host_routes: True + convergence: + slow_peer: True + time: 6 + additional_paths: "send" + log_neighbor_changes: True + vrfs: + - vrf: "vrf01" + maximum_paths: + max_equal_cost_paths: 55 + aggregate_address: + - address: "1.2.1.0/24" + as_set: true + match_map: "match01" + - address: "5.2.1.0/24" + attribute_map: "attrmatch01" + advertise_only: true + redistribute: + - protocol: "static" + route_map: "map_static" + - protocol: "attached-host" + distance: + internal: 50 + neighbor: + - neighbor_address: "10.1.3.2" + allowas_in: + set: true + default_originate: + always: true + dont_capability_negotiate: true + export_localpref: 4000 + maximum_received_routes: + count: 500 + warning_limit: + limit_percent: 5 + next_hop_unchanged: true + prefix_list: + name: "prefix01" + direction: "out" + - neighbor_address: "peer1" + fall_over: true + link_bandwidth: + update_delay: 5 + monitoring: True + send_community: + community_attribute: "extended" + sub_attribute: "link-bandwidth" + link_bandwidth_attribute: "aggregate" + speed: "600" + state: replaced + +# After State: + +# veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# bgp additional-paths send any +# ! +# vrf vrf01 +# distance bgp 50 50 50 +# maximum-paths 55 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! +# address-family ipv4 +# neighbor 10.1.3.2 prefix-list prefix01 out +# veos(config)# +# +# +# Module Execution: +# +# "after": { +# "as_number": "100", +# "bgp_params": { +# "additional_paths": "send", +# "convergence": { +# "slow_peer": true, +# "time": 6 +# } +# }, +# "vrfs": [ +# { +# "aggregate_address": [ +# { +# "address": "1.2.1.0/24", +# "as_set": true, +# "match_map": "match01" +# }, +# { +# "address": "5.2.1.0/24", +# "advertise_only": true, +# "attribute_map": "attrmatch01" +# } +# ], +# "distance": { +# "external": 50, +# "internal": 50, +# "local": 50 +# }, +# "maximum_paths": { +# "max_equal_cost_paths": 55 +# }, +# "neighbor": [ +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "export_localpref": 4000, +# "maximum_received_routes": { +# "count": 500, +# "warning_limit": { +# "limit_percent": 5 +# } +# }, +# "next_hop_unchanged": true, +# "peer": "10.1.3.2" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map_static" +# }, +# { +# "protocol": "attached-host" +# } +# ], +# "vrf": "vrf01" +# } +# ] +# }, +# "before": { +# "aggregate_address": [ +# { +# "address": "1.2.1.0/24", +# "as_set": true, +# "match_map": "match01" +# }, +# { +# "address": "5.2.1.0/24", +# "advertise_only": true, +# "attribute_map": "attrmatch01" +# } +# ], +# "as_number": "100", +# "bgp_params": { +# "additional_paths": "send", +# "convergence": { +# "slow_peer": true, +# "time": 6 +# } +# }, +# "distance": { +# "external": 50, +# "internal": 50, +# "local": 50 +# }, +# "maximum_paths": { +# "max_equal_cost_paths": 55 +# }, +# "neighbor": [ +# { +# "fall_over": true, +# "link_bandwidth": { +# "set": true, +# "update_delay": 5 +# }, +# "maximum_received_routes": { +# "count": 12000 +# }, +# "monitoring": true, +# "peer": "peer1", +# "peer_group": "peer1", +# "send_community": { +# "community_attribute": "extended", +# "link_bandwidth_attribute": "aggregate", +# "speed": "600", +# "sub_attribute": "link-bandwidth" +# } +# }, +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "export_localpref": 4000, +# "maximum_received_routes": { +# "count": 500, +# "warning_limit": { +# "limit_percent": 5 +# } +# }, +# "next_hop_unchanged": true, +# "peer": "10.1.3.2" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map_static" +# }, +# { +# "protocol": "attached-host" +# } +# ], +# "vlan": 5, +# "vrfs": [ +# { +# "neighbor": [ +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "maximum_received_routes": { +# "count": 12000 +# }, +# "peer": "12.1.3.2" +# } +# ], +# "route_target": { +# "action": "import", +# "target": "54:11" +# }, +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "router bgp 100", +# "vrf vrf01", +# "no route-target import 54:11", +# "neighbor 10.1.3.2 allowas-in", +# "neighbor 10.1.3.2 default-originate always", +# "neighbor 10.1.3.2 dont-capability-negotiate", +# "neighbor 10.1.3.2 export-localpref 4000", +# "neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent", +# "neighbor 10.1.3.2 next-hop-unchanged", +# "neighbor 10.1.3.2 prefix-list prefix01 out", +# "neighbor peer1 fall-over bfd", +# "neighbor peer1 link-bandwidth update-delay 5", +# "neighbor peer1 monitoring", +# "neighbor peer1 send-community extended link-bandwidth aggregate 600", +# "no neighbor 12.1.3.2", +# "redistribute static route-map map_static", +# "redistribute attached-host", +# "aggregate-address 1.2.1.0/24 as-set match-map match01", +# "aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only", +# "maximum-paths 55", +# "distance bgp 50", +# "exit", +# "no neighbor peer1 peer group", +# "no neighbor peer1 link-bandwidth update-delay 5", +# "no neighbor peer1 fall-over bfd", +# "no neighbor peer1 monitoring", +# "no neighbor peer1 send-community extended link-bandwidth aggregate 600", +# "no neighbor peer1 maximum-routes 12000", +# "no neighbor 10.1.3.2", +# "no redistribute static route-map map_static", +# "no redistribute attached-host", +# "no aggregate-address 1.2.1.0/24 as-set match-map match01", +# "no aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only", +# "bgp host-routes fib direct-install", +# "bgp log-neighbor-changes", +# "no distance bgp 50 50 50", +# "no maximum-paths 55", +# "no vlan 5" +# ], +# + +# Using replaced (in presence of address_family under vrf): +# Before State: + +#veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# bgp additional-paths send any +# ! +# vrf vrf01 +# distance bgp 50 50 50 +# maximum-paths 55 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! +# address-family ipv4 +# neighbor 10.1.3.2 prefix-list prefix01 out +# ! +# address-family ipv6 +# redistribute dhcp +# veos(config)# + + - name: Replace + arista.eos.eos_bgp_global: + config: + as_number: "100" + graceful_restart: + set: True + router_id: "1.1.1.1" + timers: + keepalive: 2 + holdtime: 5 + ucmp: + mode: + set: True + vlan_aware_bundle: "bundle1 bundle2 bundle3" + state: replaced + +# Module Execution: + +# fatal: [192.168.122.113]: FAILED! => { +# "changed": false, +# "invocation": { +# "module_args": { +# "config": { +# "access_group": null, +# "aggregate_address": null, +# "as_number": "100", +# "bgp_params": null, +# "default_metric": null, +# "distance": null, +# "graceful_restart": { +# "restart_time": null, +# "set": true, +# "stalepath_time": null +# }, +# "graceful_restart_helper": null, +# "maximum_paths": null, +# "monitoring": null, +# "neighbor": null, +# "network": null, +# "redistribute": null, +# "route_target": null, +# "router_id": "1.1.1.1", +# "shutdown": null, +# "timers": { +# "holdtime": 5, +# "keepalive": 2 +# }, +# "ucmp": { +# "fec": null, +# "link_bandwidth": null, +# "mode": { +# "nexthops": null, +# "set": true +# } +# }, +# "update": null, +# "vlan": null, +# "vlan_aware_bundle": "bundle1 bundle2 bundle3", +# "vrfs": null +# }, +# "running_config": null, +# "state": "replaced" +# } +# }, +# "msg": "Use the _bgp_af module to delete the address_family under vrf, before replacing/deleting the vrf." +# } + +# Using deleted: + +# Before state: + +# veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# bgp additional-paths send any +# ! +# vrf vrf01 +# distance bgp 50 50 50 +# maximum-paths 55 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! + + - name: Delete configuration + arista.eos.eos_bgp_global: + config: + as_number: "100" + state: deleted + +# After State: + +# veos(config)#show running-config | section bgp +# router bgp 100 +# +# +# Module Execution: +# +# "after": { +# "as_number": "100" +# }, +# "before": { +# "as_number": "100", +# "bgp_params": { +# "additional_paths": "send", +# "convergence": { +# "slow_peer": true, +# "time": 6 +# } +# }, +# "vrfs": [ +# { +# "aggregate_address": [ +# { +# "address": "1.2.1.0/24", +# "as_set": true, +# "match_map": "match01" +# }, +# { +# "address": "5.2.1.0/24", +# "advertise_only": true, +# "attribute_map": "attrmatch01" +# } +# ], +# "distance": { +# "external": 50, +# "internal": 50, +# "local": 50 +# }, +# "maximum_paths": { +# "max_equal_cost_paths": 55 +# }, +# "neighbor": [ +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "export_localpref": 4000, +# "maximum_received_routes": { +# "count": 500, +# "warning_limit": { +# "limit_percent": 5 +# } +# }, +# "next_hop_unchanged": true, +# "peer": "10.1.3.2" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map_static" +# }, +# { +# "protocol": "attached-host" +# } +# ], +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "router bgp 100", +# "no vrf vrf01", +# "no bgp convergence slow-peer time 6", +# "no bgp additional-paths send any" +# ], +# + +# Using purged: + +# Before state: + +# veos(config)#show running-config | section bgp +# router bgp 100 +# bgp convergence slow-peer time 6 +# distance bgp 50 50 50 +# maximum-paths 55 +# bgp additional-paths send any +# neighbor peer1 peer group +# neighbor peer1 link-bandwidth update-delay 5 +# neighbor peer1 fall-over bfd +# neighbor peer1 monitoring +# neighbor peer1 send-community extended link-bandwidth aggregate 600 +# neighbor peer1 maximum-routes 12000 +# neighbor 10.1.3.2 export-localpref 4000 +# neighbor 10.1.3.2 next-hop-unchanged +# neighbor 10.1.3.2 dont-capability-negotiate +# neighbor 10.1.3.2 allowas-in 3 +# neighbor 10.1.3.2 default-originate always +# neighbor 10.1.3.2 maximum-routes 500 warning-limit 5 percent +# aggregate-address 1.2.1.0/24 as-set match-map match01 +# aggregate-address 5.2.1.0/24 attribute-map attrmatch01 advertise-only +# redistribute static route-map map_static +# redistribute attached-host +# ! +# vlan 5 +# ! +# address-family ipv4 +# neighbor 10.1.3.2 prefix-list prefix01 out +# ! +# vrf vrf01 +# route-target import 54:11 +# neighbor 12.1.3.2 dont-capability-negotiate +# neighbor 12.1.3.2 allowas-in 3 +# neighbor 12.1.3.2 default-originate always +# neighbor 12.1.3.2 maximum-routes 12000 +# veos(config)# + + - name: Purge configuration + arista.eos.eos_bgp_global: + config: + as_number: "100" + state: purged + +# After State: + +# veos(config)#show running-config | section bgp +# veos(config)# + +# Module Execution: + +# "after": {}, +# "before": { +# "aggregate_address": [ +# { +# "address": "1.2.1.0/24", +# "as_set": true, +# "match_map": "match01" +# }, +# { +# "address": "5.2.1.0/24", +# "advertise_only": true, +# "attribute_map": "attrmatch01" +# } +# ], +# "as_number": "100", +# "bgp_params": { +# "additional_paths": "send", +# "convergence": { +# "slow_peer": true, +# "time": 6 +# } +# }, +# "distance": { +# "external": 50, +# "internal": 50, +# "local": 50 +# }, +# "maximum_paths": { +# "max_equal_cost_paths": 55 +# }, +# "neighbor": [ +# { +# "fall_over": true, +# "link_bandwidth": { +# "set": true, +# "update_delay": 5 +# }, +# "maximum_received_routes": { +# "count": 12000 +# }, +# "monitoring": true, +# "peer": "peer1", +# "peer_group": "peer1", +# "send_community": { +# "community_attribute": "extended", +# "link_bandwidth_attribute": "aggregate", +# "speed": "600", +# "sub_attribute": "link-bandwidth" +# } +# }, +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "export_localpref": 4000, +# "maximum_received_routes": { +# "count": 500, +# "warning_limit": { +# "limit_percent": 5 +# } +# }, +# "next_hop_unchanged": true, +# "peer": "10.1.3.2" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map_static" +# }, +# { +# "protocol": "attached-host" +# } +# ], +# "vlan": 5, +# "vrfs": [ +# { +# "neighbor": [ +# { +# "allowas_in": { +# "count": 3 +# }, +# "default_originate": { +# "always": true +# }, +# "dont_capability_negotiate": true, +# "maximum_received_routes": { +# "count": 12000 +# }, +# "peer": "12.1.3.2" +# } +# ], +# "route_target": { +# "action": "import", +# "target": "54:11" +# }, +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "no router bgp 100" +# ], + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.bgp_global.bgp_global import ( + Bgp_globalArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.bgp_global.bgp_global import ( + Bgp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Bgp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_command.py b/ansible_collections/arista/eos/plugins/modules/eos_command.py new file mode 100644 index 000000000..437e3bc63 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_command.py @@ -0,0 +1,320 @@ +#!/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: eos_command +author: Peter Sprygada (@privateip) +short_description: Run arbitrary commands on an Arista EOS device +description: +- Sends an arbitrary set of commands to an EOS 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. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +options: + commands: + description: + - The commands to send to the remote EOS device. 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 I(retries) has been exceeded. + - Commands may be represented either as simple strings or as dictionaries as described below. + Refer to the Examples setion for some common uses. + required: true + type: list + elements: raw + suboptions: + command: + description: + - The command to send to the remote network device. The resulting output from + the command is returned, unless I(sendonly) is set. + required: true + type: str + output: + description: + - How the remote device should format the command response data. + type: str + choices: ["text", "json"] + version: + description: + - Specifies the version of the JSON response returned when I(output=json). + type: str + choices: ["1", "latest"] + default: "latest" + prompt: + description: + - A single regex pattern or a sequence of patterns to evaluate the expected prompt + from I(command). + required: false + type: list + elements: str + answer: + description: + - The answer to reply with if I(prompt) is matched. The value can be a single + answer or a list of answer for multiple prompts. In case the command execution + results in multiple prompts the sequence of the prompt and excepted answer should + be in same order. + required: false + type: list + elements: str + sendonly: + description: + - The boolean value, that when set to true will send I(command) to the device + but not wait for a result. + type: bool + default: false + required: false + newline: + description: + - The boolean value, that when set to false will send I(answer) to the device + without a trailing newline. + type: bool + default: true + required: false + check_all: + description: + - By default if any one of the prompts mentioned in C(prompt) option is matched + it won't check for other prompts. This boolean flag, that when set to I(True) + will check for all the prompts mentioned in C(prompt) option in the given order. + If the option is set to I(True) all the prompts should be received from remote + host if not it will result in timeout. + type: bool + default: false + wait_for: + description: + - Specifies what to evaluate from the output of the command and what conditionals + to apply. This argument will cause the task to wait for a particular conditional + to be true before moving forward. If the conditional is not true by the configured + retries, the task fails. Note - With I(wait_for) the value in C(result['stdout']) + can be accessed using C(result), that is to access C(result['stdout'][0]) use + C(result[0]) See examples. + type: list + elements: str + aliases: + - waitfor + 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 I(wait_for) must be satisfied. If + the value is set to C(any) then only one of the values must be satisfied. + type: str + default: all + choices: + - any + - all + retries: + description: + - Specifies the number of retries a command should be tried before it is considered + failed. The command is run on the target device every retry and evaluated against + the I(wait_for) conditionals. + 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 conditional, the interval indicates + how to long to wait before trying the command again. + default: 1 + type: int +""" + +EXAMPLES = r""" +- name: run show version on remote devices + arista.eos.eos_command: + commands: show version + +- name: run show version and check to see if output contains Arista + arista.eos.eos_command: + commands: show version + wait_for: result[0] contains Arista + +- name: run multiple commands on remote nodes + arista.eos.eos_command: + commands: + - show version + - show interfaces + +- name: run multiple commands and evaluate the output + arista.eos.eos_command: + commands: + - show version + - show interfaces + wait_for: + - result[0] contains Arista + - result[1] contains Loopback0 + +- name: run commands and specify the output format + arista.eos.eos_command: + commands: + - command: show version + output: json + +- name: check whether the switch is in maintenance mode + arista.eos.eos_command: + commands: show maintenance + wait_for: result[0] contains 'Under Maintenance' + +- name: check whether the switch is in maintenance mode using json output + arista.eos.eos_command: + commands: + - command: show maintenance + output: json + wait_for: result[0].units.System.state eq 'underMaintenance' + +- name: check whether the switch is in maintenance, with 8 retries + and 2 second interval between retries + arista.eos.eos_command: + commands: show maintenance + wait_for: result[0]['units']['System']['state'] eq 'underMaintenance' + interval: 2 + retries: 8 + +- name: run a command that requires a confirmation. Note that prompt + takes regexes, and so strings containing characters like brackets + need to be escaped. + arista.eos.eos_command: + commands: + - command: reload power + prompt: \[confirm\] + answer: y + newline: false +""" + +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 ( + to_lines, +) + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + run_commands, + transform_commands, +) + + +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 to_cli(obj): + cmd = obj["command"] + if obj.get("output") == "json": + cmd += " | json" + return cmd + + +def main(): + """entry point for module execution""" + argument_spec = dict( + commands=dict(type="list", required=True, elements="raw"), + wait_for=dict(type="list", aliases=["waitfor"], elements="str"), + match=dict(default="all", choices=["all", "any"]), + retries=dict(default=10, type="int"), + interval=dict(default=1, type="int"), + ) + + 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/ansible_collections/arista/eos/plugins/modules/eos_config.py b/ansible_collections/arista/eos/plugins/modules/eos_config.py new file mode 100644 index 000000000..0c8271adc --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_config.py @@ -0,0 +1,630 @@ +#!/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: eos_config +author: Peter Sprygada (@privateip) +short_description: Manage Arista EOS configuration sections +description: +- Arista EOS configurations use a simple block indent file syntax for segmenting configuration + into sections. This module provides an implementation for working with EOS configuration + sections in a deterministic way. This module works with either CLI or eAPI transports. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +- 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 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. + aliases: + - commands + type: list + elements: str + 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: + - The I(src) argument provides a path to the configuration file to load into the + remote system. The path can either be a full system path to the configuration + file if the value starts with / or relative to the root of the implemented role + or playbook. This argument is mutually exclusive with the I(lines) and I(parents) + arguments. It can be a Jinja2 template as well. The configuration lines in the source + file should be similar to how it will appear if present in the running-configuration + (live switch config) of the device i ncluding the indentation to ensure idempotency + and correct diff. Arista EOS device config has 3 spaces indentation. + type: path + 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. + type: str + default: line + choices: + - line + - strict + - exact + - none + 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. + type: str + default: line + choices: + - line + - block + - config + 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 this module. + 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: + - The I(defaults) argument will influence how the running-config is collected + from the device. When the value is set to true, the command used to collect + the running-config is append with the all keyword. When the value is set to + false, the command is issued without the all keyword + 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 + type: str + choices: + - always + - never + - modified + - changed + 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. + - When this option is configured as C(session), the diff returned will be based + on the configuration session. + - When this option is configured as C(validate_config), the module will return before + with the running-config before applying the intended config and after with the session + config after applying the intended config to the session. + default: session + type: str + choices: + - startup + - running + - intended + - session + - validate_config + 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 +""" +# noqa: E501 + +EXAMPLES = """ +- name: configure top level settings + arista.eos.eos_config: + lines: hostname {{ inventory_hostname }} + +- name: load an acl into the device + arista.eos.eos_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 + parents: ip access-list test + before: no ip access-list test + replace: block + +- name: load configuration from file + arista.eos.eos_config: + src: eos.cfg + +- name: render a Jinja2 template onto an Arista switch + arista.eos.eos_config: + backup: yes + src: eos_template.j2 + +- name: diff the running config against a master config + arista.eos.eos_config: + diff_against: intended + intended_config: "{{ lookup('file', 'master.cfg') }}" + +- name: for idempotency, use full-form commands + arista.eos.eos_config: + lines: + # - shut + - shutdown + # parents: int eth1 + parents: interface Ethernet1 + +- name: configurable backup path + arista.eos.eos_config: + src: eos_template.j2 + backup: yes + backup_options: + filename: backup.cfg + dir_path: /home/user +""" + +RETURN = """ +commands: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['hostname switch01', 'interface Ethernet1', 'no shutdown'] +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['hostname switch01', 'interface Ethernet1', 'no shutdown'] +backup_path: + description: The full path to the backup file + returned: when backup is yes + type: str + sample: /playbooks/ansible/backup/eos_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: eos_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/eos_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" +""" +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import ConnectionError +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + get_config, + get_connection, + get_session_config, + load_config, + run_commands, +) + + +def get_candidate(module): + candidate = "" + if module.params["src"]: + candidate = module.params["src"] + elif module.params["lines"]: + candidate_obj = NetworkConfig(indent=3) + 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, config=None, flags=None): + contents = module.params["running_config"] + if not contents: + if config: + contents = config + else: + contents = get_config(module, flags=flags) + return contents + + +def save_config(module, result): + result["changed"] = True + if not module.check_mode: + cmd = { + "command": "copy running-config startup-config", + "output": "text", + } + run_commands(module, [cmd]) + 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="path"), + 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", "config"]), + 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", + "session", + "intended", + "running", + "validate_config", + ], + default="session", + ), + diff_ignore_lines=dict(type="list", elements="str"), + running_config=dict(aliases=["config"]), + intended_config=dict(), + ) + + mutually_exclusive = [("lines", "src"), ("parents", "src")] + + required_if = [ + ("match", "strict", ["lines"]), + ("match", "exact", ["lines"]), + ("replace", "block", ["lines"]), + ("replace", "config", ["src"]), + ("diff_against", "intended", ["intended_config"]), + ("diff_against", "validate_config", ["intended_config"]), + ] + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + supports_check_mode=True, + ) + + warnings = list() + + result = {"changed": False} + if warnings: + result["warnings"] = warnings + + diff_ignore_lines = module.params["diff_ignore_lines"] + config = None + contents = None + flags = ["all"] if module.params["defaults"] else [] + connection = get_connection(module) + # Refuse to diff_against: session if sessions are disabled + if ( + module.params["diff_against"] in ["session", "validate_config"] + and not connection.supports_sessions + ): + module.fail_json( + msg="Cannot diff against sessions when sessions are disabled. Please change diff_against to another value", + ) + + 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["src"], module.params["lines"])): + match = module.params["match"] + replace = module.params["replace"] + path = module.params["parents"] + + candidate = get_candidate(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"] + if config_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 + + replace = module.params["replace"] == "config" + commit = not module.check_mode + + response = load_config( + module, + commands, + replace=replace, + commit=commit, + ) + + result["changed"] = True + + if module.params["diff_against"] == "session": + if "diff" in response: + result["diff"] = {"prepared": response["diff"]} + else: + result["changed"] = False + + if "session" in response: + result["session"] = response["session"] + + 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, + [ + {"command": "show running-config", "output": "text"}, + {"command": "show startup-config", "output": "text"}, + ], + ) + + running_config = NetworkConfig( + indent=3, + contents=output[0], + ignore_lines=diff_ignore_lines, + ) + startup_config = NetworkConfig( + indent=3, + 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, + {"command": "show running-config", "output": "text"}, + ) + contents = output[0] + else: + contents = running_config + + # recreate the object in order to process diff_ignore_lines + running_config = NetworkConfig( + indent=3, + 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, + {"command": "show startup-config", "output": "text"}, + ) + contents = output[0] + else: + contents = startup_config.config_text + + elif module.params["diff_against"] in ["intended", "validate_config"]: + contents = module.params["intended_config"] + + if contents is not None: + base_config = NetworkConfig( + indent=3, + contents=contents, + ignore_lines=diff_ignore_lines, + ) + + if running_config.sha1 != base_config.sha1: + before = "" + after = "" + 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 + elif module.params["diff_against"] == "validate_config": + before = running = get_running_config( + module, + None, + flags=flags, + ) + replace = module.params["replace"] == "config" + after = get_session_config( + module, + contents.split("\n"), + replace=replace, + commit=False, + ) + + result.update( + { + "changed": False, + "diff": {"before": str(before), "after": str(after)}, + }, + ) + + if result.get("changed") and any( + (module.params["src"], module.params["lines"]), + ): + 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" + if "warnings" in result: + result["warnings"].append(msg) + else: + result["warnings"] = msg + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_eapi.py b/ansible_collections/arista/eos/plugins/modules/eos_eapi.py new file mode 100644 index 000000000..2b3add753 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_eapi.py @@ -0,0 +1,437 @@ +#!/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: eos_eapi +author: Peter Sprygada (@privateip) +short_description: Manage and configure Arista EOS eAPI. +requirements: +- EOS v4.12 or greater +description: +- Use to enable or disable eAPI access, and set the port and state of http, https, + local_http and unix-socket servers. +- When enabling eAPI access the default is to enable HTTP on port 80, enable HTTPS + on port 443, disable local HTTP, and disable Unix socket server. Use the options + listed below to override the default configuration. +- Requires EOS v4.12 or greater. +version_added: 1.0.0 +options: + http: + description: + - The C(http) argument controls the operating state of the HTTP transport protocol + when eAPI is present in the running-config. When the value is set to True, the + HTTP protocol is enabled and when the value is set to False, the HTTP protocol + is disabled. By default, when eAPI is first configured, the HTTP protocol is + disabled. + type: bool + aliases: + - enable_http + http_port: + description: + - Configures the HTTP port that will listen for connections when the HTTP transport + protocol is enabled. This argument accepts integer values in the valid range + of 1 to 65535. + type: int + https: + description: + - The C(https) argument controls the operating state of the HTTPS transport protocol + when eAPI is present in the running-config. When the value is set to True, the + HTTPS protocol is enabled and when the value is set to False, the HTTPS protocol + is disabled. By default, when eAPI is first configured, the HTTPS protocol is + enabled. + type: bool + aliases: + - enable_https + https_port: + description: + - Configures the HTTP port that will listen for connections when the HTTP transport + protocol is enabled. This argument accepts integer values in the valid range + of 1 to 65535. + type: int + local_http: + description: + - The C(local_http) argument controls the operating state of the local HTTP transport + protocol when eAPI is present in the running-config. When the value is set + to True, the HTTP protocol is enabled and restricted to connections from localhost + only. When the value is set to False, the HTTP local protocol is disabled. + - Note is value is independent of the C(http) argument + type: bool + aliases: + - enable_local_http + local_http_port: + description: + - Configures the HTTP port that will listen for connections when the HTTP transport + protocol is enabled. This argument accepts integer values in the valid range + of 1 to 65535. + type: int + socket: + description: + - The C(socket) argument controls the operating state of the UNIX Domain Socket + used to receive eAPI requests. When the value of this argument is set to True, + the UDS will listen for eAPI requests. When the value is set to False, the + UDS will not be available to handle requests. By default when eAPI is first + configured, the UDS is disabled. + type: bool + aliases: + - enable_socket + timeout: + description: + - The time (in seconds) to wait for the eAPI configuration to be reflected in + the running-config. + type: int + default: 30 + vrf: + description: + - The C(vrf) argument will configure eAPI to listen for connections in the specified + VRF. By default, eAPI transports will listen for connections in the global + table. This value requires the VRF to already be created otherwise the task + will fail. + default: default + type: str + 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(config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. + type: str + state: + description: + - The C(state) argument controls the operational state of eAPI on the remote device. When + this argument is set to C(started), eAPI is enabled to receive requests and + when this argument is C(stopped), eAPI is disabled and will not receive requests. + type: str + default: started + choices: + - started + - stopped +""" + +EXAMPLES = """ +- name: Enable eAPI access with default configuration + arista.eos.eos_eapi: + state: started + +- name: Enable eAPI with no HTTP, HTTPS at port 9443, local HTTP at port 80, and socket + enabled + arista.eos.eos_eapi: + state: started + http: false + https_port: 9443 + local_http: yes + local_http_port: 80 + socket: yes + +- name: Shutdown eAPI access + arista.eos.eos_eapi: + state: stopped +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - management api http-commands + - protocol http port 81 + - no protocol https +urls: + description: Hash of URL endpoints eAPI is listening on per interface + returned: when eAPI is started + type: dict + sample: {'Management1': ['http://172.26.10.1:80']} +session_name: + description: The EOS config session name used to load the configuration + returned: when changed is True + type: str + sample: ansible_1479315771 +""" +import re +import time + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import iteritems + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + load_config, + run_commands, +) + + +def validate_http_port(value, module): + if not 1 <= value <= 65535: + module.fail_json(msg="http_port must be between 1 and 65535") + + +def validate_https_port(value, module): + if not 1 <= value <= 65535: + module.fail_json(msg="http_port must be between 1 and 65535") + + +def validate_local_http_port(value, module): + if not 1 <= value <= 65535: + module.fail_json(msg="http_port must be between 1 and 65535") + + +def validate_vrf(value, module): + out = run_commands(module, ["show vrf"]) + configured_vrfs = [] + lines = out[0].strip().splitlines()[3:] + for line in lines: + if not line: + continue + splitted_line = re.split(r"\s{2,}", line.strip()) + if len(splitted_line) > 2: + configured_vrfs.append(splitted_line[0]) + + configured_vrfs.append("default") + if value not in configured_vrfs: + module.fail_json( + msg="vrf `%s` is not configured on the system" % value, + ) + + +def map_obj_to_commands(updates, module, warnings): + commands = list() + want, have = updates + + def needs_update(x): + return want.get(x) is not None and (want.get(x) != have.get(x)) + + def add(cmd): + if "management api http-commands" not in commands: + commands.insert(0, "management api http-commands") + commands.append(cmd) + + if any((needs_update("http"), needs_update("http_port"))): + if want["http"] is False: + add("no protocol http") + else: + if have["http"] is False and want["http"] in (False, None): + warnings.append( + "protocol http is not enabled, not configuring http port value", + ) + else: + port = want["http_port"] or 80 + add("protocol http port %s" % port) + + if any((needs_update("https"), needs_update("https_port"))): + if want["https"] is False: + add("no protocol https") + else: + if have["https"] is False and want["https"] in (False, None): + warnings.append( + "protocol https is not enabled, not configuring https port value", + ) + else: + port = want["https_port"] or 443 + add("protocol https port %s" % port) + + if any((needs_update("local_http"), needs_update("local_http_port"))): + if want["local_http"] is False: + add("no protocol http localhost") + else: + if have["local_http"] is False and want["local_http"] in ( + False, + None, + ): + warnings.append( + "protocol local_http is not enabled, not configuring local_http port value", + ) + else: + port = want["local_http_port"] or 8080 + add("protocol http localhost port %s" % port) + + if any((needs_update("socket"), needs_update("socket"))): + if want["socket"] is False: + add("no protocol unix-socket") + else: + add("protocol unix-socket") + if needs_update("state"): + if want["state"] == "stopped": + add("shutdown") + elif want["state"] == "started": + add("no shutdown") + + if needs_update("vrf"): + add("vrf %s" % want["vrf"]) + # switching operational vrfs here + # need to add the desired state as well + if want["state"] == "stopped": + add("shutdown") + elif want["state"] == "started": + add("no shutdown") + + return commands + + +def parse_state(data): + if data[0]["enabled"]: + return "started" + else: + return "stopped" + + +def map_config_to_obj(module): + out = run_commands(module, ["show management api http-commands | json"]) + return { + "http": out[0]["httpServer"]["configured"], + "http_port": out[0]["httpServer"]["port"], + "https": out[0]["httpsServer"]["configured"], + "https_port": out[0]["httpsServer"]["port"], + "local_http": out[0]["localHttpServer"]["configured"], + "local_http_port": out[0]["localHttpServer"]["port"], + "socket": out[0]["unixSocketServer"]["configured"], + "vrf": out[0]["vrf"] or "default", + "state": parse_state(out), + } + + +def map_params_to_obj(module): + obj = { + "http": module.params["http"], + "http_port": module.params["http_port"], + "https": module.params["https"], + "https_port": module.params["https_port"], + "local_http": module.params["local_http"], + "local_http_port": module.params["local_http_port"], + "socket": module.params["socket"], + "vrf": module.params["vrf"], + "state": module.params["state"], + } + + for key, value in iteritems(obj): + if value: + validator = globals().get("validate_%s" % key) + if validator: + validator(value, module) + + return obj + + +def verify_state(updates, module): + want, have = updates + + invalid_state = [ + ("http", "httpServer"), + ("https", "httpsServer"), + ("local_http", "localHttpServer"), + ("socket", "unixSocketServer"), + ] + + timeout = module.params["timeout"] + state = module.params["state"] + + while invalid_state: + out = run_commands( + module, + ["show management api http-commands | json"], + ) + for index, item in enumerate(invalid_state): + want_key, eapi_key = item + if want[want_key] is not None: + if want[want_key] == out[0][eapi_key]["running"]: + del invalid_state[index] + elif state == "stopped": + if not out[0][eapi_key]["running"]: + del invalid_state[index] + else: + del invalid_state[index] + time.sleep(1) + timeout -= 1 + if timeout == 0: + module.fail_json( + msg="timeout expired before eapi running state changed", + ) + + +def collect_facts(module, result): + out = run_commands(module, ["show management api http-commands | json"]) + facts = dict(eos_eapi_urls=dict()) + for each in out[0]["urls"]: + intf, url = each.split(":", 1) + key = str(intf).strip() + if key not in facts["eos_eapi_urls"]: + facts["eos_eapi_urls"][key] = list() + facts["eos_eapi_urls"][key].append(str(url).strip()) + result["ansible_facts"] = facts + + +def main(): + """main entry point for module execution""" + argument_spec = dict( + http=dict(aliases=["enable_http"], type="bool"), + http_port=dict(type="int"), + https=dict(aliases=["enable_https"], type="bool"), + https_port=dict(type="int"), + local_http=dict(aliases=["enable_local_http"], type="bool"), + local_http_port=dict(type="int"), + socket=dict(aliases=["enable_socket"], type="bool"), + timeout=dict(type="int", default=30), + vrf=dict(default="default"), + config=dict(), + state=dict(default="started", choices=["stopped", "started"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + result = {"changed": False} + + warnings = list() + if module.params["config"]: + warnings.append( + "config parameter is no longer necessary and will be ignored", + ) + + want = map_params_to_obj(module) + have = map_config_to_obj(module) + + commands = map_obj_to_commands((want, have), module, warnings) + result["commands"] = commands + + if commands: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + if result["changed"]: + verify_state((want, have), module) + + collect_facts(module, result) + + if warnings: + result["warnings"] = warnings + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_facts.py b/ansible_collections/arista/eos/plugins/modules/eos_facts.py new file mode 100644 index 000000000..f404d54bb --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_facts.py @@ -0,0 +1,210 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_facts +author: +- Peter Sprygada (@privateip) +- Nathaniel Case (@Qalthos) +short_description: Collect facts from remote devices running Arista EOS +description: +- Collects facts from Arista devices running the EOS operating system. This module + places the facts gathered in the fact tree keyed by the respective resource name. 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 +options: + gather_subset: + description: + - When supplied, this argument will restrict the facts collected to a given subset. Possible + values for this argument include C(all), C(hardware), C(config), C(legacy), C(interfaces), and C(min). + Can specify a list of values to include a larger subset. Values can also be used + with an initial C(!) to specify that a specific subset should not be collected. + required: false + type: list + elements: str + default: 'min' + 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(!) to specify that a specific subset should + not be collected. Values can also be used with an initial C(!) to specify + that a specific subset should not be collected. Valid subsets are 'all', 'interfaces', + 'l2_interfaces', 'l3_interfaces', 'lacp', 'lacp_interfaces', 'lag_interfaces', + 'lldp_global', 'lldp_interfaces', 'vlans', 'acls'. + required: false + type: list + elements: str + available_network_resources: + description: When 'True' a list of network resources for which resource modules are available will be provided. + type: bool + default: false +""" + +EXAMPLES = """ +- name: Gather all legacy facts +- arista.eos.eos_facts: + gather_subset: all + +- name: Gather only the config and default facts + arista.eos.eos_facts: + gather_subset: + - config + +- name: Do not gather hardware facts + arista.eos.eos_facts: + gather_subset: + - '!hardware' + +- name: Gather legacy and resource facts + arista.eos.eos_facts: + gather_subset: all + gather_network_resources: all + +- name: Gather only the interfaces resource facts and no legacy facts +- arista.eos.eos_facts: + gather_subset: + - '!all' + - '!min' + gather_network_resources: + - interfaces + +- name: Gather all resource facts and minimal legacy facts + arista.eos.eos_facts: + gather_subset: min + gather_network_resources: all +""" + +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_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_fqdn: + description: The fully qualified domain name of the device + returned: always + type: str +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_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 LLDP neighbors from the remote device + returned: when interfaces is configured + type: dict +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.facts.facts import ( + FactsArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.facts.facts import ( + FACT_RESOURCE_SUBSETS, + Facts, +) + + +def main(): + """ + Main entry point for module execution + + :returns: ansible_facts + """ + argument_spec = FactsArgs.argument_spec + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + warnings = [] + ansible_facts = {} + if module.params.get("available_network_resources"): + ansible_facts["available_network_resources"] = sorted( + FACT_RESOURCE_SUBSETS.keys(), + ) + result = Facts(module).get_facts() + additional_facts, additional_warnings = result + ansible_facts.update(additional_facts) + warnings.extend(additional_warnings) + + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_hostname.py b/ansible_collections/arista/eos/plugins/modules/eos_hostname.py new file mode 100644 index 000000000..dddadb71a --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_hostname.py @@ -0,0 +1,333 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for eos_hostname +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: eos_hostname +short_description: Manages hostname resource module +description: This module configures and manages the attribute of hostname on Arista + EOS platforms. +version_added: 4.1.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.60M +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: A dictionary of hostname options + type: dict + suboptions: + hostname: + description: + - The system's hostname + 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 EOS device by + executing the command B(show running-config | section hostname). + - 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 states I(merged), I(replaced) and I(overridden) have identical + behaviour for this module. + - 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 ^hostname) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" + +EXAMPLES = """ + +# Using state: merged +# Before state: +# ------------- +# test#show running-config | section ^hostname +# hostname eos +# Merged play: +# ------------ +- name: Apply the provided configuration + arista.eos.eos_hostname: + config: + hostname: eos + state: merged +# Commands Fired: +# --------------- +# "commands": [ +# "hostname eos", +# ], +# After state: +# ------------ +# test#show running-config | section ^hostname +# hostname eos + + +# Using state: deleted +# Before state: +# ------------- +# test#show running-config | section ^hostname +# hostname eosTest +# Deleted play: +# ------------- +- name: Remove all existing configuration + arista.eos.eos_hostname: + state: deleted +# Commands Fired: +# --------------- +# "commands": [ +# "no hostname eosTest", +# ], +# After state: +# ------------ +# test#show running-config | section ^hostname +# hostname eos + + +# Using state: overridden +# Before state: +# ------------- +# test#show running-config | section ^hostname +# hostname eos +# Overridden play: +# ---------------- +- name: Override commands with provided configuration + arista.eos.eos_hostname: + config: + hostname: eosTest + state: overridden +# Commands Fired: +# --------------- +# "commands": [ +# "hostname eosTest", +# ], +# After state: +# ------------ +# test#show running-config | section ^hostname +# hostname eosTest + + +# Using state: replaced +# Before state: +# ------------- +# test#show running-config | section ^hostname +# hostname eosTest +# Replaced play: +# -------------- +- name: Replace commands with provided configuration + arista.eos.eos_hostname: + config: + hostname: eosTest + state: replaced +# Commands Fired: +# --------------- +# "commands": [], +# After state: +# ------------ +# test#show running-config | section ^hostname +# hostname eosTest + +# Using state: gathered +# Before state: +# ------------- +#test#show running-config | section ^hostname +# hostname eosTest +# Gathered play: +# -------------- +- name: Gather listed hostname config + arista.eos.eos_hostname: + state: gathered +# Module Execution Result: +# ------------------------ +# "gathered": { +# "hostname": "eosTest" +# }, + +# Using state: rendered +# Rendered play: +# -------------- +- name: Render the commands for provided configuration + arista.eos.eos_hostname: + config: + hostname: eosTest + state: rendered +# Module Execution Result: +# ------------------------ +# "rendered": [ +# "hostname eosTest", +# ] + +# Using state: parsed +# File: parsed.cfg +# ---------------- +# hostname eosTest +# Parsed play: +# ------------ +- name: Parse the provided configuration with the existing running configuration + arista.eos.eos_hostname: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed +# Module Execution Result: +# ------------------------ +# "parsed": { +# "hostname": "eosTest" +# } +""" + +RETURN = """ +before: + 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: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + 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: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - hostname eos +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - hostname eos +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. +""" + +RETURN = """ +before: + 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: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + 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: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - hostname eost_test +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - hostname eost_test +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.arista.eos.plugins.module_utils.network.eos.argspec.hostname.hostname import ( + HostnameArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.hostname.hostname import ( + Hostname, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=HostnameArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Hostname(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_interfaces.py new file mode 100644 index 000000000..c7d0ae021 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_interfaces.py @@ -0,0 +1,415 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_interfaces +short_description: Interfaces resource module +description: +- This module manages the interface attributes of Arista EOS interfaces. +version_added: 1.0.0 +author: +- Nathaniel Case (@qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: The provided configuration + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface, e.g. GigabitEthernet1. + type: str + required: True + description: + description: + - Interface description + type: str + duplex: + description: + - Interface link status. Applicable for Ethernet interfaces only. + - Values other than C(auto) must also set I(speed). + - Ignored when I(speed) is set above C(1000). + type: str + enabled: + default: true + 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 + mtu: + description: + - MTU for a specific interface. Must be an even number between 576 and 9216. + Applicable for Ethernet interfaces only. + type: int + speed: + description: + - Interface link speed. Applicable for Ethernet interfaces only. + type: str + mode: + description: + - Manage Layer2 or Layer3 state of the interface. Applicable for Ethernet + and port channel interfaces only. + choices: + - layer2 + - layer3 + 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 EOS 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 + - parsed + - rendered + - gathered + default: merged + description: + - The state of the configuration after module completion. + type: str + +""" + +EXAMPLES = """ + +# Using merged + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# description "Interface 1" +# ! +# interface Ethernet2 +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +- name: Merge provided configuration with device configuration + arista.eos.eos_interfaces: + config: + - name: Ethernet1 + enabled: true + mode: layer3 + - name: Ethernet2 + description: Configured by Ansible + enabled: false + state: merged + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# description "Interface 1" +# no switchport +# ! +# interface Ethernet2 +# description "Configured by Ansible" +# shutdown +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +# Using replaced + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# description "Interface 1" +# ! +# interface Ethernet2 +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +- name: Replaces device configuration of listed interfaces with provided configuration + arista.eos.eos_interfaces: + config: + - name: Ethernet1 + enabled: true + - name: Ethernet2 + description: Configured by Ansible + enabled: false + state: replaced + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# description "Configured by Ansible" +# shutdown +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +# Using overridden + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# description "Interface 1" +# ! +# interface Ethernet2 +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +- name: Overrides all device configuration with provided configuration + arista.eos.eos_interfaces: + config: + - name: Ethernet1 + enabled: true + - name: Ethernet2 + description: Configured by Ansible + enabled: false + state: overridden + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# description "Configured by Ansible" +# shutdown +# ! +# interface Management1 +# ip address dhcp +# ! + +# Using deleted + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# description "Interface 1" +# no switchport +# ! +# interface Ethernet2 +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +- name: Delete or return interface parameters to default settings + arista.eos.eos_interfaces: + config: + - name: Ethernet1 + state: deleted + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# ! +# interface Management1 +# description "Management interface" +# ip address dhcp +# ! + +# Using rendered + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_interfaces: + config: + - name: Ethernet1 + enabled: true + mode: layer3 + - name: Ethernet2 + description: Configured by Ansible + enabled: false + state: merged + +# Output: +# ------------ + +# - "interface Ethernet1" +# - "description "Interface 1"" +# - "no swithcport" +# - "interface Ethernet2" +# - "description "Configured by Ansible"" +# - "shutdown" +# - "interface Management1" +# - "description "Management interface"" +# - "ip address dhcp" + +# Using parsed +# parsed.cfg + +# interface Ethernet1 +# description "Interface 1" +# ! +# interface Ethernet2 +# description "Configured by Ansible" +# shutdown +# ! + +- name: Use parsed to convert native configs to structured data + arista.eos.interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output +# parsed: +# - name: Ethernet1 +# enabled: True +# mode: layer2 +# - name: Ethernet2 +# description: 'Configured by Ansible' +# enabled: False +# mode: layer2 + +# Using gathered: + +# Existing config on the device +# ----------------------------- +# interface Ethernet1 +# description "Interface 1" +# ! +# interface Ethernet2 +# description "Configured by Ansible" +# shutdown +# ! + +- name: Gather interfaces facts from the device + arista.eos.interfaces: + state: gathered + +# output +# gathered: +# - name: Ethernet1 +# enabled: True +# mode: layer2 +# - name: Ethernet2 +# description: 'Configured by Ansible' +# enabled: False +# mode: layer2 +""" + +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: ['interface Ethernet2', 'shutdown', 'speed 10full'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.interfaces.interfaces import ( + InterfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_l2_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_l2_interfaces.py new file mode 100644 index 000000000..863a2cf2a --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_l2_interfaces.py @@ -0,0 +1,430 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_l2_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_l2_interfaces +short_description: L2 interfaces resource module +description: This module provides declarative management of Layer-2 interface on Arista + EOS devices. +version_added: 1.0.0 +author: Nathaniel Case (@qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A dictionary of Layer-2 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of interface, e.g. Ethernet1. + 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 + trunk: + description: + - Switchport mode trunk command to configure the interface as a Layer 2 trunk. + type: dict + suboptions: + native_vlan: + description: + - Native VLAN to be configured in trunk port. It is used as the trunk + native VLAN ID. + type: int + trunk_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 + mode: + description: + - Mode in which interface needs to be configured. + - Access mode is not shown in interface facts, so idempotency will not be + maintained for switchport mode access and every time the output will come + as changed=True. + 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 EOS 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 + - parsed + - rendered + - gathered + default: merged + description: + - The state of the configuration after module completion + type: str + +""" + +EXAMPLES = """ + +# Using merged + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport access vlan 20 +# ! +# interface Ethernet2 +# switchport trunk native vlan 20 +# switchport mode trunk +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +- name: Merge provided configuration with device configuration. + arista.eos.eos_l2_interfaces: + config: + - name: Ethernet1 + mode: trunk + trunk: + native_vlan: 10 + - name: Ethernet2 + mode: access + access: + vlan: 30 + state: merged + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport trunk native vlan 10 +# switchport mode trunk +# ! +# interface Ethernet2 +# switchport access vlan 30 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +# Using replaced + +# Before state: +# ------------- +# +# veos2#show running-config | s int +# interface Ethernet1 +# switchport access vlan 20 +# ! +# interface Ethernet2 +# switchport trunk native vlan 20 +# switchport mode trunk +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +- name: Replace device configuration of specified L2 interfaces with provided configuration. + arista.eos.eos_l2_interfaces: + config: + - name: Ethernet1 + mode: trunk + trunk: + native_vlan: 20 + trunk_allowed_vlans: 5-10, 15 + state: replaced + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport trunk native vlan 20 +# switchport trunk allowed vlan 5-10,15 +# switchport mode trunk +# ! +# interface Ethernet2 +# switchport trunk native vlan 20 +# switchport mode trunk +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +# Using overridden + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport access vlan 20 +# ! +# interface Ethernet2 +# switchport trunk native vlan 20 +# switchport mode trunk +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +- name: Override device configuration of all L2 interfaces on device with provided + configuration. + arista.eos.eos_l2_interfaces: + config: + - name: Ethernet2 + mode: access + access: + vlan: 30 + state: overridden + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# switchport access vlan 30 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +# Using deleted + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport access vlan 20 +# ! +# interface Ethernet2 +# switchport trunk native vlan 20 +# switchport mode trunk +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config +# ! + +- name: Delete EOS L2 interfaces as in given arguments. + arista.eos.eos_l2_interfaces: + config: + - name: Ethernet1 + - name: Ethernet2 + state: deleted + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +# using rendered + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_l2_interfaces: + config: + - name: Ethernet1 + mode: trunk + trunk: + native_vlan: 10 + - name: Ethernet2 + mode: access + access: + vlan: 30 + state: merged + +# Output : +# ------------ +# +# - "interface Ethernet1" +# - "switchport trunk native vlan 10" +# - "switchport mode trunk" +# - "interface Ethernet2" +# - "switchport access vlan 30" +# - "interface Management1" +# - "ip address dhcp" +# - "ipv6 address auto-config" + + +# using parsed + +# parsed.cfg + +# interface Ethernet1 +# switchport trunk native vlan 10 +# switchport mode trunk +# ! +# interface Ethernet2 +# switchport access vlan 30 +# ! + +- name: Use parsed to convert native configs to structured data + arista.eos.l2_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: +# parsed: +# - name: Ethernet1 +# mode: trunk +# trunk: +# native_vlan: 10 +# - name: Ethernet2 +# mode: access +# access: +# vlan: 30 + + +# Using gathered: +# Existing config on the device: +# +# veos#show running-config | section interface +# interface Ethernet1 +# switchport trunk native vlan 10 +# switchport mode trunk +# ! +# interface Ethernet2 +# switchport access vlan 30 +# ! + +- name: Gather interfaces facts from the device + arista.eos.l2_interfaces: + state: gathered +# output: +# gathered: +# - name: Ethernet1 +# mode: trunk +# trunk: +# native_vlan: 10 +# - name: Ethernet2 +# mode: access +# access: +# vlan: 30 + +""" + +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 Ethernet2', 'switchport access vlan 20'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.l2_interfaces.l2_interfaces import ( + L2_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = L2_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_l3_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_l3_interfaces.py new file mode 100644 index 000000000..93da7612c --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_l3_interfaces.py @@ -0,0 +1,412 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_l3_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_l3_interfaces +short_description: L3 interfaces resource module +description: This module provides declarative management of Layer 3 interfaces on + Arista EOS devices. +version_added: 1.0.0 +author: Nathaniel Case (@qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). + 'eos_l2_interfaces/eos_interfaces' should be used for preparing the interfaces , before applying L3 configurations using + this module (eos_l3_interfaces). +options: + config: + description: A dictionary of Layer 3 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface, i.e. Ethernet1. + type: str + required: true + ipv4: + description: + - List of IPv4 addresses to be set for the Layer 3 interface mentioned in + I(name) option. + type: list + elements: dict + suboptions: + address: + description: + - IPv4 address to be set in the format <ipv4 address>/<mask> eg. 192.0.2.1/24, + or C(dhcp) to query DHCP for an IP address. + type: str + secondary: + description: + - Whether or not this address is a secondary address. + type: bool + virtual: + description: + - Whether or not this address is a virtual address. + type: bool + ipv6: + description: + - List of IPv6 addresses to be set for the Layer 3 interface mentioned in + I(name) option. + type: list + elements: dict + suboptions: + address: + description: + - IPv6 address to be set in the address format is <ipv6 address>/<mask> + eg. 2001:db8:2201:1::1/64 or C(auto-config) to use SLAAC to chose an + address. + 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 EOS 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 of the configuration after module completion + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - gathered + - rendered + default: merged + +""" + +EXAMPLES = """ + +# Using deleted + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 192.0.2.12/24 +# ! +# interface Ethernet2 +# ipv6 address 2001:db8::1/64 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +- name: Delete L3 attributes of given interfaces. + arista.eos.eos_l3_interfaces: + config: + - name: Ethernet1 + - name: Ethernet2 + state: deleted + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ! +# interface Ethernet2 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + + +# Using merged + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 192.0.2.12/24 +# ! +# interface Ethernet2 +# ipv6 address 2001:db8::1/64 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +- name: Merge provided configuration with device configuration. + arista.eos.eos_l3_interfaces: + config: + - name: Ethernet1 + ipv4: + - address: 198.51.100.14/24 + - name: Ethernet2 + ipv4: + - address: 203.0.113.27/24 + state: merged + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 198.51.100.14/24 +# ! +# interface Ethernet2 +# ip address 203.0.113.27/24 +# ipv6 address 2001:db8::1/64 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + + +# Using overridden + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 192.0.2.12/24 +# ! +# interface Ethernet2 +# ipv6 address 2001:db8::1/64 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +- name: Override device configuration of all L2 interfaces on device with provided + configuration. + arista.eos.eos_l3_interfaces: + config: + - name: Ethernet1 + ipv6: + - address: 2001:db8:feed::1/96 + - name: Management1 + ipv4: + - address: dhcp + ipv6: auto-config + state: overridden + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ipv6 address 2001:db8:feed::1/96 +# ! +# interface Ethernet2 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + + +# Using replaced + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 192.0.2.12/24 +# ! +# interface Ethernet2 +# ipv6 address 2001:db8::1/64 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +- name: Replace device configuration of specified L2 interfaces with provided configuration. + arista.eos.eos_l3_interfaces: + config: + - name: Ethernet2 + ipv4: + - address: 203.0.113.27/24 + state: replaced + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 192.0.2.12/24 +# ! +# interface Ethernet2 +# ip address 203.0.113.27/24 +# ! +# interface Management1 +# ip address dhcp +# ipv6 address auto-config + +# Using parsed: + +# parsed.cfg +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 198.51.100.14/24 +# ! +# interface Ethernet2 +# ip address 203.0.113.27/24 +# ! + +- name: Use parsed to convert native configs to structured data + arista.eos.interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: + +# parsed: +# - name: Ethernet1 +# ipv4: +# - address: 198.51.100.14/24 +# - name: Ethernet2 +# ipv4: +# - address: 203.0.113.27/24 + +# Using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_l3_interfaces: + config: + - name: Ethernet1 + ipv4: + - address: 198.51.100.14/24 + - name: Ethernet2 + ipv4: + - address: 203.0.113.27/24 + state: rendered + +# Output +# ------------ +#rendered: +# - "interface Ethernet1" +# - "ip address 198.51.100.14/24" +# - "interface Ethernet2" +# - "ip address 203.0.113.27/24" + +# using gathered: + +# Native COnfig: +# veos#show running-config | section interface +# interface Ethernet1 +# ip address 198.51.100.14/24 +# ! +# interface Ethernet2 +# ip address 203.0.113.27/24 +# ! + +- name: Gather l3 interfaces facts from the device + arista.eos.l3_interfaces: + state: gathered + +# gathered: +# - name: Ethernet1 +# ipv4: +# - address: 198.51.100.14/24 +# - name: Ethernet2 +# ipv4: +# - address: 203.0.113.27/24 + + +""" +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 Ethernet2', 'ip address 192.0.2.12/24'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.l3_interfaces.l3_interfaces import ( + L3_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = L3_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lacp.py b/ansible_collections/arista/eos/plugins/modules/eos_lacp.py new file mode 100644 index 000000000..d79ca8805 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lacp.py @@ -0,0 +1,247 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_lacp +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lacp +short_description: LACP resource module +description: +- This module manages Global Link Aggregation Control Protocol (LACP) on Arista EOS + devices. +version_added: 1.0.0 +author: Nathaniel Case (@Qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: LACP global options. + type: dict + suboptions: + system: + description: LACP system options. + type: dict + suboptions: + priority: + description: + - The system priority to use in LACP negotiations. + - Lower value is higher priority. + - 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 EOS device by + executing the command B(show running-config | section ^lacp). + - 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 of the configuration after module completion. + type: str + choices: + - merged + - replaced + - deleted + - parsed + - rendered + - gathered + default: merged + +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# veos# show running-config | include lacp +# lacp system-priority 10 + +- name: Merge provided global LACP attributes with device attributes + arista.eos.eos_lacp: + config: + system: + priority: 20 + state: merged + +# After state: +# ------------ +# veos# show running-config | include lacp +# lacp system-priority 20 +# + + +# Using replaced + +# Before state: +# ------------- +# veos# show running-config | include lacp +# lacp system-priority 10 + +- name: Replace device global LACP attributes with provided attributes + arista.eos.eos_lacp: + config: + system: + priority: 20 + state: replaced + +# After state: +# ------------ +# veos# show running-config | include lacp +# lacp system-priority 20 +# + + +# Using deleted + +# Before state: +# ------------- +# veos# show running-config | include lacp +# lacp system-priority 10 + +- name: Delete global LACP attributes + arista.eos.eos_lacp: + state: deleted + +# After state: +# ------------ +# veos# show running-config | include lacp +# + +#Using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_lacp: + config: + system: + priority: 20 + state: rendered + +# Output: +# ------------ +# rendered: +# - "lacp system-priority 20" +# + +# Using parsed: + +# parsed.cfg +# lacp system-priority 20 + +- name: Use parsed to convert native configs to structured data + arista.eos.eos_lacp: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: +# parsed: +# system: +# priority: 20 + +# Using gathered: +# nathive config: +# ------------- +# lacp system-priority 10 + +- name: Gather lacp facts from the device + arista.eos.eos_lacp: + state: gathered + +# Output: +# gathered: +# system: +# priority: 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: ['lacp system-priority 10'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.lacp.lacp import ( + LacpArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lacp(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lacp_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_lacp_interfaces.py new file mode 100644 index 000000000..47a3662e8 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lacp_interfaces.py @@ -0,0 +1,340 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_lacp_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lacp_interfaces +short_description: LACP interfaces resource module +description: +- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces + on Arista EOS devices. +version_added: 1.0.0 +author: Nathaniel Case (@Qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A dictionary of LACP interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface (i.e. Ethernet1). + type: str + port_priority: + description: + - LACP port priority for the interface. Range 1-65535. + type: int + timer: + description: + - Rate at which PDUs are sent by LACP. At fast rate LACP is transmitted once + every 1 second. At normal rate LACP is transmitted every 30 seconds after + the link is bundled. + type: str + choices: + - fast + - normal + aliases: + - rate + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device by + executing the command B(show running-config | section ^interfaces). + - 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 of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - rendered + - gathered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# interface Ethernet2 +# lacp rate fast + +- name: Merge provided configuration with device configuration + arista.eos.eos_lacp_interfaces: + config: + - name: Ethernet1 + rate: fast + - name: Ethernet2 + rate: normal + state: merged + +# +# ----------- +# After state +# ----------- +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# lacp rate fast +# interface Ethernet2 + + +# Using replaced +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# interface Ethernet2 +# lacp rate fast + +- name: Replace existing LACP configuration of specified interfaces with provided + configuration + arista.eos.eos_lacp_interfaces: + config: + - name: Ethernet1 + rate: fast + state: replaced + +# +# ----------- +# After state +# ----------- +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp rate fast +# interface Ethernet2 +# lacp rate fast + + +# Using overridden +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# interface Ethernet2 +# lacp rate fast + +- name: Override the LACP configuration of all the interfaces with provided configuration + arista.eos.eos_lacp_interfaces: + config: + - name: Ethernet1 + rate: fast + state: overridden + +# +# ----------- +# After state +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp rate fast +# interface Ethernet2 + + +# Using deleted +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# interface Ethernet2 +# lacp rate fast + +- name: Delete LACP attributes of given interfaces (or all interfaces if none specified). + arista.eos.eos_lacp_interfaces: + state: deleted + +# +# ----------- +# After state +# ----------- +# +# veos#show run | section ^interface +# interface Ethernet1 +# interface Ethernet2 + +# using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_lacp_interfaces: + config: + - name: Ethernet1 + rate: fast + - name: Ethernet2 + rate: normal + state: rendered + +# +# ----------- +# Output +# ----------- +# rendered: +# - "interface Ethernet1" +# - "lacp rate fast" + +# Using parsed: + +# parsed.cfg: +# "interface Ethernet1" +# "lacp rate fast" +# "interface Ethernet2" + +- name: Use parsed to convert native configs to structured data + arista.eos.eos_lacp_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: +# parsed: +# - name: Ethernet1 +# rate: fast +# - name: Ethernet2 +# rate: normal + +# Using gathered: +# native config: +# veos#show run | section ^interface +# interface Ethernet1 +# lacp port-priority 30 +# interface Ethernet2 +# lacp rate fast + +- name: Gather LACP facts from the device + arista.eos.eos_lacp_interfaces: + state: gathered + +# Output: +# gathered: +# - name: Ethernet1 +# - name: Ethernet2 +# rate: fast + +""" +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 Ethernet1', 'lacp rate fast'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.lacp_interfaces.lacp_interfaces import ( + Lacp_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lacp_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lag_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_lag_interfaces.py new file mode 100644 index 000000000..471652772 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lag_interfaces.py @@ -0,0 +1,342 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_lag_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lag_interfaces +short_description: LAG interfaces resource module +description: This module manages attributes of link aggregation groups on Arista EOS + devices. +version_added: 1.0.0 +author: Nathaniel Case (@Qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A list of link aggregation group configurations. + type: list + elements: dict + suboptions: + name: + description: + - Name of the port-channel interface of the link aggregation group (LAG) e.g., + Port-Channel5. + type: str + required: true + members: + description: + - Ethernet interfaces that are part of the group. + type: list + elements: dict + suboptions: + member: + description: + - Name of ethernet interface that is a member of the LAG. + type: str + mode: + description: + - LAG mode for this interface. + type: str + choices: + - 'active' + - 'on' + - 'passive' + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device by + executing the command B(show running-config | section interfaces). + - 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 of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + +""" + +EXAMPLES = """ + +# Using merged + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 + +- name: Merge provided LAG attributes with existing device configuration + arista.eos.eos_lag_interfaces: + config: + - name: 5 + members: + - member: Ethernet2 + mode: on + state: merged + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 +# channel-group 5 mode on + + +# Using replaced + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 + +- name: Replace all device configuration of specified LAGs with provided configuration + arista.eos.eos_lag_interfaces: + config: + - name: 5 + members: + - member: Ethernet2 + mode: on + state: replaced + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# interface Ethernet2 +# channel-group 5 mode on + + +# Using overridden + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 + +- name: Override all device configuration of all LAG attributes with provided configuration + arista.eos.eos_lag_interfaces: + config: + - name: 10 + members: + - member: Ethernet2 + mode: on + state: overridden + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# interface Ethernet2 +# channel-group 10 mode on + + +# Using deleted + +# Before state: +# ------------- +# +# veos#show running-config | section interface +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 +# channel-group 5 mode on + +- name: Delete LAG attributes of the given interfaces. + arista.eos.eos_lag_interfaces: + config: + - name: 5 + members: + - member: Ethernet1 + state: deleted + +# After state: +# ------------ +# +# veos#show running-config | section interface +# interface Ethernet1 +# interface Ethernet2 +# channel-group 5 mode on + +# Using parsed: + +# parsed.cfg +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 +# channel-group 5 mode on + +- name: Use parsed to convert native configs to structured data + arista.eos.lag_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: +# parsed: +# - name: 5 +# members: +# - member: Ethernet2 +# mode: on +# - member: Ethernet1 +# mode: on + +# using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_lag_interfaces: + config: + - name: 5 + members: + - member: Ethernet2 + mode: on + - member: Ethernet1 + mode: on + state: rendered +# ----------- +# Output +# ----------- +# +# rendered: + +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 +# channel-group 5 mode on + + +# Using gathered: + +# native config: +# interface Ethernet1 +# channel-group 5 mode on +# interface Ethernet2 +# channel-group 5 mode on + +- name: Gather lldp_global facts from the device + arista.eos.lldp_global: + state: gathered + +# Output: +# gathered: +# - name: 5 +# members: +# - member: Ethernet2 +# mode: on +# - member: Ethernet1 +# mode: on + +""" + +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: ['command 1', 'command 2', 'command 3'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.lag_interfaces.lag_interfaces import ( + Lag_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lag_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lldp.py b/ansible_collections/arista/eos/plugins/modules/eos_lldp.py new file mode 100644 index 000000000..86a3cfba8 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lldp.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lldp +author: Ganesh Nalawade (@ganeshrn) +short_description: Manage LLDP configuration on Arista EOS network devices +description: +- This module provides declarative management of LLDP service on Arista EOS network + devices. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +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 + type: str + choices: + - present + - absent + - enabled + - disabled +""" + +EXAMPLES = """ +- name: Enable LLDP service + arista.eos.eos_lldp: + state: present + +- name: Disable LLDP service + arista.eos.eos_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.arista.eos.plugins.module_utils.network.eos.eos import ( + get_config, + load_config, +) + + +def has_lldp(module): + config = get_config(module, flags=["| section lldp"]) + + is_lldp_enable = False + if "no lldp run" not in config: + 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"], + ), + ) + + 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: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lldp_global.py b/ansible_collections/arista/eos/plugins/modules/eos_lldp_global.py new file mode 100644 index 000000000..a98535c66 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lldp_global.py @@ -0,0 +1,347 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_lldp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lldp_global +short_description: LLDP resource module +description: +- This module manages Global Link Layer Discovery Protocol (LLDP) settings on Arista + EOS devices. +version_added: 1.0.0 +author: Nathaniel Case (@Qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: The provided global LLDP configuration. + type: dict + suboptions: + holdtime: + description: + - Specifies the holdtime (in sec) to be sent in packets. + type: int + reinit: + description: + - Specifies the delay (in sec) for LLDP initialization on any interface. + type: int + timer: + description: + - Specifies the rate at which LLDP packets are sent (in sec). + type: int + tlv_select: + description: + - Specifies the LLDP TLVs to enable or disable. + type: dict + suboptions: + link_aggregation: + description: + - Enable or disable link aggregation TLV. + type: bool + management_address: + description: + - Enable or disable management address TLV. + type: bool + max_frame_size: + description: + - Enable or disable maximum frame size TLV. + type: bool + port_description: + description: + - Enable or disable port description TLV. + type: bool + system_capabilities: + description: + - Enable or disable system capabilities TLV. + type: bool + system_description: + description: + - Enable or disable system description TLV. + type: bool + system_name: + description: + - Enable or disable 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 EOS 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 of the configuration after module completion. + type: str + choices: + - merged + - replaced + - deleted + - rendered + - gathered + - parsed + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# ------------ +# Before State +# ------------ +# +# veos# show run | section lldp +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select system-description + +- name: Merge provided LLDP configuration with the existing configuration + arista.eos.eos_lldp_global: + config: + holdtime: 100 + tlv_select: + management_address: false + port_description: false + system_description: true + state: merged + +# ----------- +# After state +# ----------- +# +# veos# show run | section lldp +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select port-description + + +# Using replaced +# +# ------------ +# Before State +# ------------ +# +# veos# show run | section lldp +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select system-description + +- name: Replace existing LLDP device configuration with provided configuration + arista.eos.eos_lldp_global: + config: + holdtime: 100 + tlv_select: + management_address: false + port_description: false + system_description: true + state: replaced + +# ----------- +# After state +# ----------- +# +# veos# show run | section lldp +# lldp holdtime 100 +# no lldp tlv-select management-address +# no lldp tlv-select port-description + + +# Using deleted +# +# ------------ +# Before State +# ------------ +# +# veos# show run | section lldp +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select system-description + +- name: Delete existing LLDP configurations from the device + arista.eos.eos_lldp_global: + state: deleted + +# ----------- +# After state +# ----------- +# +# veos# show run | section ^lldp + +# Using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_lldp_global: + config: + holdtime: 100 + tlv_select: + management_address: false + port_description: false + system_description: true + state: rendered + +# ----------- +# Output +# ----------- +# +# rendered: +# - "lldp holdtime 100" +# - "no lldp tlv-select management-address" +# - "no lldp tlv-select port-description" + +# Using parsed + +# parsed.cfg + +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select system-description + +- name: Use parsed to convert native configs to structured data + arista.eos.lldp_global: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# ----------- +# Output +# ----------- + +# parsed: +# holdtime: 100 +# timer 3000 +# reinit 5 +# tlv_select: +# management_address: False +# port_description: False +# system_description: True + +# Using gathered: +# native config: +# lldp timer 3000 +# lldp holdtime 100 +# lldp reinit 5 +# no lldp tlv-select management-address +# no lldp tlv-select system-description + + +- name: Gather lldp_global facts from the device + arista.eos.lldp_global: + state: gathered + +# ----------- +# Output +# ----------- + +# gathered: +# holdtime: 100 +# timer 3000 +# reinit 5 +# tlv_select: +# management_address: False +# port_description: False +# system_description: True + +""" +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 100', 'no lldp timer', 'lldp tlv-select system-description'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.lldp_global.lldp_global import ( + Lldp_globalArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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", "overridden", ("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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lldp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_lldp_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_lldp_interfaces.py new file mode 100644 index 000000000..6b5aae118 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_lldp_interfaces.py @@ -0,0 +1,346 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_lldp_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_lldp_interfaces +short_description: LLDP interfaces resource module +description: +- This module manages Link Layer Discovery Protocol (LLDP) attributes of interfaces + on Arista EOS devices. +version_added: 1.0.0 +author: Nathaniel Case (@Qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A dictionary of LLDP interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface (i.e. Ethernet1). + type: str + receive: + description: + - Enable/disable LLDP RX on an interface. + type: bool + transmit: + description: + - Enable/disable LLDP TX on an interface. + 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 EOS 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 of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - gathered + - rendered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp receive +# interface Ethernet2 +# no lldp transmit + +- name: Merge provided configuration with running configuration + arista.eos.eos_lldp_interfaces: + config: + - name: Ethernet1 + transmit: false + - name: Ethernet2 + transmit: false + state: merged + +# +# ------------ +# After state +# ------------ +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp transmit +# no lldp receive +# interface Ethernet2 +# no lldp transmit + + +# Using replaced +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp receive +# interface Ethernet2 +# no lldp transmit + +- name: Replace existing LLDP configuration of specified interfaces with provided + configuration + arista.eos.eos_lldp_interfaces: + config: + - name: Ethernet1 + transmit: false + state: replaced + +# +# ------------ +# After state +# ------------ +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp transmit +# interface Ethernet2 +# no lldp transmit + + +# Using overridden +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp receive +# interface Ethernet2 +# no lldp transmit + +- name: Override the LLDP configuration of all the interfaces with provided configuration + arista.eos.eos_lldp_interfaces: + config: + - name: Ethernet1 + transmit: false + state: overridden + +# +# ------------ +# After state +# ------------ +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp transmit +# interface Ethernet2 + + +# Using deleted +# +# +# ------------ +# Before state +# ------------ +# +# +# veos#show run | section ^interface +# interface Ethernet1 +# no lldp receive +# interface Ethernet2 +# no lldp transmit + +- name: Delete LLDP configuration of specified interfaces (or all interfaces if none + are specified) + arista.eos.eos_lldp_interfaces: + state: deleted + +# +# ------------ +# After state +# ------------ +# +# veos#show run | section ^interface +# interface Ethernet1 +# interface Ethernet2 + +# using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_lldp_interfaces: + config: + - name: Ethernet1 + transmit: false + - name: Ethernet2 + transmit: false + state: rendered + +# +# ------------ +# Output +# ------------ +# +# interface Ethernet1 +# no lldp transmit +# interface Ethernet2 +# no lldp transmit + +# Using parsed +# parsed.cfg + +# interface Ethernet1 +# no lldp transmit +# interface Ethernet2 +# no lldp transmit + + +- name: Use parsed to convert native configs to structured data + arista.eos.lldp_interfaces: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# ------------ +# Output +# ------------ + +# parsed: +# - name: Ethernet1 +# transmit: False +# - name: Ethernet2 +# transmit: False + +# Using gathered: + +# native config: +# interface Ethernet1 +# no lldp transmit +# interface Ethernet2 +# no lldp transmit + +- name: Gather lldp interfaces facts from the device + arista.eos.lldp_interfaces: + state: gathered + +# ------------ +# Output +# ------------ + +# gathered: +# - name: Ethernet1 +# transmit: False +# - name: Ethernet2 +# 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 Ethernet1', 'no lldp transmit'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.lldp_interfaces.lldp_interfaces import ( + Lldp_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lldp_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_logging.py b/ansible_collections/arista/eos/plugins/modules/eos_logging.py new file mode 100644 index 000000000..b2b9106f6 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_logging.py @@ -0,0 +1,505 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +# Copyright: (c) 2017, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +DOCUMENTATION = """ +module: eos_logging +author: Trishna Guha (@trishnaguha) +short_description: Manage logging on network devices +description: +- This module provides declarative management of logging on Arista Eos devices. +version_added: 1.0.0 +deprecated: + alternative: eos_logging_global + why: Updated module released with more functionality. + removed_at_date: '2024-01-01' +notes: +- Tested against Arista EOS 4.24.6F +options: + dest: + description: + - Destination of the logs. + choices: + - "on" + - host + - console + - monitor + - buffered + 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 10 to 2147483647 bytes. + type: int + facility: + description: + - Set logging facility. + type: str + level: + description: + - Set logging severity levels. + 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. + choices: + - "on" + - host + - console + - monitor + - buffered + 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 10 to 2147483647 bytes. + type: int + facility: + description: + - Set logging facility. + type: str + level: + description: + - Set logging severity levels. + choices: + - emergencies + - alerts + - critical + - errors + - warnings + - notifications + - informational + - debugging + type: str + state: + description: + - State of the logging configuration. + default: present + type: str + choices: + - present + - absent + state: + description: + - State of the logging configuration. + default: present + type: str + choices: + - present + - absent +""" + +EXAMPLES = """ +- name: configure host logging + arista.eos.eos_logging: + dest: host + name: 172.16.0.1 + state: present + +- name: remove host logging configuration + arista.eos.eos_logging: + dest: host + name: 172.16.0.1 + state: absent + +- name: configure console logging level and facility + arista.eos.eos_logging: + dest: console + facility: local7 + level: debugging + state: present + +- name: enable logging to all + arista.eos.eos_logging: + dest: on + +- name: configure buffer size + arista.eos.eos_logging: + dest: buffered + size: 5000 + +- name: Configure logging using aggregate + arista.eos.eos_logging: + aggregate: + - {dest: console, level: warnings} + - {dest: buffered, size: 480000} + state: present +""" + +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._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.common.validation import check_required_if +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + get_config, + load_config, +) + + +DEST_GROUP = ["on", "host", "console", "monitor", "buffered"] +LEVEL_GROUP = [ + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", +] + + +def validate_size(value, module): + if value: + if not int(10) <= value <= int(2147483647): + module.fail_json(msg="size must be between 10 and 2147483647") + else: + return value + + +def map_obj_to_commands(updates, module): + 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 state == "absent" and w in have: + if dest: + if dest == "host": + 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", + ) + + if facility: + commands.append("no logging facility {0}".format(facility)) + + if state == "present" and w not in have: + if facility: + present = False + + # Iterate over every dictionary in the 'have' list to check if + # similar configuration for facility exists or not + + for entry in have: + if not entry["dest"] and entry["facility"] == facility: + present = True + + if not present: + commands.append("logging facility {0}".format(facility)) + + if dest == "host": + commands.append("logging host {0}".format(name)) + + elif dest == "on": + commands.append("logging on") + + elif dest == "buffered" and size: + present = False + + # Deals with the following two cases: + # Case 1: logging buffered <size> <level> + # logging buffered <same-size> + # + # Case 2: Same buffered logging configuration + # already exists (i.e., both size & + # level are same) + + for entry in have: + if entry["dest"] == "buffered" and entry["size"] == size: + if not level or entry["level"] == level: + present = True + + if not present: + if size and level: + commands.append( + "logging buffered {0} {1}".format(size, level), + ) + else: + commands.append("logging buffered {0}".format(size)) + + else: + if dest: + dest_cmd = "logging {0}".format(dest) + if level: + dest_cmd += " {0}".format(level) + + commands.append(dest_cmd) + return commands + + +def parse_facility(line): + facility = None + match = re.search(r"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(r"logging buffered (\S+)", line, re.M) + if match: + try: + int_size = int(match.group(1)) + except ValueError: + int_size = None + + if int_size: + if isinstance(int_size, int): + size = str(match.group(1)) + else: + size = str(10) + + return size + + +def parse_name(line, dest): + name = None + if dest == "host": + match = re.search(r"logging host (\S+)", line, re.M) + if match: + name = match.group(1) + + return name + + +def parse_level(line, dest): + level = None + + if dest != "host": + # Line for buffer logging entry in running-config is of the form: + # logging buffered <size> <level> + + if dest == "buffered": + match = re.search(r"logging buffered (?:\d+) (\S+)", line, re.M) + + else: + match = re.search(r"logging {0} (\S+)".format(dest), line, re.M) + + if match: + if match.group(1) in LEVEL_GROUP: + level = match.group(1) + + return level + + +def map_config_to_obj(module): + obj = [] + + data = get_config(module, flags=["section logging"]) + + for line in data.split("\n"): + match = re.search(r"logging (\S+)", line, re.M) + + if match: + if match.group(1) in DEST_GROUP: + dest = match.group(1) + + else: + dest = None + + obj.append( + { + "dest": dest, + "name": parse_name(line, dest), + "size": parse_size(line, dest), + "facility": parse_facility(line), + "level": parse_level(line, dest), + }, + ) + + return obj + + +def parse_obj(obj, module): + 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 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] + + try: + check_required_if(required_if, item) + except TypeError as exc: + module.fail_json(to_text(exc)) + 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(10) + 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(10) + else: + module.params["size"] = None + + parse_obj(obj, module) + + return obj + + +def main(): + """main entry point for module execution""" + element_spec = dict( + dest=dict(choices=DEST_GROUP), + name=dict(), + size=dict(type="int"), + facility=dict(), + level=dict(choices=LEVEL_GROUP), + 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) + + aggregate_spec["state"].update(default="present") + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec), + ) + + argument_spec.update(element_spec) + + required_if = [("dest", "host", ["name"])] + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + + warnings = list() + + result = {"changed": False} + if warnings: + result["warnings"] = warnings + + have = map_config_to_obj(module) + want = map_params_to_obj(module, required_if=required_if) + + commands = map_obj_to_commands((want, have), module) + result["commands"] = commands + + if commands: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_logging_global.py b/ansible_collections/arista/eos/plugins/modules/eos_logging_global.py new file mode 100644 index 000000000..a614dcb8e --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_logging_global.py @@ -0,0 +1,942 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for eos_logging_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: eos_logging_global +short_description: Manages logging resource module +description: This module configures and manages the attributes of logging on Arista + EOS platforms. +version_added: 3.0.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6M +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: A dictionary of logging options + type: dict + suboptions: + buffered: + description: + - Set buffered logging parameters. + type: dict + suboptions: &message_options + severity: &sev + description: Severity level . + type: str + choices: + - emergencies + - alerts + - critical + - errors + - warnings + - notifications + - informational + - debugging + buffer_size: + description: Logging buffer size + type: int + console: + description: + - Set console logging parameters. + type: dict + suboptions: + severity: *sev + event: + description: Global events + type: str + choices: ["link-status", "port-channel", "spanning-tree"] + facility: + description: Set logging facility. + type: str + "choices": [ + "auth", + "cron", + "daemon", + "kern", + "local0", + "local1", + "local2", + "local3", + "local4", + "local5", + "local6", + "local7", + "lpr", + "mail", + "news", + "sys10", + "sys11", + "sys12", + "sys13", + "sys14", + "sys9", + "syslog", + "user", + "uucp", + ] + format: + description: Set logging format parameters + type: dict + suboptions: + hostname: + description: Specify hostname logging format. + type: str + timestamp: + description: Set timestamp logging parameters. + type: dict + suboptions: + high_resolution: + description: RFC3339 timestamps. + type: bool + traditional: + description: Traditional syslog timestamp format as specified in RFC3164. + type: dict + suboptions: + state: + description: When enabled traditional timestamp format is set. + type: str + choices: ["enabled", "disabled"] + timezone: + description: Show timezone in traditional format timestamp + type: bool + year: + description: Show year in traditional format timestamp + type: bool + sequence_numbers: + description: No. of log messages. + type: bool + hosts: &host + description: Set syslog server IP address and parameters. + type: list + elements: dict + suboptions: + name: + description: Hostname or IP address of the syslog server. + type: str + add: + description: Configure ports on the given host. + type: bool + remove: + description: Remove configured ports from the given host + type: bool + protocol: + description: Set syslog server transport protocol + type: str + choices: ["tcp", "udp"] + port: + description: Port of the syslog server. + type: int + level: + description: Configure logging severity + type: dict + suboptions: + facility: + description: Facility level + type: str + severity: *sev + monitor: + description: Set terminal monitor severity + type: str + turn_on: + description: Turn on logging. + type: bool + persistent: + description: Save logging messages to the flash disk. + type: dict + suboptions: + set: + description: Save logging messages to the flash dis. + type: bool + size: + description: The maximum size (in bytes) of logging file stored on flash disk. + type: int + policy: + description: Configure logging policies. + type: dict + suboptions: + invert_result: + description: Invert the match of match-list. + type: bool + match_list: + description: Configure logging message filtering. + type: str + qos: + description: Set DSCP value in IP header. + type: int + relogging_interval: + description: Configure relogging-interval for critical log messages + type: int + repeat_messages: + description: Repeat messages instead of summarizing number of repeats + type: bool + source_interface: &srcint + description: Use IP Address of interface as source IP of log messages. + type: str + synchronous: + description: Set synchronizing unsolicited with solicited messages + type: dict + suboptions: + set: + description: Set synchronizing unsolicited with solicited messages. + type: bool + level: + description: Configure logging severity + type: str + trap: + description: Severity of messages sent to the syslog server. + type: dict + suboptions: + set: + description: Severity of messages sent to the syslog server. + type: bool + severity: *sev + vrfs: + description: Specify vrf + type: list + elements: dict + suboptions: + name: + description: vrf name. + type: str + hosts: *host + source_interface: *srcint + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device by + executing the command B(show running-config | section access-list). + - The states I(replaced) and I(overridden) have identical + behaviour for this module. + - 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. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ + +# Using merged + +# Before state + +# test(config)#show running-config | section logging +# test(config)# + + - name: Merge provided configuration with device configuration + arista.eos.eos_logging_global: + config: + hosts: + - name: "host01" + protocol: "tcp" + - name: "11.11.11.1" + port: 25 + vrfs: + - name: "vrf01" + source_interface: "Ethernet1" + - name: "vrf02" + hosts: + - name: "hostvrf1" + protocol: "tcp" + - name: "24.1.1.1" + port: "33" + +# After State: + +# test(config)#show running-config | section logging +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging vrf vrf01 source-interface Ethernet1 +# test(config)# +# +# +# Module Execution: +# "after": { +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# } +# ] +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "logging host host01 protocol tcp", +# "logging host 11.11.11.1 25", +# "logging vrf vrf01 source-interface Ethernet1", +# "logging vrf vrf02 host hostvrf1 protocol tcp", +# "logging vrf vrf02 host 24.1.1.1 33" +# ], +# + +# Using replaced: +# Before State: + +# test(config)#show running-config | section logging +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging format timestamp traditional timezone +# logging vrf vrf01 source-interface Ethernet1 +# logging policy match inverse-result match-list list01 discard +# logging persistent 4096 +# ! +# logging level AAA alerts +# test(config)# + + - name: Repalce + arista.eos.eos_logging_global: + config: + synchronous: + set: True + trap: + severity: "critical" + hosts: + - name: "host02" + protocol: "tcp" + vrfs: + - name: "vrf03" + source_interface: "Vlan100" + - name: "vrf04" + hosts: + - name: "hostvrf1" + protocol: "tcp" + + state: replaced + +# After State: +# test(config)#show running-config | section logging +# logging synchronous +# logging trap critical +# logging host host02 514 protocol tcp +# logging vrf vrf04 host hostvrf1 514 protocol tcp +# logging vrf vrf03 source-interface Vlan100 +# test(config)# +# +# Module Execution: +# "after": { +# "hosts": [ +# { +# "name": "host02", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "synchronous": { +# "set": True +# }, +# "trap": { +# "severity": "critical" +# }, +# "vrfs": [ +# { +# "name": "vrf03", +# "source_interface": "Vlan100" +# }, +# { +# "hosts": [ +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf04" +# } +# ] +# }, +# "before": { +# "format": { +# "timestamp": { +# "traditional": { +# "timezone": true +# } +# } +# }, +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "level": { +# "facility": "AAA", +# "severity": "alerts" +# }, +# "persistent": { +# "size": 4096 +# }, +# "policy": { +# "invert_result": true, +# "match_list": "list01" +# }, +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "logging host host02 protocol tcp", +# "no logging host 11.11.11.1 25", +# "no logging host host01 514 protocol tcp", +# "logging vrf vrf03 source-interface Vlan100", +# "logging vrf vrf04 host hostvrf1 protocol tcp", +# "no logging vrf vrf01 source-interface Ethernet1", +# "no logging vrf vrf02 host 24.1.1.1 33", +# "no logging vrf vrf02 host hostvrf1 514 protocol tcp", +# "no logging format timestamp traditional timezone", +# "no logging level AAA alerts", +# "no logging persistent 4096", +# "no logging policy match invert-result match-list list01 discard", +# "logging synchronous", +# "logging trap critical" +# ], +# +# + + +# Using overridden: +# Before State: + +# test(config)#show running-config | section logging +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging format timestamp traditional timezone +# logging vrf vrf01 source-interface Ethernet1 +# logging policy match inverse-result match-list list01 discard +# logging persistent 4096 +# ! +# logging level AAA alerts +# test(config)# + + - name: Repalce + arista.eos.eos_logging_global: + config: + synchronous: + set: True + trap: + severity: "critical" + hosts: + - name: "host02" + protocol: "tcp" + vrfs: + - name: "vrf03" + source_interface: "Vlan100" + - name: "vrf04" + hosts: + - name: "hostvrf1" + protocol: "tcp" + + state: overridden + +# After State: +# test(config)#show running-config | section logging +# logging synchronous +# logging trap critical +# logging host host02 514 protocol tcp +# logging vrf vrf04 host hostvrf1 514 protocol tcp +# logging vrf vrf03 source-interface Vlan100 +# test(config)# +# +# Module Execution: +# "after": { +# "hosts": [ +# { +# "name": "host02", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "synchronous": { +# "set": True +# }, +# "trap": { +# "severity": "critical" +# }, +# "vrfs": [ +# { +# "name": "vrf03", +# "source_interface": "Vlan100" +# }, +# { +# "hosts": [ +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf04" +# } +# ] +# }, +# "before": { +# "format": { +# "timestamp": { +# "traditional": { +# "timezone": true +# } +# } +# }, +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "level": { +# "facility": "AAA", +# "severity": "alerts" +# }, +# "persistent": { +# "size": 4096 +# }, +# "policy": { +# "invert_result": true, +# "match_list": "list01" +# }, +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "logging host host02 protocol tcp", +# "no logging host 11.11.11.1 25", +# "no logging host host01 514 protocol tcp", +# "logging vrf vrf03 source-interface Vlan100", +# "logging vrf vrf04 host hostvrf1 protocol tcp", +# "no logging vrf vrf01 source-interface Ethernet1", +# "no logging vrf vrf02 host 24.1.1.1 33", +# "no logging vrf vrf02 host hostvrf1 514 protocol tcp", +# "no logging format timestamp traditional timezone", +# "no logging level AAA alerts", +# "no logging persistent 4096", +# "no logging policy match invert-result match-list list01 discard", +# "logging synchronous", +# "logging trap critical" +# ], +# +# + +# Using deleted: + +# Before State: +# test(config)#show running-config | section logging +# logging synchronous level critical +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging host host02 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging vrf vrf04 host hostvrf1 514 protocol tcp +# logging vrf vrf01 source-interface Ethernet1 +# logging vrf vrf03 source-interface Vlan100 +# test(config)# + + - name: Delete all logging configs + arista.eos.eos_logging_global: + state: deleted + become: yes + +# After state: +# test(config)#show running-config | section logging +# test(config)# +# +# "after": {}, +# "before": { +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# }, +# { +# "name": "host02", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "synchronous": { +# "level": "critical" +# }, +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# }, +# { +# "name": "vrf03", +# "source_interface": "Vlan100" +# }, +# { +# "hosts": [ +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf04" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "no logging host 11.11.11.1 25", +# "no logging host host01 514 protocol tcp", +# "no logging host host02 514 protocol tcp", +# "no logging vrf vrf01 source-interface Ethernet1", +# "no logging vrf vrf02 host 24.1.1.1 33", +# "no logging vrf vrf02 host hostvrf1 514 protocol tcp", +# "no logging vrf vrf03 source-interface Vlan100", +# "no logging vrf vrf04 host hostvrf1 514 protocol tcp", +# "no logging synchronous level critical" +# ], + +# Using parsed: +# parsed.cfg + +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging format timestamp traditional timezone +# logging vrf vrf01 source-interface Ethernet1 +# logging policy match inverse-result match-list list01 discard +# logging persistent 4096 +# ! +# logging level AAA alerts + + - name: parse configs + arista.eos.eos_logging_global: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution +# "parsed": { +# "format": { +# "timestamp": { +# "traditional": { +# "timezone": true +# } +# } +# }, +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "level": { +# "facility": "AAA", +# "severity": "alerts" +# }, +# "persistent": { +# "size": 4096 +# }, +# "policy": { +# "invert_result": true, +# "match_list": "list01" +# }, +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# } +# ] +# } +# + +# Using gathered: +# Before State: +# test(config)#show running-config | section logging +# logging host 11.11.11.1 25 +# logging host host01 514 protocol tcp +# logging vrf vrf02 host 24.1.1.1 33 +# logging vrf vrf02 host hostvrf1 514 protocol tcp +# logging format timestamp traditional timezone +# logging vrf vrf01 source-interface Ethernet1 +# logging policy match inverse-result match-list list01 discard +# logging persistent 4096 +# ! +# logging level AAA alerts +# test(config)# + + - name: gather configs + arista.eos.eos_logging_global: + state: gathered + +# Module Execution: +# "gathered": { +# "format": { +# "timestamp": { +# "traditional": { +# "timezone": true +# } +# } +# }, +# "hosts": [ +# { +# "name": "11.11.11.1", +# "port": 25 +# }, +# { +# "name": "host01", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "level": { +# "facility": "AAA", +# "severity": "alerts" +# }, +# "persistent": { +# "size": 4096 +# }, +# "policy": { +# "invert_result": true, +# "match_list": "list01" +# }, +# "vrfs": [ +# { +# "name": "vrf01", +# "source_interface": "Ethernet1" +# }, +# { +# "hosts": [ +# { +# "name": "24.1.1.1", +# "port": 33 +# }, +# { +# "name": "hostvrf1", +# "port": 514, +# "protocol": "tcp" +# } +# ], +# "name": "vrf02" +# } +# ] +# }, +# + +# Using rendered: + - name: Render provided configuration + arista.eos.eos_logging_global: + config: + format: + timestamp: + traditional: + timezone: True + level: + facility: "AAA" + severity: "alerts" + persistent: + size: 4096 + policy: + invert_result: True + match_list: "list01" + hosts: + - name: "host01" + protocol: "tcp" + - name: "11.11.11.1" + port: 25 + vrfs: + - name: "vrf01" + source_interface: "Ethernet1" + - name: "vrf02" + hosts: + - name: "hostvrf1" + protocol: "tcp" + - name: "24.1.1.1" + port: "33" +# Module Execution: + +# "rendered": [ +# "logging host host01 protocol tcp", +# "logging host 11.11.11.1 25", +# "logging vrf vrf01 source-interface Ethernet1", +# "logging vrf vrf02 host hostvrf1 protocol tcp", +# "logging vrf vrf02 host 24.1.1.1 33", +# "logging format timestamp traditional timezone", +# "logging level AAA alerts", +# "logging persistent 4096", +# "logging policy match invert-result match-list list01 discard" +# ] +# + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.logging_global.logging_global import ( + Logging_globalArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.logging_global.logging_global import ( + Logging_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Logging_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Logging_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_ntp_global.py b/ansible_collections/arista/eos/plugins/modules/eos_ntp_global.py new file mode 100644 index 000000000..cb89f3a9d --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_ntp_global.py @@ -0,0 +1,1053 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for eos_ntp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: eos_ntp_global +short_description: Manages ntp resource module +description: This module configures and manages the attributes of ntp on Arista + EOS platforms. +version_added: 3.1.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.60M +- This module works with connection C(network_cli). See the U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_eos.html). +options: + config: + description: A dictionary of ntp options + type: dict + suboptions: + authenticate: + description: + - Require authentication for NTP synchronization. + type: dict + suboptions: + enable: + description: Enable authentication for NTP synchronization. + type: bool + servers: + description: Authentication required only for incoming NTP server responses. + type: bool + authentication_keys: + description: + - Define a key to use for authentication. + type: list + elements: dict + suboptions: + id: + description: key identifier. + type: int + algorithm: + description: hash algorithm, + type: str + choices: ["md5", "sha1"] + encryption: + description: key type + type: int + choices: [0, 7] + key: + description: Unobfuscated key string. + type: str + local_interface: + description: Configure the interface from which the IP source address is taken. + type: str + qos_dscp: + description: Set DSCP value in IP header + type: int + serve: + description: Configure the switch as an NTP server. + type: dict + suboptions: + all: + description: Service NTP requests received on any interface. + type: bool + access_lists: + description: Configure access control list. + type: list + elements: dict + suboptions: + afi: + description: ip/ipv6 config commands. + type: str + acls: + description: Access lists to be configured under the afi + type: list + elements: dict + suboptions: + acl_name: + description: Name of the access list. + type: str + direction: + description: direction for the packets. + type: str + choices: ["in", "out"] + vrf: + description: VRF in which to apply the access control list. + type: str + servers: + description: Configure NTP server to synchronize to. + type: list + elements: dict + suboptions: + vrf: + description: vrf name. + type: str + server: + description: Hostname or A.B.C.D or A:B:C:D:E:F:G:H. + type: str + required: True + burst: + description: Send a burst of packets instead of the usual one. + type: bool + iburst: + description: Send bursts of packets until the server is reached + type: bool + key_id: + description: Set a key to use for authentication. + type: int + local_interface: + description: Configure the interface from which the IP source address is taken. + type: str + source: + description: Configure the interface from which the IP source address is taken. + type: str + maxpoll: + description: Maximum poll interval. + type: int + minpoll: + description: Minimum poll interval. + type: int + prefer: + description: Mark this server as preferred. + type: bool + version: + description: NTP version. + type: int + trusted_key: + description: Configure the set of keys that are accepted for incoming messages + 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 EOS device by + executing the command B(show running-config | section ntp). + - 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(replaced) and I(overridden) have identical + behaviour for this module. + - Please refer to examples for more details. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ + +# Using merged + +# Before state + +# localhost(config)#show running-config | section ntp +# localhost(config)# + + - name: Merge provided configuration with device configuration + arista.eos.eos_ntp_global: + config: + authenticate: + enable: true + authentication_keys: + - id: 2 + algorithm: "sha1" + encryption: 7 + key: "123456" + - id: 23 + algorithm: "md5" + encryption: 7 + key: "123456" + local_interface: "Ethernet1" + qos_dscp: 10 + trusted_key: 23 + servers: + - server: "10.1.1.1" + vrf: "vrf01" + burst: True + prefer: True + - server: "25.1.1.1" + vrf: "vrf01" + maxpoll: 15 + key_id: 2 + serve: + access_lists: + - afi: "ip" + acls: + - acl_name: "acl01" + direction: "in" + - afi: "ipv6" + acls: + - acl_name: "acl02" + direction: "in" + +# After State + +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in +# localhost(config)# +# +# +# Module Execution: +# "after": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "key_id": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "ntp serve ip access-group acl01 in", +# "ntp serve ipv6 access-group acl02 in", +# "ntp authentication-key 2 sha1 7 ********", +# "ntp authentication-key 23 md5 7 ********", +# "ntp server vrf vrf01 10.1.1.1 burst prefer", +# "ntp server vrf vrf01 25.1.1.1 key 2 maxpoll 15", +# "ntp authenticate", +# "ntp local-interface Ethernet1", +# "ntp qos dscp 10", +# "ntp trusted-key 23" +# ], + +# Using Replaced + +# Before State + +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in +# localhost(config)# + + - name: Replace + arista.eos.eos_ntp_global: + config: + qos_dscp: 15 + authentication_keys: + - id: 2 + algorithm: "md5" + encryption: 7 + key: "123456" + servers: + - server: "11.21.1.1" + vrf: "vrf01" + burst: True + prefer: True + minpoll: 13 + serve: + access_lists: + - afi: "ip" + acls: + - acl_name: "acl03" + direction: "in" + state: replaced +# After State: +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 md5 7 123456 +# ntp qos dscp 15 +# ntp server vrf vrf01 11.21.1.1 prefer burst minpoll 13 +# ntp serve ip access-group acl03 in +# localhost(config)# +# +# +# Module Execution: +# "after": { +# "authentication_keys": [ +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "qos_dscp": 15, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl03", +# "direction": "in" +# } +# ], +# "afi": "ip" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "minpoll": 13, +# "prefer": true, +# "server": "11.21.1.1", +# "vrf": "vrf01" +# } +# ] +# }, +# "before": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "key_id": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# }, +# "changed": true, +# "commands": [ +# "no ntp serve ip access-group acl01 in", +# "no ntp serve ipv6 access-group acl02 in", +# "no ntp authentication-key 23 md5 7 ********", +# "no ntp server vrf vrf01 10.1.1.1 burst prefer", +# "no ntp server vrf vrf01 25.1.1.1 key 2 maxpoll 15", +# "no ntp authenticate", +# "no ntp local-interface Ethernet1", +# "no ntp trusted-key 23", +# "ntp serve ip access-group acl03 in", +# "ntp authentication-key 2 md5 7 ********", +# "ntp server vrf vrf01 11.21.1.1 burst minpoll 13 prefer", +# "ntp qos dscp 15" +# ], +# +# Using Overridden + +# Before State + +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in +# localhost(config)# + + - name: Replace + arista.eos.eos_ntp_global: + config: + qos_dscp: 15 + authentication_keys: + - id: 2 + algorithm: "md5" + encryption: 7 + key: "123456" + servers: + - server: "11.21.1.1" + vrf: "vrf01" + burst: True + prefer: True + minpoll: 13 + serve: + access_lists: + - afi: "ip" + acls: + - acl_name: "acl03" + direction: "in" + state: overridden +# After State: +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 md5 7 123456 +# ntp qos dscp 15 +# ntp server vrf vrf01 11.21.1.1 prefer burst minpoll 13 +# ntp serve ip access-group acl03 in +# localhost(config)# +# +# +# Module Execution: +# "after": { +# "authentication_keys": [ +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "qos_dscp": 15, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl03", +# "direction": "in" +# } +# ], +# "afi": "ip" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "minpoll": 13, +# "prefer": true, +# "server": "11.21.1.1", +# "vrf": "vrf01" +# } +# ] +# }, +# "before": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "key_id": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# }, +# "changed": true, +# "commands": [ +# "no ntp serve ip access-group acl01 in", +# "no ntp serve ipv6 access-group acl02 in", +# "no ntp authentication-key 23 md5 7 ********", +# "no ntp server vrf vrf01 10.1.1.1 burst prefer", +# "no ntp server vrf vrf01 25.1.1.1 key 2 maxpoll 15", +# "no ntp authenticate", +# "no ntp local-interface Ethernet1", +# "no ntp trusted-key 23", +# "ntp serve ip access-group acl03 in", +# "ntp authentication-key 2 md5 7 ********", +# "ntp server vrf vrf01 11.21.1.1 burst minpoll 13 prefer", +# "ntp qos dscp 15" +# ], +# + +# using deleted: +# Before State + +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 11.21.1.1 prefer burst minpoll 13 +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in +# localhost(config)# + + - name: Delete ntp-global + arista.eos.eos_ntp_global: + state: deleted + +# After State: +# localhost(config)#show running-config | section ntp +# localhost(config)# +# +# +# # Module Execution +# "after": {}, +# "before": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "burst": true, +# "minpoll": 13, +# "prefer": true, +# "server": "11.21.1.1", +# "vrf": "vrf01" +# }, +# { +# "key": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# }, +# "changed": true, +# "commands": [ +# "no ntp serve ip access-group acl01 in", +# "no ntp serve ipv6 access-group acl02 in", +# "no ntp authentication-key 2 sha1 7 ********", +# "no ntp authentication-key 23 md5 7 ********", +# "no ntp server vrf vrf01 10.1.1.1 burst prefer", +# "no ntp server vrf vrf01 11.21.1.1 burst minpoll 13 prefer", +# "no ntp server vrf vrf01 25.1.1.1 key 2 maxpoll 15", +# "no ntp authenticate", +# "no ntp local-interface Ethernet1", +# "no ntp qos dscp 10", +# "no ntp trusted-key 23" +# ], +# + +# Using parsed: +# parsed.cfg +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 11.21.1.1 prefer burst minpoll 13 +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in + + - name: parse configs + arista.eos.eos_ntp_global: + running_config: "{{ lookup('file', './parsed_ntp_global.cfg') }}" + state: parsed + tags: + - parsed +# Module Execution +# "parsed": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "burst": true, +# "minpoll": 13, +# "prefer": true, +# "server": "11.21.1.1", +# "vrf": "vrf01" +# }, +# { +# "key": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# } +# } + +# using Gathered +# Device config: +# localhost(config)#show running-config | section ntp +# ntp authentication-key 2 sha1 7 123456 +# ntp authentication-key 23 md5 7 123456 +# ntp trusted-key 23 +# ntp authenticate +# ntp local-interface Ethernet1 +# ntp qos dscp 10 +# ntp server vrf vrf01 10.1.1.1 prefer burst +# ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 +# ntp serve ip access-group acl01 in +# ntp serve ipv6 access-group acl02 in +# localhost(config)# + + + - name: gather configs + arista.eos.eos_ntp_global: + state: gathered + tags: + - gathered +# Module Execution +# "gathered": { +# "authenticate": { +# "enable": true +# }, +# "authentication_keys": [ +# { +# "algorithm": "sha1", +# "encryption": 7, +# "id": 2, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# }, +# { +# "algorithm": "md5", +# "encryption": 7, +# "id": 23, +# "key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" +# } +# ], +# "local_interface": "Ethernet1", +# "qos_dscp": 10, +# "serve": { +# "access_lists": [ +# { +# "acls": [ +# { +# "acl_name": "acl01", +# "direction": "in" +# } +# ], +# "afi": "ip" +# }, +# { +# "acls": [ +# { +# "acl_name": "acl02", +# "direction": "in" +# } +# ], +# "afi": "ipv6" +# } +# ] +# }, +# "servers": [ +# { +# "burst": true, +# "prefer": true, +# "server": "10.1.1.1", +# "vrf": "vrf01" +# }, +# { +# "key_id": 2, +# "maxpoll": 15, +# "server": "25.1.1.1", +# "vrf": "vrf01" +# } +# ], +# "trusted_key": "23" +# }, +# "invocation": { +# "module_args": { +# "config": null, +# "running_config": null, +# "state": "gathered" +# } +# } +# } + + +# using rendered: + + - name: Render provided configuration + arista.eos.eos_ntp_global: + config: + authenticate: + enable: true + authentication_keys: + - id: 2 + algorithm: "sha1" + encryption: 7 + key: "123456" + - id: 23 + algorithm: "md5" + encryption: 7 + key: "123456" + local_interface: "Ethernet1" + qos_dscp: 10 + trusted_key: 23 + servers: + - server: "10.1.1.1" + vrf: "vrf01" + burst: True + prefer: True + - server: "25.1.1.1" + vrf: "vrf01" + maxpoll: 15 + key_id: 2 + serve: + access_lists: + - afi: "ip" + acls: + - acl_name: "acl01" + direction: "in" + - afi: "ipv6" + acls: + - acl_name: "acl02" + direction: "in" + state: rendered + become: yes + +# Module Execution: +# "rendered": [ +# "ntp serve ip access-group acl01 in", +# "ntp serve ipv6 access-group acl02 in", +# "ntp authentication-key 2 sha1 7 ********", +# "ntp authentication-key 23 md5 7 ********", +# "ntp server vrf vrf01 10.1.1.1 burst prefer", +# "ntp server vrf vrf01 25.1.1.1 key 2 maxpoll 15", +# "ntp authenticate", +# "ntp local-interface Ethernet1", +# "ntp qos dscp 10", +# "ntp trusted-key 23" +# ] +# +""" + +RETURN = """ +before: + 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: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + 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: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - ntp master stratum 2 + - ntp peer 198.51.100.1 use-vrf test maxpoll 7 + - ntp authentication-key 10 md5 wawyhanx2 7 + - ntp access-group peer PeerAcl1 + - ntp access-group peer PeerAcl2 + - ntp access-group query-only QueryAcl1 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + + - ntp authentication-key 2 sha1 7 123456 + - ntp authentication-key 23 md5 7 123456 + - ntp trusted-key 23 + - ntp authenticate + - ntp local-interface Ethernet1 + - ntp qos dscp 10 + - ntp server vrf vrf01 10.1.1.1 prefer burst + - ntp server vrf vrf01 25.1.1.1 maxpoll 15 key 2 + - ntp serve ip access-group acl01 in + - ntp serve ipv6 access-group acl02 in + +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.arista.eos.plugins.module_utils.network.eos.argspec.ntp_global.ntp_global import ( + Ntp_globalArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.ntp_global.ntp_global import ( + Ntp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ntp_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Ntp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_ospf_interfaces.py b/ansible_collections/arista/eos/plugins/modules/eos_ospf_interfaces.py new file mode 100644 index 000000000..29ad037f7 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_ospf_interfaces.py @@ -0,0 +1,1230 @@ +#!/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 eos_ospf_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_ospf_interfaces +version_added: 1.1.0 +short_description: OSPF Interfaces Resource Module. +description: +- This module manages OSPF configuration of interfaces on devices running Arista EOS. +author: Gomathi Selvi Srinivasan (@GomathiselviS) +options: + config: + description: A list of OSPF configuration for interfaces. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier of the interface. + type: str + address_family: + description: + - OSPF settings on the interfaces in address-family context. + type: list + elements: dict + suboptions: + afi: + description: + - Address Family Identifier (AFI) for OSPF settings on the interfaces. + type: str + choices: ['ipv4', 'ipv6'] + required: True + area: + description: + - Area associated with interface. + - Valid only when afi = ipv4. + type: dict + suboptions: + area_id: + description: + - Area ID as a decimal or IP address format. + type: str + required: True + authentication_v2: + description: + - Authentication settings on the interface. + - Valid only when afi = ipv4. + type: dict + suboptions: + message_digest: + description: + - Use message-digest authentication. + type: bool + set: + description: + - Enable authentication on the interface. + type: bool + authentication_v3: + description: + - Authentication settings on the interface. + - Valid only when afi = ipv6. + type: dict + suboptions: + spi: + description: IPsec Security Parameter Index. + type: int + algorithm: + description: Encryption alsgorithm. + type: str + choices: ["md5", "sha1"] + keytype: + description: + - Specifies if an unencrypted/hidden follows. + - 0 denotes unencrypted key. + - 7 denotes hidden key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + key: + description: 128 bit MD5 key or 140 bit SHA1 key. + type: str + authentication_key: + description: + - Configure the authentication key for the interface. + - Valid only when afi = ipv4. + type: dict + suboptions: + encryption: + description: + - 0 Specifies an UNENCRYPTED authentication key will follow. + - 7 Specifies a proprietry encryption type.` + type: str + key: + description: + - password (up to 8 chars). + type: str + bfd: + description: Enable BFD. + type: bool + cost: + description: + - metric associated with interface. + type: int + dead_interval: + description: + - Time interval to detect a dead router. + type: int + encryption_v3: + description: + - Authentication settings on the interface. + - Valid only when afi = ipv6. + type: dict + suboptions: + spi: + description: IPsec Security Parameter Index. + type: int + encryption: + description: encryption type. + choices: ["3des-cbc", "aes-128-cbc", "aes-192-cbc", "aes-256-cbc", "null"] + type: str + algorithm: + description: algorithm. + type: str + choices: ["md5", "sha1"] + keytype: + description: + - Specifies if an unencrypted/hidden follows. + - 0 denotes unencrypted key. + - 7 denotes hidden key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + key: + description: key + type: str + hello_interval: + description: + - Timer interval between transmission of hello packets. + type: int + ip_params: + description: + - Specify parameters for IPv4/IPv6. + - Valid only when afi = ipv6. + type: list + elements: dict + suboptions: + afi: + description: + - Address Family Identifier (AFI) for OSPF settings on the interfaces. + type: str + choices: ['ipv4', 'ipv6'] + required: True + area: + description: + - Area associated with interface. + - Valid only when afi = ipv4. + type: dict + suboptions: + area_id: + description: + - Area ID as a decimal or IP address format. + type: str + required: True + bfd: + description: Enable BFD. + type: bool + cost: + description: + - metric associated with interface. + type: int + dead_interval: + description: + - Time interval to detect a dead router. + type: int + hello_interval: + description: + - Timer interval between transmission of hello packets. + type: int + mtu_ignore: + description: + - if True, Disable MTU check for Database Description packets. + type: bool + network: + description: + - Interface type. + type: str + priority: + description: + - Interface priority. + type: int + retransmit_interval: + description: + - LSA retransmission interval. + type: int + passive_interface: + description: + - Suppress routing updates in an interface. + type: bool + transmit_delay: + description: + - LSA transmission delay. + type: int + message_digest_key: + description: + - Message digest authentication password (key) settings. + type: dict + suboptions: + key_id: + description: + - Key ID. + type: int + encryption: + description: + - 0 Specifies an UNENCRYPTED ospf password (key) will follow. + - 7 Specifies a proprietry encryption type. + type: str + key: + description: + - Authentication key (upto 16 chars). + type: str + mtu_ignore: + description: + - if True, Disable MTU check for Database Description packets. + type: bool + network: + description: + - Interface type. + type: str + passive_interface: + description: + - Suppress routing updates in an interface. + - Valid only when afi = ipv6. + type: bool + priority: + description: + - Interface priority. + type: int + retransmit_interval: + description: + - LSA retransmission interval. + type: int + shutdown: + description: + - Shutdown OSPF on this interface. + type: bool + transmit_delay: + description: + - LSA transmission delay. + 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 EOS 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. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged +""" + +EXAMPLES = """ + +# Using merged + +# Before state + +# veos(config)#show running-config | section interface | ospf +# veos(config)# + + - name: Merge provided configuration with device configuration + arista.eos.eos_ospf_interfaces: + config: + - name: "Vlan1" + address_family: + - afi: "ipv4" + area: + area_id: "0.0.0.50" + cost: 500 + mtu_ignore: True + - afi: "ipv6" + dead_interval: 44 + ip_params: + - afi: "ipv6" + mtu_ignore: True + network: "point-to-point" + state: merged + +# After State + +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ip ospf cost 500 +# ip ospf mtu-ignore +# ip ospf area 0.0.0.50 +# ospfv3 dead-interval 44 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# veos(config)# +# +# +# Module Execution: +# +# "after": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.50" +# }, +# "cost": 500, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "dead_interval": 44, +# "ip_params": [ +# { +# "afi": "ipv6", +# "mtu_ignore": True, +# "network": "point-to-point" +# } +# ] +# } +# ], +# "name": "Vlan1" +# } +# ], +# "before": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# } +# ], +# "changed": True, +# "commands": [ +# "interface Vlan1", +# "ip ospf area 0.0.0.50", +# "ip ospf cost 500", +# "ip ospf mtu-ignore", +# "ospfv3 dead-interval 44", +# "ospfv3 ipv6 mtu-ignore", +# "ospfv3 ipv6 network point-to-point" +# ], +# + +# Using replaced +#--------------- + +# Before State: + +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ip ospf cost 500 +# ip ospf dead-interval 29 +# ip ospf hello-interval 66 +# ip ospf mtu-ignore +# ip ospf area 0.0.0.50 +# ospfv3 cost 106 +# ospfv3 hello-interval 77 +# ospfv3 dead-interval 44 +# ospfv3 transmit-delay 100 +# ospfv3 ipv4 priority 45 +# ospfv3 ipv4 area 0.0.0.5 +# ospfv3 ipv6 passive-interface +# ospfv3 ipv6 retransmit-interval 115 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# veos(config)# + + + - name: Replace device configuration with provided configuration + arista.eos.eos_ospf_interfaces: + config: + - name: "Vlan1" + address_family: + - afi: "ipv6" + cost: 44 + bfd: True + ip_params: + - afi: "ipv6" + mtu_ignore: True + network: "point-to-point" + dead_interval: 56 + state: replaced + +# After State: + +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ospfv3 bfd +# ospfv3 cost 44 +# no ospfv3 ipv6 passive-interface +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# veos(config)# +# +# Module Execution: +# +# "after": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "bfd": True, +# "cost": 44, +# "ip_params": [ +# { +# "afi": "ipv6", +# "mtu_ignore": True, +# "network": "point-to-point" +# } +# ] +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# "before": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.50" +# }, +# "cost": 500, +# "dead_interval": 29, +# "hello_interval": 66, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "cost": 106, +# "dead_interval": 44, +# "hello_interval": 77, +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.5" +# }, +# "priority": 45 +# }, +# { +# "afi": "ipv6", +# "mtu_ignore": True, +# "network": "point-to-point", +# "passive_interface": True, +# "retransmit_interval": 115 +# } +# ], +# "transmit_delay": 100 +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# "changed": True, +# "commands": [ +# "interface Vlan1", +# "no ip ospf cost 500", +# "no ip ospf dead-interval 29", +# "no ip ospf hello-interval 66", +# "no ip ospf mtu-ignore", +# "no ip ospf area 0.0.0.50", +# "ospfv3 cost 44", +# "ospfv3 bfd", +# "ospfv3 authentication ipsec spi 30 md5 passphrase 7 7hl8FV3lZ6H1mAKpjL47hQ==", +# "no ospfv3 ipv4 priority 45", +# "no ospfv3 ipv4 area 0.0.0.5", +# "ospfv3 ipv6 dead-interval 56", +# "no ospfv3 ipv6 passive-interface", +# "no ospfv3 ipv6 retransmit-interval 115", +# "no ospfv3 hello-interval 77", +# "no ospfv3 dead-interval 44", +# "no ospfv3 transmit-delay 100" +# ], +# + +# Using overidden: +# ---------------- + +# Before State: +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ip ospf dead-interval 29 +# ip ospf hello-interval 66 +# ip ospf mtu-ignore +# ospfv3 bfd +# ospfv3 cost 106 +# ospfv3 hello-interval 77 +# ospfv3 transmit-delay 100 +# ospfv3 ipv4 priority 45 +# ospfv3 ipv4 area 0.0.0.5 +# ospfv3 ipv6 passive-interface +# ospfv3 ipv6 dead-interval 56 +# ospfv3 ipv6 retransmit-interval 115 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# veos(config)# + + - name: Override device configuration with provided configuration + arista.eos.eos_ospf_interfaces: + config: + - name: "Vlan1" + address_family: + - afi: "ipv6" + cost: 44 + bfd: True + ip_params: + - afi: "ipv6" + mtu_ignore: True + network: "point-to-point" + dead_interval: 56 + state: overridden + +# After State: + +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ospfv3 bfd +# ospfv3 cost 44 +# no ospfv3 ipv6 passive-interface +# ospfv3 ipv6 dead-interval 56 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# veos(config)# +# +# +# Module Execution: +# +# "after": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "bfd": True, +# "cost": 44, +# "ip_params": [ +# { +# "afi": "ipv6", +# "dead_interval": 56, +# "mtu_ignore": True, +# "network": "point-to-point" +# } +# ] +# } +# ], +# "name": "Vlan1" +# }, +# { +# "name": "Vlan2" +# } +# ], +# "before": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "dead_interval": 29, +# "hello_interval": 66, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "bfd": True, +# "cost": 106, +# "hello_interval": 77, +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.5" +# }, +# "priority": 45 +# }, +# { +# "afi": "ipv6", +# "dead_interval": 56, +# "mtu_ignore": True, +# "network": "point-to-point", +# "passive_interface": True, +# "retransmit_interval": 115 +# } +# ], +# "transmit_delay": 100 +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# "changed": True, +# "commands": [ +# "interface Vlan2", +# "no ospfv3 ipv4 hello-interval 45", +# "no ospfv3 ipv4 retransmit-interval 100", +# "no ospfv3 ipv4 area 0.0.0.6", +# "interface Vlan1", +# "no ip ospf dead-interval 29", +# "no ip ospf hello-interval 66", +# "no ip ospf mtu-ignore", +# "ospfv3 cost 44", +# "ospfv3 authentication ipsec spi 30 md5 passphrase 7 7hl8FV3lZ6H1mAKpjL47hQ==", +# "no ospfv3 ipv4 priority 45", +# "no ospfv3 ipv4 area 0.0.0.5", +# "no ospfv3 ipv6 passive-interface", +# "no ospfv3 ipv6 retransmit-interval 115", +# "no ospfv3 hello-interval 77", +# "no ospfv3 transmit-delay 100" +# ], +# + +# Using deleted: +#-------------- + +# before State: + +# veos(config)#show running-config | section interface | ospf +# interface Vlan1 +# ip ospf dead-interval 29 +# ip ospf hello-interval 66 +# ip ospf mtu-ignore +# ospfv3 bfd +# ospfv3 cost 106 +# ospfv3 hello-interval 77 +# ospfv3 transmit-delay 100 +# ospfv3 ipv4 priority 45 +# ospfv3 ipv4 area 0.0.0.5 +# ospfv3 ipv6 passive-interface +# ospfv3 ipv6 dead-interval 56 +# ospfv3 ipv6 retransmit-interval 115 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# veos(config)# + + - name: Delete device configuration + arista.eos.eos_ospf_interfaces: + config: + - name: "Vlan1" + state: deleted + +# After State: + +# veos#show running-config | section interface | ospf +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# +# Module Execution: +# +# "after": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# "before": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "dead_interval": 29, +# "hello_interval": 66, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "bfd": True, +# "cost": 106, +# "hello_interval": 77, +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.5" +# }, +# "priority": 45 +# }, +# { +# "afi": "ipv6", +# "dead_interval": 56, +# "mtu_ignore": True, +# "network": "point-to-point", +# "passive_interface": True, +# "retransmit_interval": 115 +# } +# ], +# "transmit_delay": 100 +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# "changed": True, +# "commands": [ +# "interface Vlan1", +# "no ip ospf dead-interval 29", +# "no ip ospf hello-interval 66", +# "no ip ospf mtu-ignore", +# "no ospfv3 bfd", +# "no ospfv3 cost 106", +# "no ospfv3 hello-interval 77", +# "no ospfv3 transmit-delay 100", +# "no ospfv3 ipv4 priority 45", +# "no ospfv3 ipv4 area 0.0.0.5", +# "no ospfv3 ipv6 passive-interface", +# "no ospfv3 ipv6 dead-interval 56", +# "no ospfv3 ipv6 retransmit-interval 115", +# "no ospfv3 ipv6 network point-to-point", +# "no ospfv3 ipv6 mtu-ignore" +# ], +# + +# Using parsed: +# ------------ + +# parsed.cfg: +# ---------- + +# interface Vlan1 +# ip ospf dead-interval 29 +# ip ospf hello-interval 66 +# ip ospf mtu-ignore +# ip ospf cost 500 +# ospfv3 bfd +# ospfv3 cost 106 +# ospfv3 hello-interval 77 +# ospfv3 transmit-delay 100 +# ospfv3 ipv4 priority 45 +# ospfv3 ipv4 area 0.0.0.5 +# ospfv3 ipv6 passive-interface +# ospfv3 ipv6 dead-interval 56 +# ospfv3 ipv6 retransmit-interval 115 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# + + - name: parse configs + arista.eos.eos_ospf_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "cost": 500, +# "dead_interval": 29, +# "hello_interval": 66, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "bfd": True, +# "cost": 106, +# "hello_interval": 77, +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.5" +# }, +# "priority": 45 +# }, +# { +# "afi": "ipv6", +# "dead_interval": 56, +# "mtu_ignore": True, +# "network": "point-to-point", +# "passive_interface": True, +# "retransmit_interval": 115 +# } +# ], +# "transmit_delay": 100 +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ] + +# Using gathered: + +# Device COnfig: + +# veos#show running-config | section interface | ospf +# interface Vlan1 +# ip ospf cost 500 +# ip ospf dead-interval 29 +# ip ospf hello-interval 66 +# ip ospf mtu-ignore +# ip ospf area 0.0.0.50 +# ospfv3 cost 106 +# ospfv3 hello-interval 77 +# ospfv3 transmit-delay 100 +# ospfv3 ipv4 priority 45 +# ospfv3 ipv4 area 0.0.0.5 +# ospfv3 ipv6 passive-interface +# ospfv3 ipv6 dead-interval 56 +# ospfv3 ipv6 retransmit-interval 115 +# ospfv3 ipv6 network point-to-point +# ospfv3 ipv6 mtu-ignore +# ! +# interface Vlan2 +# ospfv3 ipv4 hello-interval 45 +# ospfv3 ipv4 retransmit-interval 100 +# ospfv3 ipv4 area 0.0.0.6 +# veos# + + - name: gather configs + arista.eos.eos_ospf_interfaces: + state: gathered + +# Module Execution: +# +# "gathered": [ +# { +# "name": "Ethernet1" +# }, +# { +# "name": "Ethernet2" +# }, +# { +# "name": "Management1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.50" +# }, +# "cost": 500, +# "dead_interval": 29, +# "hello_interval": 66, +# "mtu_ignore": True +# }, +# { +# "afi": "ipv6", +# "cost": 106, +# "hello_interval": 77, +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.5" +# }, +# "priority": 45 +# }, +# { +# "afi": "ipv6", +# "dead_interval": 56, +# "mtu_ignore": True, +# "network": "point-to-point", +# "passive_interface": True, +# "retransmit_interval": 115 +# } +# ], +# "transmit_delay": 100 +# } +# ], +# "name": "Vlan1" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "ip_params": [ +# { +# "afi": "ipv4", +# "area": { +# "area_id": "0.0.0.6" +# }, +# "hello_interval": 45, +# "retransmit_interval": 100 +# } +# ] +# } +# ], +# "name": "Vlan2" +# } +# ], +# + + +# Using rendered: +# -------------- + + - name: Render provided configuration + arista.eos.eos_ospf_interfaces: + config: + - name: "Vlan1" + address_family: + - afi: "ipv4" + dead_interval: 29 + mtu_ignore: True + hello_interval: 66 + - afi: "ipv6" + hello_interval: 77 + cost : 106 + transmit_delay: 100 + ip_params: + - afi: "ipv6" + retransmit_interval: 115 + dead_interval: 56 + passive_interface: True + - afi: "ipv4" + area: + area_id: "0.0.0.5" + priority: 45 + - name: "Vlan2" + address_family: + - afi: "ipv6" + ip_params: + - afi: "ipv4" + area: + area_id: "0.0.0.6" + hello_interval: 45 + retransmit_interval: 100 + - afi: "ipv4" + message_digest_key: + key_id: 200 + encryption: 7 + key: "hkdfhtu==" + + state: rendered + +# Module Execution: +# +# "rendered": [ +# "interface Vlan1", +# "ip ospf dead-interval 29", +# "ip ospf mtu-ignore", +# "ip ospf hello-interval 66", +# "ospfv3 hello-interval 77", +# "ospfv3 cost 106", +# "ospfv3 transmit-delay 100", +# "ospfv3 ipv4 area 0.0.0.5", +# "ospfv3 ipv4 priority 45", +# "ospfv3 ipv6 retransmit-interval 115", +# "ospfv3 ipv6 dead-interval 56", +# "ospfv3 ipv6 passive-interface", +# "interface Vlan2", +# "ip ospf message-digest-key 200 md5 7 hkdfhtu==", +# "ospfv3 ipv4 area 0.0.0.6", +# "ospfv3 ipv4 hello-interval 45", +# "ospfv3 ipv4 retransmit-interval 100" +# ] +# + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.ospf_interfaces.ospf_interfaces import ( + Ospf_interfacesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.ospf_interfaces.ospf_interfaces import ( + Ospf_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ospf_interfacesArgs.argument_spec, + mutually_exclusive=[], + required_if=[], + supports_check_mode=False, + ) + + result = Ospf_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_ospfv2.py b/ansible_collections/arista/eos/plugins/modules/eos_ospfv2.py new file mode 100644 index 000000000..470efb023 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_ospfv2.py @@ -0,0 +1,1563 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_ospfv2 +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_ospfv2 +short_description: OSPFv2 resource module +description: This module configures and manages the attributes of ospfv2 on Arista + EOS platforms. +version_added: 1.0.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A list of configurations for ospfv2. + type: dict + suboptions: + processes: + description: A list of dictionary specifying the ospfv2 processes. + type: list + elements: dict + suboptions: + process_id: + description: ID of OSPFV2 process. + type: int + vrf: + description: VRF name . + type: str + traffic_engineering: + description: Enter traffic engineering config mode + type: bool + adjacency: + description: Configure adjacency options for OSPF instance. + type: dict + suboptions: + exchange_start: + description: Configure exchange-start options for OSPF instance. + type: dict + suboptions: + threshold: + description: Number of peers to bring up simultaneously. + type: int + router_id: + description: 32-bit number assigned to a router running OSPFv2. + type: str + max_lsa: + description: Specifies the switch behavior on reaching max lsa count. + type: dict + suboptions: + count: + description: maximum count of lsas. + type: int + threshold: + description: percentage of <count> , when a warning should be raised. + type: int + ignore_time: + description: time in minutes, for which the switch shoud be shutdown + on max-lsa warning + type: int + ignore_count: + description: No. of times the switch can shut down temporarily on + warning + type: int + reset_time: + description: Time in minutes, after which the shutdown counter resets. + type: int + warning: + description: Only give 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: dict + suboptions: + set: + description: + - Set router-lsa attribute. + type: bool + external_lsa: + description: Override external-lsa metric with max-metric value. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + 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: + wait_period: + description: + - Wait period in seconds after startup. + type: int + summary_lsa: + description: Override summary-lsa metric with max-metric value. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + type: int + log_adjacency_changes: + description: To configure link-state changes and transitions of OSPFv2 + neighbors. + type: dict + suboptions: + detail: + description: If true , configures the switch to log all link-state + changes. + type: bool + maximum_paths: + description: Maximum number of next-hops in an ECMP route. + type: int + mpls_ldp: + description: mpls ldp sync configuration. + type: bool + networks: + description: Configure routing for a network. + type: list + elements: dict + suboptions: + network_address: + description: Network Address. + type: str + prefix: + description: Prefix. + type: str + mask: + description: Network Wildcard Mask. + type: str + area: + description: Configure OSPF area. + type: str + passive_interface: + description: Include interface but without actively running OSPF. + type: dict + suboptions: + interface_list: + description: Interface range. + type: str + default: + description: If True, Set all interfaces to passive by default + type: bool + point_to_point: + description: Configure Point-to-point specific features. + type: bool + rfc1583compatibility: + description: Specifies different methods for calculating summary route + metrics. + type: bool + distance: + description: Specifies the administrative distance for routes. + type: dict + suboptions: + external: + description: Routes external to the area + type: int + inter_area: + description: Routes from other areas + type: int + intra_area: + description: Routes with in an area + type: int + redistribute: + description: Specifies the routes to be redistributed + type: list + elements: dict + suboptions: + routes: + description: Route types (BGP,isis,connected etc) + type: str + route_map: + description: Specify which route map to use. + type: str + isis_level: + description: ISIS levels. + type: str + retransmission_threshold: + description: Configure threshold for retransmission. + type: int + distribute_list: + description: Specifies the list of routes to be filtered. + type: dict + suboptions: + route_map: + description: route map to be filtered + type: str + prefix_list: + description: prefix list to be filtered + type: str + areas: + description: Specifies the configuration for OSPF areas + type: list + elements: dict + suboptions: + area_id: + description: Specifies a 32 bit number expressed in decimal or dotted-decimal + notation. + type: str + default_cost: + description: Specify the cost for default summary route in stub/NSSA + area. + type: int + filter: + description: Specify the filter for incoming summary LSAs. + type: dict + suboptions: + address: + description: IP address. + type: str + subnet_address: + description: IP address with mask length + type: str + subnet_mask: + description: IP subnet mask + type: str + prefix_list: + description: Specify list to filter for incoming LSAs. + type: str + nssa: + description: Configures NSSA parameters. + type: dict + suboptions: + default_information_originate: + description: Originate default Type 7 LSA. + type: dict + suboptions: + metric: + description: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + nssa_only: + description: Limit default advertisement to this NSSA area. + type: bool + no_summary: + description: Filter all type-3 LSAs in the nssa area. + type: bool + nssa_only: + description: Disable Type-7 LSA p-bit setting + type: bool + set: + description: Set config up to nssa + type: bool + not_so_stubby: + description: Configures NSSA parameters. + type: dict + suboptions: + default_information_originate: + description: Originate default Type 7 LSA. + type: dict + suboptions: + metric: + description: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + nssa_only: + description: Limit default advertisement to this NSSA area. + type: bool + lsa: + description: lsa parameters + type: bool + no_summary: + description: Filter all type-3 LSAs in the nssa area. + type: bool + nssa_only: + description: Disable Type-7 LSA p-bit setting + type: bool + set: + description: Set config up to not-so-stubby + type: bool + range: + description: Configure route summarization. + type: dict + suboptions: + address: + description: IP address. + type: str + subnet_address: + description: IP address with mask length + type: str + subnet_mask: + description: IP subnet mask + type: str + advertise: + description: Enable Advertisement of the range. + type: bool + cost: + description: Configures the metric. + type: int + stub: + description: Stub area. + type: dict + suboptions: + no_summary: + description: If False , Filter all type-3 LSAs in the stub area. + type: bool + set: + description: When true sets the stub config alone. + type: bool + auto_cost: + description: Set auto-cost. + type: dict + suboptions: + reference_bandwidth: + description: reference bandwidth in megabits per sec. + type: int + bfd: + description: Enable BFD. + type: dict + suboptions: + all_interfaces: + description: Enable BFD on all interfaces. + 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: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + route_map: + description: Specify which route-map to use. + type: str + default_metric: + description: Configure the default metric for redistributed routes + type: int + dn_bit_ignore: + description: If True, Disable dn-bit check for Type-3 LSAs in non-default + VRFs. + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: dict + suboptions: + grace_period: + description: Specify maximum time to wait for graceful-restart to + complete. + type: int + set: + description: When true sets the grace_fulrestart config alone. + type: bool + graceful_restart_helper: + description: If True, Enable graceful restart helper. + type: bool + shutdown: + description: Disable the OSPF instance. + type: bool + summary_address: + description: Summary route configuration. + type: dict + suboptions: + address: + description: IP summary address. + type: str + prefix: + description: Prefix. + type: str + mask: + description: Summary Mask. + type: str + attribute_map: + description: Set attributes of summary route. + type: str + not_advertise: + description: Do not advertise summary route. + type: bool + tag: + description: Set tag. + type: int + timers: + description: Configure OSPF timers. + type: list + elements: dict + suboptions: + lsa: + description: Configure OSPF LSA timers. + type: dict + suboptions: + rx: + description: Configure OSPF LSA receiving timers + type: dict + suboptions: + min_interval: + description: Configure OSPF LSA arrival timer. + type: int + tx: + description: Configure OSPF LSA transmission timers. + type: dict + suboptions: + delay: + description: Configure OSPF LSA transmission delay. + type: dict + suboptions: + initial: + description: Delay to generate first occurrence of LSA + in msecs. + type: int + min: + description: Min delay between originating the same LSA + in msecs. + type: int + max: + description: Maximum delay between originating the same + LSA in msecs. + type: int + out_delay: + description: Configure out-delay timer. + type: int + pacing: + description: Configure OSPF packet pacing. + type: int + spf: + description: Configure SPF timers + type: dict + suboptions: + seconds: + description: Seconds. + type: int + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + throttle: + description: Configure throttle timers(valid only for eos version < 4.23). + type: dict + suboptions: + attr: + description: throttle attribute. + type: str + initial: + description: Initial schedule delay in msecs. + type: int + min: + description: Min Hold time + type: int + max: + description: Max wait time + type: int + fips_restrictions: + description: Use FIPS compliant algorithms + 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 EOS device by + executing the command B(show running-config | section 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. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged + +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------ +# localhost#show running-config | section ospf +# localhost# + + - name: replace Ospf configs + arista.eos.eos_ospfv2: + config: + - processes: + - process_id: 1 + adjacency: + exchange_start: + threshold: 20045623 + areas: + - filter: + address: "10.1.1.0/24" + id: "0.0.0.2" + - id: "0.0.0.50" + range: + address: "172.20.0.0/16" + cost: 34 + default_information: + metric: 100 + metric_type: 1 + originate: True + distance: + intra_area: 85 + max_lsa: + count: 8000 + ignore_count: 3 + ignore_time: 6 + reset_time: 20 + threshold: 40 + networks: + - area: "0.0.0.0" + prefix: 10.10.2.0/24 + - area: "0.0.0.0" + prefix: "10.10.3.0/24" + redistribute: + - routes: "static" + router_id: "170.21.0.4" + - process_id: 2 + vrf: "vrf01" + areas: + - id: "0.0.0.9" + default_cost: 20 + max_lsa: + count: 8000 + ignore_count: 3 + ignore_time: 6 + reset_time: 20 + threshold: 40 + networks: + - area: "0.0.0.0" + prefix: 10.10.2.0/24 + - area: "0.0.0.0" + prefix: "10.10.3.0/24" + redistribute: + - routes: "static" + router_id: "170.21.0.4" + - process_id: 2 + vrf: "vrf01" + areas: + - id: "0.0.0.9" + default_cost: 20 + max_lsa: + count: 8000 + ignore_count: 3 + ignore_time: 6 + reset_time: 20 + threshold: 40 + - process_id: 3 + vrf: "vrf02" + redistribute: + - routes: "connected" + +# After state: +# localhost#show running-config | section ospf +# router ospf 1 +# router-id 170.21.0.4 +# distance ospf intra-area 85 +# redistribute static +# area 0.0.0.2 filter 10.1.1.0/24 +# area 0.0.0.50 range 172.20.0.0/16 cost 34 +# network 10.10.2.0/24 area 0.0.0.0 +# network 10.10.3.0/24 area 0.0.0.0 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# adjacency exchange-start threshold 20045623 +# default-information originate metric 100 metric-type 1 +# +# router ospf 2 vrf vrf01 +# area 0.0.0.9 default-cost 20 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# ! +# router ospf 3 vrf vrf02 +# redistribute connected +# max-lsa 12000 +# localhost# +# +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] +# + + +# Using replaced: +# -------------- + +# Before State: + +# localhost#show running-config | section ospf +# router ospf 1 +# router-id 170.21.0.4 +# distance ospf intra-area 85 +# redistribute static +# area 0.0.0.2 filter 10.1.1.0/24 +# area 0.0.0.50 range 172.20.0.0/16 cost 34 +# network 10.10.2.0/24 area 0.0.0.0 +# network 10.10.3.0/24 area 0.0.0.0 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# adjacency exchange-start threshold 20045623 +# default-information originate metric 100 metric-type 1 +# ! +# router ospf 2 vrf vrf01 +# area 0.0.0.9 default-cost 20 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# ! +# router ospf 3 vrf vrf02 +# redistribute connected +# max-lsa 12000 +# localhost# +# +# "before": [ +# { +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] +# + - name: replace Ospf configs + arista.eos.eos_ospfv2: + config: + - processes: + - process_id: 2 + vrf: "vrf01" + point_to_point: True + redistribute: + - routes: "isis" + isis_level: "level-1" + + state: replaced + +# After State: +# ----------- +# "router ospf 2 vrf vrf01", +# "no area 0.0.0.9 default-cost 20", +# "no max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20", +# "point-to-point routes", +# "redistribute isis level-1" +# +# "after": [ +# { +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "isis_level": "level-1", +# "routes": "isis" +# } +# ], +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] +# + +# Using overridden: +# ---------------- + +# Before State: +# localhost#show running-config | section ospf +# router ospf 1 +# router-id 170.21.0.4 +# distance ospf intra-area 85 +# redistribute static +# area 0.0.0.2 filter 10.1.1.0/24 +# area 0.0.0.50 range 172.20.0.0/16 cost 34 +# network 10.10.2.0/24 area 0.0.0.0 +# network 10.10.3.0/24 area 0.0.0.0 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# adjacency exchange-start threshold 20045623 +# default-information originate metric 100 metric-type 1 +# ! +# router ospf 2 vrf vrf01 +# redistribute isis level-1 +# max-lsa 12000 +# ! +# router ospf 3 vrf vrf02 +# redistribute connected +# max-lsa 12000 +# localhost# +# +# "before": [ +# { +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "isis_level": "level-1", +# "routes": "isis" +# } +# ], +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] + + - name: override Ospf configs + arista.eos.eos_ospfv2: + config: + - processes: + - process_id: 2 + vrf: "vrf01" + redistribute: + - routes: "connected" + + state: override + +# After State: + +# "no router ospf 1", +# "no router ospf 3", +# "router ospf 2 vrf vrf01", +# "no max-lsa 12000", +# "no redistribute isis level-1", +# "redistribute connected" +# +# "after": [ +# { +# "processes": [ +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf01" +# } +# ] +# } +# ] + +# Using Deleted: + +# localhost#show running-config | section ospf +# router ospf 1 +# router-id 170.21.0.4 +# distance ospf intra-area 85 +# redistribute static +# area 0.0.0.2 filter 10.1.1.0/24 +# area 0.0.0.50 range 172.20.0.0/16 cost 34 +# network 10.10.2.0/24 area 0.0.0.0 +# network 10.10.3.0/24 area 0.0.0.0 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# adjacency exchange-start threshold 20045623 +# default-information originate metric 100 metric-type 1 +# ! +# router ospf 2 vrf vrf01 +# redistribute connected +# area 0.0.0.9 default-cost 20 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# ! +# router ospf 3 vrf vrf02 +# redistribute connected +# max-lsa 12000 +# localhost# +# +# "before": [ +# { +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] + + - name: Delete Ospf configs + arista.eos.eos_ospfv2: + config: + - processes: + - process_id: 1 + + state: deleted + +# After State: +# Commands: +# "no router ospf 1" + +# "after": [ +# { +# "processes": [ +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] + +# Using gathered: +# localhost#show running-config | section ospf +# router ospf 2 vrf vrf01 +# redistribute connected +# area 0.0.0.9 default-cost 20 +# max-lsa 8000 40 ignore-time 6 ignore-count 3 reset-time 20 +# ! +# router ospf 3 vrf vrf02 +# redistribute connected +# max-lsa 12000 +# localhost# + + - name: replace Ospf configs + arista.eos.eos_ospfv2: + state: gathered + +# "gathered": [ +# { +# "processes": [ +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 8000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf01" +# }, +# { +# "max_lsa": { +# "count": 12000 +# }, +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] + +# Using parsed: +# ------------ + +# parsed.cfg +# router ospf 1 +# adjacency exchange-start threshold 20045623 +# area 0.0.0.2 filter 10.1.1.0/24 +# area 0.0.0.50 range 172.20.0.0/16 cost 34 +# default-information originate metric 100 metric-type 1 +# distance ospf intra-area 85 +# max-lsa 80000 40 ignore-count 3 ignore-time 6 reset-time 20 +# network 10.10.2.0/24 area 0.0.0.0 +# network 10.10.3.0/24 area 0.0.0.0 +# redistribute static +# router-id 170.21.0.4 +# router ospf 2 vrf vrf01, +# area 0.0.0.9 default-cost 20 +# max-lsa 80000 40 ignore-count 3 ignore-time 6 reset-time 20 +# router ospf 3 vrf vrf02 +# redistribute static + + - name: Parse Ospf configs + arista.eos.eos_ospfv2: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# "parsed": [ +# { +# "processes": [ +# { +# "adjacency": { +# "exchange_start": { +# "threshold": 20045623 +# } +# }, +# "areas": [ +# { +# "filter": { +# "address": "10.1.1.0/24" +# }, +# "id": "0.0.0.2" +# }, +# { +# "id": "0.0.0.50", +# "range": { +# "address": "172.20.0.0/16", +# "cost": 34 +# } +# } +# ], +# "default_information": { +# "metric": 100, +# "metric_type": 1, +# "originate": true +# }, +# "distance": { +# "intra_area": 85 +# }, +# "max_lsa": { +# "count": 80000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "networks": [ +# { +# "area": "0.0.0.0", +# "prefix": "10.10.2.0/24" +# }, +# { +# "area": "0.0.0.0", +# "prefix": "10.10.3.0/24" +# } +# ], +# "process_id": 1, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "router_id": "170.21.0.4" +# }, +# { +# "areas": [ +# { +# "default_cost": 20, +# "id": "0.0.0.9" +# } +# ], +# "max_lsa": { +# "count": 80000, +# "ignore_count": 3, +# "ignore_time": 6, +# "reset_time": 20, +# "threshold": 40 +# }, +# "process_id": 2, +# "vrf": "vrf01," +# }, +# { +# "process_id": 3, +# "redistribute": [ +# { +# "routes": "static" +# } +# ], +# "vrf": "vrf02" +# } +# ] +# } +# ] + +# Using rendered: +# -------------- + + - name: replace Ospf configs + arista.eos.eos_ospfv2: + config: + - processes: + - process_id: 1 + adjacency: + exchange_start: + threshold: 20045623 + areas: + - filter: + address: 10.1.1.0/24 + id: 0.0.0.2 + - id: 0.0.0.50 + range: + address: 172.20.0.0/16 + cost: 34 + default_information: + metric: 100 + metric_type: 1 + originate: true + distance: + intra_area: 85 + max_lsa: + count: 8000 + ignore_count: 3 + ignore_time: 6 + reset_time: 20 + threshold: 40 + networks: + - area: 0.0.0.0 + prefix: 10.10.2.0/24 + - area: 0.0.0.0 + prefix: 10.10.3.0/24 + redistribute: + - routes: static + router_id: 170.21.0.4 + state: rendered + +# "rendered": [ +# "router ospf 1", +# "adjacency exchange-start threshold 20045623", +# "area 0.0.0.2 filter 10.1.1.0/24", +# "area 0.0.0.50 range 172.20.0.0/16 cost 34", +# "default-information originate metric 100 metric-type 1", +# "distance ospf intra-area 85", +# "max-lsa 8000 40 ignore-count 3 ignore-time 6 reset-time 20", +# "network 10.10.2.0/24 area 0.0.0.0", +# "network 10.10.3.0/24 area 0.0.0.0", +# "redistribute static", +# "router-id 170.21.0.4" +# ] +# + +""" +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: list +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: list +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ["router ospf 1", + "adjacency exchange-start threshold 20045623", + "area 0.0.0.2 filter 10.1.1.0/24", + "area 0.0.0.50 range 172.20.0.0/16 cost 34", + "default-information originate metric 100 metric-type 1", + "distance ospf intra-area 85", + "max-lsa 8000 40 ignore-count 3 ignore-time 6 reset-time 20", + "network 10.10.2.0/24 area 0.0.0.0", + "network 10.10.3.0/24 area 0.0.0.0", + "redistribute static", + "router-id 170.21.0.4"] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.ospfv2.ospfv2 import ( + Ospfv2Args, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Ospfv2(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_ospfv3.py b/ansible_collections/arista/eos/plugins/modules/eos_ospfv3.py new file mode 100644 index 000000000..8c1845262 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_ospfv3.py @@ -0,0 +1,1583 @@ +#!/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 eos_ospfv3 +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_ospfv3 +short_description: OSPFv3 resource module +description: This module configures and manages the attributes of ospfv3 on Arista + EOS platforms. +version_added: 1.1.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A list of configurations for ospfv3. + type: dict + suboptions: + processes: + description: A list of dictionary specifying the ospfv3 processes. + type: list + elements: dict + suboptions: + vrf: + description: VRF name . + type: str + adjacency: + description: Configure adjacency options for OSPF instance. + type: dict + suboptions: + exchange_start: + description: Configure exchange-start options for OSPF instance. + type: dict + suboptions: + threshold: + description: Number of peers to bring up simultaneously. + type: int + auto_cost: + description: Set auto-cost. + type: dict + suboptions: + reference_bandwidth: + description: reference bandwidth in megabits per sec. + type: int + areas: + description: Specifies the configuration for OSPF areas + type: list + elements: dict + suboptions: + area_id: + description: Specifies a 32 bit number expressed in decimal or dotted-decimal + notation. + type: str + default_cost: + description: Specify the cost for default summary route in stub/NSSA + area. + type: int + authentication: + description: Configure authentication for the area incase of ospfv3. + type: dict + suboptions: + spi: + description: Specify the SPI value + type: int + algorithm: + description: Name of algorithm to be used. + type: str + choices: ['md5', 'sha1'] + encrypt_key: + description: If False, key string is not encrypted + type: bool + hidden_key: + description: If True, Specifies that a HIDDEN key will follow. + type: bool + key: + description: 128 bit MD5 key or 140 bit SHA1 key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + encryption: + description: Configure encryption for the area + type: dict + suboptions: + spi: + description: Specify the SPI value + type: int + encryption: + description: name of encryption to be used. + type: str + choices: ['3des-cbc', 'aes-128-cbc', 'aes-192-cbc', 'aes-256-cbc', 'null'] + algorithm: + description: name of the algorithm to be used. + type: str + choices: ['sha1', 'md5'] + encrypt_key: + description: If False, key string is not encrypted + type: bool + hidden_key: + description: If True, Specifies that a HIDDEN key will follow. + type: bool + key: + description: 128 bit MD5 key or 140 bit SHA1 key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + nssa: + description: Configures NSSA parameters. + type: dict + suboptions: + default_information_originate: + description: Originate default Type 7 LSA. + type: dict + suboptions: + metric: + description: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + nssa_only: + description: Limit default advertisement to this NSSA area. + type: bool + set: + description: True if only default information orignate is set + type: bool + no_summary: + description: Filter all type-3 LSAs in the nssa area. + type: bool + nssa_only: + description: Disable Type-7 LSA p-bit setting + type: bool + translate: + description: Enable LSA translation. + type: bool + set: + description: True if only nssa is set + type: bool + stub: + description: Stub area. + type: dict + suboptions: + set: + description: True if only stub is set. + type: bool + summary_lsa: + description: If False , Filter all type-3 LSAs in the stub area. + type: bool + + bfd: + description: Enable BFD. + type: dict + suboptions: + all_interfaces: + description: Enable BFD on all interfaces. + type: bool + fips_restrictions: + description: Use FIPS compliant algorithms + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: dict + suboptions: + grace_period: + description: Specify maximum time to wait for graceful-restart to + complete. + type: int + set: + description: When true sets the grace_fulrestart config alone. + type: bool + graceful_restart_helper: + description: If True, Enable graceful restart helper. + type: bool + log_adjacency_changes: + description: To configure link-state changes and transitions of OSPFv3 + neighbors. + type: dict + suboptions: + detail: + description: If true , configures the switch to log all link-state + changes. + type: bool + set: + description: When true sets the log_adjacency_changes config alone. + type: bool + max_metric: + description: Set maximum metric. + type: dict + suboptions: + router_lsa: + description: Maximum metric in self-originated router-LSAs. + type: dict + suboptions: + set: + description: + - Set router-lsa attribute. + type: bool + external_lsa: + description: Override external-lsa metric with max-metric value. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + 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: + wait_period: + description: + - Wait period in seconds after startup. + 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. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + type: int + passive_interface: + description: Include interface but without actively running OSPF. + type: bool + router_id: + description: 32-bit number assigned to a router running OSPFv3. + type: str + shutdown: + description: Disable the OSPF instance. + type: bool + timers: + description: Configure OSPF timers. + type: dict + suboptions: + out_delay: + description: Configure out-delay timer. + type: int + pacing: + description: Configure OSPF packet pacing. + type: int + throttle: + description: This command is deprecated by 'timers lsa' or 'timers spf'. + type: dict + suboptions: + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + lsa: + description: Configure threshold for retransmission of lsa + type: bool + spf: + description: Configure time between SPF calculations + type: bool + spf: + description: Configure OSPFv3 spf timers. + type: dict + suboptions: + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + lsa: + description: Configure OSPFv3 LSA timers. + type: raw + suboptions: + direction: + description: Configure OSPFv3 LSA receiving/transmission timers. + type: str + choices: ["rx", "tx"] + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + address_family: + description: Enable address family and enter its config mode + type: list + elements: dict + suboptions: + afi: + description: address family . + type: str + choices: + - ipv4 + - ipv6 + adjacency: + description: Configure adjacency options for OSPF instance. + type: dict + suboptions: + exchange_start: + description: Configure exchange-start options for OSPF instance. + type: dict + suboptions: + threshold: + description: Number of peers to bring up simultaneously. + type: int + auto_cost: + description: Set auto-cost. + type: dict + suboptions: + reference_bandwidth: + description: reference bandwidth in megabits per sec. + type: int + areas: + description: Specifies the configuration for OSPF areas + type: list + elements: dict + suboptions: + area_id: + description: Specifies a 32 bit number expressed in decimal or dotted-decimal + notation. + type: str + default_cost: + description: Specify the cost for default summary route in stub/NSSA + area. + type: int + authentication: + description: Configure authentication for the area incase of ospfv3. + type: dict + suboptions: + spi: + description: Specify the SPI value + type: int + algorithm: + description: Name of algorithm to be used. + type: str + choices: ['md5', 'sha1'] + encrypt_key: + description: If False, key string is not encrypted + type: bool + hidden_key: + description: If True, Specifies that a HIDDEN key will follow. + type: bool + key: + description: 128 bit MD5 key or 140 bit SHA1 key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + encryption: + description: Configure encryption for the area + type: dict + suboptions: + spi: + description: Specify the SPI value + type: int + encryption: + description: name of encryption to be used. + type: str + choices: ['3des-cbc', 'aes-128-cbc', 'aes-192-cbc', 'aes-256-cbc', 'null'] + algorithm: + description: name of the algorithm to be used. + type: str + choices: ['sha1', 'md5'] + encrypt_key: + description: If False, key string is not encrypted + type: bool + hidden_key: + description: If True, Specifies that a HIDDEN key will follow. + type: bool + key: + description: 128 bit MD5 key or 140 bit SHA1 key. + type: str + passphrase: + description: Passphrase String for deriving keys for authentication and encryption. + type: str + nssa: + description: Configures NSSA parameters. + type: dict + suboptions: + default_information_originate: + description: Originate default Type 7 LSA. + type: dict + suboptions: + metric: + description: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + nssa_only: + description: Limit default advertisement to this NSSA area. + type: bool + set: + description: True if only default information orignate is set + type: bool + no_summary: + description: Filter all type-3 LSAs in the nssa area. + type: bool + nssa_only: + description: Disable Type-7 LSA p-bit setting + type: bool + translate: + description: Enable LSA translation. + type: bool + set: + description: True if only nssa is set + type: bool + ranges: + description: Configure route summarization. + type: list + elements: dict + suboptions: + address: + description: IP address. + type: str + subnet_address: + description: IP address with mask length + type: str + subnet_mask: + description: IP subnet mask + type: str + advertise: + description: Enable Advertisement of the range. + type: bool + cost: + description: Configures the metric. + type: int + stub: + description: Stub area. + type: dict + suboptions: + set: + description: True if only stub is set + type: bool + summary_lsa: + description: If False , Filter all type-3 LSAs in the stub area. + type: bool + + bfd: + description: Enable BFD. + type: dict + suboptions: + all_interfaces: + description: Enable BFD on all interfaces. + 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: Metric for default route. + type: int + metric_type: + description: Metric type for default route. + type: int + route_map: + description: Specify which route-map to use. + type: str + default_metric: + description: Configure the default metric for redistributed routes. + type: int + distance: + description: Specifies the administrative distance for routes. + type: int + fips_restrictions: + description: Use FIPS compliant algorithms + type: bool + graceful_restart: + description: Enable graceful restart mode. + type: dict + suboptions: + grace_period: + description: Specify maximum time to wait for graceful-restart to complete. + type: int + set: + description: When true sets the grace_fulrestart config alone. + type: bool + graceful_restart_helper: + description: If True, Enable graceful restart helper. + type: bool + log_adjacency_changes: + description: To configure link-state changes and transitions of OSPFv3 + neighbors. + type: dict + suboptions: + detail: + description: If true , configures the switch to log all link-state + changes. + type: bool + set: + description: When true sets the log_adjacency_changes config alone. + type: bool + max_metric: + description: Set maximum metric. + type: dict + suboptions: + router_lsa: + description: Maximum metric in self-originated router-LSAs. + type: dict + suboptions: + set: + description: + - Set router-lsa attribute. + type: bool + external_lsa: + description: Override external-lsa metric with max-metric value. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + 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: + wait_period: + description: + - Wait period in seconds after startup. + 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. + type: dict + suboptions: + set: + description: + - Set external-lsa attribute. + type: bool + max_metric_value: + description: + - Set max metric value for external LSAs. + type: int + maximum_paths: + description: Maximum number of next-hops in an ECMP route. + type: int + passive_interface: + description: Include interface but without actively running OSPF. + type: bool + redistribute: + description: Specifies the routes to be redistributed. + type: list + elements: dict + suboptions: + routes: + description: Route types (BGP,static,connected) + type: str + choices: ['bgp', 'connected', 'static'] + route_map: + description: Specify which route map to use. + type: str + router_id: + description: 32-bit number assigned to a router running OSPFv3. + type: str + shutdown: + description: Disable the OSPF instance. + type: bool + timers: + description: Configure OSPF timers. + type: dict + suboptions: + throttle: + description: This command is deprecated by 'timers lsa' or 'timers spf'. + type: dict + suboptions: + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + lsa: + description: Configure threshold for retransmission of lsa + type: bool + spf: + description: Configure time between SPF calculations + type: bool + out_delay: + description: Configure out-delay timer. + type: int + pacing: + description: Configure OSPF packet pacing. + type: int + spf: + description: Configure OSPFv3 spf timers. + type: dict + suboptions: + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + type: int + lsa: + description: Configure OSPFv3 LSA timers. + type: raw + suboptions: + direction: + description: Configure OSPFv3 LSA receiving/transmission timers. + type: str + choices: ["rx", "tx"] + initial: + description: Initial SPF schedule delay in msecs. + type: int + min: + description: Min Hold time between two SPFs in msecs + type: int + max: + description: Max wait time between two SPFs in msecs. + 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 EOS device by + executing the command B(show running-config | section 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. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged +""" + +EXAMPLES = """ + +# Using merged + +# Before state + +# veos#show running-config | section ospfv3 +# veos# + + + - arista.eos.eos_ospfv3: + config: + processes: + - address_family: + - timers: + lsa: 22 + graceful_restart: + grace_period: 35 + afi: "ipv6" + timers: + pacing: 55 + fips_restrictions: True + router_id: "2.2.2.2" + vrf: "vrfmerge" + + +# After state + +# veos#show running-config | section ospfv3 +# router ospfv3 vrf vrfmerge +# router-id 2.2.2.2 +# test +# fips restrictions +# timers pacing flood 55 +# ! +# address-family ipv6 +# fips restrictions +# timers lsa arrival 22 +# graceful-restart grace-period 35 +# veos# + +# Module Execution +# "after": { +# "processes": [ +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "fips_restrictions": true, +# "graceful_restart": { +# "grace_period": 35 +# }, +# "timers": { +# "lsa": 22 +# } +# } +# ], +# "fips_restrictions": true, +# "router_id": "2.2.2.2", +# "timers": { +# "pacing": 55 +# }, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "router ospfv3 vrf vrfmerge", +# "address-family ipv6", +# "graceful-restart grace-period 35", +# "timers lsa arrival 22", +# "exit", +# "timers pacing flood 55", +# "fips restrictions", +# "router-id 2.2.2.2", +# "exit" +# ], + + +# using replaced + +# before state + +# veos#show running-config | section ospfv3 +# router ospfv3 +# fips restrictions +# area 0.0.0.0 encryption ipsec spi 43 esp null md5 passphrase 7 h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4= +# ! +# router ospfv3 vrf vrfmerge +# router-id 2.2.2.2 +# fips restrictions +# timers pacing flood 55 +# ! +# address-family ipv6 +# fips restrictions +# timers lsa arrival 22 +# graceful-restart grace-period 35 +# veos# + + + - arista.eos.eos_ospfv3: + config: + processes: + - areas: + - area_id: "0.0.0.0" + encryption: + spi: 43 + encryption: "null" + algorithm: "md5" + encrypt_key: False + passphrase: "7hl8FV3lZ6H1mAKpjL47hQ==" + vrf: "default" + address_family: + - afi: "ipv4" + router_id: "7.1.1.1" + state: replaced + +# After state +# veos#show running-config | section ospfv3 +# router ospfv3 +# area 0.0.0.0 encryption ipsec spi 43 esp null md5 passphrase 7 h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4= +# ! +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + +# Module execution + +# "after": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "0.0.0.0", +# "encryption": { +# "algorithm": "md5", +# "encryption": "null", +# "hidden_key": true, +# "passphrase": "h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4=" +# } +# } +# ], +# "vrf": "default" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "0.0.0.0", +# "encryption": { +# "algorithm": "md5", +# "encryption": "null", +# "hidden_key": true, +# "passphrase": "h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4=" +# } +# } +# ], +# "fips_restrictions": true, +# "vrf": "default" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "fips_restrictions": true, +# "graceful_restart": { +# "grace_period": 35 +# }, +# "timers": { +# "lsa": 22 +# } +# } +# ], +# "fips_restrictions": true, +# "router_id": "2.2.2.2", +# "timers": { +# "pacing": 55 +# }, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "router ospfv3 vrf vrfmerge", +# "address-family ipv6", +# "no fips restrictions", +# "no graceful-restart", +# "no timers lsa arrival 22", +# "area 0.0.0.3 range 10.1.2.2/24 advertise", +# "area 0.0.0.3 range 60.1.1.1 255.255.0.0 cost 30", +# "exit", +# "passive-interface default", +# "no router-id", +# "no fips restrictions", +# "no timers pacing flood 55", +# "exit" +# ], + + +# using overridden + +# before state + +# veos#show running-config | section ospfv3 +# router ospfv3 +# area 0.0.0.0 encryption ipsec spi 43 esp null md5 passphrase 7 h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4= +# ! +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + + + - arista.eos.eos_ospfv3: + config: + processes: + - address_family: + - areas: + - area_id: "0.0.0.3" + ranges: + - address: 10.1.2.2/24 + advertise: True + - address: 60.1.1.1 + subnet_mask: 255.255.0.0 + cost: 30 + afi: "ipv6" + passive_interface: True + vrf: "vrfmerge" + state: overridden + +# After state + +# veos#show running-config | section ospfv3 +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + + + +# Module execution + +# "after": { +# "processes": [ +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "0.0.0.0", +# "encryption": { +# "algorithm": "md5", +# "encryption": "null", +# "hidden_key": true, +# "passphrase": "h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4=" +# } +# } +# ], +# "vrf": "default" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "no router ospfv3", +# "router ospfv3 vrf vrfmerge", +# "address-family ipv6", +# "no area 0.0.0.3 range 10.1.2.0/24", +# "no area 0.0.0.3 range 60.1.0.0/16 cost 30", +# "area 0.0.0.3 range 10.1.2.2/24 advertise", +# "area 0.0.0.3 range 60.1.1.1 255.255.0.0 cost 30", +# "exit", +# "exit" +# ], + +# using deleted + +# Before state + +# veos#show running-config | section ospfv3 +# router ospfv3 +# area 0.0.0.0 encryption ipsec spi 43 esp null md5 passphrase 7 h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4= +# ! +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv4 +# redistribute connected +# redistribute static route-map MAP01 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + + + - arista.eos.eos_ospfv3: + config: + processes: + - vrf: "default" + state: deleted + +# After state + +# veos#show running-config | section ospfv3 +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv4 +# redistribute connected +# redistribute static route-map MAP01 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + + +# Module execution +# "after": { +# "processes": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ], +# "redistribute": [ +# { +# "routes": "connected" +# }, +# { +# "route_map": "MAP01", +# "routes": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "0.0.0.0", +# "encryption": { +# "algorithm": "md5", +# "encryption": "null", +# "hidden_key": true, +# "passphrase": "h8pZp9eprTYjjoY/NKFFe0Ei7x03Y7dyLotRhI0a5t4=" +# } +# } +# ], +# "vrf": "default" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ], +# "redistribute": [ +# { +# "routes": "connected" +# }, +# { +# "route_map": "MAP01", +# "routes": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "no router ospfv3" +# ], + +# using parsed + +# parsed_ospfv3.cfg + +# router ospfv3 +# fips restrictions +# area 0.0.0.20 stub +# area 0.0.0.20 authentication ipsec spi 33 sha1 passphrase 7 4O8T3zo4xBdRWXBnsnK934o9SEb+jEhHUN6+xzZgCo2j9EnQBUvtwNxxLEmYmm6w +# area 0.0.0.40 default-cost 45 +# area 0.0.0.40 stub +# timers pacing flood 7 +# adjacency exchange-start threshold 11 +# ! +# address-family ipv4 +# fips restrictions +# redistribute connected +# ! +# address-family ipv6 +# router-id 10.1.1.1 +# fips restrictions +# ! +# router ospfv3 vrf vrf01 +# bfd all-interfaces +# fips restrictions +# area 0.0.0.0 encryption ipsec spi 256 esp null sha1 passphrase 7 7hl8FV3lZ6H1mAKpjL47hQ== +# log-adjacency-changes detail +# ! +# address-family ipv4 +# passive-interface default +# fips restrictions +# redistribute connected route-map MAP01 +# maximum-paths 100 +# ! +# address-family ipv6 +# fips restrictions +# area 0.0.0.10 nssa no-summary +# default-information originate route-map DefaultRouteFilter +# max-metric router-lsa external-lsa 25 summary-lsa +# ! +# router ospfv3 vrf vrf02 +# fips restrictions +# ! +# address-family ipv6 +# router-id 10.17.0.3 +# distance ospf intra-area 200 +# fips restrictions +# area 0.0.0.1 stub +# timers spf delay initial 56 56 56 +# timers out-delay 10 + + + - arista.eos.eos_ospfv3: + running_config: "{{ lookup('file', './parsed_ospfv3.cfg') }}" + state: parsed + +# Module execution + +# "parsed": { +# "processes": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "fips_restrictions": true, +# "redistribute": [ +# { +# "routes": "connected" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "fips_restrictions": true, +# "router_id": "10.1.1.1" +# } +# ], +# "adjacency": { +# "exchange_start": { +# "threshold": 11 +# } +# }, +# "areas": [ +# { +# "area_id": "0.0.0.20", +# "authentication": { +# "algorithm": "sha1", +# "hidden_key": true, +# "passphrase": "4O8T3zo4xBdRWXBnsnK934o9SEb+jEhHUN6+xzZgCo2j9EnQBUvtwNxxLEmYmm6w", +# "spi": 33 +# }, +# "stub": { +# "set": true +# } +# }, +# { +# "area_id": "0.0.0.40", +# "default_cost": 45, +# "stub": { +# "set": true +# } +# } +# ], +# "fips_restrictions": true, +# "timers": { +# "pacing": 7 +# }, +# "vrf": "default" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "fips_restrictions": true, +# "maximum_paths": 100, +# "passive_interface": true, +# "redistribute": [ +# { +# "route_map": "MAP01", +# "routes": "connected" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.10", +# "nssa": { +# "no_summary": true +# } +# } +# ], +# "default_information": { +# "originate": true, +# "route_map": "DefaultRouteFilter" +# }, +# "fips_restrictions": true, +# "max_metric": { +# "router_lsa": { +# "external_lsa": { +# "max_metric_value": 25 +# }, +# "summary_lsa": { +# "set": true +# } +# } +# } +# } +# ], +# "areas": [ +# { +# "area_id": "0.0.0.0", +# "encryption": { +# "algorithm": "sha1", +# "encryption": "null", +# "hidden_key": true, +# "passphrase": "7hl8FV3lZ6H1mAKpjL47hQ==" +# } +# } +# ], +# "bfd": { +# "all_interfaces": true +# }, +# "fips_restrictions": true, +# "log_adjacency_changes": { +# "detail": true +# }, +# "vrf": "vrf01" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.1", +# "stub": { +# "set": true +# } +# } +# ], +# "distance": 200, +# "fips_restrictions": true, +# "router_id": "10.17.0.3", +# "timers": { +# "out_delay": 10, +# "spf": { +# "initial": 56, +# "max": 56, +# "min": 56, +# } +# } +# } +# ], +# "fips_restrictions": true, +# "vrf": "vrf02" +# } +# ] + +# using gathered + +# native config + +# veos#show running-config | section ospfv3 +# router ospfv3 vrf vrfmerge +# passive-interface default +# ! +# address-family ipv4 +# redistribute connected +# redistribute static route-map MAP01 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# ! +# address-family ipv6 +# area 0.0.0.3 range 10.1.2.0/24 +# area 0.0.0.3 range 60.1.0.0/16 cost 30 +# veos# + + + - arista.eos.eos_ospfv3: + state: gathered + +# module execution + +# "gathered": { +# "processes": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ], +# "redistribute": [ +# { +# "routes": "connected" +# }, +# { +# "route_map": "MAP01", +# "routes": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "areas": [ +# { +# "area_id": "0.0.0.3", +# "ranges": [ +# { +# "address": "10.1.2.0/24" +# }, +# { +# "address": "60.1.0.0/16", +# "cost": 30 +# } +# ] +# } +# ] +# } +# ], +# "passive_interface": true, +# "vrf": "vrfmerge" +# } +# ] + +# using rendered + + - arista.eos.eos_ospfv3: + config: + processes: + - address_family: + - timers: + lsa: 22 + graceful_restart: + grace_period: 35 + afi: "ipv6" + timers: + pacing: 55 + fips_restrictions: True + router_id: "2.2.2.2" + vrf: "vrfmerge" + state: rendered + +# module execution + +# "rendered": [ +# "router ospfv3 vrf vrfmerge", +# "address-family ipv6", +# "graceful-restart grace-period 35", +# "timers lsa arrival 22", +# "exit", +# "timers pacing flood 55", +# "fips restrictions", +# "router-id 2.2.2.2", +# "exit" +# ] + + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.ospfv3.ospfv3 import ( + Ospfv3Args, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.ospfv3.ospfv3 import ( + Ospfv3, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ospfv3Args.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=False, + ) + + result = Ospfv3(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_prefix_lists.py b/ansible_collections/arista/eos/plugins/modules/eos_prefix_lists.py new file mode 100644 index 000000000..dffd65527 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_prefix_lists.py @@ -0,0 +1,1197 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for eos_prefix_lists +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: eos_prefix_lists +short_description: Manages Prefix lists resource module +description: This module configures and manages the attributes of Prefix lists on Arista + EOS platforms. +version_added: 2.2.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: A list of dictionary of prefix-list options + type: list + elements: dict + suboptions: + afi: + description: + - The Address Family Indicator (AFI) for the prefix list. + type: str + required: true + choices: + - ipv4 + - ipv6 + prefix_lists: + description: + - A list of prefix-lists. + type: list + elements: dict + suboptions: + name: + description: Name of the prefix-list + type: str + required: true + entries: + description: List of prefix-lists + type: list + elements: dict + suboptions: + action: + description: action to be performed on the specified path + type: str + choices: ['deny', 'permit'] + address: + description: ipv4/v6 address in prefix-mask or address-masklen format + type: str + match: + description: match masklen + type: dict + suboptions: + operator: + description: equalto/greater than/lesser than + type: str + choices: ['eq', 'le', 'ge'] + masklen: + description: Mask Length. + type: int + sequence: + description: sequence number + type: int + resequence: + description: Resequence the list. + type: dict + suboptions: + default: + description: Resequence with default values (10). + type: bool + start_seq: + description: Starting sequence number. + type: int + step: + description: Step to increment the sequence number. + 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 EOS device by + executing the command B(show running-config | section 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: + description: + - The state the configuration should be left in. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state +# veos#show running-config | section prefix-lists +# veos# + + - name: Merge provided configuration with device configuration + arista.eos.eos_prefix_lists: + config: + - afi: "ipv4" + prefix_lists: + - name: "v401" + entries: + - sequence: 25 + action: "deny" + address: "45.55.4.0/24" + - sequence: 100 + action: "permit" + address: "11.11.2.0/24" + match: + masklen: 32 + operator: "ge" + - name: "v402" + entries: + - action: "deny" + address: "10.1.1.0/24" + sequence: 10 + match: + masklen: 32 + operator: "ge" + - afi: "ipv6" + prefix_lists: + - name: "v601" + entries: + - sequence: 125 + action: "deny" + address: "5000:1::/64" + +# After State +# veos# +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 +# seq 100 permit 11.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# +# +# Module Execution: +# "after": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "before": {}, +# "changed": true, +# "commands": [ +# "ipv6 prefix-list v601", +# "seq 125 deny 5000:1::/64", +# "ip prefix-list v401", +# "seq 25 deny 45.55.4.0/24", +# "seq 100 permit 11.11.2.0/24 ge 32", +# "ip prefix-list v402", +# "seq 10 deny 10.1.1.0/24 ge 32" +# ], +# + +# using merged: +# Failure scenario : 'merged' should not be used when an existing prefix-list (sequence number) +# is to be modified. + +# Before State: +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 +# seq 100 permit 11.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# + + - name: Merge provided configuration with device configuration + arista.eos.eos_prefix_lists: + config: + - afi: "ipv4" + prefix_lists: + - name: "v401" + entries: + - sequence: 25 + action: "deny" + address: "45.55.4.0/24" + match: + masklen: 32 + operator: "ge" + - sequence: 100 + action: "permit" + address: "11.11.2.0/24" + match: + masklen: 32 + operator: "ge" + - name: "v402" + entries: + - action: "deny" + address: "10.1.1.0/24" + sequence: 10 + match: + masklen: 32 + operator: "ge" + - afi: "ipv6" + prefix_lists: + - name: "v601" + entries: + - sequence: 125 + action: "deny" + address: "5000:1::/64" + state: merged + +# Module Execution: +# fatal: [192.168.122.113]: FAILED! => { +# "changed": false, +# "invocation": { +# "module_args": { +# "config": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "resequence": null, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "resequence": null, +# "sequence": 100 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "resequence": null, +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "match": null, +# "resequence": null, +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "running_config": null, +# "state": "merged" +# } +# }, +# "msg": "Sequence number 25 is already present. Use replaced/overridden operation to change the configuration" +# } +# + +# Using Replaced: + +# Before state: +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 +# seq 100 permit 11.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# + - name: Replace + arista.eos.eos_prefix_lists: + config: + - afi: "ipv4" + prefix_lists: + - name: "v401" + entries: + - sequence: 25 + action: "deny" + address: "45.55.4.0/24" + match: + masklen: 32 + operator: "ge" + - sequence: 200 + action: "permit" + address: "200.11.2.0/24" + match: + masklen: 32 + operator: "ge" + state: replaced +# After State: +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 200 permit 200.11.2.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# +# +# +# Module Execution: +# +# "after": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "200.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 200 +# } +# ], +# "name": "v401" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "before": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "ip prefix-list v401", +# "no seq 25", +# "seq 25 deny 45.55.4.0/24 ge 32", +# "seq 200 permit 200.11.2.0/24 ge 32", +# "no seq 100", +# "no ip prefix-list v402" +# ], + +# Using overridden: +# Before State: + +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 100 permit 11.11.2.0/24 ge 32 +# seq 200 permit 200.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# + + + - name: Override + arista.eos.eos_prefix_lists: + config: + - afi: "ipv4" + prefix_lists: + - name: "v401" + entries: + - sequence: 25 + action: "deny" + address: "45.55.4.0/24" + - sequence: 300 + action: "permit" + address: "30.11.2.0/24" + match: + masklen: 32 + operator: "ge" + - name: "v403" + entries: + - action: "deny" + address: "10.1.1.0/24" + sequence: 10 + state: overridden + +# After State +# veos# +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 300 permit 30.11.2.0/24 ge 32 +# ! +# ip prefix-list v403 +# seq 10 deny 10.1.1.0/24 +# veos# +# +# +# Module Execution: +# "after": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "30.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 300 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "sequence": 10 +# } +# ], +# "name": "v403" +# } +# ] +# } +# ], +# "before": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# }, +# { +# "action": "permit", +# "address": "200.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 200 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ipv6 prefix-list v601", +# "ip prefix-list v401", +# "seq 25 deny 45.55.4.0/24", +# "seq 300 permit 30.11.2.0/24 ge 32", +# "no seq 100", +# "no seq 200", +# "ip prefix-list v403", +# "seq 10 deny 10.1.1.0/24", +# "no ip prefix-list v402" +# ], +# + +# Using deleted: +# Before State: + +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 100 permit 11.11.2.0/24 ge 32 +# seq 300 permit 30.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ip prefix-list v403 +# seq 10 deny 10.1.1.0/24 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# + + - name: Delete device configuration + arista.eos.eos_prefix_lists: + config: + - afi: "ipv6" + state: deleted + + +# after State: +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 100 permit 11.11.2.0/24 ge 32 +# seq 300 permit 30.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ip prefix-list v403 +# seq 10 deny 10.1.1.0/24 +# +# +# Module Execution: +# "after": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# }, +# { +# "action": "permit", +# "address": "30.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 300 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "sequence": 10 +# } +# ], +# "name": "v403" +# } +# ] +# } +# ], +# "before": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# }, +# { +# "action": "permit", +# "address": "30.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 300 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "sequence": 10 +# } +# ], +# "name": "v403" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ipv6 prefix-list v601" +# ], +# + +# Using deleted +# Before state: + +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 ge 32 +# seq 100 permit 11.11.2.0/24 ge 32 +# seq 300 permit 30.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ip prefix-list v403 +# seq 10 deny 10.1.1.0/24 +# veos# + + - name: Delete device configuration + arista.eos.eos_prefix_lists: + state: deleted + +# After State: +# veos#show running-config | section prefix-list +# veos# +# +# Module Execution: +# "after": {}, +# "before": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# }, +# { +# "action": "permit", +# "address": "30.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 300 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "sequence": 10 +# } +# ], +# "name": "v403" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ip prefix-list v401", +# "no ip prefix-list v402", +# "no ip prefix-list v403" +# ], +# + +# Using parsed: +# parse_prefix_lists.cfg +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 +# seq 100 permit 11.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# + - name: parse configs + arista.eos.eos_prefix_lists: + running_config: "{{ lookup('file', './parsed_prefix_lists.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ] + +# Using rendered: + - name: Render provided configuration + arista.eos.eos_prefix_lists: + config: + - afi: "ipv4" + prefix_lists: + - name: "v401" + entries: + - sequence: 25 + action: "deny" + address: "45.55.4.0/24" + - sequence: 200 + action: "permit" + address: "200.11.2.0/24" + match: + masklen: 32 + operator: "ge" + - name: "v403" + entries: + - action: "deny" + address: "10.1.1.0/24" + sequence: 10 + state: rendered + +# Module Execution: +# "rendered": [ +# "ip prefix-list v401", +# "seq 25 deny 45.55.4.0/24", +# "seq 200 permit 200.11.2.0/24 ge 32", +# "ip prefix-list v403", +# "seq 10 deny 10.1.1.0/24" +# ] +# + +# using gathered: +# Device config: +# veos#show running-config | section prefix-list +# ip prefix-list v401 +# seq 25 deny 45.55.4.0/24 +# seq 100 permit 11.11.2.0/24 ge 32 +# ! +# ip prefix-list v402 +# seq 10 deny 10.1.1.0/24 ge 32 +# ! +# ipv6 prefix-list v601 +# seq 125 deny 5000:1::/64 +# veos# + + - name: gather configs + arista.eos.eos_prefix_lists: + state: gathered + +# Module Execution: +# +# "gathered": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "45.55.4.0/24", +# "sequence": 25 +# }, +# { +# "action": "permit", +# "address": "11.11.2.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 100 +# } +# ], +# "name": "v401" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "address": "10.1.1.0/24", +# "match": { +# "masklen": 32, +# "operator": "ge" +# }, +# "sequence": 10 +# } +# ], +# "name": "v402" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "address": "5000:1::/64", +# "sequence": 125 +# } +# ], +# "name": "v601" +# } +# ] +# } +# ], + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.prefix_lists.prefix_lists import ( + Prefix_listsArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.prefix_lists.prefix_lists import ( + Prefix_lists, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Prefix_listsArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Prefix_lists(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_route_maps.py b/ansible_collections/arista/eos/plugins/modules/eos_route_maps.py new file mode 100644 index 000000000..3b1869547 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_route_maps.py @@ -0,0 +1,1406 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 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 eos_route_maps +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_route_maps +short_description: Manages Route Maps resource module +description: This module configures and manages the attributes of Route Mapd on Arista + EOS platforms. +version_added: 2.1.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,eos_platform_options). +options: + config: + description: A list of route-map options + type: list + elements: dict + suboptions: + route_map: + description: Route map name. + type: str + entries: + description: Route Map entries. + type: list + elements: dict + suboptions: + statement: + description: statement name + type: str + source: + description: Rename/Copy configuration + type: dict + suboptions: + action: + description: rename or copy configuration + type: str + choices: ["rename", "copy"] + source_map_name: + description: Source route map name. + type: str + overwrite: + description: if True, overwrite existing config. + type: bool + action: + description: Action for matching routes + type: str + choices: ["deny", "permit"] + sequence: + description: Index in the sequence. + type: int + continue_sequence: + description: Route map entry sequence number. + type: int + description: + description: Description for the route map. + type: str + sub_route_map: + description: Sub route map + type: dict + suboptions: + name: + description: sub route map name + type: str + invert_result: + description: Invert sub route map result + type: bool + set: + description: set route attributes. + type: dict + suboptions: + as_path: + description: Set as-path. + type: dict + suboptions: + match: + description: Match the entire as-path. + type: dict + suboptions: + as_number: + description: as number to use (includes auto;in csv format) + type: str + none: + description: Remove matching AS numbers + type: bool + prepend: + description: Prepend to the as-path. + type: dict + suboptions: + as_number: + description: as number to prepend (includes auto;in csv format) + type: str + last_as: + description: The number of times to prepend the last AS number. + type: int + bgp: + description: BGP AS path multipath weight. + type: int + community_attributes: + description: BGP community attribute. + type: dict + suboptions: + graceful_shutdown: + description: Graceful shutdown + type: bool + community: + description: community attributes. + type: dict + suboptions: + number: + description: community number (in csv format). + type: str + list: + description: community list name. + type: str + graceful_shutdown: + description: Gracefully shutdown. + type: bool + additive: + description: Add to existing community. + type: bool + delete: + description: Delete matching communities. + type: bool + internet: + description: Internet community + type: bool + local_as: + description: Do not send outside local AS. + type: bool + no_advertise: + description: Do not advertise to any peer. + type: bool + no_export: + description: Do not export to next AS. + type: bool + none: + description: No community attribute. + type: bool + distance: + description: Set protocol independent distance. + type: int + evpn: + description: Keep the next hop when advertising to eBGP peers. + type: bool + extcommunity: + description: BGP extended community attribute. + type: dict + suboptions: + lbw: + description: Link bandwith values. + type: dict + suboptions: + value: + description: Link Bandwidth extended community value. + type: str + aggregate: + description: Aggregate Link Bandwidth. + type: bool + divide: + description: Divide Link Bandwidth. + type: str + choices: ["equal", "ration"] + none: + description: No attribute. + type: bool + rt: + description: Route target extended community + type: dict + suboptions: ¶ms01 + vpn: + description: VPN extended community. + type: str + additive: + description: Add to the existing community. + type: bool + delete: + description: Delete matching communities. + type: bool + soo: + description: Site-of-Origin extended community. + type: dict + suboptions: *params01 + ip: + description: Set IP specific information. + type: dict + suboptions: ¶ms02 + address: + description: next hop address. + type: str + unchanged: + description: Keep the next hop when advertising to eBGP peer + type: bool + peer_address: + description: Use BGP peering addr as next-hop. + type: bool + ipv6: + description: Set IPv6 specific information. + type: dict + suboptions: *params02 + isis_level: + description: IS-IS level. + type: str + local_preference: + description: BGP local preference. + type: int + metric: + description: Route metric. + type: dict + suboptions: + igp_param: + description: IGP parameter + type: str + choices: ['igp-metric', 'igp-nexthop-cost'] + add: + description: Add igp-metric / igp-nexthop-cost + type: str + choices: ['igp-metric', 'igp-nexthop-cost'] + value: + description: metric value to add or subtract(with +/- sign). + type: str + metric_type: + description: Route metric type. + type: str + choices: ["type-1", "type-2"] + nexthop: + description: Route next hop. + type: dict + suboptions: + value: + description: IGP metric value. + type: int + max_metric: + description: Set IGP max metric value. + type: bool + origin: + description: Set bgp origin. + type: str + choices: ["egp", "igp", "incomplete"] + segment_index: + description: MPLS Segment-routing Segment Index. + type: int + tag: + description: Route tag + type: int + weight: + description: BGP weight. + type: int + match: + description: Route map match rules. + type: dict + suboptions: + aggregate_role: ¶ms04 + description: Role in BGP contributor-aggregate relation. + type: dict + suboptions: + contributor: + description: BGP aggregate's contributor. + type: bool + route_map: + description: Route map to apply against the aggregate route. + type: str + as: + description: BGP AS number. + type: int + as_path: ¶ms05 + description: Set as-path. + type: dict + suboptions: + path_list: + description: AS path list name. + type: str + length: + description: Specify as-path length ( with comparison operators like <= 60 and >= 40 ). + type: str + community: ¶ms06 + description: BGP community attribute. + type: dict + suboptions: + community_list: + description: list of community names (in csv format). + type: str + exact_match: + description: Do exact matching of communities. + type: bool + instances: + description: Match number of community instances ( with comparison operators like <= 60 and >= 40 ). + type: str + extcommunity: ¶ms07 + description: extended community list name. + type: dict + suboptions: + community_list: + description: list of community names (in csv format). + type: str + exact_match: + description: Do exact matching of communities. + type: bool + interface: + description: interface name. + type: str + invert_result: + description: Invert match result. + type: dict + suboptions: + aggregate_role: *params04 + as_path: *params05 + community: *params06 + extcommunity: *params07 + large_community: *params07 + ip: + description: Set IP specific information. + type: dict + suboptions: ¶ms08 + address: + description: next hop destination. + type: dict + suboptions: + access_list: + description: ip access-list. + type: str + dynamic: + description: Configure dynamic prefix-list. + type: bool + prefix_list: + description: Prefix list. + type: str + next_hop: + description: next hop prefix list. + type: str + resolved_next_hop: + description: Route resolved prefix list. + type: str + ipv6: + description: Set IPv6 specific information. + type: dict + suboptions: *params08 + large_community: *params07 + isis_level: + description: IS-IS level. + type: str + local_preference: + description: BGP local preference. + type: int + metric: + description: Route metric. + type: int + metric_type: + description: Route metric type. + type: str + choices: ["type-1", "type-2"] + route_type: + description: Route type + type: str + router_id: + description: Router ID. + type: str + source_protocol: + description: Source routing protocol, + type: str + tag: + description: Route tag + 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 EOS device by + executing the command B(show running-config | section route-map). + - 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. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state +# veos#show running-config | section route-map +# veos# + + - name: Merge provided configuration with device configuration + arista.eos.eos_route_maps: + config: + - route_map: "mapmerge" + entries: + - description: "merged_map" + action: "permit" + sequence: 10 + match: + router_id: 22 + - description: "newmap" + action: "deny" + sequence: 25 + continue_sequence: 45 + match: + interface: "Ethernet1" + - route_map: "mapmerge2" + entries: + - sub_route_map: + name: "mapmerge" + action: "deny" + sequence: 45 + set: + metric: + value: 25 + add: "igp-metric" + as_path: + prepend: + last_as: 2 + match: + ipv6: + resolved_next_hop: "list1" + state: merged + +# After State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# ! +# route-map test permit 10 +# veos# + + +# Module Execution: + +# "after": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "router_id": "22" +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], +# "before": {}, +# "changed": true, +# "commands": [ +# "route-map mapmerge permit 10", +# "match router-id prefix-list 22", +# "description merged_map", +# "route-map mapmerge deny 25", +# "match interface Ethernet1", +# "description newmap", +# "continue 45", +# "route-map mapmerge2 deny 45", +# "match ipv6 resolved-next-hop prefix-list list1", +# "set metric 25 +igp-metric", +# "set as-path prepend last-as 2", +# "sub-route-map mapmerge" +# ], +# + +# Using replaced: + +# Before State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# ! +# veos# + + - name: Replace + arista.eos.eos_route_maps: + config: + - route_map: "mapmerge" + entries: + - action: "permit" + sequence: 10 + match: + ipv6: + resolved_next_hop: "listr" + - action: "deny" + sequence: 90 + set: + extcommunity: + rt: + vpn: "22:11" + delete: True + ip: + unchanged: True + state: replaced + +# After State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# match ipv6 resolved-next-hop prefix-list listr +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge deny 90 +# set ip next-hop unchanged +# set extcommunity rt 22:11 delete +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# ! +# +# Module Execution: +# +# "after": [ +# { +# "entries": [ +# { +# "action": "permit", +# "match": { +# "ipv6": { +# "resolved_next_hop": "listr" +# } +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# }, +# { +# "action": "deny", +# "sequence": 90, +# "set": { +# "extcommunity": { +# "rt": { +# "delete": true, +# "vpn": "22:11" +# } +# }, +# "ip": { +# "unchanged": true +# } +# } +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "sequence": 10 +# } +# ], +# "route_map": "test" +# } +# ], +# "before": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "router_id": "22" +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], +# "changed": true, +# "commands": [ +# "route-map mapmerge permit 10", +# "match ipv6 resolved-next-hop prefix-list listr", +# "no match router-id prefix-list 22", +# "no description", +# "route-map mapmerge deny 90", +# "set extcommunity rt 22:11 delete", +# "set ip next-hop unchanged" +# ], +# +# +# Using Overridden: + +# Before state: +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# match ipv6 resolved-next-hop prefix-list listr +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge deny 90 +# set ip next-hop unchanged +# set extcommunity rt 22:11 delete +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# ! +# route-map test permit 10 +# veos# + + - name: Override + arista.eos.eos_route_maps: + config: + - route_map: "mapmerge" + entries: + - action: "permit" + sequence: 10 + match: + ipv6: + resolved_next_hop: "listr" + - action: "deny" + sequence: 90 + set: + metric: + igp_param: "igp-nexthop-cost" + state: overridden + +# After State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# match ipv6 resolved-next-hop prefix-list listr +# ! +# route-map mapmerge deny 90 +# set metric igp-nexthop-cost +# veos# +# +# +# "after": [ +# { +# "entries": [ +# { +# "action": "permit", +# "match": { +# "ipv6": { +# "resolved_next_hop": "listr" +# } +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "sequence": 90, +# "set": { +# "metric": { +# "igp_param": "igp-nexthop-cost" +# } +# } +# } +# ], +# "route_map": "mapmerge" +# } +# ], +# "before": [ +# { +# "entries": [ +# { +# "action": "permit", +# "match": { +# "ipv6": { +# "resolved_next_hop": "listr" +# } +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# }, +# { +# "action": "deny", +# "sequence": 90, +# "set": { +# "extcommunity": { +# "rt": { +# "delete": true, +# "vpn": "22:11" +# } +# }, +# "ip": { +# "unchanged": true +# } +# } +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "sequence": 10 +# } +# ], +# "route_map": "test" +# } +# ], +# "changed": true, +# "commands": [ +# "no route-map mapmerge deny 25", +# "no route-map mapmerge2 deny 45", +# "no route-map test permit 10", +# "route-map mapmerge deny 90", +# "set metric igp-nexthop-cost", +# "no set ip next-hop unchanged", +# "no set extcommunity rt 22:11 delete" +# ], +# +# Using deleted: +# Before State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# match ipv6 resolved-next-hop prefix-list listr +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge deny 90 +# set metric igp-nexthop-cost +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# veos# + + - name: Delete route-map + arista.eos.eos_route_maps: + config: + - route_map: "mapmerge" + state: deleted + become: yes + tags: + - deleted1 + +# After State: + +# veos#show running-config | section route-map +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# veos# +# +# Module Execution: +# +# "after": [ +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], +# "before": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "ipv6": { +# "resolved_next_hop": "listr" +# }, +# "router_id": "22" +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# }, +# { +# "action": "deny", +# "sequence": 90, +# "set": { +# "metric": { +# "igp_param": "igp-nexthop-cost" +# } +# } +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], +# "changed": true, +# "commands": [ +# "no route-map mapmerge" +# ], + +# Using deleted to delete all route-maps: + +# Before State: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# veos# + + - name: Delete all route-maps + arista.eos.eos_route_maps: + state: deleted + +# After State: +# veos#show running-config | section route-map +# veos# +# +# Module Execution: +# +# "after": {}, +# "before": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "router_id": "22" +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], +# "changed": true, +# "commands": [ +# "no route-map mapmerge", +# "no route-map mapmerge2" +# ], + +# Using gathered: + +# Device configs: + +# veos#show running-config | section route-map +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 +# veos# + + - name: gather configs + arista.eos.eos_route_maps: + state: gathered + +# Module Execution: +# "gathered": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "router_id": "22" +# }, +# "sequence": 10 +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ], + +# Using rendered: + + - name: Render provided configuration + arista.eos.eos_route_maps: + config: + - route_map: "mapmerge" + entries: + - description: "merged_map" + action: "permit" + sequence: 10 + match: + router_id: 22 + set: + bgp: 20 + - description: "newmap" + action: "deny" + sequence: 25 + continue_sequence: 45 + match: + interface: "Ethernet1" + - route_map: "mapmerge2" + entries: + - sub_route_map: + name: "mapmerge" + action: "deny" + sequence: 45 + set: + metric: + value: 25 + add: "igp-metric" + as_path: + prepend: + last_as: 2 + match: + ipv6: + resolved_next_hop: "list1" + state: rendered + +# Module Execution: +# "rendered": [ +# "route-map mapmerge permit 10", +# "match router-id prefix-list 22", +# "set bgp bestpath as-path weight 20", +# "description merged_map", +# "route-map mapmerge deny 25", +# "match interface Ethernet1", +# "description newmap", +# "continue 45", +# "route-map mapmerge2 deny 45", +# "match ipv6 resolved-next-hop prefix-list list1", +# "set metric 25 +igp-metric", +# "set as-path prepend last-as 2", +# "sub-route-map mapmerge" +# ] + +# Using parsed: + +# parsed.cfg +# route-map mapmerge permit 10 +# description merged_map +# match router-id prefix-list 22 +# set bgp bestpath as-path weight 20 +# ! +# route-map mapmerge deny 25 +# description newmap +# match interface Ethernet1 +# continue 45 +# ! +# route-map mapmerge2 deny 45 +# match ipv6 resolved-next-hop prefix-list list1 +# sub-route-map mapmerge +# set metric 25 +igp-metric +# set as-path prepend last-as 2 + + - name: parse configs + arista.eos.eos_route_maps: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": "merged_map", +# "match": { +# "router_id": "22" +# }, +# "sequence": 10, +# "set": { +# "bgp": 20 +# } +# }, +# { +# "action": "deny", +# "continue_sequence": 45, +# "description": "newmap", +# "match": { +# "interface": "Ethernet1" +# }, +# "sequence": 25 +# } +# ], +# "route_map": "mapmerge" +# }, +# { +# "entries": [ +# { +# "action": "deny", +# "match": { +# "ipv6": { +# "resolved_next_hop": "list1" +# } +# }, +# "sequence": 45, +# "set": { +# "as_path": { +# "prepend": { +# "last_as": 2 +# } +# }, +# "metric": { +# "add": "igp-metric", +# "value": "25" +# } +# }, +# "sub_route_map": { +# "name": "mapmerge" +# } +# } +# ], +# "route_map": "mapmerge2" +# } +# ] + + + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.route_maps.route_maps import ( + Route_mapsArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.route_maps.route_maps import ( + Route_maps, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Route_mapsArgs.argument_spec, + mutually_exclusive=[], + required_if=[], + supports_check_mode=False, + ) + + result = Route_maps(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_snmp_server.py b/ansible_collections/arista/eos/plugins/modules/eos_snmp_server.py new file mode 100644 index 000000000..b702c8a46 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_snmp_server.py @@ -0,0 +1,1522 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for eos_snmp_server +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: eos_snmp_server +short_description: Manages snmp_server resource module +description: This module configures and manages the attributes of snmp_server on Arista + EOS platforms. +version_added: 3.2.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli) and C(httpapi). +options: + config: + description: SNMP server configuration. + type: dict + suboptions: + chassis_id: + description: SNMP chassis identifier. + type: str + communities: + description: Community name configuration. + type: list + elements: dict + suboptions: + name: + description: Community name + type: str + acl_v4: + description: standard access_list name + type: str + acl_v6: + description: IPv6 access list name. + type: str + ro: + description: Only reads are permitted. + type: bool + rw: + description: Read_write access + type: bool + view: + description: MIB view name + type: str + contact: + description: Person to contact about the syste,. + type: str + traps: + description: Enable traps to all configured recipients. + type: dict + suboptions: + bgp: + description: Enable Bgp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_backward_transition: + description: arista_backward_transition + type: bool + arista_established: + description: arista_established + type: bool + backward_transition: + description: backward_transition + type: bool + established: + description: established. + type: bool + enabled: + description: All traps are set. + type: bool + bridge: + description: Enable Bridge traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_mac_age: + description: arista_mac_age + type: bool + arista_mac_learn: + description: arista_mac_learn + type: bool + arista_mac_move: + description: arista_mac_move + type: bool + enabled: + description: All traps are set. + type: bool + capacity: + description: Enable Capacity traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_hardware_utilization_alert: + description: arista_hardware_utilization_alert + type: bool + enabled: + description: All traps are set. + type: bool + entity: + description: Enable Entity traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_ent_sensor_alarm: + description: arista_ent_sensor_alarm + type: bool + ent_config_change: + description: ent_config_change + type: bool + ent_state_oper: + description: ent_state_oper + type: bool + ent_state_oper_disabled: + description: ent_state_oper_disabled. + type: bool + ent_state_oper_enabled: + description: ent_state_oper_enabled. + type: bool + enabled: + description: All traps are set. + type: bool + external_alarm: + description: Enable external alarm traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_external_alarm_asserted_notif: + description: arista_external_alarm_asserted_notif + type: bool + arista_external_alarm_deasserted_notif: + description: arista_external_alarm_deasserted_notif + type: bool + enabled: + description: All traps are set. + type: bool + isis: + description: Enable isis traps. If set to enabled , all the traps are set. + type: dict + suboptions: + adjacency_change: + description: adjacency_change + type: bool + area_mismatch: + description: area_mismatch + type: bool + attempt_to_exceed_max_sequence: + description: attempt_to_exceed_max_sequence + type: bool + authentication_type_failure: + description: authentication_type_failure. + type: bool + database_overload: + description: database_overload + type: bool + own_lsp_purge: + description: own_lsp_purge + type: bool + rejected_adjacency: + description: rejected_adjacency + type: bool + sequence_number_skip: + description: sequence_number_skip. + type: bool + enabled: + description: All traps are set. + type: bool + lldp: + description: Enable Lldp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + rem_tables_change: + description: rem_tables_change + type: bool + enabled: + description: All traps are set. + type: bool + mpls_ldp: + description: Enable mpls_ldp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + mpls_ldp_session_down: + description: mpls_ldp_session_down + type: bool + mpls_ldp_session_up: + description: mpls_ldp_session_up + type: bool + enabled: + description: All traps are set. + type: bool + msdp: + description: Enable msdp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + backward_transition: + description: backward_transition. + type: bool + established: + description: established. + type: bool + enabled: + description: All traps are set. + type: bool + ospf: + description: Enable Ospf traps. If set to enabled , all the traps are set. + type: dict + suboptions: + if_config_error: + description: if_config_error + type: bool + if_auth_failure: + description: if_auth_failure + type: bool + if_state_change: + description: if_state_change + type: bool + nbr_state_change: + description: nbr_state_change. + type: bool + enabled: + description: All traps are set. + type: bool + ospfv3: + description: Enable Ospfv3 traps. If set to enabled , all the traps are set. + type: dict + suboptions: + if_config_error: + description: if_config_error + type: bool + if_rx_bad_packet: + description: if_rx_bad_packet + type: bool + if_state_change: + description: if_state_change + type: bool + nbr_state_change: + description: nbr_state_change. + type: bool + nbr_restart_helper_status_change: + description: Enable ospfv3NbrRestartHelperStatusChange trap + type: bool + nssa_translator_status_change: + description: Enable ospfv3NssaTranslatorStatusChange trap + type: bool + restart_status_change: + description: restart_status_change + type: bool + enabled: + description: All traps are set. + type: bool + pim: + description: Enable Pim traps. If set to enabled , all the traps are set. + type: dict + suboptions: + neighbor_loss: + description: neighbor_loss + type: bool + enabled: + description: All traps are set. + type: bool + snmp: + description: Enable snmp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + authentication: + description: authentication + type: bool + link_down: + description: link_down + type: bool + link_up: + description: link_up + type: bool + enabled: + description: All traps are set. + type: bool + snmpConfigManEvent: + description: Enable snmpConfigManEvent traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_config_man_event: + description: arista_config_man_event + type: bool + enabled: + description: All traps are set. + type: bool + switchover: + description: Enable switchover traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_redundancy_switch_over_notif: + description: arista_redundancy_switch_over_notif + type: bool + enabled: + description: All traps are set. + type: bool + test: + description: Enable test traps. If set to enabled , all the traps are set. + type: dict + suboptions: + arista_test_notification: + description: arista_test_notification + type: bool + enabled: + description: All traps are set. + type: bool + vrrp: + description: Enable vrrp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + trap_new_master: + description: vrrp + type: bool + enabled: + description: All traps are set. + type: bool + engineid: + description: SNMPv3 engine ID configuration. + type: dict + suboptions: + local: + description: Local SNMP agent + type: str + remote: + description: Remote SNMP agent + type: dict + suboptions: + host: + description: Hostname or IP address of remote SNMP notification host + type: str + udp_port: + description: The remote SNMP notification host's UDP port number. + type: int + id: + description: engine ID octet string + type: str + extension: + description: Configure extension script to serve an OID range + type: dict + suboptions: + root_oid: + description: Extension root oid + type: str + script_location: + description: script location + type: str + oneshot: + description: Use inefficient one_shot interface + type: bool + groups: + description: SNMP USM group + type: list + elements: dict + suboptions: + group: + description: SNMP group for the user + type: str + version: + description: snmp security group version + type: str + choices: ['v1', 'v3', 'v2c'] + auth_privacy: + description: auth and privacy config. Valid when version = v3. + type: str + choices: ['auth', 'noauth', 'priv'] + context: + description: Specify a context to associate with the group + type: str + notify: + description: View to restrict notifications + type: str + read: + description: View to restrict read access + type: str + write: + description: View to restrict write access + type: str + hosts: + description: Notification destinations + type: list + elements: dict + suboptions: + host: + description: Hostname or IP address of SNMP notification host. + type: str + user: + description: Community or user name. + type: str + udp_port: + description: UDP destination port for notification messages. + type: int + informs: + description: Use SNMP inform messages. + type: bool + traps: + description: Use SNMP trap messages + type: bool + version: + description: Notification message SNMP version. + type: str + choices: ['1', '2c', '3 auth', '3 noauth', '3 priv'] + vrf: + description: Specify the VRF in which the host is configured + type: str + acls: + description: ipv4/ipv6 access_lists + type: list + elements: dict + suboptions: + afi: + description: ipv4/ipv6 + type: str + choices: ['ipv4', 'ipv6'] + acl: + description: acl name + type: str + vrf: + description: vrf name + type: str + local_interface: + description: Configure the source interface for SNMP notifications. + type: str + location: + description: The sysLocation string. + type: str + notification: + description: Maximum number of notifications in the log + type: int + objects: + description: when True Disable implementation of a group of objects + type: dict + suboptions: + mac_address_tables: + description: dot1dTpFdbTable, dot1qTpFdbTable + type: bool + route_tables: + description: ipCidrRouteTable, ipCidrRouteNumber, aristaFIBStats* + type: bool + qos: + description: Configure QoS parameters. + type: int + qosmib: + description: Set QOS_MIB counter update interval + type: int + transmit: + description: Maximum number of bytes in SNMP message (UDP/TCP payload) + type: int + transport: + description: Enable snmpd transport layer protocol + type: str + users: + description: SNMP user configuration. + type: list + elements: dict + suboptions: + user: + description: SNMP user name + type: str + group: + description: SNMP group for the user. + type: str + remote: + description: System where an SNMPv3 user is hosted + type: str + udp_port: + description: UDP port used by the remote SNMP system + type: int + version: + description: snmp security version + type: str + choices: ['v1', 'v2c', 'v3'] + auth: + description: User authentication settings + type: dict + suboptions: + algorithm: + description: algorithm for authentication + type: str + auth_passphrase: + description: authentication passphrase hex string + type: str + encryption: + description: algorithm for encryption. + type: str + priv_passphrase: + description: privacy passphrase hexstring + type: str + localized: + description: localized auth and privacy passphrases. + type: dict + suboptions: + engineid: + description: Engine id + type: str + algorithm: + description: algorithm for authentication + type: str + auth_passphrase: + description: authentication passphrase hex string + type: str + encryption: + description: algorithm for encryption. + type: str + priv_passphrase: + description: privacy passphrase hexstring + type: str + views: + description: SNMPv2 MIB view configuration + type: list + elements: dict + suboptions: + view: + description: SNMP view name + type: str + mib: + description: SNMP MIB name + type: str + action: + description: Action to be performed. + type: str + choices: ['excluded', 'included'] + vrfs: + description: Specify the VRF in which the source address is used + type: list + elements: dict + suboptions: + vrf: + description: vrf name. + type: str + local_interface: + description: Configure the source interface for SNMP notifications + 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 EOS device by + executing the command B(show running_config | section snmp_server). + - 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(replaced) and I(overridden) have identical + behaviour for this module. + - Please refer to examples for more details. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged +""" +EXAMPLES = """ +# Using merged: +# Before State +# eos#show running-config | section snmp-server +# eos# + + - name: merge given snmp_server configuration + arista.eos.eos_snmp_server: + config: + communities: + - name: "comm3" + acl_v6: "list1" + view: "view1" + - name: "comm4" + acl_v4: "list3" + view: "view1" + - name: "comm5" + acl_v4: "list4" + ro: True + contact: "admin" + engineid: + remote: + host: 1.1.1.1 + id: "1234567" + groups: + - group: "group1" + version: "v1" + read: "view1" + - group: "group2" + version: "v3" + auth_privacy: "priv" + notify: "view1" + write: "view2" + hosts: + - host: "host02" + user: "user01" + udp_port: 23 + version: "2c" + - host: "host01" + user: "user01" + udp_port: 23 + version: "3 priv" + traps: + capacity: + arista_hardware_utilization_alert: True + bgp: + enabled: True + external_alarm: + arista_external_alarm_deasserted_notif: True + arista_external_alarm_asserted_notif: True + vrfs: + - vrf: "vrf01" + local_interface: "Ethernet1" + +# After state +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community comm4 view view1 list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server contact admin +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif +# +# Module Execution +# +# "after": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "snmp-server community comm3 view view1 ipv6 list1", +# "snmp-server community comm4 view view1 list3", +# "snmp-server community comm5 ro list4", +# "snmp-server group group1 v1 read view1", +# "snmp-server group group2 v3 priv write view2 notify view1", +# "snmp-server host host02 version 2c user01 udp-port 23", +# "snmp-server host host01 version 3 priv user01 udp-port 23", +# "snmp-server vrf vrf01 local-interface Ethernet1", +# "snmp-server contact admin", +# "snmp-server engineID remote 1.1.1.1 1234567", +# "snmp-server enable traps bgp", +# "snmp-server enable traps capacity arista-hardware-utilization-alert", +# "snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif" +# ], +# + +# Using replaced: +# Before State: +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community comm4 view view1 list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server contact admin +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif + + - name: Replace given snmp_server configuration + become: true + register: result + arista.eos.eos_snmp_server: &replaced + state: replaced + config: + communities: + - name: "comm3" + acl_v6: "list1" + view: "view1" + - name: "replacecomm" + acl_v4: "list4" + extension: + root_oid: "123456" + script_location: "flash:" + traps: + test: + arista_test_notification: True + bgp: + enabled: True + vrfs: + - vrf: "vrf_replace" + local_interface: "Ethernet1" + +# After State: + +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community replacecomm list4 +# snmp-server vrf vrf_replace local-interface Ethernet1 +# snmp-server extension 123456 flash: +# snmp-server enable traps test arista-test-notification +# snmp-server enable traps bgp + +# Module Execution: +# "after": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "replacecomm", +# "ro": true +# } +# ], +# "extension": { +# "root_oid": "0.123456", +# "script_location": "flash:" +# }, +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "test": { +# "arista_test_notification": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf_replace" +# } +# ] +# }, +# "before": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "snmp-server community comm3 view view1 ipv6 list1", +# "snmp-server community replacecomm list4", +# "no snmp-server community comm4 view view1 ro list3", +# "no snmp-server community comm5 ro list4", +# "no snmp-server group group1 v1 read view1", +# "no snmp-server group group2 v3 priv write view2 notify view1", +# "no snmp-server host host01 version 3 priv user01 udp-port 23", +# "no snmp-server host host02 version 2c user01 udp-port 23", +# "snmp-server vrf vrf_replace local-interface Ethernet1", +# "no snmp-server vrf vrf01 local-interface Ethernet1", +# "snmp-server extension 123456 flash:", +# "default snmp-server enable traps capacity arista-hardware-utilization-alert", +# "default snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif", +# "snmp-server enable traps test arista-test-notification", +# "no snmp-server contact admin" +# ], + +# Using overridden: +# Before State: +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community comm4 view view1 list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server contact admin +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif + + - name: Override given snmp_server configuration + arista.eos.eos_snmp_server: + state: overridden + config: + communities: + - name: "comm3" + acl_v6: "list1" + view: "view1" + - name: "replacecomm" + acl_v4: "list4" + extension: + root_oid: "123456" + script_location: "flash:" + traps: + test: + arista_test_notification: True + bgp: + enabled: True + vrfs: + - vrf: "vrf_replace" + local_interface: "Ethernet1" + +# After State: + +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community replacecomm list4 +# snmp-server vrf vrf_replace local-interface Ethernet1 +# snmp-server extension 123456 flash: +# snmp-server enable traps test arista-test-notification +# snmp-server enable traps bgp + +# Module Execution: +# "after": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "replacecomm", +# "ro": true +# } +# ], +# "extension": { +# "root_oid": "0.123456", +# "script_location": "flash:" +# }, +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "test": { +# "arista_test_notification": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf_replace" +# } +# ] +# }, +# "before": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "snmp-server community comm3 view view1 ipv6 list1", +# "snmp-server community replacecomm list4", +# "no snmp-server community comm4 view view1 ro list3", +# "no snmp-server community comm5 ro list4", +# "no snmp-server group group1 v1 read view1", +# "no snmp-server group group2 v3 priv write view2 notify view1", +# "no snmp-server host host01 version 3 priv user01 udp-port 23", +# "no snmp-server host host02 version 2c user01 udp-port 23", +# "snmp-server vrf vrf_replace local-interface Ethernet1", +# "no snmp-server vrf vrf01 local-interface Ethernet1", +# "snmp-server extension 123456 flash:", +# "default snmp-server enable traps capacity arista-hardware-utilization-alert", +# "default snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif", +# "snmp-server enable traps test arista-test-notification", +# "no snmp-server contact admin" +# ], + +# Using deleted: +# Before State: +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community comm4 view view1 list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server contact admin +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif + + - name: Delete given snmp_server configuration + arista.eos.eos_snmp_server: + state: deleted + +# After State: +# eos#show running-config | section snmp-server +# + +# Module Execution: +# "after": {}, +# "before": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "no snmp-server community comm3 view view1 ro ipv6 list1", +# "no snmp-server community comm4 view view1 ro list3", +# "no snmp-server community comm5 ro list4", +# "no snmp-server group group1 v1 read view1", +# "no snmp-server group group2 v3 priv write view2 notify view1", +# "no snmp-server host host01 version 3 priv user01 udp-port 23", +# "no snmp-server host host02 version 2c user01 udp-port 23", +# "no snmp-server vrf vrf01 local-interface Ethernet1", +# "no snmp-server contact admin", +# "default snmp-server enable traps bgp", +# "default snmp-server enable traps capacity arista-hardware-utilization-alert", +# "default snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif" +# ], +# + +# Using parsed: + +# _parsed.cfg +# snmp-server contact admin +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server community comm3 view view1 ro ipv6 list1 +# snmp-server community comm4 view view1 ro list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif +# snmp-server enable traps external-alarm arista-external-alarm-deasserted-notif + + - name: Provide the running configuration for parsing (config to be parsed) + arista.eos.eos_snmp_server: + running_config: "{{ lookup('file', '_parsed.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# } + +# Using rendered: + - name: Render given snmp_server configuration + arista.eos.eos_snmp_server: + state: "rendered" + config: + communities: + - name: "comm3" + acl_v6: "list1" + view: "view1" + - name: "comm4" + acl_v4: "list3" + view: "view1" + - name: "comm5" + acl_v4: "list4" + ro: True + contact: "admin" + engineid: + remote: + host: 1.1.1.1 + id: "1234567" + groups: + - group: "group1" + version: "v1" + read: "view1" + - group: "group2" + version: "v3" + auth_privacy: "priv" + notify: "view1" + write: "view2" + hosts: + - host: "host02" + user: "user01" + udp_port: 23 + version: "2c" + - host: "host01" + user: "user01" + udp_port: 23 + version: "3 priv" + traps: + capacity: + arista_hardware_utilization_alert: True + bgp: + enabled: True + external_alarm: + arista_external_alarm_deasserted_notif: True + arista_external_alarm_asserted_notif: True + vrfs: + - vrf: "vrf01" + local_interface: "Ethernet1" + +# Module Execution: +# "rendered": [ +# "snmp-server community comm3 view view1 ipv6 list1", +# "snmp-server community comm4 view view1 list3", +# "snmp-server community comm5 ro list4", +# "snmp-server group group1 v1 read view1", +# "snmp-server group group2 v3 priv write view2 notify view1", +# "snmp-server host host02 version 2c user01 udp-port 23", +# "snmp-server host host01 version 3 priv user01 udp-port 23", +# "snmp-server vrf vrf01 local-interface Ethernet1", +# "snmp-server contact admin", +# "snmp-server engineID remote 1.1.1.1 1234567", +# "snmp-server enable traps bgp", +# "snmp-server enable traps capacity arista-hardware-utilization-alert", +# "snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif" +# ] + +# using gathered: + +# eos#show running-config | section snmp-server +# snmp-server community comm3 view view1 ipv6 list1 +# snmp-server community comm4 view view1 list3 +# snmp-server community comm5 ro list4 +# snmp-server group group1 v1 read view1 +# snmp-server group group2 v3 priv write view2 notify view1 +# snmp-server host host02 version 2c user01 udp-port 23 +# snmp-server host host01 version 3 priv user01 udp-port 23 +# snmp-server vrf vrf01 local-interface Ethernet1 +# snmp-server contact admin +# snmp-server enable traps bgp +# snmp-server enable traps capacity arista-hardware-utilization-alert +# snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif + + - name: Gathered the provided configuration with the exisiting running configuration + arista.eos.eos_snmp_server: + config: + state: gathered + +# Module Execution: +# "gathered": { +# "communities": [ +# { +# "acl_v6": "list1", +# "name": "comm3", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list3", +# "name": "comm4", +# "ro": true, +# "view": "view1" +# }, +# { +# "acl_v4": "list4", +# "name": "comm5", +# "ro": true +# } +# ], +# "contact": "admin", +# "groups": [ +# { +# "group": "group1", +# "read": "view1", +# "version": "v1" +# }, +# { +# "auth_privacy": "priv", +# "group": "group2", +# "notify": "view1", +# "version": "v3", +# "write": "view2" +# } +# ], +# "hosts": [ +# { +# "host": "host01", +# "udp_port": 23, +# "user": "user01", +# "version": "3 priv" +# }, +# { +# "host": "host02", +# "udp_port": 23, +# "user": "user01", +# "version": "2c" +# } +# ], +# "traps": { +# "bgp": { +# "enabled": true +# }, +# "capacity": { +# "arista_hardware_utilization_alert": true +# }, +# "external_alarm": { +# "arista_external_alarm_asserted_notif": true, +# "arista_external_alarm_deasserted_notif": true +# } +# }, +# "vrfs": [ +# { +# "local_interface": "Ethernet1", +# "vrf": "vrf01" +# } +# ] +# }, + +""" + +RETURN = """ +before: + 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: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + 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: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - "snmp-server community comm3 view view1 ipv6 list1" + - "snmp-server community comm4 view view1 list3" + - "snmp-server community comm5 ro list4" + - "snmp-server group group1 v1 read view1" + - "snmp-server group group2 v3 priv write view2 notify view1" + - "snmp-server host host02 version 2c user01 udp-port 23" + - "snmp-server host host01 version 3 priv user01 udp-port 23" + - "snmp-server vrf vrf01 local-interface Ethernet1" + - "snmp-server contact admin" + - "snmp-server engineID remote 1.1.1.1 1234567" + - "snmp-server enable traps bgp" + - "snmp-server enable traps capacity arista-hardware-utilization-alert" + - "snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif" + +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - "snmp-server community comm3 view view1 ipv6 list1" + - "snmp-server community comm4 view view1 list3" + - "snmp-server community comm5 ro list4" + - "snmp-server group group1 v1 read view1" + - "snmp-server group group2 v3 priv write view2 notify view1" + - "snmp-server host host02 version 2c user01 udp-port 23" + - "snmp-server host host01 version 3 priv user01 udp-port 23" + - "snmp-server vrf vrf01 local-interface Ethernet1" + - "snmp-server contact admin" + - "snmp-server engineID remote 1.1.1.1 1234567" + - "snmp-server enable traps bgp" + - "snmp-server enable traps capacity arista-hardware-utilization-alert" + - "snmp-server enable traps external-alarm arista-external-alarm-asserted-notif arista-external-alarm-deasserted-notif" +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.arista.eos.plugins.module_utils.network.eos.argspec.snmp_server.snmp_server import ( + Snmp_serverArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.config.snmp_server.snmp_server import ( + Snmp_server, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Snmp_serverArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Snmp_server(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_static_routes.py b/ansible_collections/arista/eos/plugins/modules/eos_static_routes.py new file mode 100644 index 000000000..5b291b12d --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_static_routes.py @@ -0,0 +1,969 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_static_routes +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_static_routes +short_description: Static routes resource module +description: This module configures and manages the attributes of static routes on + Arista EOS platforms. +version_added: 1.0.0 +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: + - A list of configurations for static routes. + type: list + elements: dict + suboptions: + vrf: + description: + - The VRF to which the static route(s) belong. + type: str + address_families: + description: A dictionary specifying the address family to which the static + route(s) belong. + type: list + elements: dict + suboptions: + afi: + description: + - Specifies the top level address family indicator. + type: str + choices: + - ipv4 + - ipv6 + required: true + routes: + description: A dictionary that specifies the static route configurations. + elements: dict + type: list + suboptions: + dest: + description: + - Destination IPv4 subnet (CIDR or address-mask notation). + - The address format is <v4/v6 address>/<mask> or <v4/v6 address> + <mask>. + - The mask is number in range 0-32 for IPv4 and in range 0-128 for + IPv6. + type: str + required: true + next_hops: + description: + - Details of route to be taken. + type: list + elements: dict + suboptions: + forward_router_address: + description: + - Forwarding router's address on destination interface. + type: str + interface: + description: + - Outgoing interface to take. For anything except 'null0', then + next hop IP address should also be configured. + - IP address of the next hop router or + - null0 Null0 interface or + - ethernet e_num Ethernet interface or + - loopback l_num Loopback interface or + - management m_num Management interface or + - port-channel p_num + - vlan v_num + - vxlan vx_num + - Nexthop-Group Specify nexthop group name + - Tunnel Tunnel interface + - vtep Configure VXLAN Tunnel End Points + type: str + nexthop_grp: + description: + - Nexthop group + type: str + admin_distance: + description: + - Preference or administrative distance of route (range 1-255). + type: int + description: + description: + - Name of the static route. + type: str + tag: + description: + - Route tag value (ranges from 0 to 4294967295). + type: int + track: + description: + - Track value (range 1 - 512). Track must already be configured + on the device before adding the route. + type: str + mpls_label: + description: + - MPLS label + type: int + vrf: + description: + - VRF of the destination. + 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 EOS device by + executing the command B(show running-config | grep routes). + - 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. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged + +""" +EXAMPLES = """ +# Using deleted + +# Before State: +# ------------ + +# veos(config)#show running-config | grep route +# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute +# ipv6 route 5222:5::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 +# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 +# veos(config)# + +- name: Delete afi + arista.eos.eos_static_routes: + config: + - vrf: testvrf + address_families: + - afi: ipv4 + state: deleted + +# "after": [ +# { +# "address_families": [ +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5222:5::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2222:6::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# }, +# { +# "admin_distance": 55, +# "interface": "Ethernet1" +# }, +# { +# "admin_distance": 90, +# "description": "testroute1", +# "interface": "Null0" +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ], +# "before": [ +# { +# "address_families": [ +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5222:5::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "22.65.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 90, +# "description": "testroute", +# "interface": "Null0" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2222:6::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# }, +# { +# "admin_distance": 55, +# "interface": "Ethernet1" +# }, +# { +# "admin_distance": 90, +# "description": "testroute1", +# "interface": "Null0" +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ], +# "changed": true, +# "commands": [ +# "no ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute" +# ], + +# After State +# ___________ + +# veos(config)#show running-config | grep route +# ipv6 route 5222:5::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 +# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 + +# +# Using merged + +# Before : [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "165.10.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 100, +# "interface": "Ethernet1" +# } +# ] +# }, +# { +# "dest": "172.17.252.0/24", +# "next_hops": [ +# { +# "nexthop_grp": "testgroup" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5001::/64", +# "next_hops": [ +# { +# "admin_distance": 50, +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "130.1.122.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1", +# "tag": 50 +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ] +# +# Before State +# ------------- +# veos(config)#show running-config | grep "route" +# ip route 165.10.1.0/24 Ethernet1 100 +# ip route 172.17.252.0/24 Nexthop-Group testgroup +# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 +# ipv6 route 5001::/64 Ethernet1 50 +# veos(config)# + +- name: Merge new static route configuration + arista.eos.eos_static_routes: + config: + - vrf: testvrf + address_families: + - afi: ipv6 + routes: + - dest: 2211::0/64 + next_hop: + - forward_router_address: 100:1::2 + interface: Ethernet1 + state: merged + +# After State +# ----------- + +#After [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "165.10.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 100, +# "interface": "Ethernet1" +# } +# ] +# }, +# { +# "dest": "172.17.252.0/24", +# "next_hops": [ +# { +# "nexthop_grp": "testgroup" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5001::/64", +# "next_hops": [ +# { +# "admin_distance": 50, +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "130.1.122.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1", +# "tag": 50 +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2211::0/64", +# "next_hops": [ +# { +# "aforward_router_address": 100:1::2 +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } + +# ], +# "vrf": "testvrf" +# } +# ] +# +# veos(config)#show running-config | grep "route" +# ip route 165.10.1.0/24 Ethernet1 100 +# ip route 172.17.252.0/24 Nexthop-Group testgroup +# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 +# ipv6 route 2211::/64 Ethernet1 100:1::2 +# ipv6 route 5001::/64 Ethernet1 50 +# veos(config)# + + +# Using overridden + + +# Before State +# ------------- + +# "before": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "165.10.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 100, +# "interface": "Ethernet1" +# } +# ] +# }, +# { +# "dest": "172.17.252.0/24", +# "next_hops": [ +# { +# "nexthop_grp": "testgroup" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5001::/64", +# "next_hops": [ +# { +# "admin_distance": 50, +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "130.1.122.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1", +# "tag": 50 +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ] +# veos(config)#show running-config | grep "route" +# ip route 165.10.1.0/24 Ethernet1 100 +# ip route 172.17.252.0/24 Nexthop-Group testgroup +# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 +# ipv6 route 5001::/64 Ethernet1 50 +# veos(config)# + +- name: Overridden static route configuration + arista.eos.eos_static_routes: + config: + - address_families: + - afi: ipv4 + routes: + - dest: 10.2.2.0/24 + next_hop: + - interface: Ethernet1 + state: replaced + +# After State +# ----------- + +# "after": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "10.2.2.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } +# ] +# } +# ] +# veos(config)#show running-config | grep "route" +# ip route 10.2.2.0/24 Ethernet1 +# veos(config)# + + +# Using replaced + +# Before State +# ------------- + +# ip route 10.2.2.0/24 Ethernet1 +# ip route 10.2.2.0/24 64.1.1.1 label 17 33 +# ip route 33.33.33.0/24 Nexthop-Group testgrp +# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute +# ipv6 route 5222:5::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 +# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 + +# [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "10.2.2.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1" +# }, +# { +# "admin_distance": 33, +# "interface": "64.1.1.1", +# "mpls_label": 17 +# } +# ] +# }, +# { +# "dest": "33.33.33.0/24", +# "next_hops": [ +# { +# "nexthop_grp": "testgrp" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5222:5::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "22.65.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 90, +# "description": "testroute", +# "interface": "Null0" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2222:6::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# }, +# { +# "admin_distance": 90, +# "description": "testroute1", +# "interface": "Null0" +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ] + +- name: Replace nexthop + arista.eos.eos_static_routes: + config: + - vrf: testvrf + address_families: + - afi: ipv6 + routes: + - dest: 2222:6::/64 + next_hops: + - admin_distance: 55 + interface: Ethernet1 + state: replaced + +# After State +# ----------- + +# veos(config)#show running-config | grep route +# ip route 10.2.2.0/24 Ethernet1 +# ip route 10.2.2.0/24 64.1.1.1 label 17 33 +# ip route 33.33.33.0/24 Nexthop-Group testgrp +# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute +# ipv6 route 5222:5::/64 Management1 4312:100::1 +# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 + +# "after": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "10.2.2.0/24", +# "next_hops": [ +# { +# "interface": "Ethernet1" +# }, +# { +# "admin_distance": 33, +# "interface": "64.1.1.1", +# "mpls_label": 17 +# } +# ] +# }, +# { +# "dest": "33.33.33.0/24", +# "next_hops": [ +# { +# "nexthop_grp": "testgrp" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "5222:5::/64", +# "next_hops": [ +# { +# "forward_router_address": "4312:100::1", +# "interface": "Management1" +# } +# ] +# } +# ] +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "22.65.1.0/24", +# "next_hops": [ +# { +# "admin_distance": 90, +# "description": "testroute", +# "interface": "Null0" +# } +# ] +# } +# ] +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2222:6::/64", +# "next_hops": [ +# { +# "admin_distance": 55, +# "interface": "Ethernet1" +# } +# ] +# } +# ] +# } +# ], +# "vrf": "testvrf" +# } +# ] + +# Before State +# ------------- +# veos(config)#show running-config | grep "route" +# ip route 165.10.1.0/24 Ethernet1 10.1.1.2 100 +# ipv6 route 5001::/64 Ethernet1 +# veos(config)# + + +- name: Gather the exisitng condiguration + arista.eos.eos_static_routes: + state: gathered + +# returns : +# arista.eos.eos_static_routes: +# config: +# - address_families: +# - afi: ipv4 +# routes: +# - dest: 165.10.1.0/24 +# next_hop: +# - forward_router_address: 10.1.1.2 +# interface: "Ethernet1" +# admin_distance: 100 +# - afi: ipv6 +# routes: +# - dest: 5001::/64 +# next_hop: +# - interface: "Ethernet1" + + +# Using rendered + +# arista.eos.eos_static_routes: +# config: +# - address_families: +# - afi: ipv4 +# routes: +# - dest: 165.10.1.0/24 +# next_hop: +# - forward_router_address: 10.1.1.2 +# interface: "Ethernet1" +# admin_distance: 100 +# - afi: ipv6 +# routes: +# - dest: 5001::/64 +# next_hop: +# - interface: "Ethernet1" + +# returns: + +# ip route 165.10.1.0/24 Ethernet1 10.1.1.2 100 +# ipv6 route 5001::/64 Ethernet1 + + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The resulting configuration model invocation. + 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 vrf1 192.2.2.0/24 125.2.3.1 93 +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: > + "address_families": [ + { + "afi": "ipv4", + "routes": [ + { + "dest": "192.2.2.0/24", + "next_hops": [ + { + "admin_distance": 93, + "description": null, + "forward_router_address": null, + "interface": "125.2.3.1", + "mpls_label": null, + "nexthop_grp": null, + "tag": null, + "track": null, + "vrf": null + } + ] + } + ] + } + ], + "vrf": "vrf1" + } + ], + "running_config": null, + "state": "rendered" + } +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.arista.eos.plugins.module_utils.network.eos.argspec.static_routes.static_routes import ( + Static_routesArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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", "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/ansible_collections/arista/eos/plugins/modules/eos_system.py b/ansible_collections/arista/eos/plugins/modules/eos_system.py new file mode 100644 index 000000000..9fb1aca9f --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_system.py @@ -0,0 +1,378 @@ +#!/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: eos_system +author: Peter Sprygada (@privateip) +short_description: Manage the system attributes on Arista EOS devices +description: +- This module provides declarative management of node system attributes on Arista + EOS devices. It provides an option to configure host system parameters or remove + those parameters from the device active configuration. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +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: str + domain_list: + 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. + aliases: + - domain_search + type: list + elements: str + lookup_source: + description: + - Provides one or more source interfaces to use for performing DNS lookups. The + interface provided in C(lookup_source) can only exist in a single VRF. This + argument accepts either a list of interface names or a list of hashes that configure + the interface name and VRF name. See examples. + elements: raw + type: list + 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 or a list of hashes that configure + the name server and VRF name. See examples. + type: list + elements: str + 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 + type: str + choices: + - present + - absent +""" + +EXAMPLES = """ +- name: configure hostname and domain-name + arista.eos.eos_system: + hostname: eos01 + domain_name: test.example.com + +- name: remove configuration + arista.eos.eos_system: + state: absent + +- name: configure DNS lookup sources + arista.eos.eos_system: + lookup_source: Management1 + +- name: configure DNS lookup sources with VRF support + arista.eos.eos_system: + lookup_source: + - interface: Management1 + vrf: mgmt + - interface: Ethernet1 + vrf: myvrf + +- name: configure name servers + arista.eos.eos_system: + name_servers: + - 8.8.8.8 + - 8.8.4.4 + +- name: configure name servers with VRF support + arista.eos.eos_system: + name_servers: + - {server: 8.8.8.8, vrf: mgmt} + - {server: 8.8.4.4, vrf: mgmt} +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - hostname eos01 + - dns domain test.example.com +session_name: + description: The EOS config session name used to load the configuration + returned: changed + type: str + sample: ansible_1479315771 +""" +import re + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + ComplexList, +) + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + get_config, + load_config, +) + + +_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(r"vrf instance (\S+)", config) + _CONFIGURED_VRFS.append("default") + return vrf in _CONFIGURED_VRFS + + +def map_obj_to_commands(want, have, module): + commands = list() + state = module.params["state"] + + def needs_update(x): + return want.get(x) and (want.get(x) != have.get(x)) + + if state == "absent": + if have["domain_name"]: + commands.append("no dns domain") + + if have["hostname"] != "localhost": + commands.append("no hostname") + + if state == "present": + if needs_update("hostname"): + commands.append("hostname %s" % want["hostname"]) + + if needs_update("domain_name"): + commands.append("dns domain %s" % want["domain_name"]) + + if want["domain_list"]: + # handle domain_list items to be removed + for item in set(have["domain_list"]).difference( + want["domain_list"], + ): + commands.append("no ip domain-list %s" % item) + + # handle domain_list items to be added + for item in set(want["domain_list"]).difference( + have["domain_list"], + ): + commands.append("ip domain-list %s" % item) + + if want["lookup_source"]: + # handle lookup_source items to be removed + for item in have["lookup_source"]: + if item not in want["lookup_source"]: + if item["vrf"]: + if not has_vrf(module, item["vrf"]): + module.fail_json( + msg="vrf %s is not configured" % item["vrf"], + ) + values = (item["vrf"], item["interface"]) + commands.append( + "no ip domain lookup vrf %s source-interface %s" + % values, + ) + else: + commands.append( + "no ip domain lookup source-interface %s" + % item["interface"], + ) + + # handle lookup_source items to be added + for item in want["lookup_source"]: + if item not in have["lookup_source"]: + if item["vrf"]: + if not has_vrf(module, item["vrf"]): + module.fail_json( + msg="vrf %s is not configured" % item["vrf"], + ) + values = (item["vrf"], item["interface"]) + commands.append( + "ip domain lookup vrf %s source-interface %s" + % values, + ) + else: + commands.append( + "ip domain lookup source-interface %s" + % item["interface"], + ) + + if want["name_servers"]: + # handle name_servers items to be removed. Order does matter here + # since name servers can only be in one vrf at a time + for item in have["name_servers"]: + if item not in want["name_servers"]: + if not has_vrf(module, item["vrf"]): + module.fail_json( + msg="vrf %s is not configured" % item["vrf"], + ) + if item["vrf"] not in ("default", None): + values = (item["vrf"], item["server"]) + commands.append("no ip name-server vrf %s %s" % values) + else: + commands.append( + "no ip name-server %s" % item["server"], + ) + + # handle name_servers items to be added + for item in want["name_servers"]: + if item not in have["name_servers"]: + if not has_vrf(module, item["vrf"]): + module.fail_json( + msg="vrf %s is not configured" % item["vrf"], + ) + if item["vrf"] not in ("default", None): + values = (item["vrf"], item["server"]) + commands.append("ip name-server vrf %s %s" % values) + else: + commands.append("ip name-server %s" % item["server"]) + + return commands + + +def parse_hostname(config): + match = re.search(r"^hostname (\S+)", config, re.M) + if match: + return match.group(1) + + +def parse_domain_name(config): + match = re.search(r"^dns domain (\S+)", config, re.M) + if match: + return match.group(1) + + +def parse_lookup_source(config): + objects = list() + regex = r"ip domain lookup (?:vrf (\S+) )*source-interface (\S+)" + for vrf, intf in re.findall(regex, config, re.M): + if len(vrf) == 0: + vrf = None + objects.append({"interface": intf, "vrf": vrf}) + return objects + + +def parse_name_servers(config): + objects = list() + for vrf, addr in re.findall( + r"ip name-server vrf (\S+) (\S+)", + config, + re.M, + ): + objects.append({"server": addr, "vrf": vrf}) + return objects + + +def map_config_to_obj(module): + config = get_config(module) + return { + "hostname": parse_hostname(config), + "domain_name": parse_domain_name(config), + "domain_list": re.findall(r"^ip domain-list (\S+)", config, re.M), + "lookup_source": parse_lookup_source(config), + "name_servers": parse_name_servers(config), + } + + +def map_params_to_obj(module): + obj = { + "hostname": module.params["hostname"], + "domain_name": module.params["domain_name"], + "domain_list": module.params["domain_list"], + } + + lookup_source = ComplexList( + dict(interface=dict(key=True), vrf=dict()), + module, + ) + + name_servers = ComplexList( + dict(server=dict(key=True), vrf=dict(default="default")), + module, + ) + + for arg, cast in [ + ("lookup_source", lookup_source), + ("name_servers", name_servers), + ]: + if module.params[arg] is not None: + obj[arg] = cast(module.params[arg]) + else: + obj[arg] = None + + return obj + + +def main(): + """main entry point for module execution""" + argument_spec = dict( + hostname=dict(), + domain_name=dict(), + domain_list=dict( + type="list", + aliases=["domain_search"], + elements="str", + ), + # { interface: <str>, vrf: <str> } + lookup_source=dict(type="list", elements="raw"), + # { server: <str>; vrf: <str> } + name_servers=dict(type="list", elements="str"), + state=dict(default="present", choices=["present", "absent"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + 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: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_user.py b/ansible_collections/arista/eos/plugins/modules/eos_user.py new file mode 100644 index 000000000..519892daf --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_user.py @@ -0,0 +1,491 @@ +#!/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: eos_user +author: Peter Sprygada (@privateip) +short_description: Manage the collection of local users on EOS devices +description: +- This module provides declarative management of the local usernames configured on + Arista EOS devices. It allows playbooks to manage either individual usernames or + the collection 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 Arista EOS 4.24.6F +options: + aggregate: + description: + - The set of username objects to be configured on the remote Arista EOS device. The + list entries can either be the username or a hash of username and properties. This + argument is mutually exclusive with the C(username) argument. + aliases: + - users + - collection + type: list + elements: dict + suboptions: + name: + description: + - The username to be configured on the remote Arista EOS device. This argument + accepts a stringv value and is mutually exclusive with the C(aggregate) argument. + type: str + configured_password: + description: + - The password to be configured on the remote Arista EOS device. The password + needs to be provided in clear and it will be encrypted on the device. + 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. + type: str + choices: + - on_create + - always + 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 + role: + description: + - Configures the role for the username in the device running configuration. The + argument accepts a string value defining the role name. This argument does + not check if the role has been configured on the device. + type: str + sshkey: + description: + - Specifies the SSH public key to configure for the given username. This argument + accepts a valid SSH key value. + type: 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 + type: str + choices: + - present + - absent + name: + description: + - The username to be configured on the remote Arista EOS device. This argument + accepts a stringv value and is mutually exclusive with the C(aggregate) argument. + type: str + configured_password: + description: + - The password to be configured on the remote Arista EOS device. The password + needs to be provided in clear and it will be encrypted on the device. + 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 + type: str + choices: + - on_create + - always + 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 + role: + description: + - Configures the role for the username in the device running configuration. The + argument accepts a string value defining the role name. This argument does + not check if the role has been configured on the device. + type: str + sshkey: + description: + - Specifies the SSH public key to configure for the given username. This argument + accepts a valid SSH key value. + type: 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 which cannot be deleted per EOS constraints. + 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 + type: str + default: present + choices: + - present + - absent +""" + +EXAMPLES = """ +- name: create a new user + arista.eos.eos_user: + name: ansible + sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + state: present + +- name: remove all users except admin + arista.eos.eos_user: + purge: yes + +- name: set multiple users to privilege level 15 + arista.eos.eos_user: + aggregate: + - name: netop + - name: netend + privilege: 15 + state: present + +- name: Change Password for User netop + arista.eos.eos_user: + username: netop + configured_password: '{{ new_password }}' + update_password: always + state: present +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - name ansible secret password + - name admin secret admin +session_name: + description: The EOS config session name used to load the configuration + returned: when changed is True + type: str + sample: ansible_1479315771 +""" + +import re + +from copy import deepcopy +from functools import partial + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.eos import ( + get_config, + load_config, + run_commands, +) + + +def validate_privilege(value, module): + if not 1 <= value <= 15: + module.fail_json( + msg="privilege must be between 1 and 15, got %s" % value, + ) + + +def get_os_version(module): + os_version = "4.20.10" + response = run_commands( + module, + 'show version | grep "Software image version"', + ) + version_match = re.search( + r"Software image version:\s+([\d\.]+)", + response[0], + re.M, + ) + if version_match: + v = version_match.group(1).split(".") + os_version = tuple(int(digit) for digit in v) + return os_version + + +def map_obj_to_commands(updates, module): + commands = list() + update_password = module.params["update_password"] + + for update in updates: + want, have = update + + def needs_update(x): + return want.get(x) and (want.get(x) != have.get(x)) + + def add(x): + return commands.append("username %s %s" % (want["name"], x)) + + if want["state"] == "absent": + commands.append("no username %s" % want["name"]) + continue + + if needs_update("configured_password"): + if update_password == "always" or not have: + add("secret %s" % want["configured_password"]) + + if needs_update("role"): + add("role %s" % want["role"]) + + if needs_update("privilege"): + add("privilege %s" % want["privilege"]) + + if needs_update("sshkey"): + ver = get_os_version(module) + # compare against image version 4.20.10 + if ver > (4, 20, 10): + add("ssh-key %s" % want["sshkey"]) + else: + add("sshkey %s" % want["sshkey"]) + + if needs_update("nopassword"): + if want["nopassword"]: + add("nopassword") + else: + add("no username %s nopassword" % want["name"]) + + if want.get("state") == "present" and want.get("name"): + value = [ + want.get("configured_password"), + want.get("nopassword"), + want.get("sshkey"), + ] + if all(v is None for v in value) is True: + module.fail_json( + msg="configured_password, sshkey or nopassword should be provided", + ) + return commands + + +def parse_role(data): + match = re.search(r"role (\S+)", data, re.M) + if match: + return match.group(1) + + +def parse_sshkey(data): + match = re.search(r"sshkey|ssh-key (.+)$", data, re.M) + if match: + return match.group(1) + + +def parse_privilege(data): + match = re.search(r"privilege (\S+)", data, re.M) + if match: + return int(match.group(1)) + + +def map_config_to_obj(module): + data = get_config(module, flags=["section username"]) + + match = re.findall(r"^username (\S+)", data, re.M) + if not match: + return list() + + instances = list() + + for user in set(match): + regex = r"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, + "sshkey": parse_sshkey(cfg), + "privilege": parse_privilege(cfg), + "role": parse_role(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): + aggregate = module.params["aggregate"] + if not aggregate: + if not module.params["name"] and module.params["purge"]: + return list() + elif not module.params["name"]: + module.fail_json(msg="name is required") + else: + collection = [{"name": module.params["name"]}] + else: + collection = list() + for item in aggregate: + 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["configured_password"] = get_value("configured_password") + item["nopassword"] = get_value("nopassword") + item["privilege"] = get_value("privilege") + item["role"] = get_value("role") + item["sshkey"] = get_value("sshkey") + item["state"] = get_value("state") + objects.append(item) + + return objects + + +def update_objects(want, have): + updates = list() + for entry in want: + if "name" in entry: + 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""" + element_spec = dict( + name=dict(), + configured_password=dict(no_log=True), + nopassword=dict(type="bool"), + update_password=dict( + default="always", + choices=["on_create", "always"], + ), + privilege=dict(type="int"), + role=dict(), + sshkey=dict(no_log=True), + 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, + aliases=["collection", "users"], + ), + purge=dict(type="bool", default=False), + ) + + argument_spec.update(element_spec) + mutually_exclusive = [("name", "aggregate")] + + module = AnsibleModule( + argument_spec=argument_spec, + 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(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("no username %s" % item) + + result["commands"] = commands + + # the eos cli prevents this by rule so capture it and display + # a nice failure message + if "no username admin" in commands: + module.fail_json(msg="cannot delete the `admin` account") + + if commands: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_vlans.py b/ansible_collections/arista/eos/plugins/modules/eos_vlans.py new file mode 100644 index 000000000..7c834a3ac --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_vlans.py @@ -0,0 +1,329 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 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 eos_vlans +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: eos_vlans +short_description: VLANs resource module +description: This module provides declarative management of VLANs on Arista EOS network + devices. +version_added: 1.0.0 +author: Nathaniel Case (@qalthos) +notes: +- Tested against Arista EOS 4.24.6F +- This module works with connection C(network_cli). See the L(EOS Platform Options,../network/user_guide/platform_eos.html). +options: + config: + description: A dictionary of VLANs options + type: list + elements: dict + suboptions: + name: + description: + - Name of the VLAN. + type: str + vlan_id: + description: + - ID of the VLAN. Range 1-4094 + type: int + required: true + state: + description: + - Operational state of the VLAN + type: str + choices: + - active + - suspend + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device + by executing the command B(show running-config | section 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 + type: str + state: + description: + - The state of the configuration after module completion + type: str + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + +""" +EXAMPLES = """ +# Using deleted + +# Before state: +# ------------- +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty + +- name: Delete attributes of the given VLANs. + arista.eos.eos_vlans: + config: + - vlan_id: 20 + state: deleted + +# After state: +# ------------ +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten + + +# Using merged + +# Before state: +# ------------- +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty + +- name: Merge given VLAN attributes with device configuration + arista.eos.eos_vlans: + config: + - vlan_id: 20 + state: suspend + state: merged + +# After state: +# ------------ +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty +# state suspend + + +# Using overridden + +# Before state: +# ------------- +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty + +- name: Override device configuration of all VLANs with provided configuration + arista.eos.eos_vlans: + config: + - vlan_id: 20 + state: suspend + state: overridden + +# After state: +# ------------ +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 20 +# state suspend + + +# Using replaced + +# Before state: +# ------------- +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty + +- name: Replace all attributes of specified VLANs with provided configuration + arista.eos.eos_vlans: + config: + - vlan_id: 20 + state: suspend + state: replaced + +# After state: +# ------------ +# +# veos(config-vlan-20)#show running-config | section vlan +# vlan 10 +# name ten +# ! +# vlan 20 +# state suspend + +# using parsed + +# parsed.cfg +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty +# state suspend + +- name: Use parsed to convert native configs to structured data + arista.eos.eos_vlans: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Output: +# ------- +# parsed: +# - vlan_id: 10 +# name: ten +# - vlan_id: 20 +# state: suspend + +# Using rendered: + +- name: Use Rendered to convert the structured data to native config + arista.eos.eos_vlans: + config: + - vlan_id: 10 + name: ten + - vlan_id: 20 + state: suspend + state: rendered + +# Output: +# ------ +# rendered: +# - "vlan 10" +# - "name ten" +# - "vlan 20" +# - "state suspend" + +# Using gathered: +# native_config: +# vlan 10 +# name ten +# ! +# vlan 20 +# name twenty +# state suspend + +- name: Gather vlans facts from the device + arista.eos.eos_vlans: + state: gathered + +# Output: +# ------ + +# gathered: +# - vlan_id: 10 +# name: ten +# - vlan_id: 20 +# state: suspend + +""" +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 10', 'no name', 'vlan 11', 'name Eleven'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.arista.eos.plugins.module_utils.network.eos.argspec.vlans.vlans import ( + VlansArgs, +) +from ansible_collections.arista.eos.plugins.module_utils.network.eos.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, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Vlans(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/arista/eos/plugins/modules/eos_vrf.py b/ansible_collections/arista/eos/plugins/modules/eos_vrf.py new file mode 100644 index 000000000..705796512 --- /dev/null +++ b/ansible_collections/arista/eos/plugins/modules/eos_vrf.py @@ -0,0 +1,427 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +# (c) 2017, Ansible by Red Hat, inc +# +# This file is part of Ansible by Red Hat +# +# 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/>. +# + + +DOCUMENTATION = """ +module: eos_vrf +author: Ricardo Carrillo Cruz (@rcarrillocruz) +short_description: Manage VRFs on Arista EOS network devices +description: +- This module provides declarative management of VRFs on Arista EOS network devices. +version_added: 1.0.0 +notes: +- Tested against Arista EOS 4.24.6F +options: + name: + description: + - Name of the VRF. + type: str + rd: + description: + - Route distinguisher of the VRF + 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. The name of interface + should be in expanded format and not abbreviated. + 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 + aggregate: + description: List of VRFs instances + type: list + elements: dict + suboptions: + name: + description: + - Name of the VRF. + required: true + type: str + rd: + description: + - Route distinguisher of the VRF + 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. The name of interface + should be in expanded format and not abbreviated. + 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. This wait is applicable for operational state arguments. + default: 10 + type: int + state: + description: + - State of the VRF configuration. + default: present + type: str + choices: + - present + - absent + purge: + description: + - Purge VRFs not defined in the I(aggregate) parameter. + default: false + type: bool + delay: + description: + - Time in seconds to wait before checking for the operational state on remote + device. This wait is applicable for operational state arguments. + default: 10 + type: int + state: + description: + - State of the VRF configuration. + default: present + type: str + choices: + - present + - absent +""" + +EXAMPLES = """ +- name: Create vrf + arista.eos.eos_vrf: + name: test + rd: 1:200 + interfaces: + - Ethernet2 + state: present + +- name: Delete VRFs + arista.eos.eos_vrf: + name: test + state: absent + +- name: Create aggregate of VRFs with purge + arista.eos.eos_vrf: + aggregate: + - name: test4 + rd: 1:204 + - name: test5 + rd: 1:205 + state: present + purge: yes + +- name: Delete aggregate of VRFs + arista.eos.eos_vrf: + aggregate: + - name: test2 + - name: test3 + - name: test4 + - name: test5 + state: absent +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - vrf instance test + - rd 1:100 + - interface Ethernet1 + - vrf test +""" +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.arista.eos.plugins.module_utils.network.eos.eos import ( + load_config, + run_commands, +) + + +def search_obj_in_list(name, lst): + for o in lst: + if o["name"] == name: + return o + + +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + state = module.params["state"] + purge = module.params["purge"] + + for w in want: + name = w["name"] + rd = w["rd"] + + obj_in_have = search_obj_in_list(name, have) + + if state == "absent": + if obj_in_have: + commands.append("no vrf instance %s" % name) + elif state == "present": + if not obj_in_have: + commands.append("vrf instance %s" % name) + + if rd is not None: + commands.append("rd %s" % rd) + + if w["interfaces"]: + for i in w["interfaces"]: + commands.append("interface %s" % i) + commands.append("vrf %s" % w["name"]) + else: + if w["rd"] is not None and w["rd"] != obj_in_have["rd"]: + commands.append("vrf instance %s" % w["name"]) + commands.append("rd %s" % w["rd"]) + + if w["interfaces"]: + if not obj_in_have["interfaces"]: + for i in w["interfaces"]: + commands.append("interface %s" % i) + commands.append("vrf %s" % w["name"]) + elif set(w["interfaces"]) != obj_in_have["interfaces"]: + missing_interfaces = list( + set(w["interfaces"]) + - set(obj_in_have["interfaces"]), + ) + + for i in missing_interfaces: + commands.append("interface %s" % i) + commands.append("vrf %s" % w["name"]) + + if purge: + for h in have: + obj_in_want = search_obj_in_list(h["name"], want) + if not obj_in_want: + commands.append("no vrf instance %s" % h["name"]) + + return commands + + +def map_config_to_obj(module): + objs = [] + output = run_commands(module, {"command": "show vrf", "output": "text"}) + + lines = output[0].strip().splitlines()[3:] + + out_len = len(lines) + index = 0 + while out_len > index: + line = lines[index] + if not line: + continue + + splitted_line = re.split(r"\s{2,}", line.strip()) + + if len(splitted_line) == 1: + index += 1 + continue + obj = dict() + obj["name"] = splitted_line[0] + obj["rd"] = splitted_line[1] + obj["interfaces"] = [] + + if len(splitted_line) > 4: + obj["interfaces"] = [] + interfaces = splitted_line[4] + if interfaces.endswith(","): + while interfaces.endswith(","): + # gather all comma separated interfaces + if out_len <= index: + break + index += 1 + line = lines[index] + vrf_line = re.split(r"\s{2,}", line.strip()) + interfaces += vrf_line[-1] + + for i in interfaces.split(","): + obj["interfaces"].append(i.strip().lower()) + index += 1 + objs.append(obj) + + return objs + + +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] + + if item.get("interfaces"): + item["interfaces"] = [ + intf.replace(" ", "").lower() + for intf in item.get("interfaces") + if intf + ] + + if item.get("associated_interfaces"): + item["associated_interfaces"] = [ + intf.replace(" ", "").lower() + for intf in item.get("associated_interfaces") + if intf + ] + + obj.append(item.copy()) + else: + obj.append( + { + "name": module.params["name"], + "state": module.params["state"], + "rd": module.params["rd"], + "interfaces": [ + intf.replace(" ", "").lower() + for intf in module.params["interfaces"] + ] + if module.params["interfaces"] + else [], + "associated_interfaces": [ + intf.replace(" ", "").lower() + for intf in module.params["associated_interfaces"] + ] + if module.params["associated_interfaces"] + else [], + }, + ) + + return obj + + +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["name"], have) + + if obj_in_have: + interfaces = obj_in_have.get("interfaces") + if interfaces is not None and i not in interfaces: + module.fail_json( + msg="Interface %s not configured on vrf %s" + % (i, w["name"]), + ) + + +def main(): + """main entry point for module execution""" + element_spec = dict( + name=dict(), + interfaces=dict(type="list", elements="str"), + associated_interfaces=dict(type="list", elements="str"), + delay=dict(default=10, type="int"), + rd=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) + aggregate_spec["state"].update(default="present") + aggregate_spec["delay"].update(default=10) + + argument_spec = dict( + aggregate=dict(type="list", elements="dict", options=aggregate_spec), + purge=dict(default=False, type="bool"), + ) + + argument_spec.update(element_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), module) + result["commands"] = commands + + if commands: + commit = not module.check_mode + response = load_config(module, commands, commit=commit) + if response.get("diff") and module._diff: + result["diff"] = {"prepared": response.get("diff")} + result["session_name"] = response.get("session") + result["changed"] = True + + check_declarative_intent_params(want, module, result) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() |