diff options
Diffstat (limited to 'lib/ansible/module_utils')
46 files changed, 0 insertions, 7487 deletions
diff --git a/lib/ansible/module_utils/network/eos/argspec/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/acl_interfaces/acl_interfaces.py deleted file mode 100644 index 7e1409a7d9..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# -*- 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 arg spec for the eos_acl_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Acl_interfacesArgs(object): # pylint: disable=R0903 - """The arg spec for the eos_acl_interfaces module - """ - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'access_groups': { - 'elements': 'dict', - 'options': { - 'acls': { - 'elements': 'dict', - 'options': { - 'direction': { - 'required': True, - 'choices': ['in', 'out'], - 'type': 'str' - }, - 'name': { - 'required': True, - 'type': 'str' - } - }, - 'type': 'list' - }, - 'afi': { - 'required': True, - 'choices': ['ipv4', 'ipv6'], - 'type': 'str' - } - }, - 'type': 'list' - }, - 'name': { - 'required': True, - 'type': 'str' - } - }, - 'type': 'list' - }, - 'running_config': { - 'type': 'str' - }, - 'state': { - 'choices': [ - 'merged', 'replaced', 'overridden', 'deleted', 'gathered', - 'parsed', 'rendered' - ], - 'default': - 'merged', - 'type': - 'str' - } - } # pylint: disable=C0301 diff --git a/lib/ansible/module_utils/network/eos/argspec/acls/acls.py b/lib/ansible/module_utils/network/eos/argspec/acls/acls.py deleted file mode 100644 index f998982404..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/acls/acls.py +++ /dev/null @@ -1,468 +0,0 @@ -# -# -*- 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 arg spec for the eos_acls module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class AclsArgs(object): # pylint: disable=R0903 - """The arg spec for the eos_acls module - """ - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'acls': { - 'elements': 'dict', - 'options': { - 'aces': { - 'elements': 'dict', - 'options': { - 'destination': { - 'mutually_exclusive': - [['address', 'subnet_address', 'any', 'host'], - ['wildcard_bits', 'subnet_address', 'any', 'host']], - 'options': { - 'address': { - 'type': 'str' - }, - 'any': { - 'type': 'bool' - }, - 'host': { - 'type': 'str' - }, - 'port_protocol': { - 'type': 'dict' - }, - 'subnet_address': { - 'type': 'str' - }, - 'wildcard_bits': { - 'type': 'str' - } - }, - 'required_together': - [['address', 'wildcard_bits']], - 'type': - 'dict' - }, - 'fragment_rules': { - 'type': 'bool' - }, - 'fragments': { - 'type': 'bool' - }, - 'grant': { - 'choices': ['permit', 'deny'], - 'type': 'str' - }, - 'line': { - 'type': 'str', - 'aliases': ['ace'] - }, - 'hop_limit': { - 'type': 'dict' - }, - 'log': { - 'type': 'bool' - }, - 'protocol': { - 'type': 'str' - }, - 'protocol_options': { - 'options': { - 'icmp': { - 'options': { - 'administratively_prohibited': - { - 'type': 'bool' - }, - 'alternate_address': { - 'type': 'bool' - }, - 'conversion_error': { - 'type': 'bool' - }, - 'dod_host_prohibited': { - 'type': 'bool' - }, - 'dod_net_prohibited': { - 'type': 'bool' - }, - 'echo': { - 'type': 'bool' - }, - 'echo_reply': { - 'type': 'bool' - }, - 'general_parameter_problem': { - 'type': 'bool' - }, - 'host_isolated': { - 'type': 'bool' - }, - 'host_precedence_unreachable': - { - 'type': 'bool' - }, - 'host_redirect': { - 'type': 'bool' - }, - 'host_tos_redirect': { - 'type': 'bool' - }, - 'host_tos_unreachable': { - 'type': 'bool' - }, - 'host_unknown': { - 'type': 'bool' - }, - 'host_unreachable': { - 'type': 'bool' - }, - 'information_reply': { - 'type': 'bool' - }, - 'information_request': { - 'type': 'bool' - }, - 'mask_reply': { - 'type': 'bool' - }, - 'mask_request': { - 'type': 'bool' - }, - 'message_code': { - 'type': 'int' - }, - 'message_num': { - 'type': 'int' - }, - 'message_type': { - 'type': 'int' - }, - 'mobile_redirect': { - 'type': 'bool' - }, - 'net_redirect': { - 'type': 'bool' - }, - 'net_tos_redirect': { - 'type': 'bool' - }, - 'net_tos_unreachable': { - 'type': 'bool' - }, - 'net_unreachable': { - 'type': 'bool' - }, - 'network_unknown': { - 'type': 'bool' - }, - 'no_room_for_option': { - 'type': 'bool' - }, - 'option_missing': { - 'type': 'bool' - }, - 'packet_too_big': { - 'type': 'bool' - }, - 'parameter_problem': { - 'type': 'bool' - }, - 'port_unreachable': { - 'type': 'bool' - }, - 'precedence_unreachable': { - 'type': 'bool' - }, - 'protocol_unreachable': { - 'type': 'bool' - }, - 'reassembly_timeout': { - 'type': 'bool' - }, - 'redirect': { - 'type': 'bool' - }, - 'router_advertisement': { - 'type': 'bool' - }, - 'router_solicitation': { - 'type': 'bool' - }, - 'source_quench': { - 'type': 'bool' - }, - 'source_route_failed': { - 'type': 'bool' - }, - 'time_exceeded': { - 'type': 'bool' - }, - 'timestamp_reply': { - 'type': 'bool' - }, - 'timestamp_request': { - 'type': 'bool' - }, - 'traceroute': { - 'type': 'bool' - }, - 'ttl_exceeded': { - 'type': 'bool' - }, - 'unreachable': { - 'type': 'bool' - } - }, - 'type': 'dict' - }, - 'icmpv6': { - 'options': { - 'address_unreachable': { - 'type': 'bool' - }, - 'beyond_scope': { - 'type': 'bool' - }, - 'echo_reply': { - 'type': 'bool' - }, - 'echo_request': { - 'type': 'bool' - }, - 'erroneous_header': { - 'type': 'bool' - }, - 'fragment_reassembly_exceeded': - { - 'type': 'bool' - }, - 'hop_limit_exceeded': { - 'type': 'bool' - }, - 'neighbor_advertisement': { - 'type': 'bool' - }, - 'neighbor_solicitation': { - 'type': 'bool' - }, - 'no_admin': { - 'type': 'bool' - }, - 'no_route': { - 'type': 'bool' - }, - 'packet_too_big': { - 'type': 'bool' - }, - 'parameter_problem': { - 'type': 'bool' - }, - 'port_unreachable': { - 'type': 'bool' - }, - 'redirect_message': { - 'type': 'bool' - }, - 'reject_route': { - 'type': 'bool' - }, - 'router_advertisement': { - 'type': 'bool' - }, - 'router_solicitation': { - 'type': 'bool' - }, - 'source_address_failed': { - 'type': 'bool' - }, - 'source_routing_error': { - 'type': 'bool' - }, - 'time_exceeded': { - 'type': 'bool' - }, - 'unreachable': { - 'type': 'bool' - }, - 'unrecognized_ipv6_option': { - 'type': 'bool' - }, - 'unrecognized_next_header': { - 'type': 'bool' - } - }, - 'type': 'dict' - }, - 'ip': { - 'options': { - 'nexthop_group': { - 'type': 'str' - } - }, - 'type': 'dict' - }, - 'ipv6': { - 'options': { - 'nexthop_group': { - 'type': 'str' - } - }, - 'type': 'dict' - }, - 'tcp': { - 'options': { - 'flags': { - 'options': { - 'ack': { - 'type': 'bool' - }, - 'established': { - 'type': 'bool' - }, - 'fin': { - 'type': 'bool' - }, - 'psh': { - 'type': 'bool' - }, - 'rst': { - 'type': 'bool' - }, - 'syn': { - 'type': 'bool' - }, - 'urg': { - 'type': 'bool' - } - }, - 'type': 'dict' - } - }, - 'type': 'dict' - } - }, - 'type': 'dict' - }, - 'remark': { - 'type': 'str' - }, - 'sequence': { - 'type': 'int' - }, - 'source': { - 'mutually_exclusive': - [['address', 'subnet_address', 'any', 'host'], - ['wildcard_bits', 'subnet_address', 'any', 'host']], - 'options': { - 'address': { - 'type': 'str' - }, - 'any': { - 'type': 'bool' - }, - 'host': { - 'type': 'str' - }, - 'port_protocol': { - 'type': 'dict' - }, - 'subnet_address': { - 'type': 'str' - }, - 'wildcard_bits': { - 'type': 'str' - } - }, - 'required_together': [['address', 'wildcard_bits']], - 'type': 'dict' - }, - 'tracked': { - 'type': 'bool' - }, - 'ttl': { - 'options': { - 'eq': { - 'type': 'int' - }, - 'gt': { - 'type': 'int' - }, - 'lt': { - 'type': 'int' - }, - 'neq': { - 'type': 'int' - } - }, - 'type': 'dict' - }, - 'vlan': { - 'type': 'str' - } - }, - 'type': 'list' - }, - 'name': { - 'required': True, - 'type': 'str' - }, - 'standard': { - 'type': 'bool' - } - }, - 'type': 'list' - }, - 'afi': { - 'choices': ['ipv4', 'ipv6'], - 'required': True, - 'type': 'str' - } - }, - 'type': 'list' - }, - 'running_config': { - 'type': 'str' - }, - 'state': { - 'choices': [ - 'deleted', 'merged', 'overridden', 'replaced', 'gathered', - 'rendered', 'parsed' - ], - 'default': - 'merged', - 'type': - 'str' - } - } # pylint: disable=C0301 diff --git a/lib/ansible/module_utils/network/eos/argspec/facts/facts.py b/lib/ansible/module_utils/network/eos/argspec/facts/facts.py deleted file mode 100644 index 79446b03be..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/facts/facts.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- 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) -""" -The arg spec for the eos facts module. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class FactsArgs(object): - """ The arg spec for the eos facts module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'gather_subset': dict(default=['!config'], type='list'), - 'gather_network_resources': dict(type='list'), - } diff --git a/lib/ansible/module_utils/network/eos/argspec/interfaces/interfaces.py b/lib/ansible/module_utils/network/eos/argspec/interfaces/interfaces.py deleted file mode 100644 index 880e5126e7..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/interfaces/interfaces.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- 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 arg spec for the eos_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class InterfacesArgs(object): - """The arg spec for the eos_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'options': { - 'name': {'required': True, 'type': 'str'}, - 'description': {'required': False, 'type': 'str'}, - 'enabled': {'default': True, 'required': False, 'type': 'bool'}, - 'mtu': {'required': False, 'type': 'int'}, - 'speed': {'required': False, 'type': 'str'}, - 'duplex': {'required': False, 'type': 'str'} - }, - 'type': 'list'}, - 'state': {'default': 'merged', 'choices': ['merged', 'replaced', 'overridden', 'deleted'], 'required': False, 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/eos/argspec/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/l2_interfaces/l2_interfaces.py deleted file mode 100644 index e9b9a5be19..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- 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 arg spec for the eos_l2_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class L2_interfacesArgs(object): - """The arg spec for the eos_l2_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'access': {'options': {'vlan': {'type': 'int'}}, - 'type': 'dict'}, - 'mode': {'type': 'str', 'choices': ['access', 'trunk']}, - 'name': {'required': True, 'type': 'str'}, - 'trunk': {'options': {'native_vlan': {'type': 'int'}, 'trunk_allowed_vlans': {'type': 'list'}}, - 'type': 'dict'}}, - 'type': 'list'}, - 'state': {'default': 'merged', 'choices': ['merged', 'replaced', 'overridden', 'deleted'], 'required': False, 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/eos/argspec/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/l3_interfaces/l3_interfaces.py deleted file mode 100644 index 2708b47c42..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/l3_interfaces/l3_interfaces.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- 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 arg spec for the eos_l3_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class L3_interfacesArgs(object): - """The arg spec for the eos_l3_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'name': {'required': True, 'type': 'str'}, - 'ipv4': {'elements': 'dict', - 'options': {'address': {'type': 'str'}, 'secondary': {'type': 'bool'}}, - 'type': 'list'}, - 'ipv6': {'elements': 'dict', - 'options': {'address': {'type': 'str'}}, - 'type': 'list'}, - }, - 'type': 'list'}, - 'state': {'default': 'merged', 'choices': ['merged', 'replaced', 'overridden', 'deleted'], 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/eos/argspec/lacp/lacp.py b/lib/ansible/module_utils/network/eos/argspec/lacp/lacp.py deleted file mode 100644 index b0862a222e..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/lacp/lacp.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- 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 arg spec for the eos_lacp module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class LacpArgs(object): - """The arg spec for the eos_lacp module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'options': { - 'system': { - 'options': { - 'priority': {'type': 'int'} - }, - 'type': 'dict' - } - }, - 'type': 'dict' - }, - 'state': {'choices': ['merged', 'replaced', 'deleted'], 'default': 'merged', 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/eos/argspec/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index bbe20867f0..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/lacp_interfaces/lacp_interfaces.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# -*- 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 arg spec for the eos_lacp_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Lacp_interfacesArgs(object): - """The arg spec for the eos_lacp_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': {'elements': 'dict', - 'options': {'name': {'type': 'str'}, - 'port_priority': {'type': 'int'}, - 'rate': {'choices': ['fast', 'normal'], 'type': 'str'}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/eos/argspec/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/lag_interfaces/lag_interfaces.py deleted file mode 100644 index ff672ffb93..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- 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 arg spec for the eos_lag_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Lag_interfacesArgs(object): - """The arg spec for the eos_lag_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'name': {'required': True, 'type': 'str'}, - 'members': { - 'elements': 'dict', - 'options': { - 'member': {'type': 'str'}, - 'mode': {'choices': ['active', 'on', 'passive'], 'type': 'str'}, - }, - 'type': 'list', - }, - }, - 'type': 'list'}, - 'state': {'default': 'merged', 'choices': ['merged', 'replaced', 'overridden', 'deleted'], 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/eos/argspec/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/eos/argspec/lldp_global/lldp_global.py deleted file mode 100644 index 2dc3e0cf58..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/lldp_global/lldp_global.py +++ /dev/null @@ -1,58 +0,0 @@ -# -# -*- 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 arg spec for the eos_lldp_global module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Lldp_globalArgs(object): - """The arg spec for the eos_lldp_global module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'options': { - 'holdtime': {'type': 'int'}, - 'reinit': {'type': 'int'}, - 'timer': {'type': 'int'}, - 'tlv_select': { - 'options': { - 'link_aggregation': {'type': 'bool'}, - 'management_address': {'type': 'bool'}, - 'max_frame_size': {'type': 'bool'}, - 'port_description': {'type': 'bool'}, - 'system_capabilities': {'type': 'bool'}, - 'system_description': {'type': 'bool'}, - 'system_name': {'type': 'bool'}}, - 'type': 'dict'}}, - 'type': 'dict'}, - 'state': {'choices': ['merged', 'replaced', 'deleted'], 'default': 'merged', 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/eos/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/eos/argspec/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index 2cdc866891..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/lldp_interfaces/lldp_interfaces.py +++ /dev/null @@ -1,49 +0,0 @@ -# -# -*- 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 arg spec for the eos_lldp_interfaces module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Lldp_interfacesArgs(object): - """The arg spec for the eos_lldp_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': {'name': {'type': 'str'}, - 'receive': {'type': 'bool'}, - 'transmit': {'type': 'bool'}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/eos/argspec/static_routes/static_routes.py b/lib/ansible/module_utils/network/eos/argspec/static_routes/static_routes.py deleted file mode 100644 index f4b9277b1e..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/static_routes/static_routes.py +++ /dev/null @@ -1,115 +0,0 @@ -# -# -*- 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 arg spec for the eos_static_routes module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class Static_routesArgs(object): - """The arg spec for the eos_static_routes module - """ - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'address_families': { - 'elements': 'dict', - 'options': { - 'afi': { - 'choices': ['ipv4', 'ipv6'], - 'required': True, - 'type': 'str' - }, - 'routes': { - 'elements': 'dict', - 'options': { - 'dest': { - 'required': True, - 'type': 'str' - }, - 'next_hops': { - 'elements': 'dict', - 'options': { - 'admin_distance': { - 'type': 'int' - }, - 'description': { - 'type': 'str' - }, - 'forward_router_address': { - 'type': 'str' - }, - 'interface': { - 'type': 'str' - }, - 'nexthop_grp': { - 'type': 'str' - }, - 'mpls_label': { - 'type': 'int' - }, - 'tag': { - 'type': 'int' - }, - 'track': { - 'type': 'str' - }, - 'vrf': { - 'type': 'str' - } - }, - 'type': 'list' - } - }, - 'type': 'list' - } - }, - 'type': 'list' - }, - 'vrf': { - 'type': 'str' - } - }, - 'type': 'list' - }, - 'running_config': { - 'type': 'str' - }, - 'state': { - 'choices': [ - 'deleted', 'merged', 'overridden', 'replaced', 'gathered', - 'rendered', 'parsed' - ], - 'default': - 'merged', - 'type': - 'str' - } - } # pylint: disable=C0301 diff --git a/lib/ansible/module_utils/network/eos/argspec/vlans/vlans.py b/lib/ansible/module_utils/network/eos/argspec/vlans/vlans.py deleted file mode 100644 index ea2211ca3d..0000000000 --- a/lib/ansible/module_utils/network/eos/argspec/vlans/vlans.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- 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 arg spec for the eos_vlans module -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -class VlansArgs(object): - """The arg spec for the eos_vlans module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'vlan_id': {'required': True, 'type': 'int'}, - 'name': {'type': 'str'}, - 'state': {'choices': ['active', 'suspend'], 'type': 'str'}, - }, - 'type': 'list', - }, - 'state': { - 'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str', - }, - } diff --git a/lib/ansible/module_utils/network/eos/config/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/eos/config/acl_interfaces/acl_interfaces.py deleted file mode 100644 index c3eb56ace2..0000000000 --- a/lib/ansible/module_utils/network/eos/config/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,394 +0,0 @@ -# -# -*- 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) -""" -The eos_acl_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import itertools - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, search_obj_in_list -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Acl_interfaces(ConfigBase): - """ - The eos_acl_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'acl_interfaces', - ] - - def __init__(self, module): - super(Acl_interfaces, self).__init__(module) - - def get_acl_interfaces_facts(self, data=None): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data) - acl_interfaces_facts = facts['ansible_network_resources'].get('acl_interfaces') - if not acl_interfaces_facts: - return [] - return acl_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - changed = False - - if self.state in self.ACTION_STATES: - existing_acl_interfaces_facts = self.get_acl_interfaces_facts() - else: - existing_acl_interfaces_facts = [] - if self.state in self.ACTION_STATES or self.state == 'rendered': - commands.extend(self.set_config(existing_acl_interfaces_facts)) - if commands and self.state in self.ACTION_STATES: - if not self._module.check_mode: - self._connection.edit_config(commands) - changed = True - if changed: - result['changed'] = True - if self.state in self.ACTION_STATES: - result['commands'] = commands - if self.state in self.ACTION_STATES or self.state == 'gathered': - changed_acl_interfaces_facts = self.get_acl_interfaces_facts() - elif self.state == 'rendered': - result['rendered'] = commands - elif self.state == 'parsed': - if not self._module.params['running_config']: - self._module.fail_json(msg="Value of running_config parameter must not be empty for state parsed") - result['parsed'] = self.get_acl_interfaces_facts(data=self._module.params['running_config']) - else: - changed_acl_interfaces_facts = [] - if self.state in self.ACTION_STATES: - result['before'] = existing_acl_interfaces_facts - if result['changed']: - result['after'] = changed_acl_interfaces_facts - elif self.state == 'gathered': - result['gathered'] = changed_acl_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_acl_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_acl_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - if self.state in ('merged', 'replaced', 'overridden') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(self.state)) - state = self._module.params['state'] - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or self.state == 'rendered': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - def _state_replaced(self, want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commandset = [] - want_interface = [] - for w in want: - commands = [] - diff_access_group = [] - want_interface.append(w['name']) - obj_in_have = search_obj_in_list(w['name'], have, 'name') - if not obj_in_have or 'access_groups' not in obj_in_have.keys(): - commands.append(add_commands(w['access_groups'], w['name'])) - else: - if 'access_groups' in obj_in_have.keys(): - obj = self.get_acl_diff(obj_in_have, w) - if obj[0]: - to_delete = {'access_groups': [{'acls': obj[0], 'afi': 'ipv4'}]} - commands.append(remove_commands(to_delete, w['name'])) - if obj[1]: - to_delete = {'access_groups': [{'acls': obj[1], 'afi': 'ipv6'}]} - commands.append(remove_commands(to_delete, w['name'])) - diff = self.get_acl_diff(w, obj_in_have) - if diff[0]: - diff_access_group.append({'afi': 'ipv4', 'acls': diff[0]}) - if diff[1]: - diff_access_group.append({'afi': 'ipv6', 'acls': diff[1]}) - if diff_access_group: - commands.append(add_commands(diff_access_group, w['name'])) - if commands: - intf_command = ["interface " + w['name']] - commands = list(itertools.chain(*commands)) - commandset.append(intf_command) - commandset.append(commands) - - if commandset: - commandset = list(itertools.chain(*commandset)) - return commandset - - def _state_overridden(self, want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commandset = [] - want_interface = [] - for w in want: - commands = [] - diff_access_group = [] - want_interface.append(w['name']) - obj_in_have = search_obj_in_list(w['name'], have, 'name') - if not obj_in_have or 'access_groups' not in obj_in_have.keys(): - commands.append(add_commands(w['access_groups'], w['name'])) - else: - if 'access_groups' in obj_in_have.keys(): - obj = self.get_acl_diff(obj_in_have, w) - if obj[0]: - to_delete = {'access_groups': [{'acls': obj[0], 'afi': 'ipv4'}]} - commands.append(remove_commands(to_delete, w['name'])) - if obj[1]: - to_delete = {'access_groups': [{'acls': obj[1], 'afi': 'ipv6'}]} - commands.append(remove_commands(to_delete, w['name'])) - diff = self.get_acl_diff(w, obj_in_have) - if diff[0]: - diff_access_group.append({'afi': 'ipv4', 'acls': diff[0]}) - if diff[1]: - diff_access_group.append({'afi': 'ipv6', 'acls': diff[1]}) - if diff_access_group: - commands.append(add_commands(diff_access_group, w['name'])) - if commands: - intf_command = ["interface " + w['name']] - commands = list(itertools.chain(*commands)) - commandset.append(intf_command) - commandset.append(commands) - for h in have: - commands = [] - if 'access_groups' in h.keys() and h['access_groups']: - if h['name'] not in want_interface: - for h_group in h['access_groups']: - to_delete = {'access_groups': [h_group]} - commands.append(remove_commands(to_delete, h['name'])) - if commands: - intf_command = ["interface " + h['name']] - commands = list(itertools.chain(*commands)) - commandset.append(intf_command) - commandset.append(commands) - - if commandset: - commandset = list(itertools.chain(*commandset)) - - return commandset - - def _state_merged(self, want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commandset = [] - for w in want: - commands = [] - diff_access_group = [] - obj_in_have = search_obj_in_list(w['name'], have, 'name') - if not obj_in_have: - commands = add_commands(w['access_groups'], w['name']) - else: - if 'access_groups' in obj_in_have.keys(): - diff = self.get_acl_diff(w, obj_in_have) - if diff[0]: - diff_access_group.append({'afi': 'ipv4', 'acls': diff[0]}) - if diff[1]: - diff_access_group.append({'afi': 'ipv6', 'acls': diff[1]}) - if diff_access_group: - commands = add_commands(diff_access_group, w['name']) - else: - commands = add_commands(w['access_groups'], w['name']) - if commands: - intf_command = ["interface " + w['name']] - commandset.append(intf_command) - commandset.append(commands) - if commandset: - commandset = list(itertools.chain(*commandset)) - return commandset - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commandset = [] - for w in want: - commands = [] - intf_command = ["interface " + w['name']] - obj_in_have = search_obj_in_list(w['name'], have, 'name') - if 'access_groups' not in w.keys() or not w['access_groups']: - commands = remove_commands(obj_in_have, w['name']) - if w['access_groups']: - for w_grp in w['access_groups']: - if 'acls' not in w_grp.keys() or not w_grp['acls']: - obj = self.get_acls_from_afi(w['name'], w_grp['afi'], have) - to_delete = {'access_groups': [{'acls': obj, 'afi': w_grp['afi']}]} - commands = remove_commands(to_delete, w['name']) - else: - if 'access_groups' not in obj_in_have.keys() or not obj_in_have['access_groups']: - continue - group = {'access_groups': [w_grp]} - obj = self.get_acl_diff(group, obj_in_have, True) - if obj[0]: - to_delete = {'access_groups': [{'acls': obj[0], 'afi': 'ipv4'}]} - commands.append(remove_commands(to_delete, w['name'])) - if obj[1]: - to_delete = {'access_groups': [{'acls': obj[1], 'afi': 'ipv6'}]} - commands.append(remove_commands(to_delete, w['name'])) - if commands: - commands = list(itertools.chain(*commands)) - if commands: - commandset.append(intf_command) - commandset.append(commands) - - if commandset: - commandset = list(itertools.chain(*commandset)) - return commandset - - def get_acl_diff(self, w, h, intersection=False): - diff_v4 = [] - diff_v6 = [] - w_acls_v4 = [] - w_acls_v6 = [] - h_acls_v4 = [] - h_acls_v6 = [] - for w_group in w['access_groups']: - if w_group['afi'] == 'ipv4': - w_acls_v4 = w_group['acls'] - if w_group['afi'] == 'ipv6': - w_acls_v6 = w_group['acls'] - for h_group in h['access_groups']: - if h_group['afi'] == 'ipv4': - h_acls_v4 = h_group['acls'] - if h_group['afi'] == 'ipv6': - h_acls_v6 = h_group['acls'] - for item in w_acls_v4: - match = list(filter(lambda x: x['name'] == item['name'], h_acls_v4)) - if match: - if item['direction'] == match[0]['direction']: - if intersection: - diff_v4.append(item) - else: - if not intersection: - diff_v4.append(item) - else: - if not intersection: - diff_v4.append(item) - for item in w_acls_v6: - match = list(filter(lambda x: x['name'] == item['name'], h_acls_v6)) - if match: - if item['direction'] == match[0]['direction']: - if intersection: - diff_v6.append(item) - else: - if not intersection: - diff_v6.append(item) - else: - if not intersection: - diff_v6.append(item) - return diff_v4, diff_v6 - - def get_acls_from_afi(self, interface, afi, have): - config = [] - for h in have: - if h['name'] == interface: - if 'access_groups' not in h.keys() or not h['access_groups']: - continue - if h['access_groups']: - for h_grp in h['access_groups']: - if h_grp['afi'] == afi: - config = h_grp['acls'] - return config - - -def add_commands(want, interface): - commands = [] - - for w in want: - # This module was verified on an ios device since vEOS doesnot support - # acl_interfaces cnfiguration. In ios, ipv6 acl is configured as - # traffic-filter and in eos it is access-group - - # a_cmd = "traffic-filter" if w['afi'] == 'ipv6' else "access-group" - a_cmd = "access-group" - afi = 'ip' if w['afi'] == 'ipv4' else w['afi'] - if 'acls' in w.keys(): - for acl in w['acls']: - commands.append(afi + " " + a_cmd + " " + acl['name'] + " " + acl['direction']) - return commands - - -def remove_commands(want, interface): - commands = [] - if 'access_groups' not in want.keys() or not want['access_groups']: - return commands - for w in want['access_groups']: - # This module was verified on an ios device since vEOS doesnot support - # acl_interfaces cnfiguration. In ios, ipv6 acl is configured as - # traffic-filter and in eos it is access-group - - # a_cmd = "traffic-filter" if w['afi'] == 'ipv6' else "access-group" - a_cmd = "access-group" - - afi = 'ip' if w['afi'] == 'ipv4' else w['afi'] - if 'acls' in w.keys(): - for acl in w['acls']: - commands.append("no " + afi + " " + a_cmd + " " + acl['name'] + " " + acl['direction']) - return commands diff --git a/lib/ansible/module_utils/network/eos/config/acls/acls.py b/lib/ansible/module_utils/network/eos/config/acls/acls.py deleted file mode 100644 index 90fee80b04..0000000000 --- a/lib/ansible/module_utils/network/eos/config/acls/acls.py +++ /dev/null @@ -1,483 +0,0 @@ -# -# -*- 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) -""" -The eos_acls class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import socket -import re -import itertools - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.common.utils import remove_empties, dict_diff -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Acls(ConfigBase): - """ - The eos_acls class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'acls', - ] - - def __init__(self, module): - super(Acls, self).__init__(module) - - def get_acls_facts(self, data=None): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data) - acls_facts = facts['ansible_network_resources'].get('acls') - if not acls_facts: - return [] - return acls_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - changed = False - - if self.state in self.ACTION_STATES: - existing_acls_facts = self.get_acls_facts() - else: - existing_acls_facts = [] - if self.state in self.ACTION_STATES or self.state == 'rendered': - commands.extend(self.set_config(existing_acls_facts)) - if commands and self.state in self.ACTION_STATES: - if not self._module.check_mode: - self._connection.edit_config(commands) - changed = True - if changed: - result['changed'] = True - if self.state in self.ACTION_STATES: - result['commands'] = commands - if self.state in self.ACTION_STATES or self.state == 'gathered': - changed_acls_facts = self.get_acls_facts() - elif self.state == 'rendered': - commands = list(itertools.chain(*commands)) - result['rendered'] = commands - elif self.state == 'parsed': - if not self._module.params['running_config']: - self._module.fail_json(msg="Value of running_config parameter must not be empty for state parsed") - result['parsed'] = self.get_acls_facts(data=self._module.params['running_config']) - else: - changed_acls_facts = [] - if self.state in self.ACTION_STATES: - result['before'] = existing_acls_facts - if result['changed']: - result['after'] = changed_acls_facts - elif self.state == 'gathered': - result['gathered'] = changed_acls_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_acls_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - config = self._module.params.get('config') - want = [] - onbox_configs = [] - for h in existing_acls_facts: - have_configs = add_commands(remove_empties(h)) - onbox_configs.append(have_configs) - if config: - for w in config: - want.append(remove_empties(w)) - have = existing_acls_facts - resp = self.set_state(want, have) - if self.state == 'merged': - to_config = self.compare_configs(onbox_configs, to_list(resp)) - else: - to_config = resp - return to_config - - def compare_configs(self, have, want): - commands = [] - want = list(itertools.chain(*want)) - have = list(itertools.chain(*have)) - h_index = 0 - config = list(want) - for w in want: - access_list = re.findall(r'(ip.*) access-list (.*)', w) - if access_list: - if w in have: - h_index = have.index(w) - else: - for num, h in enumerate(have, start=h_index + 1): - if "access-list" not in h: - seq_num = re.search(r'(\d+) (.*)', w) - if seq_num: - have_seq_num = re.search(r'(\d+) (.*)', h) - if seq_num.group(1) == have_seq_num.group(1) and have_seq_num.group(2) != seq_num.group(2): - negate_cmd = "no " + seq_num.group(1) - config.insert(config.index(w), negate_cmd) - if w in h: - config.pop(config.index(w)) - break - for c in config: - access_list = re.findall(r'(ip.*) access-list (.*)', c) - if access_list: - acl_index = config.index(c) - else: - if config[acl_index] not in commands: - commands.append(config[acl_index]) - commands.append(c) - return commands - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - if self.state in ('merged', 'replaced', 'overridden', 'rendered') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(self.state)) - state = self._module.params['state'] - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or self.state == 'rendered': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - have_commands = [] - remove_cmds = [] - diff = {} - present = False - diff_present = False - for w in want: - afi = "ipv6" if w["afi"] == "ipv6" else "ipv4" - for acl in w["acls"]: - name = acl["name"] - want_ace = acl["aces"] - for h in have: - if h["afi"] == afi: - for h_acl in h["acls"]: - if h_acl["name"] == name: - present = True - h = {"afi": afi, "acls": [{"name": name}]} - for h_ace in h_acl['aces']: - diff = get_ace_diff(h_ace, want_ace) - if diff: - diff_present = True - h = {"afi": afi, "acls": [{"name": name, "aces": [h_ace]}]} - remove_cmds.append(del_commands(h, have)) - if diff_present or not present: - config_cmds = set_commands(want, have) - config_cmds = list(itertools.chain(*config_cmds)) - for cmd in have: - have_configs = add_commands(cmd) - have_commands.append(have_configs) - have_commands = list(itertools.chain(*have_commands)) - if remove_cmds: - remove_cmds = list(itertools.chain(*remove_cmds)) - commands.append(remove_cmds) - commands.append(config_cmds) - commands = list(itertools.chain(*commands)) - commandset = [] - [commandset.append(cmd) for cmd in commands if cmd not in commandset] - return commandset - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - ace_diff = {} - h_afi_list = [] - w_afi_list = [] - diff = False - for h in have: - h_afi_list.append(h["afi"]) - for w in want: - w_afi_list.append(w["afi"]) - for hafi in h_afi_list: - if hafi not in w_afi_list: - h = {"afi": hafi} - remove_cmds = del_commands(h, have) - commands.append(remove_cmds) - for w in want: - w_names = [] - for h in have: - h_names = [] - if w["afi"] == h["afi"]: - for w_acl in w["acls"]: - w_names.append(w_acl["name"]) - for h_acl in h["acls"]: - h_names.append(h_acl["name"]) - if h_acl["name"] == w_acl["name"]: - for w_ace in w_acl['aces']: - ace_diff = get_ace_diff(w_ace, h_acl["aces"]) - if ace_diff: - diff = True - h = {"afi": h["afi"], "acls": [{"name": h_acl["name"], "aces": h_acl["aces"]}]} - remove_cmds = del_commands(h, have) - commands.append(remove_cmds) - for hname in h_names: - if hname not in w_names: - h = {"afi": h["afi"], "acls": [{"name": hname}]} - remove_cmds = del_commands(h, have) - if remove_cmds not in commands: - commands.append(remove_cmds) - - if diff: - config_cmds = set_commands(want, have) - config_cmds = list(itertools.chain(*config_cmds)) - commands.append(config_cmds) - if commands: - commands = list(itertools.chain(*commands)) - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - return set_commands(want, have) - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - if not want: - for h in have: - return_command = add_commands(h) - for command in return_command: - command = "no " + command - commands.append(command) - else: - for w in want: - return_command = del_commands(w, have) - commands.append(return_command) - commands = list(itertools.chain(*commands)) - return commands - - -def set_commands(want, have): - commands = [] - for w in want: - wace_updated = [] - for h in have: - if w['afi'] == h['afi']: - for wacl in w["acls"]: - for hacl in h["acls"]: - if wacl['name'] == hacl['name']: - want_aces = wacl['aces'] - for wace in wacl['aces']: - for hace in hacl['aces']: - if 'sequence' in wace.keys() and 'sequence' in hace.keys(): - if wace['sequence'] == hace['sequence']: - wace_updated = get_updated_ace(wace, hace) - if wace_updated: - want_aces.pop(want_aces.index(wace)) - want_aces.append(wace_updated) - return_command = add_commands(w) - commands.append(return_command) - return commands - - -def get_updated_ace(w, h): - # gives the ace to be updated in case of merge update. - w_updated = w.copy() - for hkey in h.keys(): - if hkey not in w.keys(): - w_updated.update({hkey: h[hkey]}) - else: - w_updated.update({hkey: w[hkey]}) - return w_updated - - -def add_commands(want): - commandset = [] - protocol_name = {"51": "ahp", "47": "gre", "1": "icmp", "2": "igmp", - "4": "ip", "89": "ospf", "103": "pim", "6": "tcp", - "17": "udp", "112": "vrrp"} - if not want: - return commandset - command = "" - afi = "ip" if want["afi"] == "ipv4" else "ipv6" - for acl in want["acls"]: - if "standard" in acl.keys() and acl["standard"]: - command = afi + " access-list standard " + acl["name"] - else: - command = afi + " access-list " + acl["name"] - commandset.append(command) - if "aces" not in acl.keys(): - continue - for ace in acl["aces"]: - command = "" - if "sequence" in ace.keys(): - command = str(ace["sequence"]) - if "remark" in ace.keys(): - command = command + " remark " + ace["remark"] - if "fragment_rules" in ace.keys() and ace["fragment_rules"]: - command = command + " fragment-rules" - if "grant" in ace.keys(): - command = command + " " + ace["grant"] - if "vlan" in ace.keys(): - command = command + " vlan " + ace["vlan"] - if "protocol" in ace.keys(): - protocol = ace["protocol"] - if protocol.isdigit(): - if protocol in protocol_name.keys(): - protocol = protocol_name[protocol] - command = command + " " + protocol - if "source" in ace.keys(): - if "any" in ace["source"].keys(): - command = command + " any" - elif "subnet_address" in ace["source"].keys(): - command = command + " " + ace["source"]["subnet_address"] - elif "host" in ace["source"].keys(): - command = command + " host " + ace["source"]["host"] - elif "address" in ace["source"].keys(): - command = command + " " + ace["source"]["address"] + " " + ace["source"]["wildcard_bits"] - if "port_protocol" in ace["source"].keys(): - for op, val in ace["source"]["port_protocol"].items(): - if val.isdigit(): - val = socket.getservbyport(int(val)) - command = command + " " + op + " " + val - if "destination" in ace.keys(): - if "any" in ace["destination"].keys(): - command = command + " any" - elif "subnet_address" in ace["destination"].keys(): - command = command + " " + ace["destination"]["subnet_address"] - elif "host" in ace["destination"].keys(): - command = command + " host " + ace["destination"]["host"] - elif "address" in ace["destination"].keys(): - command = command + " " + ace["destination"]["address"] + " " + ace["destination"]["wildcard_bits"] - if "port_protocol" in ace["destination"].keys(): - for op in ace["destination"]["port_protocol"].keys(): - command = command + " " + op + " " + ace["destination"]["port_protocol"][op] - if "protocol_options" in ace.keys(): - for proto in ace["protocol_options"].keys(): - if proto == "icmp" or proto == "icmpv6": - for icmp_msg in ace["protocol_options"][proto].keys(): - command = command + " " + icmp_msg - elif proto == "ip" or proto == "ipv6": - command = command + " nexthop-group " + ace["protocol_options"][proto]["nexthop_group"] - elif proto == "tcp": - for flag, val in ace["prtocol_options"][proto]["flags"].items(): - command = command + " " + val - if "hop_limit" in ace.keys(): - for op, val in ace["hop_limit"].items(): - command = command + " hop-limit " + op + " " + val - if "tracked" in ace.keys() and ace["tracked"]: - command = command + " tracked" - if "ttl" in ace.keys(): - for op, val in ace["ttl"].items(): - command = command + " ttl " + op + " " + str(val) - if "fragments" in ace.keys(): - command = command + " fragments" - if "log" in ace.keys(): - command = command + " log" - commandset.append(command.strip()) - return commandset - - -def del_commands(want, have): - commandset = [] - command = "" - have_command = [] - for h in have: - have_configs = add_commands(h) - have_command.append(have_configs) - have_command = list(itertools.chain(*have_command)) - afi = "ip" if want["afi"] == "ipv4" else "ipv6" - if "acls" not in want.keys(): - for have_cmd in have_command: - access_list = re.search(r'(ip.*)\s+access-list .*', have_cmd) - if access_list and access_list.group(1) == afi: - commandset.append("no " + have_cmd) - return commandset - - for acl in want["acls"]: - ace_present = True - if "standard" in acl.keys() and acl["standard"]: - command = afi + " access-list standard " + acl["name"] - else: - command = afi + " access-list " + acl["name"] - if "aces" not in acl.keys(): - ace_present = False - commandset.append("no " + command) - if ace_present: - return_command = add_commands(want) - for cmd in return_command: - if "access-list" in cmd: - commandset.append(cmd) - continue - seq = re.search(r'(\d+) (permit|deny|fragment-rules|remark) .*', cmd) - if seq: - commandset.append("no " + seq.group(1)) - else: - commandset.append("no " + cmd) - return commandset - - -def get_ace_diff(want_ace, have_ace): - # gives the diff of the aces passed. - for h_a in have_ace: - d = dict_diff(want_ace, h_a) - if not d: - break - return d diff --git a/lib/ansible/module_utils/network/eos/config/interfaces/interfaces.py b/lib/ansible/module_utils/network/eos/config/interfaces/interfaces.py deleted file mode 100644 index 7687ae296f..0000000000 --- a/lib/ansible/module_utils/network/eos/config/interfaces/interfaces.py +++ /dev/null @@ -1,236 +0,0 @@ -# -*- 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) -""" -The eos_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class Interfaces(ConfigBase): - """ - The eos_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'interfaces', - ] - - def get_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - interfaces_facts = facts['ansible_network_resources'].get('interfaces') - if not interfaces_facts: - return [] - return interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - existing_interfaces_facts = self.get_interfaces_facts() - commands.extend(self.set_config(existing_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_interfaces_facts = self.get_interfaces_facts() - - result['before'] = existing_interfaces_facts - if result['changed']: - result['after'] = changed_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want) - have = param_list_to_dict(have) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, add_config, del_config)) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, extant in have.items(): - if key in want: - desired = want[key] - else: - desired = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, add_config, del_config)) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - - commands.extend(generate_commands(key, add_config, {})) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for key in want: - desired = dict() - if key in have: - extant = have[key] - else: - continue - - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, {}, del_config)) - - return commands - - -def generate_commands(interface, to_set, to_remove): - commands = [] - for key, value in to_set.items(): - if value is None: - continue - - if key == "enabled": - commands.append('{0}shutdown'.format('no ' if value else '')) - elif key == "speed": - if value == "auto": - commands.append("{0} {1}".format(key, value)) - else: - commands.append('speed {0}{1}'.format(value, to_set['duplex'])) - elif key == "duplex": - # duplex is handled with speed - continue - else: - commands.append("{0} {1}".format(key, value)) - - # Don't try to also remove the same key, if present in to_remove - to_remove.pop(key, None) - - for key in to_remove.keys(): - if key == "enabled": - commands.append('no shutdown') - elif key == "speed": - commands.append("speed auto") - elif key == "duplex": - # duplex is handled with speed - continue - else: - commands.append("no {0}".format(key)) - - if commands: - commands.insert(0, "interface {0}".format(interface)) - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/eos/config/l2_interfaces/l2_interfaces.py deleted file mode 100644 index 32e4c62306..0000000000 --- a/lib/ansible/module_utils/network/eos/config/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,250 +0,0 @@ -# -*- 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) -""" -The eos_l2_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class L2_interfaces(ConfigBase): - """ - The eos_l2_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'l2_interfaces', - ] - - def get_l2_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - l2_interfaces_facts = facts['ansible_network_resources'].get('l2_interfaces') - if not l2_interfaces_facts: - return [] - return l2_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - existing_l2_interfaces_facts = self.get_l2_interfaces_facts() - commands.extend(self.set_config(existing_l2_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_l2_interfaces_facts = self.get_l2_interfaces_facts() - - result['before'] = existing_l2_interfaces_facts - if result['changed']: - result['after'] = changed_l2_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_l2_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_l2_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want) - have = param_list_to_dict(have) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - intf_commands = set_interface(desired, extant) - intf_commands.extend(clear_interface(desired, extant)) - - if intf_commands: - commands.append("interface {0}".format(interface_name)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, extant in have.items(): - if key in want: - desired = want[key] - else: - desired = dict() - - intf_commands = set_interface(desired, extant) - intf_commands.extend(clear_interface(desired, extant)) - - if intf_commands: - commands.append("interface {0}".format(key)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - intf_commands = set_interface(desired, extant) - - if intf_commands: - commands.append("interface {0}".format(interface_name)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for key in want: - desired = dict() - if key in have: - extant = have[key] - else: - continue - - intf_commands = clear_interface(desired, extant) - - if intf_commands: - commands.append("interface {0}".format(key)) - commands.extend(intf_commands) - - return commands - - -def set_interface(want, have): - commands = [] - - want_mode = want.get("mode") - if want_mode and want_mode != have.get("mode"): - commands.append("switchport mode {0}".format(want_mode)) - - wants_access = want.get("access") - if wants_access: - access_vlan = wants_access.get("vlan") - if access_vlan and access_vlan != have.get("access", {}).get("vlan"): - commands.append("switchport access vlan {0}".format(access_vlan)) - - wants_trunk = want.get("trunk") - if wants_trunk: - has_trunk = have.get("trunk", {}) - native_vlan = wants_trunk.get("native_vlan") - if native_vlan and native_vlan != has_trunk.get("native_vlan"): - commands.append("switchport trunk native vlan {0}".format(native_vlan)) - - allowed_vlans = want['trunk'].get("trunk_allowed_vlans") - if allowed_vlans: - allowed_vlans = ','.join(allowed_vlans) - commands.append("switchport trunk allowed vlan {0}".format(allowed_vlans)) - return commands - - -def clear_interface(want, have): - commands = [] - - if 'mode' in have and want.get('mode') is None: - commands.append("no switchport mode") - - if "access" in have and not want.get('access'): - commands.append("no switchport access vlan") - - has_trunk = have.get("trunk") or {} - wants_trunk = want.get("trunk") or {} - if "trunk_allowed_vlans" in has_trunk and "trunk_allowed_vlans" not in wants_trunk: - commands.append("no switchport trunk allowed vlan") - if "native_vlan" in has_trunk and "native_vlan" not in wants_trunk: - commands.append("no switchport trunk native vlan") - return commands diff --git a/lib/ansible/module_utils/network/eos/config/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/eos/config/l3_interfaces/l3_interfaces.py deleted file mode 100644 index d32743fa86..0000000000 --- a/lib/ansible/module_utils/network/eos/config/l3_interfaces/l3_interfaces.py +++ /dev/null @@ -1,263 +0,0 @@ -# -*- 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) -""" -The eos_l3_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class L3_interfaces(ConfigBase): - """ - The eos_l3_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'l3_interfaces', - ] - - def get_l3_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - l3_interfaces_facts = facts['ansible_network_resources'].get('l3_interfaces') - if not l3_interfaces_facts: - return [] - return l3_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - existing_l3_interfaces_facts = self.get_l3_interfaces_facts() - commands.extend(self.set_config(existing_l3_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_l3_interfaces_facts = self.get_l3_interfaces_facts() - - result['before'] = existing_l3_interfaces_facts - if result['changed']: - result['after'] = changed_l3_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_l3_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_l3_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want) - have = param_list_to_dict(have) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - intf_commands = set_interface(desired, extant) - intf_commands.extend(clear_interface(desired, extant)) - - if intf_commands: - commands.append("interface {0}".format(interface_name)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, extant in have.items(): - if key in want: - desired = want[key] - else: - desired = dict() - if desired.get("ipv4"): - for ipv4 in desired["ipv4"]: - if ipv4["secondary"] is None: - del ipv4["secondary"] - - intf_commands = set_interface(desired, extant) - intf_commands.extend(clear_interface(desired, extant)) - - if intf_commands: - commands.append("interface {0}".format(key)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - intf_commands = set_interface(desired, extant) - if intf_commands: - commands.append("interface {0}".format(interface_name)) - commands.extend(intf_commands) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for key in want: - desired = dict() - if key in have: - extant = have[key] - else: - continue - - intf_commands = clear_interface(desired, extant) - - if intf_commands: - commands.append("interface {0}".format(key)) - commands.extend(intf_commands) - - return commands - - -def set_interface(want, have): - commands = [] - - want_ipv4 = set(tuple(address.items()) for address in want.get("ipv4") or []) - have_ipv4 = set(tuple(address.items()) for address in have.get("ipv4") or []) - for address in want_ipv4 - have_ipv4: - address = dict(address) - if "secondary" in address and not address["secondary"]: - del address["secondary"] - if tuple(address.items()) in have_ipv4: - continue - - address_cmd = "ip address {0}".format(address["address"]) - if address.get("secondary"): - address_cmd += " secondary" - commands.append(address_cmd) - - want_ipv6 = set(tuple(address.items()) for address in want.get("ipv6") or []) - have_ipv6 = set(tuple(address.items()) for address in have.get("ipv6") or []) - for address in want_ipv6 - have_ipv6: - address = dict(address) - commands.append("ipv6 address {0}".format(address["address"])) - return commands - - -def clear_interface(want, have): - commands = [] - - want_ipv4 = set(tuple(address.items()) for address in want.get("ipv4") or []) - have_ipv4 = set(tuple(address.items()) for address in have.get("ipv4") or []) - if not want_ipv4 and have_ipv4: - commands.append("no ip address") - else: - for address in have_ipv4 - want_ipv4: - address = dict(address) - if "secondary" not in address: - address["secondary"] = False - if tuple(address.items()) in want_ipv4: - continue - - if address.get("secondary"): - address_cmd = " {0} secondary".format(address["address"]) - commands.append(address_cmd) - - if "secondary" not in address: - # Removing non-secondary removes all other interfaces - break - - want_ipv6 = set(tuple(address.items()) for address in want.get("ipv6") or []) - have_ipv6 = set(tuple(address.items()) for address in have.get("ipv6") or []) - for address in have_ipv6 - want_ipv6: - address = dict(address) - commands.append("no ipv6 address {0}".format(address["address"])) - return commands diff --git a/lib/ansible/module_utils/network/eos/config/lacp/lacp.py b/lib/ansible/module_utils/network/eos/config/lacp/lacp.py deleted file mode 100644 index 38d368238a..0000000000 --- a/lib/ansible/module_utils/network/eos/config/lacp/lacp.py +++ /dev/null @@ -1,161 +0,0 @@ -# -*- 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) -""" -The eos_lacp class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, dict_diff -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Lacp(ConfigBase): - """ - The eos_lacp class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lacp', - ] - - def get_lacp_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - lacp_facts = facts['ansible_network_resources'].get('lacp') - if not lacp_facts: - return {} - return lacp_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - - existing_lacp_facts = self.get_lacp_facts() - commands.extend(self.set_config(existing_lacp_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_lacp_facts = self.get_lacp_facts() - - result['before'] = existing_lacp_facts - if result['changed']: - result['after'] = changed_lacp_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_lacp_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] or {} - have = existing_lacp_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - if state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - to_set = dict_diff(have, want) - if 'system' in to_set: - system = to_set['system'] - if 'priority' in system: - commands.append('lacp system-priority {0}'.format(system['priority'])) - - to_del = dict_diff(want, have) - if 'system' in to_del: - system = to_del['system'] - system_set = to_set.get('system', {}) - if 'priority' in system and 'priority' not in system_set: - commands.append('no lacp system-priority') - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - to_set = dict_diff(have, want) - if 'system' in to_set: - system = to_set['system'] - if 'priority' in system: - commands.append('lacp system-priority {0}'.format(system['priority'])) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - to_del = dict_diff(want, have) - if 'system' in to_del: - system = to_del['system'] - if 'priority' in system: - commands.append('no lacp system-priority') - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/eos/config/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index ffd2f36676..0000000000 --- a/lib/ansible/module_utils/network/eos/config/lacp_interfaces/lacp_interfaces.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- 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) -""" -The eos_lacp_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class Lacp_interfaces(ConfigBase): - """ - The eos_lacp_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lacp_interfaces', - ] - - def get_lacp_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - lacp_interfaces_facts = facts['ansible_network_resources'].get('lacp_interfaces') - if not lacp_interfaces_facts: - return [] - return lacp_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - - existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts() - commands.extend(self.set_config(existing_lacp_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts() - - result['before'] = existing_lacp_interfaces_facts - if result['changed']: - result['after'] = changed_lacp_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_lacp_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_lacp_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want) - have = param_list_to_dict(have) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, add_config, del_config)) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, extant in have.items(): - if key in want: - desired = want[key] - else: - desired = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, add_config, del_config)) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - - commands.extend(generate_commands(key, add_config, {})) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for key in want: - desired = dict() - if key in have: - extant = have[key] - else: - continue - - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, {}, del_config)) - - return commands - - -def generate_commands(interface, to_set, to_remove): - commands = [] - for key in to_remove.keys(): - commands.append("no lacp {0}".format(key.replace("_", "-"))) - - for key, value in to_set.items(): - if value is None: - continue - - commands.append("lacp {0} {1}".format(key.replace("_", "-"), value)) - - if commands: - commands.insert(0, "interface {0}".format(interface)) - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/eos/config/lag_interfaces/lag_interfaces.py deleted file mode 100644 index f9affa404a..0000000000 --- a/lib/ansible/module_utils/network/eos/config/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- 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) -""" -The eos_lag_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.utils import to_list, dict_diff - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class Lag_interfaces(ConfigBase): - """ - The eos_lag_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lag_interfaces', - ] - - def get_lag_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - lag_interfaces_facts = facts['ansible_network_resources'].get('lag_interfaces') - if not lag_interfaces_facts: - return [] - return lag_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - existing_lag_interfaces_facts = self.get_lag_interfaces_facts() - commands.extend(self.set_config(existing_lag_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_lag_interfaces_facts = self.get_lag_interfaces_facts() - - result['before'] = existing_lag_interfaces_facts - if result['changed']: - result['after'] = changed_lag_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_lag_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_lag_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for interface in want: - interface_name = normalize_interface(interface["name"]) - for extant in have: - if extant["name"] == interface_name: - break - else: - extant = dict(name=interface_name) - - commands.extend(set_config(interface, extant)) - commands.extend(remove_config(interface, extant)) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for extant in have: - for interface in want: - if normalize_interface(interface["name"]) == extant["name"]: - break - else: - interface = dict(name=extant["name"]) - commands.extend(remove_config(interface, extant)) - - for interface in want: - interface_name = normalize_interface(interface["name"]) - for extant in have: - if extant["name"] == interface_name: - break - else: - extant = dict(name=interface_name) - commands.extend(set_config(interface, extant)) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for interface in want: - interface_name = normalize_interface(interface["name"]) - for extant in have: - if extant["name"] == interface_name: - break - else: - extant = dict(name=interface_name) - - commands.extend(set_config(interface, extant)) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for interface in want: - interface_name = normalize_interface(interface["name"]) - for extant in have: - if extant["name"] == interface_name: - break - else: - extant = dict(name=interface_name) - - # Clearing all args, send empty dictionary - interface = dict(name=interface_name) - commands.extend(remove_config(interface, extant)) - - return commands - - -def set_config(want, have): - commands = [] - to_set = dict_diff(have, want) - for member in to_set.get("members", []): - channel_id = want["name"][12:] - commands.extend([ - "interface {0}".format(member["member"]), - "channel-group {0} mode {1}".format(channel_id, member["mode"]), - ]) - - return commands - - -def remove_config(want, have): - commands = [] - if not want.get("members"): - return ["no interface {0}".format(want["name"])] - - to_remove = dict_diff(want, have) - for member in to_remove.get("members", []): - commands.extend([ - "interface {0}".format(member["member"]), - "no channel-group", - ]) - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/eos/config/lldp_global/lldp_global.py deleted file mode 100644 index 94f00087c2..0000000000 --- a/lib/ansible/module_utils/network/eos/config/lldp_global/lldp_global.py +++ /dev/null @@ -1,166 +0,0 @@ -# -# -*- 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) -""" -The eos_lldp_global class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import dict_diff, to_list -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Lldp_global(ConfigBase): - """ - The eos_lldp_global class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lldp_global', - ] - - def __init__(self, module): - super(Lldp_global, self).__init__(module) - - def get_lldp_global_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - lldp_global_facts = facts['ansible_network_resources'].get('lldp_global') - if not lldp_global_facts: - return {} - return lldp_global_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - - existing_lldp_global_facts = self.get_lldp_global_facts() - commands.extend(self.set_config(existing_lldp_global_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_lldp_global_facts = self.get_lldp_global_facts() - - result['before'] = existing_lldp_global_facts - if result['changed']: - result['after'] = changed_lldp_global_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_lldp_global_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] or {} - have = existing_lldp_global_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - if state == 'deleted': - commands = state_deleted(want, have) - elif state == 'merged': - commands = state_merged(want, have) - elif state == 'replaced': - commands = state_replaced(want, have) - return commands - - -def state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = set() - # merged and deleted are likely to emit duplicate tlv-select commands - commands.update(state_merged(want, have)) - commands.update(state_deleted(want, have)) - - return list(commands) - - -def state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - to_set = dict_diff(have, want) - tlv_options = to_set.pop("tlv_select", {}) - for key, value in to_set.items(): - commands.append("lldp {0} {1}".format(key, value)) - for key, value in tlv_options.items(): - device_option = key.replace("_", "-") - if value is True: - commands.append("lldp tlv-select {0}".format(device_option)) - elif value is False: - commands.append("no lldp tlv-select {0}".format(device_option)) - - return commands - - -def state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - to_remove = dict_diff(want, have) - tlv_options = to_remove.pop("tlv_select", {}) - for key in to_remove: - commands.append("no lldp {0}".format(key)) - for key, value in tlv_options.items(): - device_option = key.replace("_", "-") - if value is False: - commands.append("lldp tlv-select {0}".format(device_option)) - elif value is True: - commands.append("no lldp tlv-select {0}".format(device_option)) - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/eos/config/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index 93dcd8db9d..0000000000 --- a/lib/ansible/module_utils/network/eos/config/lldp_interfaces/lldp_interfaces.py +++ /dev/null @@ -1,216 +0,0 @@ -# -*- 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) -""" -The eos_lldp_interfaces class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.utils.utils import normalize_interface - - -class Lldp_interfaces(ConfigBase): - """ - The eos_lldp_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lldp_interfaces', - ] - - def get_lldp_interfaces_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - lldp_interfaces_facts = facts['ansible_network_resources'].get('lldp_interfaces') - if not lldp_interfaces_facts: - return [] - return lldp_interfaces_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - - existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts() - commands.extend(self.set_config(existing_lldp_interfaces_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts() - - result['before'] = existing_lldp_interfaces_facts - if result['changed']: - result['after'] = changed_lldp_interfaces_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_lldp_interfaces_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_lldp_interfaces_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want, remove_key=False) - have = param_list_to_dict(have, remove_key=False) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict(name=interface_name) - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(interface_name, add_config, del_config)) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for key, extant in have.items(): - if key in want: - desired = want[key] - else: - desired = dict(name=key) - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(key, add_config, del_config)) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for key, desired in want.items(): - interface_name = normalize_interface(key) - if interface_name in have: - extant = have[interface_name] - else: - extant = dict(name=interface_name) - - add_config = dict_diff(extant, desired) - - commands.extend(generate_commands(interface_name, add_config, {})) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for key in want.keys(): - interface_name = normalize_interface(key) - desired = dict(name=interface_name) - if interface_name in have: - extant = have[interface_name] - else: - continue - - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(interface_name, {}, del_config)) - - return commands - - -def generate_commands(name, to_set, to_remove): - commands = [] - for key, value in to_set.items(): - if value is None: - continue - - prefix = "" if value else "no " - commands.append("{0}lldp {1}".format(prefix, key)) - - for key in to_remove: - commands.append("lldp {0}".format(key)) - - if commands: - commands.insert(0, "interface {0}".format(name)) - - return commands diff --git a/lib/ansible/module_utils/network/eos/config/static_routes/static_routes.py b/lib/ansible/module_utils/network/eos/config/static_routes/static_routes.py deleted file mode 100644 index ae3e4609c1..0000000000 --- a/lib/ansible/module_utils/network/eos/config/static_routes/static_routes.py +++ /dev/null @@ -1,390 +0,0 @@ -# -# -*- 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) -""" -The eos_static_routes class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import remove_empties -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Static_routes(ConfigBase): - """ - The eos_static_routes class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'static_routes', - ] - - def __init__(self, module): - super(Static_routes, self).__init__(module) - - def get_static_routes_facts(self, data=None): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data) - static_routes_facts = facts['ansible_network_resources'].get('static_routes') - if not static_routes_facts: - return [] - return static_routes_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - if self.state in self.ACTION_STATES: - existing_static_routes_facts = self.get_static_routes_facts() - else: - existing_static_routes_facts = [] - - if self.state in self.ACTION_STATES or self.state == 'rendered': - commands.extend(self.set_config(existing_static_routes_facts)) - - if commands and self.state in self.ACTION_STATES: - if not self._module.check_mode: - for command in commands: - self._connection.edit_config(command) - result['changed'] = True - if self.state in self.ACTION_STATES: - result['commands'] = commands - if self.state in self.ACTION_STATES or self.state == 'gathered': - changed_static_routes_facts = self.get_static_routes_facts() - elif self.state == 'rendered': - result['rendered'] = commands - elif self.state == 'parsed': - if not self._module.params['running_config']: - self._module.fail_json(msg="Value of running_config parameter must not be empty for state parsed") - result['parsed'] = self.get_static_routes_facts(data=self._module.params['running_config']) - else: - changed_static_routes_facts = [] - - if self.state in self.ACTION_STATES: - result['before'] = existing_static_routes_facts - if result['changed']: - result['after'] = changed_static_routes_facts - elif self.state == 'gathered': - result['gathered'] = changed_static_routes_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_static_routes_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - onbox_configs = [] - for h in existing_static_routes_facts: - return_command = add_commands(h) - for command in return_command: - onbox_configs.append(command) - config = self._module.params.get('config') - want = [] - if config: - for w in config: - want.append(remove_empties(w)) - have = existing_static_routes_facts - resp = self.set_state(want, have) - for want_config in resp: - if want_config not in onbox_configs: - commands.append(want_config) - return commands - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - if self.state in ('merged', 'replaced', 'overridden') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(self.state)) - state = self._module.params['state'] - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or self.state == 'rendered': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - haveconfigs = [] - vrf = get_vrf(want) - dest = get_dest(want) - for h in have: - return_command = add_commands(h) - for command in return_command: - for d in dest: - if d in command: - if vrf is None: - if "vrf" not in command: - haveconfigs.append(command) - else: - if vrf in command: - haveconfigs.append(command) - wantconfigs = set_commands(want, have) - - removeconfigs = list(set(haveconfigs) - set(wantconfigs)) - for command in removeconfigs: - commands.append("no " + command) - for wantcmd in wantconfigs: - commands.append(wantcmd) - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - haveconfigs = [] - for h in have: - return_command = add_commands(h) - for command in return_command: - haveconfigs.append(command) - wantconfigs = set_commands(want, have) - idempotentconfigs = list(set(haveconfigs) - set(wantconfigs)) - if not idempotentconfigs: - return idempotentconfigs - removeconfigs = list(set(haveconfigs) - set(wantconfigs)) - for command in removeconfigs: - commands.append("no " + command) - for wantcmd in wantconfigs: - commands.append(wantcmd) - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - return set_commands(want, have) - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - if not want: - for h in have: - return_command = add_commands(h) - for command in return_command: - command = "no " + command - commands.append(command) - else: - for w in want: - return_command = del_commands(w, have) - for command in return_command: - commands.append(command) - return commands - - -def set_commands(want, have): - commands = [] - for w in want: - return_command = add_commands(w) - for command in return_command: - commands.append(command) - return commands - - -def add_commands(want): - commandset = [] - if not want: - return commandset - vrf = want["vrf"] if "vrf" in want.keys() and want["vrf"] is not None else None - for address_family in want["address_families"]: - for route in address_family["routes"]: - for next_hop in route["next_hops"]: - commands = [] - if address_family["afi"] == "ipv4": - commands.append('ip route') - else: - commands.append('ipv6 route') - if vrf: - commands.append(' vrf ' + vrf) - if not re.search(r'/', route["dest"]): - mask = route["dest"].split()[1] - cidr = get_net_size(mask) - commands.append(' ' + route["dest"].split()[0] + '/' + cidr) - else: - commands.append(' ' + route["dest"]) - if "interface" in next_hop.keys(): - commands.append(' ' + next_hop["interface"]) - if "nexthop_grp" in next_hop.keys(): - commands.append(' Nexthop-Group' + ' ' + next_hop["nexthop_grp"]) - if "forward_router_address" in next_hop.keys(): - commands.append(' ' + next_hop["forward_router_address"]) - if "mpls_label" in next_hop.keys(): - commands.append(' label ' + str(next_hop["mpls_label"])) - if "track" in next_hop.keys(): - commands.append(' track ' + next_hop["track"]) - if "admin_distance" in next_hop.keys(): - commands.append(' ' + str(next_hop["admin_distance"])) - if "description" in next_hop.keys(): - commands.append(' name ' + str(next_hop["description"])) - if "tag" in next_hop.keys(): - commands.append(' tag ' + str(next_hop["tag"])) - - config_commands = "".join(commands) - commandset.append(config_commands) - return commandset - - -def del_commands(want, have): - commandset = [] - haveconfigs = [] - for h in have: - return_command = add_commands(h) - for command in return_command: - command = "no " + command - haveconfigs.append(command) - if want is None or "address_families" not in want.keys(): - commandset = haveconfigs - if "address_families" not in want.keys() and "vrf" in want.keys(): - commandset = [] - for command in haveconfigs: - if want["vrf"] in command: - commandset.append(command) - elif want is not None and "vrf" not in want.keys() and "address_families" not in want.keys(): - commandset = [] - for command in haveconfigs: - if "vrf" not in command: - commandset.append(command) - - elif want["address_families"]: - vrf = want["vrf"] if "vrf" in want.keys() and want["vrf"] else None - for address_family in want["address_families"]: - if "routes" not in address_family.keys(): - for command in haveconfigs: - afi = "ip " if address_family["afi"] == "ipv4" else "ipv6" - if afi in command: - if vrf: - if vrf in command: - commandset.append(command) - else: - commandset.append(command) - else: - for route in address_family["routes"]: - if not re.search(r'/', route["dest"]): - mask = route["dest"].split()[1] - cidr = get_net_size(mask) - destination = route["dest"].split()[0] + '/' + cidr - else: - destination = route["dest"] - if "next_hops" not in route.keys(): - for command in haveconfigs: - if destination in command: - if vrf: - if vrf in command: - commandset.append(command) - else: - commandset.append(command) - else: - for next_hop in route["next_hops"]: - commands = [] - if address_family["afi"] == "ipv4": - commands.append('no ip route') - else: - commands.append('no ipv6 route') - if vrf: - commands.append(' vrf ' + vrf) - commands.append(' ' + destination) - if "interface" in next_hop.keys(): - commands.append(' ' + next_hop["interface"]) - if "nexhop_grp" in next_hop.keys(): - commands.append(' Nexthop-Group' + ' ' + next_hop["nexthop_grp"]) - if "forward_router_address" in next_hop.keys(): - commands.append(' ' + next_hop["forward_router_address"]) - if "mpls_label" in next_hop.keys(): - commands.append(' label ' + str(next_hop["mpls_label"])) - if "track" in next_hop.keys(): - commands.append(' track ' + next_hop["track"]) - if "admin_distance" in next_hop.keys(): - commands.append(' ' + str(next_hop["admin_distance"])) - if "description" in next_hop.keys(): - commands.append(' name ' + str(next_hop["description"])) - if "tag" in next_hop.keys(): - commands.append(' tag ' + str(next_hop["tag"])) - - config_commands = "".join(commands) - commandset.append(config_commands) - return commandset - - -def get_net_size(netmask): - binary_str = '' - netmask = netmask.split('.') - for octet in netmask: - binary_str += bin(int(octet))[2:].zfill(8) - return str(len(binary_str.rstrip('0'))) - - -def get_vrf(config): - vrf = "" - for c in config: - vrf = c["vrf"] if "vrf" in c.keys() and c["vrf"] else None - return vrf - - -def get_dest(config): - dest = [] - for c in config: - for address_family in c["address_families"]: - for route in address_family["routes"]: - dest.append(route['dest']) - return dest diff --git a/lib/ansible/module_utils/network/eos/config/vlans/vlans.py b/lib/ansible/module_utils/network/eos/config/vlans/vlans.py deleted file mode 100644 index c2a701637d..0000000000 --- a/lib/ansible/module_utils/network/eos/config/vlans/vlans.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- 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) -""" -The eos_vlans class -It is in this file where the current configuration (as dict) -is compared to the provided configuration (as dict) and the command set -necessary to bring the current configuration to it's desired end-state is -created -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.cfg.base import ConfigBase -from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict -from ansible.module_utils.network.eos.facts.facts import Facts - - -class Vlans(ConfigBase): - """ - The eos_vlans class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'vlans', - ] - - def get_vlans_facts(self): - """ Get the 'facts' (the current configuration) - - :rtype: A dictionary - :returns: The current configuration as a dictionary - """ - facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources) - vlans_facts = facts['ansible_network_resources'].get('vlans') - if not vlans_facts: - return [] - return vlans_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from module execution - """ - result = {'changed': False} - warnings = list() - commands = list() - - existing_vlans_facts = self.get_vlans_facts() - commands.extend(self.set_config(existing_vlans_facts)) - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - changed_vlans_facts = self.get_vlans_facts() - - result['before'] = existing_vlans_facts - if result['changed']: - result['after'] = changed_vlans_facts - - result['warnings'] = warnings - return result - - def set_config(self, existing_vlans_facts): - """ Collect the configuration from the args passed to the module, - collect the current configuration (as a dict from facts) - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - want = self._module.params['config'] - have = existing_vlans_facts - resp = self.set_state(want, have) - return to_list(resp) - - def set_state(self, want, have): - """ Select the appropriate function based on the state provided - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - state = self._module.params['state'] - want = param_list_to_dict(want, "vlan_id", remove_key=False) - have = param_list_to_dict(have, "vlan_id", remove_key=False) - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have) - elif state == 'replaced': - commands = self._state_replaced(want, have) - return commands - - @staticmethod - def _state_replaced(want, have): - """ The command generator when state is replaced - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for vlan_id, desired in want.items(): - if vlan_id in have: - extant = have[vlan_id] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(vlan_id, add_config, del_config)) - - return commands - - @staticmethod - def _state_overridden(want, have): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - for vlan_id, extant in have.items(): - if vlan_id in want: - desired = want[vlan_id] - else: - desired = dict() - - add_config = dict_diff(extant, desired) - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(vlan_id, add_config, del_config)) - - # Handle vlans not already in config - new_vlans = [vlan_id for vlan_id in want if vlan_id not in have] - for vlan_id in new_vlans: - desired = want[vlan_id] - extant = dict(vlan_id=vlan_id) - add_config = dict_diff(extant, desired) - - commands.extend(generate_commands(vlan_id, add_config, {})) - - return commands - - @staticmethod - def _state_merged(want, have): - """ The command generator when state is merged - - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - for vlan_id, desired in want.items(): - if vlan_id in have: - extant = have[vlan_id] - else: - extant = dict() - - add_config = dict_diff(extant, desired) - - commands.extend(generate_commands(vlan_id, add_config, {})) - - return commands - - @staticmethod - def _state_deleted(want, have): - """ The command generator when state is deleted - - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - for vlan_id in want: - desired = dict() - if vlan_id in have: - extant = have[vlan_id] - else: - continue - - del_config = dict_diff(desired, extant) - - commands.extend(generate_commands(vlan_id, {}, del_config)) - - return commands - - -def generate_commands(vlan_id, to_set, to_remove): - commands = [] - if "vlan_id" in to_remove: - return ["no vlan {0}".format(vlan_id)] - - for key in to_remove: - if key in to_set.keys(): - continue - commands.append("no {0}".format(key)) - - for key, value in to_set.items(): - if key == "vlan_id" or value is None: - continue - - commands.append("{0} {1}".format(key, value)) - - if commands: - commands.insert(0, "vlan {0}".format(vlan_id)) - return commands diff --git a/lib/ansible/module_utils/network/eos/eos.py b/lib/ansible/module_utils/network/eos/eos.py deleted file mode 100644 index 22c675153e..0000000000 --- a/lib/ansible/module_utils/network/eos/eos.py +++ /dev/null @@ -1,630 +0,0 @@ -# -# This code is part of Ansible, but is an independent component. -# -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# (c) 2017 Red Hat, Inc. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -import json -import os -import time - -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import env_fallback -from ansible.module_utils.connection import Connection, ConnectionError -from ansible.module_utils.network.common.config import NetworkConfig, dumps -from ansible.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.urls import fetch_url - -_DEVICE_CONNECTION = None - -eos_provider_spec = { - 'host': dict(), - 'port': dict(type='int'), - 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), - 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - 'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'), - - 'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'), - 'auth_pass': dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])), - - 'use_ssl': dict(default=True, type='bool'), - 'use_proxy': dict(default=True, type='bool'), - 'validate_certs': dict(default=True, type='bool'), - 'timeout': dict(type='int'), - - 'transport': dict(default='cli', choices=['cli', 'eapi']) -} -eos_argument_spec = { - 'provider': dict(type='dict', options=eos_provider_spec, removed_in_version=2.14), -} - - -def get_provider_argspec(): - return eos_provider_spec - - -def get_connection(module): - global _DEVICE_CONNECTION - if not _DEVICE_CONNECTION: - if is_local_eapi(module): - conn = LocalEapi(module) - else: - connection_proxy = Connection(module._socket_path) - cap = json.loads(connection_proxy.get_capabilities()) - if cap['network_api'] == 'cliconf': - conn = Cli(module) - elif cap['network_api'] == 'eapi': - conn = HttpApi(module) - _DEVICE_CONNECTION = conn - return _DEVICE_CONNECTION - - -class Cli: - - def __init__(self, module): - self._module = module - self._device_configs = {} - self._session_support = None - self._connection = None - - @property - def supports_sessions(self): - if self._session_support is None: - self._session_support = self._get_connection().supports_sessions() - return self._session_support - - def _get_connection(self): - if self._connection: - return self._connection - self._connection = Connection(self._module._socket_path) - - return self._connection - - def get_config(self, flags=None): - """Retrieves the current config from the device or cache - """ - flags = [] if flags is None else flags - - cmd = 'show running-config ' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return self._device_configs[cmd] - except KeyError: - conn = self._get_connection() - try: - out = conn.get_config(flags=flags) - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - cfg = to_text(out, errors='surrogate_then_replace').strip() - self._device_configs[cmd] = cfg - return cfg - - def run_commands(self, commands, check_rc=True): - """Run list of commands on remote device and return results - """ - connection = self._get_connection() - try: - response = connection.run_commands(commands=commands, check_rc=check_rc) - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - return response - - def load_config(self, commands, commit=False, replace=False): - """Loads the config commands onto the remote device - """ - conn = self._get_connection() - try: - response = conn.edit_config(commands, commit, replace) - except ConnectionError as exc: - message = getattr(exc, 'err', to_text(exc)) - if "check mode is not supported without configuration session" in message: - self._module.warn("EOS can not check config without config session") - response = {'changed': True} - else: - self._module.fail_json(msg="%s" % message, data=to_text(message, errors='surrogate_then_replace')) - - return response - - def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'): - conn = self._get_connection() - try: - diff = conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path, - diff_replace=diff_replace) - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - return diff - - def get_capabilities(self): - """Returns platform info of the remove device - """ - if hasattr(self._module, '_capabilities'): - return self._module._capabilities - - connection = self._get_connection() - try: - capabilities = connection.get_capabilities() - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - self._module._capabilities = json.loads(capabilities) - return self._module._capabilities - - -class LocalEapi: - - def __init__(self, module): - self._module = module - self._enable = None - self._session_support = None - self._device_configs = {} - - provider = module.params.get("provider") or {} - host = provider.get('host') - port = provider.get('port') - - self._module.params['url_username'] = provider.get('username') - self._module.params['url_password'] = provider.get('password') - - if provider.get('use_ssl'): - proto = 'https' - else: - proto = 'http' - - module.params['validate_certs'] = provider.get('validate_certs') - - self._url = '%s://%s:%s/command-api' % (proto, host, port) - - if provider.get("auth_pass"): - self._enable = {'cmd': 'enable', 'input': provider.get('auth_pass')} - else: - self._enable = 'enable' - - @property - def supports_sessions(self): - if self._session_support is None: - response = self.send_request(['show configuration sessions']) - self._session_support = 'error' not in response - return self._session_support - - def _request_builder(self, commands, output, reqid=None): - params = dict(version=1, cmds=commands, format=output) - return dict(jsonrpc='2.0', id=reqid, method='runCmds', params=params) - - def send_request(self, commands, output='text'): - commands = to_list(commands) - - if self._enable: - commands.insert(0, self._enable) - - body = self._request_builder(commands, output) - data = self._module.jsonify(body) - - headers = {'Content-Type': 'application/json-rpc'} - timeout = self._module.params['provider']['timeout'] - use_proxy = self._module.params['provider']['use_proxy'] - - response, headers = fetch_url( - self._module, self._url, data=data, headers=headers, - method='POST', timeout=timeout, use_proxy=use_proxy - ) - - if headers['status'] != 200: - self._module.fail_json(**headers) - - try: - data = response.read() - response = self._module.from_json(to_text(data, errors='surrogate_then_replace')) - except ValueError: - self._module.fail_json(msg='unable to load response from device', data=data) - - if self._enable and 'result' in response: - response['result'].pop(0) - - return response - - def run_commands(self, commands, check_rc=True): - """Runs list of commands on remote device and returns results - """ - output = None - queue = list() - responses = list() - - def _send(commands, output): - response = self.send_request(commands, output=output) - if 'error' in response: - err = response['error'] - self._module.fail_json(msg=err['message'], code=err['code']) - return response['result'] - - for item in to_list(commands): - if is_json(item['command']): - item['command'] = str(item['command']).replace('| json', '') - item['output'] = 'json' - - if output and output != item['output']: - responses.extend(_send(queue, output)) - queue = list() - - output = item['output'] or 'json' - queue.append(item['command']) - - if queue: - responses.extend(_send(queue, output)) - - for index, item in enumerate(commands): - try: - responses[index] = responses[index]['output'].strip() - except KeyError: - pass - - return responses - - def get_config(self, flags=None): - """Retrieves the current config from the device or cache - """ - flags = [] if flags is None else flags - - cmd = 'show running-config ' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return self._device_configs[cmd] - except KeyError: - out = self.send_request(cmd) - cfg = str(out['result'][0]['output']).strip() - self._device_configs[cmd] = cfg - return cfg - - def configure(self, commands): - """Sends the ordered set of commands to the device - """ - cmds = ['configure terminal'] - cmds.extend(commands) - - responses = self.send_request(commands) - if 'error' in responses: - err = responses['error'] - self._module.fail_json(msg=err['message'], code=err['code']) - - return responses[1:] - - def load_config(self, config, commit=False, replace=False): - """Loads the configuration onto the remote devices - - If the device doesn't support configuration sessions, this will - fallback to using configure() to load the commands. If that happens, - there will be no returned diff or session values - """ - use_session = os.getenv('ANSIBLE_EOS_USE_SESSIONS', True) - try: - use_session = int(use_session) - except ValueError: - pass - - if not all((bool(use_session), self.supports_sessions)): - if commit: - return self.configure(config) - else: - self._module.warn("EOS can not check config without config session") - result = {'changed': True} - return result - - session = 'ansible_%s' % int(time.time()) - result = {'session': session} - commands = ['configure session %s' % session] - - if replace: - commands.append('rollback clean-config') - - commands.extend(config) - - response = self.send_request(commands) - if 'error' in response: - commands = ['configure session %s' % session, 'abort'] - self.send_request(commands) - err = response['error'] - error_text = [] - for data in err['data']: - error_text.extend(data.get('errors', [])) - error_text = '\n'.join(error_text) or err['message'] - self._module.fail_json(msg=error_text, code=err['code']) - - commands = ['configure session %s' % session, 'show session-config diffs'] - if commit: - commands.append('commit') - else: - commands.append('abort') - - response = self.send_request(commands, output='text') - diff = response['result'][1]['output'] - if len(diff) > 0: - result['diff'] = diff - - return result - - # get_diff added here to support connection=local and transport=eapi scenario - def get_diff(self, candidate, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'): - diff = {} - - # prepare candidate configuration - candidate_obj = NetworkConfig(indent=3) - candidate_obj.load(candidate) - - if running and diff_match != 'none' and diff_replace != 'config': - # running configuration - running_obj = NetworkConfig(indent=3, contents=running, ignore_lines=diff_ignore_lines) - configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace) - - else: - configdiffobjs = candidate_obj.items - - configdiff = dumps(configdiffobjs, 'commands') if configdiffobjs else '' - diff['config_diff'] = configdiff if configdiffobjs else {} - return diff - - def get_capabilities(self): - # Implement the bare minimum to support eos_facts - return dict( - device_info=dict( - network_os="eos", - ), - network_api="eapi", - ) - - -class HttpApi: - def __init__(self, module): - self._module = module - self._device_configs = {} - self._session_support = None - self._connection_obj = None - - @property - def _connection(self): - if not self._connection_obj: - self._connection_obj = Connection(self._module._socket_path) - - return self._connection_obj - - @property - def supports_sessions(self): - if self._session_support is None: - self._session_support = self._connection.supports_sessions() - return self._session_support - - def run_commands(self, commands, check_rc=True): - """Runs list of commands on remote device and returns results - """ - output = None - queue = list() - responses = list() - - def run_queue(queue, output): - try: - response = to_list(self._connection.send_request(queue, output=output)) - except ConnectionError as exc: - if check_rc: - raise - return to_list(to_text(exc)) - - if output == 'json': - response = [json.loads(item) for item in response] - return response - - for item in to_list(commands): - cmd_output = 'text' - if isinstance(item, dict): - command = item['command'] - if 'output' in item: - cmd_output = item['output'] - else: - command = item - - # Emulate '| json' from CLI - if is_json(command): - command = command.rsplit('|', 1)[0] - cmd_output = 'json' - - if output and output != cmd_output: - responses.extend(run_queue(queue, output)) - queue = list() - - output = cmd_output - queue.append(command) - - if queue: - responses.extend(run_queue(queue, output)) - - return responses - - def get_config(self, flags=None): - """Retrieves the current config from the device or cache - """ - flags = [] if flags is None else flags - - cmd = 'show running-config ' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return self._device_configs[cmd] - except KeyError: - try: - out = self._connection.send_request(cmd) - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - cfg = to_text(out).strip() - self._device_configs[cmd] = cfg - return cfg - - def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'): - diff = {} - - # prepare candidate configuration - candidate_obj = NetworkConfig(indent=3) - candidate_obj.load(candidate) - - if running and diff_match != 'none' and diff_replace != 'config': - # running configuration - running_obj = NetworkConfig(indent=3, contents=running, ignore_lines=diff_ignore_lines) - configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace) - - else: - configdiffobjs = candidate_obj.items - - diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else {} - return diff - - def load_config(self, config, commit=False, replace=False): - """Loads the configuration onto the remote devices - - If the device doesn't support configuration sessions, this will - fallback to using configure() to load the commands. If that happens, - there will be no returned diff or session values - """ - return self.edit_config(config, commit, replace) - - def edit_config(self, config, commit=False, replace=False): - """Loads the configuration onto the remote devices - - If the device doesn't support configuration sessions, this will - fallback to using configure() to load the commands. If that happens, - there will be no returned diff or session values - """ - session = 'ansible_%s' % int(time.time()) - result = {'session': session} - banner_cmd = None - banner_input = [] - - commands = ['configure session %s' % session] - if replace: - commands.append('rollback clean-config') - - for command in config: - if command.startswith('banner'): - banner_cmd = command - banner_input = [] - elif banner_cmd: - if command == 'EOF': - command = {'cmd': banner_cmd, 'input': '\n'.join(banner_input)} - banner_cmd = None - commands.append(command) - else: - banner_input.append(command) - continue - else: - commands.append(command) - - try: - response = self._connection.send_request(commands) - except Exception: - commands = ['configure session %s' % session, 'abort'] - response = self._connection.send_request(commands, output='text') - raise - - commands = ['configure session %s' % session, 'show session-config diffs'] - if commit: - commands.append('commit') - else: - commands.append('abort') - - response = self._connection.send_request(commands, output='text') - diff = response[1].strip() - if diff: - result['diff'] = diff - - return result - - def get_capabilities(self): - """Returns platform info of the remove device - """ - try: - capabilities = self._connection.get_capabilities() - except ConnectionError as exc: - self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - return json.loads(capabilities) - - -def is_json(cmd): - return to_text(cmd, errors='surrogate_then_replace').endswith('| json') - - -def is_local_eapi(module): - provider = module.params.get('provider') - if provider: - return provider.get('transport') == 'eapi' - return False - - -def to_command(module, commands): - if is_local_eapi(module): - default_output = 'json' - else: - default_output = 'text' - - transform = ComplexList(dict( - command=dict(key=True), - output=dict(default=default_output), - prompt=dict(type='list'), - answer=dict(type='list'), - newline=dict(type='bool', default=True), - sendonly=dict(type='bool', default=False), - check_all=dict(type='bool', default=False), - ), module) - - return transform(to_list(commands)) - - -def get_config(module, flags=None): - flags = None if flags is None else flags - - conn = get_connection(module) - return conn.get_config(flags) - - -def run_commands(module, commands, check_rc=True): - conn = get_connection(module) - return conn.run_commands(to_command(module, commands), check_rc=check_rc) - - -def load_config(module, config, commit=False, replace=False): - conn = get_connection(module) - return conn.load_config(config, commit, replace) - - -def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'): - conn = self.get_connection() - return conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path, diff_replace=diff_replace) - - -def get_capabilities(module): - conn = get_connection(module) - return conn.get_capabilities() diff --git a/lib/ansible/module_utils/network/eos/facts/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/eos/facts/acl_interfaces/acl_interfaces.py deleted file mode 100644 index 89c3336a62..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,133 +0,0 @@ -# -# -*- 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) -""" -The eos acl_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.acl_interfaces.acl_interfaces import Acl_interfacesArgs - - -class Acl_interfacesFacts(object): - """ The eos acl_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Acl_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | include interface | access-group | traffic-filter') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for acl_interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - - if not data: - data = self.get_device_data(connection) - # split the config into instances of the resource - resource_delim = 'interface' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, - data, - re.DOTALL)] - objs = [] - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - - ansible_facts['ansible_network_resources'].pop('acl_interfaces', None) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['acl_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - access_group_list = [] - access_group_v6_list = [] - acls_list = [] - group_list = [] - group_dict = {} - config['name'] = utils.parse_conf_arg(conf, 'interface') - conf_lines = conf.split('\n') - for line in conf_lines: - if config['name'] in line: - continue - access_group = utils.parse_conf_arg(line, 'ip access-group') - # This module was verified on an ios device since vEOS doesnot support - # acl_interfaces cnfiguration. In ios, ipv6 acl is configured as - # traffic-filter and in eos it is access-group - - # access_group_v6 = utils.parse_conf_arg(line, 'ipv6 traffic-filter') - access_group_v6 = utils.parse_conf_arg(line, 'ipv6 access-group') - if access_group: - access_group_list.append(access_group) - if access_group_v6: - access_group_v6_list.append(access_group_v6) - if access_group_list: - for acl in access_group_list: - a_name = acl.split()[0] - a_dir = acl.split()[1] - acls_dict = {"name": a_name, "direction": a_dir} - acls_list.append(acls_dict) - group_dict = {"afi": "ipv4", "acls": acls_list} - group_list.append(group_dict) - acls_list = [] - if group_list: - config['access_groups'] = group_list - if access_group_v6_list: - for acl in access_group_v6_list: - a_name = acl.split()[0] - a_dir = acl.split()[1] - acls_dict = {"name": a_name, "direction": a_dir} - acls_list.append(acls_dict) - group_dict = {"acls": acls_list, "afi": "ipv6"} - group_list.append(group_dict) - acls_list = [] - if group_list: - config['access_groups'] = group_list - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/acls/acls.py b/lib/ansible/module_utils/network/eos/facts/acls/acls.py deleted file mode 100644 index edd7752c13..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/acls/acls.py +++ /dev/null @@ -1,300 +0,0 @@ -# -# -*- 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) -""" -The eos acls fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.acls.acls import AclsArgs - - -class AclsFacts(object): - """ The eos acls fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = AclsArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | section access-list') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for acls - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # split the config into instances of the resource - find_pattern = r'(?:^|\n)(?:ip|ipv6) access\-list.*?(?=(?:^|\n)(?:ip|ipv6) access\-list|$)' - resources = [p for p in re.findall(find_pattern, - data, - re.DOTALL)] - - objs = [] - ipv4list = [] - ipv6list = [] - for resource in resources: - if "ipv6" in resource: - ipv6list.append(resource) - else: - ipv4list.append(resource) - ipv4list = ["\n".join(ipv4list)] - ipv6list = ["\n".join(ipv6list)] - for resource in ipv4list: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - for resource in ipv6list: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - - ansible_facts['ansible_network_resources'].pop('acls', None) - facts = {} - if objs: - facts['acls'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['acls'].append(utils.remove_empties(cfg)) - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - afi_list = [] - acls_list = [] - name_dict = {} - standard = 0 - operator = ['eq', 'lt', 'neq', 'range', 'gt'] - flags = ['ack', 'established', 'fin', 'psh', 'rst', 'syn', 'urg'] - others = ['hop_limit', 'log', 'ttl', 'fragments', 'tracked'] - for dev_config in conf.split('\n'): - ace_dict = {} - if not dev_config: - continue - if dev_config == '!': - continue - dev_config = dev_config.strip() - matches = re.findall(r'(ip.*?) access-list (.*)', dev_config) - if matches: - afi = "ipv4" if matches[0][0] == "ip" else "ipv6" - ace_list = [] - if bool(name_dict): - acls_list.append(name_dict.copy()) - name_dict = {} - if afi not in afi_list: - afi_list.append(afi) - config.update({"afi": afi}) - if "standard" in matches[0][1]: - standard = 1 - name = matches[0][1].split() - name_dict.update({"name": name[1]}) - name_dict.update({"standard": True}) - else: - name_dict.update({"name": matches[0][1]}) - else: - source_dict = {} - dest_dict = {} - dev_config = re.sub('-', '_', dev_config) - dev_config_remainder = dev_config.split() - if "fragment_rules" in dev_config: - ace_dict.update({"sequence": dev_config_remainder.pop(0)}) - ace_dict.update({"fragment_rules": True}) - if "remark" in dev_config: - ace_dict.update({"sequence": dev_config_remainder.pop(0)}) - ace_dict.update({"remark": ' '.join(dev_config_remainder[1:])}) - seq = re.search(r'\d+ (permit|deny) .*', dev_config) - if seq: - ace_dict.update({"sequence": dev_config_remainder.pop(0)}) - ace_dict.update({"grant": dev_config_remainder.pop(0)}) - if dev_config_remainder[0] == "vlan": - vlan_str = "" - dev_config_remainder.pop(0) - if dev_config_remainder[0] == "inner": - vlan_str = dev_config_remainder.pop(0) + " " - vlan_str = dev_config_remainder.pop(0) + " " + dev_config_remainder.pop(0) - ace_dict.update({"vlan": vlan_str}) - if not standard: - protocol = dev_config_remainder[0] - ace_dict.update({"protocol": dev_config_remainder.pop(0)}) - src_prefix = re.search(r'/', dev_config_remainder[0]) - src_address = re.search(r'[a-z\d:\.]+', dev_config_remainder[0]) - if dev_config_remainder[0] == "host": - source_dict.update({"host": dev_config_remainder.pop(1)}) - dev_config_remainder.pop(0) - elif dev_config_remainder[0] == "any": - source_dict.update({"any": True}) - dev_config_remainder.pop(0) - elif src_prefix: - source_dict.update({"subnet_address": dev_config_remainder.pop(0)}) - elif src_address: - source_dict.update({"address": dev_config_remainder.pop(0)}) - source_dict.update({"wildcard_bits": dev_config_remainder.pop(0)}) - if dev_config_remainder: - if dev_config_remainder[0] in operator: - port_dict = {} - src_port = "" - src_opr = dev_config_remainder.pop(0) - portlist = dev_config_remainder[:] - for config_remainder in portlist: - addr = re.search(r'[\.\:]', config_remainder) - if config_remainder == "any" or config_remainder == "host" or addr: - break - else: - src_port = src_port + " " + config_remainder - dev_config_remainder.pop(0) - src_port = src_port.strip() - port_dict.update({src_opr: src_port}) - source_dict.update({"port_protocol": port_dict}) - ace_dict.update({"source": source_dict}) - if not dev_config_remainder or standard: - if dev_config_remainder and "log" in dev_config_remainder: - ace_dict.update({"log": True}) - if bool(ace_dict): - ace_list.append(ace_dict.copy()) - if len(ace_list): - name_dict = name_dict.copy() - name_dict.update({"aces": ace_list[:]}) - # acls_list.append(name_dict) - continue - dest_prefix = re.search(r'/', dev_config_remainder[0]) - dest_address = re.search(r'[a-z\d:\.]+', dev_config_remainder[0]) - if dev_config_remainder[0] == "host": - dest_dict.update({"host": dev_config_remainder.pop(1)}) - dev_config_remainder.pop(0) - elif dev_config_remainder[0] == "any": - dest_dict.update({"any": True}) - dev_config_remainder.pop(0) - elif dest_prefix: - dest_dict.update({"subnet_address": dev_config_remainder.pop(0)}) - elif dest_address: - dest_dict.update({"address": dev_config_remainder.pop(0)}) - dest_dict.update({"wildcard_bits": dev_config_remainder.pop(0)}) - if dev_config_remainder: - if dev_config_remainder[0] in operator: - port_dict = {} - dest_port = "" - dest_opr = dev_config_remainder.pop(0) - portlist = dev_config_remainder[:] - for config_remainder in portlist: - if config_remainder in operator or config_remainder in others: - break - else: - dest_port = dest_port + " " + config_remainder - dev_config_remainder.pop(0) - dest_port = dest_port.strip() - port_dict.update({dest_opr: dest_port}) - dest_dict.update({"port_protocol": port_dict}) - ace_dict.update({"destination": dest_dict}) - protocol_option_dict = {} - tcp_dict = {} - icmp_dict = {} - ip_dict = {} - if not dev_config_remainder: - if bool(ace_dict): - ace_list.append(ace_dict.copy()) - if len(ace_list): - name_dict = name_dict.copy() - name_dict.update({"aces": ace_list[:]}) - # acls_list.append(name_dict) - continue - if protocol == "tcp" or "6": - protocol = "tcp" - flags_dict = {} - if dev_config_remainder[0] in flags: - flaglist = dev_config_remainder.copy() - for config_remainder in flaglist: - if config_remainder not in flags: - break - else: - flags_dict.update({config_remainder: True}) - dev_config_remainder.pop(0) - if bool(flags_dict): - tcp_dict.update({"flags": flags_dict}) - if bool(tcp_dict): - protocol_option_dict.update({"tcp": tcp_dict}) - if protocol == "icmp" or protocol == "icmpv6" \ - or protocol == "1" or protocol == "58": - if protocol == "1": - protocol = "icmp" - elif protocol == "58": - protocol = "icmpv6" - if dev_config_remainder[0] not in others: - icmp_dict.update({dev_config_remainder[0]: True}) - dev_config_remainder.pop(0) - if bool(icmp_dict): - protocol_option_dict.update({protocol: icmp_dict}) - if protocol == "ip" or "ipv6": - if dev_config_remainder[0] == "nexthop_group": - dev_config_remainder.pop(0) - ip_dict.update({"nexthop_group": dev_config_remainder.pop(0)}) - if bool(ip_dict): - protocol_option_dict.update({protocol: ip_dict}) - if bool(protocol_option_dict): - ace_dict.update({"protocol_options": protocol_option_dict}) - if dev_config_remainder[0] == "ttl": - dev_config_remainder.pop(0) - op = dev_config_remainder.pop(0) - ttl_dict = {op: dev_config_remainder.pop(0)} - ace_dict.update({"ttl": ttl_dict}) - for config_remainder in dev_config_remainder: - if config_remainder in others: - if config_remainder == "hop_limit": - hop_index = dev_config_remainder.index(config_remainder) - hoplimit_dict = {dev_config_remainder[hop_index + 1]: dev_config_remainder[hop_index + 2]} - ace_dict.update({"hop_limit": hoplimit_dict}) - dev_config_remainder.pop(0) - continue - ace_dict.update({config_remainder: True}) - dev_config_remainder.pop(0) - if dev_config_remainder: - config.update({"line": dev_config}) - return utils.remove_empties(config) - if bool(ace_dict): - ace_list.append(ace_dict.copy()) - if len(ace_list): - name_dict = name_dict.copy() - name_dict.update({"aces": ace_list[:]}) - acls_list.append(name_dict.copy()) - config.update({"acls": acls_list}) - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/facts.py b/lib/ansible/module_utils/network/eos/facts/facts.py deleted file mode 100644 index 4ff7d87150..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/facts.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- 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) -""" -The facts class for eos -this file validates each subset of facts and selectively -calls the appropriate facts gathering function -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible.module_utils.network.common.facts.facts import FactsBase -from ansible.module_utils.network.eos.facts.interfaces.interfaces import InterfacesFacts -from ansible.module_utils.network.eos.facts.l2_interfaces.l2_interfaces import L2_interfacesFacts -from ansible.module_utils.network.eos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts -from ansible.module_utils.network.eos.facts.lacp.lacp import LacpFacts -from ansible.module_utils.network.eos.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts -from ansible.module_utils.network.eos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts -from ansible.module_utils.network.eos.facts.lldp_global.lldp_global import Lldp_globalFacts -from ansible.module_utils.network.eos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts -from ansible.module_utils.network.eos.facts.vlans.vlans import VlansFacts -from ansible.module_utils.network.eos.facts.legacy.base import Default, Hardware, Config, Interfaces -from ansible.module_utils.network.eos.facts.acl_interfaces.acl_interfaces import Acl_interfacesFacts -from ansible.module_utils.network.eos.facts.acls.acls import AclsFacts -from ansible.module_utils.network.eos.facts.static_routes.static_routes import Static_routesFacts - - -FACT_LEGACY_SUBSETS = dict( - default=Default, - hardware=Hardware, - interfaces=Interfaces, - config=Config, -) -FACT_RESOURCE_SUBSETS = dict( - interfaces=InterfacesFacts, - l2_interfaces=L2_interfacesFacts, - l3_interfaces=L3_interfacesFacts, - lacp=LacpFacts, - lacp_interfaces=Lacp_interfacesFacts, - lag_interfaces=Lag_interfacesFacts, - lldp_global=Lldp_globalFacts, - lldp_interfaces=Lldp_interfacesFacts, - vlans=VlansFacts, - acl_interfaces=Acl_interfacesFacts, - acls=AclsFacts, - static_routes=Static_routesFacts, -) - - -class Facts(FactsBase): - """ The fact class for eos - """ - - VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys()) - VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys()) - - def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None): - """ Collect the facts for eos - :param legacy_facts_type: List of legacy facts types - :param resource_facts_type: List of resource fact types - :param data: previously collected conf - :rtype: dict - :return: the facts gathered - """ - if self.VALID_RESOURCE_SUBSETS: - self.get_network_resources_facts(FACT_RESOURCE_SUBSETS, resource_facts_type, data) - - if self.VALID_LEGACY_GATHER_SUBSETS: - self.get_network_legacy_facts(FACT_LEGACY_SUBSETS, legacy_facts_type) - - return self.ansible_facts, self._warnings diff --git a/lib/ansible/module_utils/network/eos/facts/interfaces/interfaces.py b/lib/ansible/module_utils/network/eos/facts/interfaces/interfaces.py deleted file mode 100644 index c3c515e6f5..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/interfaces/interfaces.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- 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) -""" -The eos interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from copy import deepcopy -import re - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.interfaces.interfaces import InterfacesArgs - - -class InterfacesFacts(object): - """ The eos interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = InterfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | section ^interface') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for interfaces - - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # operate on a collection of resource x - config = data.split('interface ') - objs = [] - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {'interfaces': []} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['interfaces'].append(utils.remove_empties(cfg)) - ansible_facts['ansible_network_resources'].update(facts) - - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - - # populate the facts from the configuration - config['name'] = re.match(r'(\S+)', conf).group(1) - description = utils.parse_conf_arg(conf, 'description') - if description is not None: - config['description'] = description.replace('"', '') - shutdown = utils.parse_conf_cmd_arg(conf, 'shutdown', False) - config['enabled'] = shutdown if shutdown is False else True - config['mtu'] = utils.parse_conf_arg(conf, 'mtu') - - speed_pair = utils.parse_conf_arg(conf, 'speed') - if speed_pair: - state = speed_pair.split() - if state[0] == 'forced': - state = state[1] - else: - state = state[0] - - if state == 'auto': - config['duplex'] = state - else: - # remaining options are all e.g., 10half or 40gfull - config['speed'] = state[:-4] - config['duplex'] = state[-4:] - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/eos/facts/l2_interfaces/l2_interfaces.py deleted file mode 100644 index 86e8109864..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- 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) -""" -The eos l2_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from copy import deepcopy -import re - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs - - -class L2_interfacesFacts(object): - """ The eos l2_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = L2_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | section ^interface') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for l2_interfaces - - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # operate on a collection of resource x - config = data.split('interface ') - objs = [] - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['l2_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - ansible_facts['ansible_network_resources'].update(facts) - - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - - # populate the facts from the configuration - config['name'] = re.match(r'(\S+)', conf).group(1).replace('"', '') - has_mode = re.search(r"switchport mode (\S+)", conf) - if has_mode: - config["mode"] = has_mode.group(1) - - has_access = re.search(r"switchport access vlan (\d+)", conf) - if has_access: - config["access"] = {"vlan": int(has_access.group(1))} - - has_trunk = re.findall(r"switchport trunk (.+)", conf) - if has_trunk: - trunk = {} - for match in has_trunk: - has_native = re.match(r"native vlan (\d+)", match) - if has_native: - trunk["native_vlan"] = int(has_native.group(1)) - continue - - has_allowed = re.match(r"allowed vlan (\S+)", match) - if has_allowed: - # TODO: listify? - trunk["trunk_allowed_vlans"] = has_allowed.group(1) - continue - config['trunk'] = trunk - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/eos/facts/l3_interfaces/l3_interfaces.py deleted file mode 100644 index 67041729df..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/l3_interfaces/l3_interfaces.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- 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) -""" -The eos l3_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from copy import deepcopy -import re - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.l3_interfaces.l3_interfaces import L3_interfacesArgs - - -class L3_interfacesFacts(object): - """ The eos l3_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = L3_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for l3_interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = connection.get('show running-config | section ^interface') - - # split the config into instances of the resource - resource_delim = 'interface' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, data, re.DOTALL)] - - objs = [] - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['l3_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - - config['name'] = utils.parse_conf_arg(conf, 'interface') - - matches = re.findall(r'.*ip address (.+)$', conf, re.MULTILINE) - if matches: - config["ipv4"] = [] - for match in matches: - address, dummy, remainder = match.partition(" ") - ipv4 = {"address": address} - if remainder == "secondary": - ipv4["secondary"] = True - config['ipv4'].append(ipv4) - - matches = re.findall(r'.*ipv6 address (.+)$', conf, re.MULTILINE) - if matches: - config["ipv6"] = [] - for match in matches: - address, dummy, remainder = match.partition(" ") - ipv6 = {"address": address} - config['ipv6'].append(ipv6) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/lacp/lacp.py b/lib/ansible/module_utils/network/eos/facts/lacp/lacp.py deleted file mode 100644 index 370cb9df67..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/lacp/lacp.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- 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) -""" -The eos lacp fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.lacp.lacp import LacpArgs - - -class LacpFacts(object): - """ The eos lacp fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = LacpArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | section ^lacp') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for lacp - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # split the config into instances of the resource - resource_delim = 'lacp' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, data, re.DOTALL)] - - objs = {} - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.update(obj) - - ansible_facts['ansible_network_resources'].pop('lacp', None) - facts = {'lacp': {}} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['lacp'] = utils.remove_empties(params['config']) - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - config['system']['priority'] = utils.parse_conf_arg(conf, 'system-priority') - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/eos/facts/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index 6f0560fe3b..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/lacp_interfaces/lacp_interfaces.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- 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) -""" -The eos lacp_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs - - -class Lacp_interfacesFacts(object): - """ The eos lacp_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Lacp_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | section lacp') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for lacp_interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # split the config into instances of the resource - resource_delim = 'interface' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, data, re.DOTALL)] - - objs = [] - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - - ansible_facts['ansible_network_resources'].pop('lacp_interfaces', None) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['lacp_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - config['name'] = utils.parse_conf_arg(conf, 'interface') - config['port_priority'] = utils.parse_conf_arg(conf, 'port-priority') - config['rate'] = utils.parse_conf_arg(conf, 'rate') - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/eos/facts/lag_interfaces/lag_interfaces.py deleted file mode 100644 index d93152a01b..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- 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) -""" -The eos lag_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from copy import deepcopy -import re - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs - - -class Lag_interfacesFacts(object): - """ The eos lag_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Lag_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for lag_interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = connection.get('show running-config | section ^interface') - - # split the config into instances of the resource - resource_delim = 'interface' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, - data, - re.DOTALL)] - - objs = {} - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - group_name = obj['name'] - if group_name in objs and "members" in obj: - config = objs[group_name] - if "members" not in config: - config["members"] = [] - objs[group_name]['members'].extend(obj['members']) - else: - objs[group_name] = obj - objs = list(objs.values()) - facts = {'lag_interfaces': []} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['lag_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - interface_name = utils.parse_conf_arg(conf, 'interface') - if interface_name.startswith("Port-Channel"): - config["name"] = interface_name - return utils.remove_empties(config) - - interface = {'member': interface_name} - match = re.match(r'.*channel-group (\d+) mode (\S+)', conf, re.MULTILINE | re.DOTALL) - if match: - config['name'], interface['mode'] = match.groups() - config["name"] = "Port-Channel" + config["name"] - config['members'] = [interface] - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/legacy/base.py b/lib/ansible/module_utils/network/eos/facts/legacy/base.py deleted file mode 100644 index 50bb82e849..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/legacy/base.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- 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 - -import platform -import re - -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.eos.eos import run_commands, get_capabilities - - -class FactsBase(object): - - COMMANDS = frozenset() - - def __init__(self, module): - self.module = module - self.warnings = list() - self.facts = dict() - self.responses = None - - def populate(self): - self.responses = run_commands(self.module, list(self.COMMANDS), check_rc=False) - - -class Default(FactsBase): - - SYSTEM_MAP = { - 'serialNumber': 'serialnum', - } - - COMMANDS = [ - 'show version | json', - 'show hostname | json', - ] - - def populate(self): - super(Default, self).populate() - data = self.responses[0] - for key, value in iteritems(self.SYSTEM_MAP): - if key in data: - self.facts[value] = data[key] - - self.facts.update(self.responses[1]) - self.facts.update(self.platform_facts()) - - def platform_facts(self): - platform_facts = {} - - resp = get_capabilities(self.module) - device_info = resp['device_info'] - - platform_facts['system'] = device_info['network_os'] - - for item in ('model', 'image', 'version', 'platform', 'hostname'): - val = device_info.get('network_os_%s' % item) - if val: - platform_facts[item] = val - - platform_facts['api'] = resp['network_api'] - platform_facts['python_version'] = platform.python_version() - - return platform_facts - - -class Hardware(FactsBase): - - COMMANDS = [ - 'dir all-filesystems', - 'show version | json' - ] - - def populate(self): - super(Hardware, self).populate() - self.facts.update(self.populate_filesystems()) - self.facts.update(self.populate_memory()) - - def populate_filesystems(self): - data = self.responses[0] - - if isinstance(data, dict): - data = data['messages'][0] - - fs = re.findall(r'^Directory of (.+)/', data, re.M) - return dict(filesystems=fs) - - def populate_memory(self): - values = self.responses[1] - return dict( - memfree_mb=int(values['memFree']) / 1024, - memtotal_mb=int(values['memTotal']) / 1024 - ) - - -class Config(FactsBase): - - COMMANDS = ['show running-config'] - - def populate(self): - super(Config, self).populate() - self.facts['config'] = self.responses[0] - - -class Interfaces(FactsBase): - - INTERFACE_MAP = { - 'description': 'description', - 'physicalAddress': 'macaddress', - 'mtu': 'mtu', - 'bandwidth': 'bandwidth', - 'duplex': 'duplex', - 'lineProtocolStatus': 'lineprotocol', - 'interfaceStatus': 'operstatus', - 'forwardingModel': 'type' - } - - COMMANDS = [ - 'show interfaces | json', - 'show lldp neighbors | json' - ] - - def populate(self): - super(Interfaces, self).populate() - - self.facts['all_ipv4_addresses'] = list() - self.facts['all_ipv6_addresses'] = list() - - data = self.responses[0] - self.facts['interfaces'] = self.populate_interfaces(data) - - data = self.responses[1] - if data: - self.facts['neighbors'] = self.populate_neighbors(data['lldpNeighbors']) - - def populate_interfaces(self, data): - facts = dict() - for key, value in iteritems(data['interfaces']): - intf = dict() - - for remote, local in iteritems(self.INTERFACE_MAP): - if remote in value: - intf[local] = value[remote] - - if 'interfaceAddress' in value: - intf['ipv4'] = dict() - for entry in value['interfaceAddress']: - intf['ipv4']['address'] = entry['primaryIp']['address'] - intf['ipv4']['masklen'] = entry['primaryIp']['maskLen'] - self.add_ip_address(entry['primaryIp']['address'], 'ipv4') - - if 'interfaceAddressIp6' in value: - intf['ipv6'] = dict() - for entry in value['interfaceAddressIp6']['globalUnicastIp6s']: - intf['ipv6']['address'] = entry['address'] - intf['ipv6']['subnet'] = entry['subnet'] - self.add_ip_address(entry['address'], 'ipv6') - - facts[key] = intf - - return facts - - def add_ip_address(self, address, family): - if family == 'ipv4': - self.facts['all_ipv4_addresses'].append(address) - else: - self.facts['all_ipv6_addresses'].append(address) - - def populate_neighbors(self, neighbors): - facts = dict() - for value in neighbors: - port = value['port'] - if port not in facts: - facts[port] = list() - lldp = dict() - lldp['host'] = value['neighborDevice'] - lldp['port'] = value['neighborPort'] - facts[port].append(lldp) - return facts diff --git a/lib/ansible/module_utils/network/eos/facts/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/eos/facts/lldp_global/lldp_global.py deleted file mode 100644 index b74469d700..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/lldp_global/lldp_global.py +++ /dev/null @@ -1,86 +0,0 @@ -# -# -*- 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) -""" -The eos lldp_global fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.lldp_global.lldp_global import Lldp_globalArgs - - -class Lldp_globalFacts(object): - """ The eos lldp_global fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Lldp_globalArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for lldp_global - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - if not data: - data = connection.get('show running-config | section lldp') - - obj = {} - if data: - obj.update(self.render_config(self.generated_spec, data)) - - ansible_facts['ansible_network_resources'].pop('lldp_global', None) - facts = {} - if obj: - params = utils.validate_config(self.argument_spec, {'config': obj}) - facts['lldp_global'] = utils.remove_empties(params['config']) - else: - facts['lldp_global'] = {} - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - config['holdtime'] = utils.parse_conf_arg(conf, 'holdtime') - config['reinit'] = utils.parse_conf_arg(conf, 'reinit') - config['timer'] = utils.parse_conf_arg(conf, 'timer') - - for match in re.findall(r'^(no)? lldp tlv-select (\S+)', conf, re.MULTILINE): - tlv_option = match[1].replace("-", "_") - config['tlv_select'][tlv_option] = bool(match[0] != "no") - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/eos/facts/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index 8fa02697f6..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/lldp_interfaces/lldp_interfaces.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- 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) -""" -The eos lldp_interfaces fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs - - -class Lldp_interfacesFacts(object): - """ The eos lldp_interfaces fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Lldp_interfacesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for lldp_interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected configuration - :rtype: dictionary - :returns: facts - """ - if not data: - data = connection.get('show running-config | section lldp') - - # split the config into instances of the resource - resource_delim = 'interface' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, - data, - re.DOTALL)] - - objs = [] - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - - ansible_facts['ansible_network_resources'].pop('lldp_interfaces', None) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['lldp_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - config['name'] = utils.parse_conf_arg(conf, 'interface') - - matches = re.findall(r'(no )?lldp (\S+)', conf) - for match in matches: - config[match[1]] = not bool(match[0]) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/static_routes/static_routes.py b/lib/ansible/module_utils/network/eos/facts/static_routes/static_routes.py deleted file mode 100644 index 810b2bfa0e..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/static_routes/static_routes.py +++ /dev/null @@ -1,202 +0,0 @@ -# -# -*- 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) -""" -The eos static_routes fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.static_routes.static_routes import Static_routesArgs - - -class Static_routesFacts(object): - """ The eos static_routes fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = Static_routesArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def get_device_data(self, connection): - return connection.get('show running-config | grep route') - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for static_routes - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - if not data: - data = self.get_device_data(connection) - - # split the config into instances of the resource - resource_delim = 'ip.* route' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, data)] - resources_without_vrf = [] - resource_vrf = {} - for resource in resources: - if resource and "vrf" not in resource: - resources_without_vrf.append(resource) - else: - vrf = re.search(r'ip(v6)* route vrf (.*?) .*', resource) - if vrf.group(2) in resource_vrf.keys(): - vrf_val = resource_vrf[vrf.group(2)] - vrf_val.append(resource) - resource_vrf.update({vrf.group(2): vrf_val}) - else: - resource_vrf.update({vrf.group(2): [resource]}) - resources_without_vrf = ["\n".join(resources_without_vrf)] - for vrf in resource_vrf.keys(): - vrflist = ["\n".join(resource_vrf[vrf])] - resource_vrf.update({vrf: vrflist}) - objs = [] - for resource in resources_without_vrf: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.append(obj) - for resource in resource_vrf.keys(): - if resource: - obj = self.render_config(self.generated_spec, resource_vrf[resource][0]) - if obj: - objs.append(obj) - ansible_facts['ansible_network_resources'].pop('static_routes', None) - facts = {} - if objs: - facts['static_routes'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['static_routes'].append(utils.remove_empties(cfg)) - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - address_family_dict = {} - route_dict = {} - dest_list = [] - afi_list = [] - vrf_list = [] - routes = [] - config["address_families"] = [] - next_hops = {} - interface_list = ["Ethernet", "Loopback", "Management", - "Port-Channel", "Tunnel", "Vlan", "Vxlan", "vtep"] - conf_list = conf.split('\n') - for conf_elem in conf_list: - matches = re.findall(r'(ip|ipv6) route ([\d\.\/:]+|vrf) (.+)$', conf_elem) - if matches: - remainder = matches[0][2].split() - route_update = False - if matches[0][1] == "vrf": - vrf = remainder.pop(0) - # new vrf - if vrf not in vrf_list and vrf_list: - route_dict.update({"next_hops": next_hops}) - routes.append(route_dict) - address_family_dict.update({"routes": routes}) - config["address_families"].append(address_family_dict) - route_update = True - config.update({"vrf": vrf}) - vrf_list.append(vrf) - dest = remainder.pop(0) - else: - config["vrf"] = None - dest = matches[0][1] - afi = "ipv4" if matches[0][0] == "ip" else "ipv6" - if afi not in afi_list: - if afi_list and not route_update: - # new afi and not the first updating all prev configs - route_dict.update({"next_hops": next_hops}) - routes.append(route_dict) - address_family_dict.update({"routes": routes}) - config["address_families"].append(address_family_dict) - route_update = True - address_family_dict = {} - address_family_dict.update({"afi": afi}) - routes = [] - afi_list.append(afi) - # To check the format of the dest - prefix = re.search(r'/', dest) - if not prefix: - dest = dest + ' ' + remainder.pop(0) - if dest not in dest_list: - # For new dest and not the first dest - if dest_list and not route_update: - route_dict.update({"next_hops": next_hops}) - routes.append(route_dict) - dest_list.append(dest) - next_hops = [] - route_dict = {} - route_dict.update({"dest": dest}) - nexthops = {} - nxthop_addr = re.search(r'[\.\:]', remainder[0]) - if nxthop_addr: - nexthops.update({"interface": remainder.pop(0)}) - if remainder and remainder[0] == "label": - nexthops.update({"mpls_label": remainder.pop(1)}) - remainder.pop(0) - elif re.search(r'Nexthop-Group', remainder[0]): - nexthops.update({"nexthop_grp": remainder.pop(1)}) - remainder.pop(0) - else: - interface = remainder.pop(0) - if interface in interface_list: - interface = interface + " " + remainder.pop(0) - nexthops.update({"interface": interface}) - for attribute in remainder: - forward_addr = re.search(r'([\dA-Fa-f]+[:\.]+)+[\dA-Fa-f]+', attribute) - if forward_addr: - nexthops.update({"forward_router_address": remainder.pop(remainder.index(attribute))}) - for attribute in remainder: - for params in ["tag", "name", "track"]: - if attribute == params: - keyname = params - if attribute == "name": - keyname = "description" - nexthops.update({keyname: remainder.pop(remainder.index(attribute) + 1)}) - remainder.pop(remainder.index(attribute)) - if remainder: - metric = re.search(r'\d+', remainder[0]) - if metric: - nexthops.update({"admin_distance": remainder.pop(0)}) - next_hops.append(nexthops) - route_dict.update({"next_hops": next_hops}) - routes.append(route_dict) - address_family_dict.update({"routes": routes}) - config["address_families"].append(address_family_dict) - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/eos/facts/vlans/vlans.py b/lib/ansible/module_utils/network/eos/facts/vlans/vlans.py deleted file mode 100644 index 0e01b6c216..0000000000 --- a/lib/ansible/module_utils/network/eos/facts/vlans/vlans.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- 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) -""" -The eos vlans fact class -It is in this file the configuration is collected from the device -for a given resource, parsed, and the facts tree is populated -based on the configuration. -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from copy import deepcopy -import re - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.eos.argspec.vlans.vlans import VlansArgs - - -class VlansFacts(object): - """ The eos vlans fact class - """ - - def __init__(self, module, subspec='config', options='options'): - self._module = module - self.argument_spec = VlansArgs.argument_spec - spec = deepcopy(self.argument_spec) - if subspec: - if options: - facts_argument_spec = spec[subspec][options] - else: - facts_argument_spec = spec[subspec] - else: - facts_argument_spec = spec - - self.generated_spec = utils.generate_dict(facts_argument_spec) - - def populate_facts(self, connection, ansible_facts, data=None): - """ Populate the facts for vlans - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - if not data: - data = connection.get('show running-config | section ^vlan') - - # split the config into instances of the resource - resource_delim = 'vlan' - find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, - resource_delim) - resources = [p.strip() for p in re.findall(find_pattern, - data, - re.DOTALL)] - - objs = [] - for resource in resources: - if resource: - obj = self.render_config(self.generated_spec, resource) - if obj: - objs.extend(obj) - - ansible_facts['ansible_network_resources'].pop('vlans', None) - facts = {} - if objs: - params = utils.validate_config(self.argument_spec, {'config': objs}) - facts['vlans'] = [utils.remove_empties(cfg) for cfg in params['config']] - - ansible_facts['ansible_network_resources'].update(facts) - return ansible_facts - - def render_config(self, spec, conf): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - vlans = [] - - vlan_list = vlan_to_list(utils.parse_conf_arg(conf, 'vlan')) - for vlan in vlan_list: - config['vlan_id'] = vlan - config['name'] = utils.parse_conf_arg(conf, 'name') - config['state'] = utils.parse_conf_arg(conf, 'state') - - vlans.append(utils.remove_empties(config)) - - return vlans - - -def vlan_to_list(vlan_str): - vlans = [] - for vlan in vlan_str.split(','): - if '-' in vlan: - start, stop = vlan.split('-') - vlans.extend(range(int(start), int(stop) + 1)) - else: - vlans.append(int(vlan)) - - return vlans diff --git a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/address_family.py b/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/address_family.py deleted file mode 100644 index 0e50f6d518..0000000000 --- a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/address_family.py +++ /dev/null @@ -1,129 +0,0 @@ -# -# (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) -# -import re - -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.eos.providers.providers import CliProvider -from ansible.module_utils.network.eos.providers.cli.config.bgp.neighbors import AFNeighbors - - -class AddressFamily(CliProvider): - - def render(self, config=None): - commands = list() - safe_list = list() - - router_context = 'router bgp %s' % self.get_value('config.bgp_as') - context_config = None - - for item in self.get_value('config.address_family'): - context = 'address-family %s' % item['afi'] - context_commands = list() - - if config: - context_path = [router_context, context] - context_config = self.get_config_context(config, context_path, indent=2) - - for key, value in iteritems(item): - if value is not None: - meth = getattr(self, '_render_%s' % key, None) - if meth: - resp = meth(item, context_config) - if resp: - context_commands.extend(to_list(resp)) - - if context_commands: - commands.append(context) - commands.extend(context_commands) - commands.append('exit') - - safe_list.append(context) - - if self.params['operation'] == 'replace': - if config: - resp = self._negate_config(config, safe_list) - commands.extend(resp) - - return commands - - def _negate_config(self, config, safe_list=None): - commands = list() - matches = re.findall(r'(address-family .+)$', config, re.M) - for item in set(matches).difference(safe_list): - commands.append('no %s' % item) - return commands - - def _render_auto_summary(self, item, config=None): - cmd = 'auto-summary' - if item['auto_summary'] is False: - cmd = 'no %s' % cmd - if not config or cmd not in config: - return cmd - - def _render_synchronization(self, item, config=None): - cmd = 'synchronization' - if item['synchronization'] is False: - cmd = 'no %s' % cmd - if not config or cmd not in config: - return cmd - - def _render_networks(self, item, config=None): - commands = list() - safe_list = list() - - for entry in item['networks']: - network = entry['prefix'] - if entry['masklen']: - network = '%s/%s' % (entry['prefix'], entry['masklen']) - safe_list.append(network) - - cmd = 'network %s' % network - - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - - if not config or cmd not in config: - commands.append(cmd) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'network (\S+)', config, re.M) - for entry in set(matches).difference(safe_list): - commands.append('no network %s' % entry) - - return commands - - def _render_redistribute(self, item, config=None): - commands = list() - safe_list = list() - - for entry in item['redistribute']: - option = entry['protocol'] - - cmd = 'redistribute %s' % entry['protocol'] - - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - - if not config or cmd not in config: - commands.append(cmd) - - safe_list.append(option) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'redistribute (\S+)(?:\s*)(\d*)', config, re.M) - for i in range(0, len(matches)): - matches[i] = ' '.join(matches[i]).strip() - for entry in set(matches).difference(safe_list): - commands.append('no redistribute %s' % entry) - - return commands - - def _render_neighbors(self, item, config): - """ generate bgp neighbor configuration - """ - return AFNeighbors(self.params).render(config, nbr_list=item['neighbors']) diff --git a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/neighbors.py b/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/neighbors.py deleted file mode 100644 index 329916b69f..0000000000 --- a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/neighbors.py +++ /dev/null @@ -1,173 +0,0 @@ -# -# (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) -# -import re - -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.eos.providers.providers import CliProvider - - -class Neighbors(CliProvider): - - def render(self, config=None, nbr_list=None): - commands = list() - safe_list = list() - if not nbr_list: - nbr_list = self.get_value('config.neighbors') - - for item in nbr_list: - neighbor_commands = list() - context = 'neighbor %s' % item['neighbor'] - cmd = '%s remote-as %s' % (context, item['remote_as']) - - if not config or cmd not in config: - neighbor_commands.append(cmd) - - for key, value in iteritems(item): - if value is not None: - meth = getattr(self, '_render_%s' % key, None) - if meth: - resp = meth(item, config) - if resp: - neighbor_commands.extend(to_list(resp)) - - commands.extend(neighbor_commands) - safe_list.append(context) - - if self.params['operation'] == 'replace': - if config and safe_list: - commands.extend(self._negate_config(config, safe_list)) - - return commands - - def _negate_config(self, config, safe_list=None): - commands = list() - matches = re.findall(r'(neighbor \S+)', config, re.M) - for item in set(matches).difference(safe_list): - commands.append('no %s' % item) - return commands - - def _render_description(self, item, config=None): - cmd = 'neighbor %s description %s' % (item['neighbor'], item['description']) - if not config or cmd not in config: - return cmd - - def _render_enabled(self, item, config=None): - cmd = 'neighbor %s shutdown' % item['neighbor'] - if item['enabled'] is True: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_update_source(self, item, config=None): - cmd = 'neighbor %s update-source %s' % (item['neighbor'], item['update_source']) - if not config or cmd not in config: - return cmd - - def _render_password(self, item, config=None): - cmd = 'neighbor %s password %s' % (item['neighbor'], item['password']) - if not config or cmd not in config: - return cmd - - def _render_ebgp_multihop(self, item, config=None): - cmd = 'neighbor %s ebgp-multihop %s' % (item['neighbor'], item['ebgp_multihop']) - if not config or cmd not in config: - return cmd - - def _render_peer_group(self, item, config=None): - cmd = 'neighbor %s peer-group %s' % (item['neighbor'], item['peer_group']) - if not config or cmd not in config: - return cmd - - def _render_route_reflector_client(self, item, config=None): - cmd = 'neighbor %s route-reflector-client' % item['neighbor'] - if item['route_reflector_client'] is False: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_maximum_prefix(self, item, config=None): - cmd = 'neighbor %s maximum-routes %s' % (item['neighbor'], item['maximum_prefix']) - if not config or cmd not in config: - return cmd - - def _render_remove_private_as(self, item, config=None): - cmd = 'neighbor %s remove-private-AS' % item['neighbor'] - if item['remove_private_as'] is False: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_timers(self, item, config): - """generate bgp timer related configuration - """ - keepalive = item['timers']['keepalive'] - holdtime = item['timers']['holdtime'] - neighbor = item['neighbor'] - - if keepalive and holdtime: - cmd = 'neighbor %s timers %s %s' % (neighbor, keepalive, holdtime) - if not config or cmd not in config: - return cmd - - -class AFNeighbors(CliProvider): - - def render(self, config=None, nbr_list=None): - commands = list() - if not nbr_list: - return - - for item in nbr_list: - neighbor_commands = list() - for key, value in iteritems(item): - if value is not None: - meth = getattr(self, '_render_%s' % key, None) - if meth: - resp = meth(item, config) - if resp: - neighbor_commands.extend(to_list(resp)) - - commands.extend(neighbor_commands) - - return commands - - def _render_activate(self, item, config=None): - cmd = 'neighbor %s activate' % item['neighbor'] - if item['activate'] is False: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_default_originate(self, item, config=None): - cmd = 'neighbor %s default-originate' % item['neighbor'] - if item['activate'] is False: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_graceful_restart(self, item, config=None): - cmd = 'neighbor %s graceful-restart' % item['neighbor'] - if item['activate'] is False: - if not config or cmd in config: - cmd = 'no %s' % cmd - return cmd - elif not config or cmd not in config: - return cmd - - def _render_weight(self, item, config=None): - cmd = 'neighbor %s weight %s' % (item['neighbor'], item['weight']) - if not config or cmd not in config: - return cmd diff --git a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/process.py b/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/process.py deleted file mode 100644 index a2f40affae..0000000000 --- a/lib/ansible/module_utils/network/eos/providers/cli/config/bgp/process.py +++ /dev/null @@ -1,163 +0,0 @@ -# -# (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) -# -import re - -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.eos.providers.providers import register_provider -from ansible.module_utils.network.eos.providers.providers import CliProvider -from ansible.module_utils.network.eos.providers.cli.config.bgp.neighbors import Neighbors -from ansible.module_utils.network.eos.providers.cli.config.bgp.address_family import AddressFamily - -REDISTRIBUTE_PROTOCOLS = frozenset(['ospf', 'ospf3', 'rip', 'isis', 'static', 'connected']) - - -@register_provider('eos', 'eos_bgp') -class Provider(CliProvider): - - def render(self, config=None): - commands = list() - - existing_as = None - if config: - match = re.search(r'router bgp (\d+)', config, re.M) - if match: - existing_as = match.group(1) - - operation = self.params['operation'] - - context = None - if self.params['config']: - context = 'router bgp %s' % self.get_value('config.bgp_as') - - if operation == 'delete': - if existing_as: - commands.append('no router bgp %s' % existing_as) - elif context: - commands.append('no %s' % context) - - else: - self._validate_input(config) - if operation == 'replace': - if existing_as and int(existing_as) != self.get_value('config.bgp_as'): - commands.append('no router bgp %s' % existing_as) - config = None - - elif operation == 'override': - if existing_as: - commands.append('no router bgp %s' % existing_as) - config = None - - context_commands = list() - - for key, value in iteritems(self.get_value('config')): - if value is not None: - meth = getattr(self, '_render_%s' % key, None) - if meth: - resp = meth(config) - if resp: - context_commands.extend(to_list(resp)) - - if context and context_commands: - commands.append(context) - commands.extend(context_commands) - commands.append('exit') - return commands - - def _render_router_id(self, config=None): - cmd = 'router-id %s' % self.get_value('config.router_id') - if not config or cmd not in config: - return cmd - - def _render_log_neighbor_changes(self, config=None): - cmd = 'bgp log-neighbor-changes' - log_neighbor_changes = self.get_value('config.log_neighbor_changes') - if log_neighbor_changes is True: - if not config or cmd not in config: - return cmd - elif log_neighbor_changes is False: - if config and cmd in config: - return 'no %s' % cmd - - def _render_networks(self, config=None): - commands = list() - safe_list = list() - - for entry in self.get_value('config.networks'): - network = entry['prefix'] - if entry['masklen']: - network = '%s/%s' % (entry['prefix'], entry['masklen']) - safe_list.append(network) - - cmd = 'network %s' % network - - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - - if not config or cmd not in config: - commands.append(cmd) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'network (\S+)', config, re.M) - for entry in set(matches).difference(safe_list): - commands.append('no network %s' % entry) - - return commands - - def _render_redistribute(self, config=None): - commands = list() - safe_list = list() - - for entry in self.get_value('config.redistribute'): - option = entry['protocol'] - - cmd = 'redistribute %s' % entry['protocol'] - - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - - if not config or cmd not in config: - commands.append(cmd) - - safe_list.append(option) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'redistribute (\S+)(?:\s*)(\d*)', config, re.M) - for i in range(0, len(matches)): - matches[i] = ' '.join(matches[i]).strip() - for entry in set(matches).difference(safe_list): - commands.append('no redistribute %s' % entry) - - return commands - - def _render_neighbors(self, config): - """ generate bgp neighbor configuration - """ - return Neighbors(self.params).render(config) - - def _render_address_family(self, config): - """ generate address-family configuration - """ - return AddressFamily(self.params).render(config) - - def _validate_input(self, config): - def device_has_AF(config): - return re.search(r'address-family (?:.*)', config) - - address_family = self.get_value('config.address_family') - root_networks = self.get_value('config.networks') - operation = self.params['operation'] - - if operation == 'replace' and root_networks: - if address_family: - for item in address_family: - if item['networks']: - raise ValueError('operation is replace but provided both root level networks and networks under %s address family' - % item['afi']) - - if config and device_has_AF(config): - raise ValueError('operation is replace and device has one or more address family activated but root level network(s) provided') diff --git a/lib/ansible/module_utils/network/eos/providers/module.py b/lib/ansible/module_utils/network/eos/providers/module.py deleted file mode 100644 index 2d8fd67ebc..0000000000 --- a/lib/ansible/module_utils/network/eos/providers/module.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# (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 ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.connection import Connection -from ansible.module_utils.network.eos.providers import providers -from ansible.module_utils._text import to_text - - -class NetworkModule(AnsibleModule): - - fail_on_missing_provider = True - - def __init__(self, connection=None, *args, **kwargs): - super(NetworkModule, self).__init__(*args, **kwargs) - - if connection is None: - connection = Connection(self._socket_path) - - self.connection = connection - - @property - def provider(self): - if not hasattr(self, '_provider'): - capabilities = self.from_json(self.connection.get_capabilities()) - - network_os = capabilities['device_info']['network_os'] - network_api = capabilities['network_api'] - - if network_api == 'cliconf': - connection_type = 'network_cli' - - cls = providers.get(network_os, self._name.split('.')[-1], connection_type) - - if not cls: - msg = 'unable to find suitable provider for network os %s' % network_os - if self.fail_on_missing_provider: - self.fail_json(msg=msg) - else: - self.warn(msg) - - obj = cls(self.params, self.connection, self.check_mode) - - setattr(self, '_provider', obj) - - return getattr(self, '_provider') - - def get_facts(self, subset=None): - try: - self.provider.get_facts(subset) - except Exception as exc: - self.fail_json(msg=to_text(exc)) - - def edit_config(self, config_filter=None): - current_config = self.connection.get_config(flags=config_filter) - try: - commands = self.provider.edit_config(current_config) - changed = bool(commands) - return {'commands': commands, 'changed': changed} - except Exception as exc: - self.fail_json(msg=to_text(exc)) diff --git a/lib/ansible/module_utils/network/eos/providers/providers.py b/lib/ansible/module_utils/network/eos/providers/providers.py deleted file mode 100644 index be429dc0f8..0000000000 --- a/lib/ansible/module_utils/network/eos/providers/providers.py +++ /dev/null @@ -1,120 +0,0 @@ -# -# (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) -# -import json - -from threading import RLock - -from ansible.module_utils.six import itervalues -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.common.config import NetworkConfig - - -_registered_providers = {} -_provider_lock = RLock() - - -def register_provider(network_os, module_name): - def wrapper(cls): - _provider_lock.acquire() - try: - if network_os not in _registered_providers: - _registered_providers[network_os] = {} - for ct in cls.supported_connections: - if ct not in _registered_providers[network_os]: - _registered_providers[network_os][ct] = {} - for item in to_list(module_name): - for entry in itervalues(_registered_providers[network_os]): - entry[item] = cls - finally: - _provider_lock.release() - return cls - return wrapper - - -def get(network_os, module_name, connection_type): - network_os_providers = _registered_providers.get(network_os) - if network_os_providers is None: - raise ValueError('unable to find a suitable provider for this module') - if connection_type not in network_os_providers: - raise ValueError('provider does not support this connection type') - elif module_name not in network_os_providers[connection_type]: - raise ValueError('could not find a suitable provider for this module') - return network_os_providers[connection_type][module_name] - - -class ProviderBase(object): - - supported_connections = () - - def __init__(self, params, connection=None, check_mode=False): - self.params = params - self.connection = connection - self.check_mode = check_mode - - @property - def capabilities(self): - if not hasattr(self, '_capabilities'): - resp = self.from_json(self.connection.get_capabilities()) - setattr(self, '_capabilities', resp) - return getattr(self, '_capabilities') - - def get_value(self, path): - params = self.params.copy() - for key in path.split('.'): - params = params[key] - return params - - def get_facts(self, subset=None): - raise NotImplementedError(self.__class__.__name__) - - def edit_config(self): - raise NotImplementedError(self.__class__.__name__) - - -class CliProvider(ProviderBase): - - supported_connections = ('network_cli',) - - @property - def capabilities(self): - if not hasattr(self, '_capabilities'): - resp = self.from_json(self.connection.get_capabilities()) - setattr(self, '_capabilities', resp) - return getattr(self, '_capabilities') - - def get_config_context(self, config, path, indent=2): - if config is not None: - netcfg = NetworkConfig(indent=indent, contents=config) - try: - config = netcfg.get_block_config(to_list(path)) - except ValueError: - config = None - return config - - def render(self, config=None): - raise NotImplementedError(self.__class__.__name__) - - def cli(self, command): - try: - if not hasattr(self, '_command_output'): - setattr(self, '_command_output', {}) - return self._command_output[command] - except KeyError: - out = self.connection.get(command) - try: - out = json.loads(out) - except ValueError: - pass - self._command_output[command] = out - return out - - def get_facts(self, subset=None): - return self.populate() - - def edit_config(self, config=None): - commands = self.render(config) - if commands and self.check_mode is False: - self.connection.edit_config(commands) - return commands diff --git a/lib/ansible/module_utils/network/eos/utils/utils.py b/lib/ansible/module_utils/network/eos/utils/utils.py deleted file mode 100644 index beb3a6fd2e..0000000000 --- a/lib/ansible/module_utils/network/eos/utils/utils.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- 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) - -# utils - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -def get_interface_number(name): - digits = '' - for char in name: - if char.isdigit() or char in '/.': - digits += char - return digits - - -def normalize_interface(name): - """Return the normalized interface name - """ - if not name: - return None - - if name.lower().startswith('et'): - if_type = 'Ethernet' - elif name.lower().startswith('lo'): - if_type = 'Loopback' - elif name.lower().startswith('ma'): - if_type = 'Management' - elif name.lower().startswith('po'): - if_type = 'Port-Channel' - elif name.lower().startswith('tu'): - if_type = 'Tunnel' - elif name.lower().startswith('vl'): - if_type = 'Vlan' - elif name.lower().startswith('vx'): - if_type = 'Vxlan' - else: - if_type = None - - number_list = name.split(' ') - if len(number_list) == 2: - number = number_list[-1].strip() - else: - number = get_interface_number(name) - - if if_type: - proper_interface = if_type + number - else: - proper_interface = name - - return proper_interface |