diff options
Diffstat (limited to 'lib/ansible/module_utils')
47 files changed, 0 insertions, 8920 deletions
diff --git a/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py deleted file mode 100644 index 608cf6e728..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,66 +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 ios_acl_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Acl_InterfacesArgs(object): - """The arg spec for the ios_acl_interfaces module - """ - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'name': {'required': True, 'type': 'str'}, - 'access_groups': { - 'type': 'list', - 'elements': 'dict', - 'options': { - 'afi': {'required': True, 'choices': ['ipv4', 'ipv6'], 'type': 'str'}, - 'acls': { - 'type': 'list', - 'elements': 'dict', - 'options': { - 'name': {'required': True, 'type': 'str'}, - 'direction': {'required': True, 'choices': ['in', 'out'], 'type': 'str'} - } - } - } - } - }, - 'type': 'list' - }, - 'running_config': {'type': 'str'}, - 'state': { - 'choices': ['merged', 'replaced', 'overridden', 'deleted', 'gathered', 'rendered', 'parsed'], - 'default': 'merged', - 'type': 'str' - } - } diff --git a/lib/ansible/module_utils/network/ios/argspec/acls/acls.py b/lib/ansible/module_utils/network/ios/argspec/acls/acls.py deleted file mode 100644 index ca8982e557..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/acls/acls.py +++ /dev/null @@ -1,593 +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 ios_acls module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class AclsArgs(object): - """The arg spec for the ios_acls module - """ - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'afi': { - 'required': True, - 'choices': ['ipv4', 'ipv6'], - 'type': 'str' - }, - 'acls': { - 'elements': 'dict', - 'type': 'list', - 'options': { - 'name': { - 'required': True, - 'type': 'str' - }, - 'acl_type': { - 'choices': ['extended', 'standard'], - 'type': 'str' - }, - 'aces': { - 'elements': 'dict', - 'type': 'list', - 'options': { - 'grant': { - 'choices': ['permit', 'deny'], - 'type': 'str' - }, - 'sequence': { - 'type': 'int' - }, - 'source': { - 'type': - 'dict', - 'mutually_exclusive': - [['address', 'any', 'host'], - ['wildcard_bits', 'any', 'host']], - 'options': { - 'address': { - 'type': 'str' - }, - 'wildcard_bits': { - 'type': 'str' - }, - 'any': { - 'type': 'bool' - }, - 'host': { - 'type': 'str' - }, - 'port_protocol': { - 'type': 'dict', - 'options': { - 'eq': { - 'type': 'str' - }, - 'gt': { - 'type': 'str' - }, - 'lt': { - 'type': 'str' - }, - 'neq': { - 'type': 'str' - }, - 'range': { - 'type': 'dict', - 'options': { - 'start': { - 'type': 'int' - }, - 'end': { - 'type': 'int' - } - } - } - } - } - }, - }, - 'destination': { - 'type': - 'dict', - 'mutually_exclusive': - [['address', 'any', 'host'], - ['wildcard_bits', 'any', 'host']], - 'options': { - 'address': { - 'type': 'str' - }, - 'wildcard_bits': { - 'type': 'str' - }, - 'any': { - 'type': 'bool' - }, - 'host': { - 'type': 'str' - }, - 'port_protocol': { - 'type': 'dict', - 'options': { - 'eq': { - 'type': 'str' - }, - 'gt': { - 'type': 'str' - }, - 'lt': { - 'type': 'str' - }, - 'neq': { - 'type': 'str' - }, - 'range': { - 'type': 'dict', - 'options': { - 'start': { - 'type': 'int' - }, - 'end': { - 'type': 'int' - } - } - } - } - } - } - }, - 'protocol': { - 'type': 'str' - }, - 'protocol_options': { - 'type': 'dict', - 'options': { - 'protocol_number': { - 'type': 'int' - }, - 'ahp': { - 'type': 'bool' - }, - 'eigrp': { - 'type': 'bool' - }, - 'esp': { - 'type': 'bool' - }, - 'gre': { - 'type': 'bool' - }, - 'hbh': { - 'type': 'bool' - }, - 'icmp': { - 'type': 'dict', - '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' - }, - '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' - }, - } - }, - 'igmp': { - 'type': 'dict', - 'options': { - 'dvmrp': { - 'type': 'bool' - }, - 'host_query': { - 'type': 'bool' - }, - 'mtrace_resp': { - 'type': 'bool' - }, - 'mtrace_route': { - 'type': 'bool' - }, - 'pim': { - 'type': 'bool' - }, - 'trace': { - 'type': 'bool' - }, - 'v1host_report': { - 'type': 'bool' - }, - 'v2host_report': { - 'type': 'bool' - }, - 'v2leave_group': { - 'type': 'bool' - }, - 'v3host_report': { - 'type': 'bool' - } - } - }, - 'ip': { - 'type': 'bool' - }, - 'ipv6': { - 'type': 'bool' - }, - 'ipinip': { - 'type': 'bool' - }, - 'nos': { - 'type': 'bool' - }, - 'ospf': { - 'type': 'bool' - }, - 'pcp': { - 'type': 'bool' - }, - 'pim': { - 'type': 'bool' - }, - 'sctp': { - 'type': 'bool' - }, - 'tcp': { - 'options': { - 'ack': { - 'type': 'bool' - }, - 'established': { - 'type': 'bool' - }, - 'fin': { - 'type': 'bool' - }, - 'psh': { - 'type': 'bool' - }, - 'rst': { - 'type': 'bool' - }, - 'syn': { - 'type': 'bool' - }, - 'urg': { - 'type': 'bool' - } - }, - 'type': 'dict' - }, - 'udp': { - 'type': 'bool' - } - } - }, - 'dscp': { - 'type': 'str' - }, - 'fragments': { - 'type': 'str' - }, - 'log': { - 'type': 'str' - }, - 'log_input': { - 'type': 'str' - }, - 'option': { - 'type': 'dict', - 'options': { - 'add_ext': { - 'type': 'bool' - }, - 'any_options': { - 'type': 'bool' - }, - 'com_security': { - 'type': 'bool' - }, - 'dps': { - 'type': 'bool' - }, - 'encode': { - 'type': 'bool' - }, - 'eool': { - 'type': 'bool' - }, - 'ext_ip': { - 'type': 'bool' - }, - 'ext_security': { - 'type': 'bool' - }, - 'finn': { - 'type': 'bool' - }, - 'imitd': { - 'type': 'bool' - }, - 'lsr': { - 'type': 'bool' - }, - 'mtup': { - 'type': 'bool' - }, - 'mtur': { - 'type': 'bool' - }, - 'no_op': { - 'type': 'bool' - }, - 'nsapa': { - 'type': 'bool' - }, - 'record_route': { - 'type': 'bool' - }, - 'router_alert': { - 'type': 'bool' - }, - 'sdb': { - 'type': 'bool' - }, - 'security': { - 'type': 'bool' - }, - 'ssr': { - 'type': 'bool' - }, - 'stream_id': { - 'type': 'bool' - }, - 'timestamp': { - 'type': 'bool' - }, - 'traceroute': { - 'type': 'bool' - }, - 'ump': { - 'type': 'bool' - }, - 'visa': { - 'type': 'bool' - }, - 'zsu': { - 'type': 'bool' - } - } - }, - 'precedence': { - 'type': 'int' - }, - 'time_range': { - 'type': 'str' - }, - 'tos': { - 'type': 'dict', - 'options': { - 'service_value': { - 'type': 'int' - }, - 'max_reliability': { - 'type': 'bool' - }, - 'max_throughput': { - 'type': 'bool' - }, - 'min_delay': { - 'type': 'bool' - }, - 'min_monetary_cost': { - 'type': 'bool' - }, - 'normal': { - 'type': 'bool' - } - } - }, - 'ttl': { - 'type': 'dict', - 'options': { - 'eq': { - 'type': 'int' - }, - 'gt': { - 'type': 'int' - }, - 'lt': { - 'type': 'int' - }, - 'neq': { - 'type': 'int' - }, - 'range': { - 'type': 'dict', - 'options': { - 'start': { - 'type': 'int' - }, - 'end': { - 'type': 'int' - } - } - } - } - }, - } - } - } - }, - }, - 'type': 'list' - }, - 'running_config': { - 'type': 'str' - }, - 'state': { - 'choices': [ - 'merged', 'replaced', 'overridden', 'deleted', 'gathered', - 'rendered', 'parsed' - ], - 'default': - 'merged', - 'type': - 'str' - } - } diff --git a/lib/ansible/module_utils/network/ios/argspec/facts/facts.py b/lib/ansible/module_utils/network/ios/argspec/facts/facts.py deleted file mode 100644 index 8cac9e9827..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/facts/facts.py +++ /dev/null @@ -1,24 +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 ios facts module. -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class FactsArgs(object): - """ The arg spec for the ios 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/ios/argspec/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py deleted file mode 100644 index ae097f5307..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py +++ /dev/null @@ -1,47 +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 ios_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class InterfacesArgs(object): - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'type': 'str', 'required': True}, - 'description': {'type': 'str'}, - 'enabled': {'default': True, 'type': 'bool'}, - 'speed': {'type': 'str'}, - 'mtu': {'type': 'int'}, - 'duplex': {'type': 'str', 'choices': ['full', 'half', 'auto']}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py deleted file mode 100644 index 5ef51fa23d..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,57 +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 ios_l2_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class L2_InterfacesArgs(object): - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'type': 'str', 'required': True}, - 'mode': {'type': 'str', 'choices': ['access', 'trunk']}, - 'access': {'type': 'dict', - 'options': {'vlan': {'type': 'int'}} - }, - 'voice': {'type': 'dict', - 'options': {'vlan': {'type': 'int'}} - }, - 'trunk': {'type': 'dict', - 'options': {'allowed_vlans': {'type': 'list'}, - 'encapsulation': {'type': 'str', - 'choices': - ['dot1q', 'isl', 'negotiate']}, - 'native_vlan': {'type': 'int'}, - 'pruning_vlans': {'type': 'list'}} - }}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py deleted file mode 100644 index cdf209a27a..0000000000 --- a/lib/ansible/module_utils/network/ios/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 ios_l3_interfaces module -""" - - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class L3_InterfacesArgs(object): - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'type': 'str', 'required': True}, - 'ipv4': {'element': 'dict', - 'type': 'list', - 'options': {'address': {'type': 'str'}, - 'secondary': {'type': 'bool'}, - 'dhcp_client': {'type': 'int'}, - 'dhcp_hostname': {'type': 'str'}}}, - 'ipv6': {'element': 'dict', - 'type': 'list', - 'options': {'address': {'type': 'str'}}} - }, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py b/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py deleted file mode 100644 index 1e7294bc5c..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py +++ /dev/null @@ -1,47 +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 ios_lacp module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class LacpArgs(object): - """The arg spec for the ios_lacp module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': {'options': {'system': {'options': {'priority': {'required': True, 'type': 'int'}}, - 'type': 'dict'} - }, 'type': 'dict' - }, - 'state': {'choices': ['merged', 'replaced', 'deleted'], 'default': 'merged', - 'type': 'str'} - } diff --git a/lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index 10b17e5635..0000000000 --- a/lib/ansible/module_utils/network/ios/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 ios_lacp_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Lacp_InterfacesArgs(object): - """The arg spec for the ios_lacp_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'required': True, 'type': 'str'}, - 'port_priority': {'type': 'int'}, - 'fast_switchover': {'type': 'bool'}, - 'max_bundle': {'type': 'int'}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py deleted file mode 100644 index 0f9b7e2535..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,52 +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 ios_lag_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Lag_interfacesArgs(object): - - 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': ['auto', 'on', 'desirable', - 'active', 'passive'], - 'type': 'str', 'required': True}, - 'link': {'type': 'int'} - }, - 'type': 'list'}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py deleted file mode 100644 index 62630036c2..0000000000 --- a/lib/ansible/module_utils/network/ios/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 ios_lldp_global module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Lldp_globalArgs(object): - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'options': {'holdtime': {'type': 'int'}, - 'reinit': {'type': 'int'}, - 'enabled': {'type': 'bool'}, - 'timer': {'type': 'int'}, - 'tlv_select': { - 'options': { - 'four_wire_power_management': {'type': 'bool'}, - 'mac_phy_cfg': {'type': 'bool'}, - 'management_address': {'type': 'bool'}, - 'port_description': {'type': 'bool'}, - 'port_vlan': {'type': 'bool'}, - 'power_management': {'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/ios/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index 45af268d4d..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py +++ /dev/null @@ -1,52 +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 ios_lldp_interfaces module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Lldp_InterfacesArgs(object): - """The arg spec for the ios_lldp_interfaces module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'required': True, 'type': 'str'}, - 'transmit': {'type': 'bool'}, - 'receive': {'type': 'bool'}, - 'med_tlv_select': {'options': {'inventory_management': {'type': 'bool'}}, - 'type': 'dict'}, - 'tlv_select': {'options': {'power_management': {'type': 'bool'}}, - 'type': 'dict'} - }, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py deleted file mode 100644 index 3362187987..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py +++ /dev/null @@ -1,85 +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 ios_static_routes module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class Static_RoutesArgs(object): - """The arg spec for the ios_static_routes module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = { - 'config': { - 'elements': 'dict', - 'options': { - 'vrf': {'type': 'str'}, - 'address_families': { - 'elements': 'dict', - 'type': 'list', - 'options': { - 'afi': {'required': True, 'choices': ['ipv4', 'ipv6'], 'type': 'str'}, - 'routes': { - 'elements': 'dict', - 'type': 'list', - 'options': { - 'dest': {'required': True, 'type': 'str'}, - 'topology': {'type': 'str'}, - 'next_hops': { - 'elements': 'dict', - 'type': 'list', - 'options': { - 'forward_router_address': {'type': 'str'}, - 'interface': {'type': 'str'}, - 'dhcp': {'type': 'bool'}, - 'distance_metric': {'type': 'int'}, - 'global': {'type': 'bool'}, - 'name': {'type': 'str'}, - 'multicast': {'type': 'bool'}, - 'permanent': {'type': 'bool'}, - 'tag': {'type': 'int'}, - 'track': {'type': 'int'} - } - } - } - } - } - } - }, - 'type': 'list' - }, - 'running_config': {'type': 'str'}, - 'state': { - 'choices': ['merged', 'replaced', 'overridden', 'deleted', 'gathered', 'rendered', 'parsed'], - 'default': 'merged', - 'type': 'str' - } - } diff --git a/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py b/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py deleted file mode 100644 index 893904cfe7..0000000000 --- a/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.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 ios_vlans module -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -class VlansArgs(object): - """The arg spec for the ios_vlans module - """ - - def __init__(self, **kwargs): - pass - - argument_spec = {'config': {'elements': 'dict', - 'options': {'name': {'type': 'str'}, - 'vlan_id': {'required': True, 'type': 'int'}, - 'mtu': {'type': 'int'}, - 'remote_span': {'type': 'bool'}, - 'state': {'type': 'str', 'choices': ['active', 'suspend']}, - 'shutdown': {'type': 'str', 'choices': ['enabled', 'disabled']}}, - 'type': 'list'}, - 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'], - 'default': 'merged', - 'type': 'str'}} diff --git a/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py deleted file mode 100644 index fa3352389c..0000000000 --- a/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,405 +0,0 @@ -# -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 - -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.ios.facts.facts import Facts -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.ios.utils.utils import remove_duplicate_interface, normalize_interface - - -class Acl_Interfaces(ConfigBase): - """ - The ios_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 moduel execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - 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) - 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': - running_config = self._module.params['running_config'] - if not 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=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 deisred configuration - """ - want = self._module.params['config'] - if want: - for item in want: - item['name'] = normalize_interface(item['name']) - - 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 deisred configuration - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced', 'rendered') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or 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 - :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 deisred configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - commands.extend(self._clear_config(interface, each, 'replaced')) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_overridden(self, want, have): - """ The command generator when state is overridden - :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 = [] - - for each in have: - for interface in want: - if each['name'] == interface['name']: - break - else: - # We didn't find a matching desired state, which means we can - # pretend we recieved an empty desired state. - interface = dict(name=each['name']) - commands.extend(self._clear_config(interface, each)) - continue - commands.extend(self._clear_config(interface, each, 'overridden')) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_merged(self, want, have): - """ The command generator when state is merged - :param want: the additive configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - # configuring non-existing interface - commands.extend(self._set_config(interface, dict())) - continue - commands.extend(self._set_config(interface, each)) - - return commands - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - :param want: the objects from which the configuration should be removed - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - commands.extend(self._clear_config(dict(), each)) - - return commands - - def dict_to_set(self, input_dict, test_set, final_set, count=0): - # recursive function to convert input dict to set for comparision - test_dict = dict() - if isinstance(input_dict, dict): - input_dict_len = len(input_dict) - for k, v in sorted(iteritems(input_dict)): - count += 1 - if isinstance(v, list): - for each in v: - if isinstance(each, dict): - input_dict_len = len(each) - if [True for i in each.values() if type(i) == list]: - self.dict_to_set(each, set(), final_set, count) - else: - self.dict_to_set(each, test_set, final_set, 0) - else: - if v is not None: - test_dict.update({k: v}) - if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len: - test_set.add(tuple(iteritems(test_dict))) - count = 0 - if count == input_dict_len + 1: - test_set.update(tuple(iteritems(test_dict))) - final_set.add(tuple(test_set)) - - def _set_config(self, want, have): - """ Function that sets the acls config based on the want and have config - :param want: want config - :param have: have config - :param acl_want: want acl config - :param afi: acl afi type - :rtype: A list - :returns: the commands generated based on input want/have params - """ - commands = [] - - want_set = set() - have_set = set() - self.dict_to_set(want, set(), want_set) - self.dict_to_set(have, set(), have_set) - - for w in want_set: - want_afi = dict(w).get('afi') - if have_set: - def common_diff_config_code(diff_list, cmd, commands): - for each in diff_list: - try: - temp = dict(each) - temp_cmd = cmd + ' {0} {1}'.format(temp['name'], temp['direction']) - if temp_cmd not in commands: - commands.append(temp_cmd) - except ValueError: - continue - for h in have_set: - have_afi = dict(h).get('afi') - if have_afi == want_afi: - if want_afi == 'ipv4': - diff = set(w) - set(h) - if diff: - cmd = 'ip access-group' - common_diff_config_code(diff, cmd, commands) - if want_afi == 'ipv6': - diff = set(w) - set(h) - if diff: - cmd = 'ipv6 traffic-filter' - common_diff_config_code(diff, cmd, commands) - break - else: - if want_afi == 'ipv4': - diff = set(w) - set(h) - if diff: - cmd = 'ip access-group' - common_diff_config_code(diff, cmd, commands) - if want_afi == 'ipv6': - diff = set(w) - set(h) - if diff: - cmd = 'ipv6 traffic-filter' - common_diff_config_code(diff, cmd, commands) - else: - def common_want_config_code(want, cmd, commands): - for each in want: - if each[0] == 'afi': - continue - temp = dict(each) - temp_cmd = cmd + ' {0} {1}'.format(temp['name'], temp['direction']) - commands.append(temp_cmd) - if want_afi == 'ipv4': - cmd = 'ip access-group' - common_want_config_code(w, cmd, commands) - if want_afi == 'ipv6': - cmd = 'ipv6 traffic-filter' - common_want_config_code(w, cmd, commands) - commands.sort() - if commands: - interface = want.get('name') - commands.insert(0, 'interface {0}'.format(interface)) - - return commands - - def _clear_config(self, want, have, state=''): - """ Function that deletes the acl config based on the want and have config - :param acl: acl config - :param config: config - :rtype: A list - :returns: the commands generated based on input acl/config params - """ - commands = [] - - if want.get('name'): - interface = 'interface ' + want['name'] - else: - interface = 'interface ' + have['name'] - - w_access_group = want.get('access_groups') - temp_want_afi = [] - temp_want_acl_name = [] - if w_access_group: - # get the user input afi and acls - for each in w_access_group: - want_afi = each.get('afi') - want_acls = each.get('acls') - if want_afi: - temp_want_afi.append(want_afi) - if want_acls: - for each in want_acls: - temp_want_acl_name.append(each.get('name')) - - h_access_group = have.get('access_groups') - if h_access_group: - for access_grp in h_access_group: - for acl in access_grp.get('acls'): - have_afi = access_grp.get('afi') - acl_name = acl.get('name') - acl_direction = acl.get('direction') - if temp_want_afi and state not in ['replaced', 'overridden']: - # if user want to delete acls based on afi - if 'ipv4' in temp_want_afi and have_afi == 'ipv4': - if acl_name in temp_want_acl_name: - continue - cmd = 'no ip access-group' - cmd += ' {0} {1}'.format(acl_name, acl_direction) - commands.append(cmd) - if 'ipv6' in temp_want_afi and have_afi == 'ipv6': - if acl_name in temp_want_acl_name: - continue - cmd = 'no ipv6 traffic-filter' - cmd += ' {0} {1}'.format(acl_name, acl_direction) - commands.append(cmd) - else: - # if user want to delete acls based on interface - if access_grp.get('afi') == 'ipv4': - if acl_name in temp_want_acl_name: - continue - cmd = 'no ip access-group' - cmd += ' {0} {1}'.format(acl_name, acl_direction) - commands.append(cmd) - elif access_grp.get('afi') == 'ipv6': - if acl_name in temp_want_acl_name: - continue - cmd = 'no ipv6 traffic-filter' - cmd += ' {0} {1}'.format(acl_name, acl_direction) - commands.append(cmd) - if commands: - # inserting the interface at first - commands.insert(0, interface) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/acls/acls.py b/lib/ansible/module_utils/network/ios/config/acls/acls.py deleted file mode 100644 index 2a3f3f244b..0000000000 --- a/lib/ansible/module_utils/network/ios/config/acls/acls.py +++ /dev/null @@ -1,717 +0,0 @@ -# -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 copy -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.ios.facts.facts import Facts -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.common.utils import remove_empties -from ansible.module_utils.network.ios.utils.utils import new_dict_to_set - - -class Acls(ConfigBase): - """ - The ios_acls class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'acls', - ] - - def __init__(self, module): - super(Acls, self).__init__(module) - - def get_acl_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_facts = facts['ansible_network_resources'].get('acls') - if not acl_facts: - return [] - - return acl_facts - - def execute_module(self): - """ Execute the module - - :rtype: A dictionary - :returns: The result from moduel execution - """ - result = {'changed': False} - commands = list() - warnings = list() - - if self.state in self.ACTION_STATES: - existing_acl_facts = self.get_acl_facts() - else: - existing_acl_facts = [] - - if self.state in self.ACTION_STATES or self.state == 'rendered': - commands.extend(self.set_config(existing_acl_facts)) - - if commands and self.state in self.ACTION_STATES: - if not self._module.check_mode: - self._connection.edit_config(commands) - 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_facts = self.get_acl_facts() - elif self.state == 'rendered': - result['rendered'] = commands - elif self.state == 'parsed': - running_config = self._module.params['running_config'] - if not running_config: - self._module.fail_json(msg="value of running_config parameter must not be empty for state parsed") - result['parsed'] = self.get_acl_facts(data=running_config) - else: - changed_acl_facts = [] - - if self.state in self.ACTION_STATES: - result['before'] = existing_acl_facts - if result['changed']: - result['after'] = changed_acl_facts - elif self.state == 'gathered': - result['gathered'] = changed_acl_facts - - result['warnings'] = warnings - - return result - - def set_config(self, existing_acl_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 deisred configuration - """ - want = self._module.params['config'] - have = existing_acl_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 deisred configuration - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced', 'rendered') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or 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 - - :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 deisred configuration - """ - commands = [] - - for config_want in want: - for acls_want in config_want.get('acls'): - for ace_want in acls_want.get('aces'): - check = False - for config_have in have: - for acls_have in config_have.get('acls'): - for ace_have in acls_have.get('aces'): - if acls_want.get('name') == acls_have.get('name'): - ace_want = remove_empties(ace_want) - acls_want = remove_empties(acls_want) - cmd, change = self._set_config(ace_want, - ace_have, - acls_want, - config_want['afi']) - if cmd: - for temp_acls_have in config_have.get('acls'): - for temp_ace_have in temp_acls_have.get('aces'): - if acls_want.get('name') == temp_acls_have.get('name'): - commands.extend( - self._clear_config(temp_acls_have, - config_have, - temp_ace_have.get('sequence'))) - commands.extend(cmd) - check = True - if check: - break - if check: - break - if not check: - # For configuring any non-existing want config - ace_want = remove_empties(ace_want) - cmd, change = self._set_config(ace_want, - {}, - acls_want, - config_want['afi']) - commands.extend(cmd) - # Split and arrange the config commands - commands = self.split_set_cmd(commands) - - return commands - - def _state_overridden(self, want, have): - """ The command generator when state is overridden - :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 = [] - # Creating a copy of want, so that want dict is intact even after delete operation - # performed during override want n have comparison - temp_want = copy.deepcopy(want) - - for config_have in have: - for acls_have in config_have.get('acls'): - for ace_have in acls_have.get('aces'): - check = False - for config_want in temp_want: - count = 0 - for acls_want in config_want.get('acls'): - for ace_want in acls_want.get('aces'): - if acls_want.get('name') == acls_have.get('name'): - ace_want = remove_empties(ace_want) - acls_want = remove_empties(acls_want) - cmd, change = self._set_config(ace_want, ace_have, acls_want, config_want['afi']) - if cmd: - for temp_acls_have in config_have.get('acls'): - for temp_ace_have in temp_acls_have.get('aces'): - if acls_want.get('name') == temp_acls_have.get('name'): - commands.extend( - self._clear_config(temp_acls_have, - config_have, - temp_ace_have.get('sequence'))) - commands.extend(cmd) - check = True - if check: - del config_want.get('acls')[count] - else: - count += 1 - if check: - break - if check: - break - if not check: - # Delete the config not present in want config - commands.extend(self._clear_config(acls_have, config_have)) - - # For configuring any non-existing want config - for config_want in temp_want: - for acls_want in config_want.get('acls'): - for ace_want in acls_want.get('aces'): - ace_want = remove_empties(ace_want) - cmd, change = self._set_config(ace_want, - {}, - acls_want, - config_want['afi']) - commands.extend(cmd) - - # Split and arrange the config commands - commands = self.split_set_cmd(commands) - # Arranging the cmds suct that all delete cmds are fired before all set cmds - negate_commands = [each for each in commands if 'no' in each and 'access-list' in each] - negate_commands.extend([each for each in commands if each not in negate_commands]) - commands = negate_commands - - return commands - - def _state_merged(self, want, have): - """ The command generator when state is merged - - :param want: the additive configuration as a dictionary - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - - for config_want in want: - for acls_want in config_want.get('acls'): - for ace_want in acls_want.get('aces'): - check = False - for config_have in have: - for acls_have in config_have.get('acls'): - for ace_have in acls_have.get('aces'): - if acls_want.get('name') == acls_have.get('name') and \ - ace_want.get('sequence') == ace_have.get('sequence'): - ace_want = remove_empties(ace_want) - cmd, change = self._set_config(ace_want, - ace_have, - acls_want, - config_want['afi']) - # clear config will be fired only when there's command wrt to config - if config_want.get('afi') == 'ipv4' and change: - # for ipv4 only inplace update cannot be done, so deleting the sequence ace - # and then updating the want ace changes - commands.extend(self._clear_config(acls_want, - config_want, - ace_want.get('sequence'))) - commands.extend(cmd) - check = True - elif acls_want.get('name') == acls_have.get('name'): - ace_want = remove_empties(ace_want) - cmd, check = self.common_condition_check(ace_want, - ace_have, - acls_want, - config_want, - check, - acls_have) - if acls_have.get('acl_type') == 'standard': - check = True - commands.extend(cmd) - if check: - break - if check: - break - if not check: - # For configuring any non-existing want config - ace_want = remove_empties(ace_want) - cmd, change = self._set_config(ace_want, - {}, - acls_want, - config_want['afi']) - commands.extend(cmd) - # Split and arrange the config commands - commands = self.split_set_cmd(commands) - - return commands - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - - :param want: the objects from which the configuration should be removed - :param have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - if want: - for config_want in want: - if config_want.get('acls'): - for acls_want in config_want.get('acls'): - if acls_want.get('aces'): - for ace_want in acls_want.get('aces'): - for config_have in have: - for acls_have in config_have.get('acls'): - if acls_want.get('name') == acls_have.get('name'): - if ace_want.get('sequence'): - commands.extend(self._clear_config(acls_want, - config_want, - ace_want.get('sequence'))) - else: - commands.extend(self._clear_config(acls_want, - config_want)) - else: - for config_have in have: - for acls_have in config_have.get('acls'): - if acls_want.get('name') == acls_have.get('name'): - commands.extend(self._clear_config(acls_want, - config_want)) - else: - afi_want = config_want.get('afi') - for config_have in have: - if config_have.get('afi') == afi_want: - for acls_have in config_have.get('acls'): - commands.extend(self._clear_config(acls_have, config_want)) - # Split and arrange the config commands - commands = self.split_set_cmd(commands) - else: - for config_have in have: - for acls_have in config_have.get('acls'): - commands.extend(self._clear_config(acls_have, config_have)) - - return commands - - def common_condition_check(self, want, have, acls_want, config_want, check, state='', acls_have=None): - """ The command formatter from the generated command - :param want: want config - :param have: have config - :param acls_want: acls want config - :param config_want: want config list - :param check: for same acls in want and have config, check=True - :param state: operation state - :rtype: A list - :returns: commands generated from want n have config diff - """ - commands = [] - - if want.get('source') and want.get('destination') and have.get('source') and have.get('destination'): - if want.get('destination') and have.get('destination') or \ - want.get('source').get('address') and have.get('source'): - if want.get('destination').get('address') == \ - have.get('destination').get('address') and \ - want.get('source').get('address') == \ - have.get('source').get('address'): - cmd, change = self._set_config(want, - have, - acls_want, - config_want['afi']) - commands.extend(cmd) - check = True - if commands: - if state == 'replaced' or state == 'overridden': - commands.extend(self._clear_config(acls_want, config_want)) - elif want.get('destination').get('any') == \ - have.get('destination').get('any') and \ - want.get('source').get('address') == \ - have.get('source').get('address') and \ - want.get('destination').get('any'): - cmd, change = self._set_config(want, - have, - acls_want, - config_want['afi']) - commands.extend(cmd) - check = True - if commands: - if state == 'replaced' or state == 'overridden': - commands.extend(self._clear_config(acls_want, config_want)) - elif want.get('destination').get('address') == \ - have.get('destination').get('address') and \ - want.get('source').get('any') == have.get('source').get('any') and \ - want.get('source').get('any'): - cmd, change = self._set_config(want, - have, - acls_want, - config_want['afi']) - commands.extend(cmd) - check = True - if commands: - if state == 'replaced' or state == 'overridden': - commands.extend(self._clear_config(acls_want, config_want)) - elif want.get('destination').get('any') == \ - have.get('destination').get('any') and \ - want.get('source').get('any') == have.get('source').get('any') and \ - want.get('destination').get('any'): - cmd, change = self._set_config(want, - have, - acls_want, - config_want['afi']) - commands.extend(cmd) - check = True - if commands: - if state == 'replaced' or state == 'overridden': - commands.extend(self._clear_config(acls_want, config_want)) - elif acls_have and acls_have.get('acl_type') == 'standard': - check = True - if want.get('source') == have.get('source'): - cmd, change = self._set_config(want, - have, - acls_want, - config_want['afi']) - commands.extend(cmd) - - return commands, check - - def split_set_cmd(self, cmds): - """ The command formatter from the generated command - :param cmds: generated command - :rtype: A list - :returns: the formatted commands which is compliant and - actually fired on the device - """ - command = [] - - def common_code(access_grant, cmd, command): - cmd = cmd.split(access_grant) - access_list = cmd[0].strip(' ') - if access_list not in command: - command.append(access_list) - command_items = len(command) - # get the last index of the list and push the trimmed cmd at the end of list - index = command.index(access_list) + (command_items - command.index(access_list)) - cmd = access_grant + cmd[1] - command.insert(index + 1, cmd) - - def sequence_common_code(sequence_index, each_list, command): - # Command to split - def join_list_to_str(temp_list, cmd=''): - for item in temp_list: - cmd += item - cmd += ' ' - return cmd - - temp_list = each_list[:sequence_index] - cmd = join_list_to_str(temp_list).rstrip(' ') - if cmd not in command: - command.append(cmd) - temp_list = each_list[sequence_index:] - cmd = join_list_to_str(temp_list).rstrip(' ') - command.append(cmd) - - def grant_common_code(cmd_list, grant_type, command): - index = cmd_list.index(grant_type) - if 'extended' in each_list: - if cmd_list.index('extended') == (index - 2): - common_code(grant_type, each, command) - else: - sequence_common_code((index - 1), each_list, command) - elif 'standard' in each_list: - if cmd_list.index('standard') == (index - 2): - common_code(grant_type, each, command) - else: - sequence_common_code((index - 1), each_list, command) - elif 'ipv6' in each_list: - if 'sequence' in each_list: - sequence_index = each_list.index('sequence') - sequence_common_code(sequence_index, each_list, command) - else: - common_code(grant_type, each, command) - return command - - for each in cmds: - each_list = each.split(' ') - if 'no' in each: - if each_list.index('no') == 0: - command.append(each) - else: - common_code('no', each, command) - if 'deny' in each: - grant_common_code(each_list, 'deny', command) - if 'permit' in each: - grant_common_code(each_list, 'permit', command) - - return command - - def source_dest_config(self, config, cmd, protocol_option): - """ Function to populate source/destination address and port protocol options - :param config: want and have diff config - :param cmd: source/destination command - :param protocol_option: source/destination protocol option - :rtype: A list - :returns: the commands generated based on input source/destination params - """ - if 'ipv6' in cmd: - address = config.get('address') - host = config.get('host') - if (address and '::' not in address) or (host and '::' not in host): - self._module.fail_json(msg='Incorrect IPV6 address!') - else: - address = config.get('address') - wildcard = config.get('wildcard_bits') - host = config.get('host') - any = config.get('any') - if 'standard' in cmd and address and not wildcard: - cmd = cmd + ' {0}'.format(address) - elif address and wildcard: - cmd = cmd + ' {0} {1}'.format(address, wildcard) - elif host: - cmd = cmd + ' host {0}'.format(host) - if any: - cmd = cmd + ' {0}'.format('any') - port_protocol = config.get('port_protocol') - if port_protocol and (protocol_option.get('tcp') or protocol_option.get('udp')): - cmd = cmd + ' {0} {1}'.format(list(port_protocol)[0], list(port_protocol.values())[0]) - elif port_protocol and not (protocol_option.get('tcp') or protocol_option.get('udp')): - self._module.fail_json(msg='Port Protocol option is valid only with TCP/UDP Protocol option!') - - return cmd - - def _set_config(self, want, have, acl_want, afi): - """ Function that sets the acls config based on the want and have config - :param want: want config - :param have: have config - :param acl_want: want acls config - :param afi: acls afi type - :rtype: A list - :returns: the commands generated based on input want/have params - """ - commands = [] - change = False - want_set = set() - have_set = set() - # Convert the want and have dict to its respective set for taking the set diff - new_dict_to_set(want, [], want_set) - new_dict_to_set(have, [], have_set) - diff = want_set - have_set - - # Populate the config only when there's a diff b/w want and have config - if diff: - name = acl_want.get('name') - if afi == 'ipv4': - try: - name = int(name) - # If name is numbered acls - if name <= 99: - cmd = 'ip access-list standard {0}'.format(name) - elif name >= 100: - cmd = 'ip access-list extended {0}'.format(name) - except ValueError: - # If name is named acls - acl_type = acl_want.get('acl_type') - if acl_type: - cmd = 'ip access-list {0} {1}'.format(acl_type, name) - else: - self._module.fail_json(msg='ACL type value is required for Named ACL!') - - elif afi == 'ipv6': - cmd = 'ipv6 access-list {0}'.format(name) - - # Get all of aces option values from diff dict - sequence = want.get('sequence') - grant = want.get('grant') - source = want.get('source') - destination = want.get('destination') - po = want.get('protocol_options') - protocol = want.get('protocol') - dscp = want.get('dscp') - fragments = want.get('fragments') - log = want.get('log') - log_input = want.get('log_input') - option = want.get('option') - precedence = want.get('precedence') - time_range = want.get('time_range') - tos = want.get('tos') - ttl = want.get('ttl') - - if sequence: - if afi == 'ipv6': - cmd = cmd + ' sequence {0}'.format(sequence) - else: - cmd = cmd + ' {0}'.format(sequence) - if grant: - cmd = cmd + ' {0}'.format(grant) - if po and isinstance(po, dict): - po_key = list(po)[0] - if protocol and protocol != po_key: - self._module.fail_json(msg='Protocol value cannot be different from Protocol option protocol value!') - cmd = cmd + ' {0}'.format(po_key) - if po.get('icmp'): - po_val = po.get('icmp') - elif po.get('igmp'): - po_val = po.get('igmp') - elif po.get('tcp'): - po_val = po.get('tcp') - elif protocol: - cmd = cmd + ' {0}'.format(protocol) - if source: - cmd = self.source_dest_config(source, cmd, po) - if destination: - cmd = self.source_dest_config(destination, cmd, po) - if po: - cmd = cmd + ' {0}'.format(list(po_val)[0]) - if dscp: - cmd = cmd + ' dscp {0}'.format(dscp) - if fragments: - cmd = cmd + ' fragments {0}'.format(fragments) - if log: - cmd = cmd + ' log {0}'.format(log) - if log_input: - cmd = cmd + ' log-input {0}'.format(log_input) - if option: - cmd = cmd + ' option {0}'.format(list(option)[0]) - if precedence: - cmd = cmd + ' precedence {0}'.format(precedence) - if time_range: - cmd = cmd + ' time-range {0}'.format(time_range) - if tos: - for k, v in iteritems(tos): - if k == 'service_value': - cmd = cmd + ' tos {0}'.format(v) - else: - cmd = cmd + ' tos {0}'.format(v) - if ttl: - for k, v in iteritems(ttl): - if k == 'range' and v: - start = v.get('start') - end = v.get('start') - cmd = cmd + ' ttl {0} {1}'.format(start, end) - elif v: - cmd = cmd + ' ttl {0} {1}'.format(k, v) - - commands.append(cmd) - if commands: - change = True - - return commands, change - - def _clear_config(self, acls, config, sequence=''): - """ Function that deletes the acls config based on the want and have config - :param acls: acls config - :param config: config - :rtype: A list - :returns: the commands generated based on input acls/config params - """ - commands = [] - afi = config.get('afi') - name = acls.get('name') - if afi == 'ipv4' and name: - try: - name = int(name) - if name <= 99 and not sequence: - cmd = 'no ip access-list standard {0}'.format(name) - elif name >= 100 and not sequence: - cmd = 'no ip access-list extended {0}'.format(name) - elif sequence: - if name <= 99: - cmd = 'ip access-list standard {0} '.format(name) - elif name >= 100: - cmd = 'ip access-list extended {0} '.format(name) - cmd += 'no {0}'.format(sequence) - except ValueError: - acl_type = acls.get('acl_type') - if acl_type == 'extended' and not sequence: - cmd = 'no ip access-list extended {0}'.format(name) - elif acl_type == 'standard' and not sequence: - cmd = 'no ip access-list standard {0}'.format(name) - elif sequence: - if acl_type == 'extended': - cmd = 'ip access-list extended {0} '.format(name) - elif acl_type == 'standard': - cmd = 'ip access-list standard {0}'.format(name) - cmd += 'no {0}'.format(sequence) - else: - self._module.fail_json(msg="ACL type value is required for Named ACL!") - elif afi == 'ipv6' and name: - if sequence: - cmd = 'no sequence {0}'.format(sequence) - else: - cmd = 'no ipv6 access-list {0}'.format(name) - commands.append(cmd) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py deleted file mode 100644 index bcf817f4d8..0000000000 --- a/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py +++ /dev/null @@ -1,295 +0,0 @@ -# -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import get_interface_type, dict_to_set -from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface - - -class Interfaces(ConfigBase): - """ - The ios_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'interfaces', - ] - - params = ('description', 'mtu', 'speed', 'duplex') - - def __init__(self, module): - super(Interfaces, self).__init__(module) - - 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 moduel 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 deisred 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 deisred configuration - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(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 - - def _state_replaced(self, want, have): - """ The command generator when state is replaced - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the deisred configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - elif interface['name'] in each['name']: - break - else: - # configuring non-existing interface - commands.extend(self._set_config(interface, dict())) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_overridden(self, want, have): - """ The command generator when state is overridden - - :param want: the desired configuration as a dictionary - :param obj_in_have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - - for each in have: - for interface in want: - count = 0 - if each['name'] == interface['name']: - break - elif interface['name'] in each['name']: - break - count += 1 - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - interface = dict(name=each['name']) - commands.extend(self._clear_config(interface, each)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # as the pre-existing interface are now configured by - # above set_config call, deleting the respective - # interface entry from the want list - del want[count] - - # Iterating through want list which now only have new interfaces to be - # configured - for each in want: - commands.extend(self._set_config(each, dict())) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_merged(self, want, have): - """ The command generator when state is merged - - :param want: the additive configuration as a dictionary - :param obj_in_have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - # configuring non-existing interface - commands.extend(self._set_config(interface, dict())) - continue - commands.extend(self._set_config(interface, each)) - - return commands - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - - :param want: the objects from which the configuration should be removed - :param obj_in_have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - interface = dict(name=interface['name']) - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - want = dict() - commands.extend(self._clear_config(want, each)) - - return commands - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - interface = 'interface ' + want['name'] - - # Get the diff b/w want and have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - diff = dict(diff) - for item in self.params: - if diff.get(item): - cmd = item + ' ' + str(want.get(item)) - add_command_to_config_list(interface, cmd, commands) - if diff.get('enabled'): - add_command_to_config_list(interface, 'no shutdown', commands) - elif diff.get('enabled') is False: - add_command_to_config_list(interface, 'shutdown', commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - commands = [] - - if want.get('name'): - interface_type = get_interface_type(want['name']) - interface = 'interface ' + want['name'] - else: - interface_type = get_interface_type(have['name']) - interface = 'interface ' + have['name'] - - if have.get('description') and want.get('description') != have.get('description'): - remove_command_from_config_list(interface, 'description', commands) - if not have.get('enabled') and want.get('enabled') != have.get('enabled'): - # if enable is False set enable as True which is the default behavior - remove_command_from_config_list(interface, 'shutdown', commands) - - if interface_type.lower() == 'gigabitethernet': - if have.get('speed') and have.get('speed') != 'auto' and want.get('speed') != have.get('speed'): - remove_command_from_config_list(interface, 'speed', commands) - if have.get('duplex') and have.get('duplex') != 'auto' and want.get('duplex') != have.get('duplex'): - remove_command_from_config_list(interface, 'duplex', commands) - if have.get('mtu') and want.get('mtu') != have.get('mtu'): - remove_command_from_config_list(interface, 'mtu', commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py deleted file mode 100644 index 1ebfcbda58..0000000000 --- a/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,336 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface - - -class L2_Interfaces(ConfigBase): - """ - The ios_l2_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'l2_interfaces', - ] - - access_cmds = {'access_vlan': 'switchport access vlan'} - voice_cmds = {'voice_vlan': 'switchport voice vlan'} - trunk_cmds = {'encapsulation': 'switchport trunk encapsulation', 'pruning_vlans': 'switchport trunk pruning vlan', - 'native_vlan': 'switchport trunk native vlan', 'allowed_vlans': 'switchport trunk allowed vlan'} - - 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('l2_interfaces') - if not interfaces_facts: - return [] - - return interfaces_facts - - def execute_module(self): - """ Execute the module - :rtype: A dictionary - :returns: The result from moduel execution - """ - result = {'changed': False} - commands = [] - warnings = [] - existing_facts = self.get_interfaces_facts() - commands.extend(self.set_config(existing_facts)) - result['before'] = existing_facts - if commands: - if not self._module.check_mode: - self._connection.edit_config(commands) - result['changed'] = True - result['commands'] = commands - - interfaces_facts = self.get_interfaces_facts() - - if result['changed']: - result['after'] = interfaces_facts - result['warnings'] = warnings - return result - - def set_config(self, existing_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 deisred configuration - """ - - want = self._module.params['config'] - have = existing_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 deisred configuration - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - if state == 'overridden': - commands = self._state_overridden(want, have, self._module) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have, self._module) - elif state == 'replaced': - commands = self._state_replaced(want, have, self._module) - - return commands - - def _state_replaced(self, want, have, module): - """ The command generator when state is replaced - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the deisred configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_overridden(self, want, have, module): - """ The command generator when state is overridden - :param want: the desired configuration as a dictionary - :param obj_in_have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - - for each in have: - for interface in want: - if each['name'] == interface['name']: - break - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - interface = dict(name=each['name']) - kwargs = {'want': interface, 'have': each} - commands.extend(self._clear_config(**kwargs)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_merged(self, want, have, module): - """ The command generator when state is merged - :param want: the additive configuration as a dictionary - :param obj_in_have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - commands.extend(self._set_config(interface, each, module)) - - return commands - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - :param want: the objects from which the configuration should be removed - :param obj_in_have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - interface = dict(name=interface['name']) - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - want = dict() - commands.extend(self._clear_config(want, each)) - - return commands - - def _check_for_correct_vlan_range(self, vlan, module): - # Function to check if the VLAN range passed is Valid - for each in vlan: - vlan_range = each.split('-') - if len(vlan_range) > 1: - if vlan_range[0] < vlan_range[1]: - return True - else: - module.fail_json(msg='Command rejected: Bad VLAN list - end of range not larger than the' - ' start of range!') - else: - return True - - def _set_config(self, want, have, module): - # Set the interface config based on the want and have config - commands = [] - interface = 'interface ' + want['name'] - - # Get the diff b/w want and have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - want_trunk = dict(want_dict).get('trunk') - have_trunk = dict(have_dict).get('trunk') - if want_trunk and have_trunk: - diff = set(tuple(dict(want_dict).get('trunk'))) - set(tuple(dict(have_dict).get('trunk'))) - else: - diff = want_dict - have_dict - - if diff: - diff = dict(diff) - mode = diff.get('mode') - access = diff.get('access') - trunk = diff.get('trunk') - - if access: - cmd = 'switchport access vlan {0}'.format(access[0][1]) - add_command_to_config_list(interface, cmd, commands) - - if diff.get('voice'): - cmd = 'switchport voice vlan {0}'.format(diff.get('voice')[0][1]) - add_command_to_config_list(interface, cmd, commands) - - if want_trunk: - if trunk: - diff = dict(trunk) - if diff.get('encapsulation'): - cmd = self.trunk_cmds['encapsulation'] + ' {0}'.format(diff.get('encapsulation')) - add_command_to_config_list(interface, cmd, commands) - if diff.get('native_vlan'): - cmd = self.trunk_cmds['native_vlan'] + ' {0}'.format(diff.get('native_vlan')) - add_command_to_config_list(interface, cmd, commands) - allowed_vlans = diff.get('allowed_vlans') - pruning_vlans = diff.get('pruning_vlans') - - if allowed_vlans and self._check_for_correct_vlan_range(allowed_vlans, module): - allowed_vlans = ','.join(allowed_vlans) - cmd = self.trunk_cmds['allowed_vlans'] + ' {0}'.format(allowed_vlans) - add_command_to_config_list(interface, cmd, commands) - if pruning_vlans and self._check_for_correct_vlan_range(pruning_vlans, module): - pruning_vlans = ','.join(pruning_vlans) - cmd = self.trunk_cmds['pruning_vlans'] + ' {0}'.format(pruning_vlans) - add_command_to_config_list(interface, cmd, commands) - - if mode: - cmd = 'switchport mode {0}'.format(mode) - add_command_to_config_list(interface, cmd, commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - commands = [] - if want.get('name'): - interface = 'interface ' + want['name'] - else: - interface = 'interface ' + have['name'] - - if have.get('mode') or want.get('mode'): - remove_command_from_config_list(interface, 'switchport mode', commands) - - if have.get('access') and want.get('access') is None: - remove_command_from_config_list(interface, L2_Interfaces.access_cmds['access_vlan'], commands) - elif have.get('access') and want.get('access'): - if have.get('access').get('vlan') != want.get('access').get('vlan'): - remove_command_from_config_list(interface, L2_Interfaces.access_cmds['access_vlan'], commands) - - if have.get('voice') and want.get('voice') is None: - remove_command_from_config_list(interface, L2_Interfaces.voice_cmds['voice_vlan'], commands) - elif have.get('voice') and want.get('voice'): - if have.get('voice').get('vlan') != want.get('voice').get('vlan'): - remove_command_from_config_list(interface, L2_Interfaces.voice_cmds['voice_vlan'], commands) - - if have.get('trunk') and want.get('trunk') is None: - # Check when no config is passed - if have.get('trunk').get('encapsulation'): - remove_command_from_config_list(interface, self.trunk_cmds['encapsulation'], commands) - if have.get('trunk').get('native_vlan'): - remove_command_from_config_list(interface, self.trunk_cmds['native_vlan'], commands) - if have.get('trunk').get('allowed_vlans'): - remove_command_from_config_list(interface, self.trunk_cmds['allowed_vlans'], commands) - if have.get('trunk').get('pruning_vlans'): - remove_command_from_config_list(interface, self.trunk_cmds['pruning_vlans'], commands) - elif have.get('trunk') and want.get('trunk'): - # Check when config is passed, also used in replaced and override state - if have.get('trunk').get('encapsulation')\ - and have.get('trunk').get('encapsulation') != want.get('trunk').get('encapsulation'): - remove_command_from_config_list(interface, self.trunk_cmds['encapsulation'], commands) - if have.get('trunk').get('native_vlan') \ - and have.get('trunk').get('native_vlan') != want.get('trunk').get('native_vlan'): - remove_command_from_config_list(interface, self.trunk_cmds['native_vlan'], commands) - if have.get('trunk').get('allowed_vlans') \ - and have.get('trunk').get('allowed_vlans') != want.get('trunk').get('allowed_vlans'): - remove_command_from_config_list(interface, self.trunk_cmds['allowed_vlans'], commands) - if have.get('trunk').get('pruning_vlans') \ - and have.get('trunk').get('pruning_vlans') != want.get('trunk').get('pruning_vlans'): - remove_command_from_config_list(interface, self.trunk_cmds['pruning_vlans'], commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py deleted file mode 100644 index 221f276ab2..0000000000 --- a/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py +++ /dev/null @@ -1,328 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface -from ansible.module_utils.network.ios.utils.utils import validate_n_expand_ipv4, validate_ipv6 - - -class L3_Interfaces(ConfigBase): - """ - The ios_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 - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - if state == 'overridden': - commands = self._state_overridden(want, have, self._module) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have, self._module) - elif state == 'replaced': - commands = self._state_replaced(want, have, self._module) - - return commands - - def _state_replaced(self, want, have, module): - """ 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: - for each in have: - if each['name'] == interface['name']: - break - else: - if '.' in interface['name']: - commands.extend(self._set_config(interface, dict(), module)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_overridden(self, want, have, module): - """ 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 each in have: - for interface in want: - if each['name'] == interface['name']: - break - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - interface = dict(name=each['name']) - kwargs = {'want': interface, 'have': each} - commands.extend(self._clear_config(**kwargs)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_merged(self, want, have, module): - """ 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: - for each in have: - if each['name'] == interface['name']: - break - else: - if '.' in interface['name']: - commands.extend(self._set_config(interface, dict(), module)) - continue - commands.extend(self._set_config(interface, each, module)) - - return commands - - 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 - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - elif interface['name'] in each['name']: - break - else: - continue - interface = dict(name=interface['name']) - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - want = dict() - commands.extend(self._clear_config(want, each)) - - return commands - - def verify_diff_again(self, want, have): - """ - Verify the IPV4 difference again as sometimes due to - change in order of set, set difference may result into change, - when there's actually no difference between want and have - :param want: want_dict IPV4 - :param have: have_dict IPV4 - :return: diff - """ - diff = False - for each in want: - each_want = dict(each) - for every in have: - every_have = dict(every) - if each_want.get('address') != every_have.get('address') and \ - each_want.get('secondary') != every_have.get('secondary') and \ - len(each_want.keys()) == len(every_have.keys()): - diff = True - break - elif each_want.get('dhcp_client') != every_have.get('dhcp_client') and each_want.get( - 'dhcp_client') is not None: - diff = True - break - elif each_want.get('dhcp_hostname') != every_have.get('dhcp_hostname') and each_want.get( - 'dhcp_hostname') is not None: - diff = True - break - elif each_want.get('address') != every_have.get('address') and len(each_want.keys()) == len( - every_have.keys()): - diff = True - break - if diff: - break - - return diff - - def _set_config(self, want, have, module): - # Set the interface config based on the want and have config - commands = [] - interface = 'interface ' + want['name'] - - # To handle L3 IPV4 configuration - if want.get("ipv4"): - for each in want.get("ipv4"): - if each.get('address') != 'dhcp': - ip_addr_want = validate_n_expand_ipv4(module, each) - each['address'] = ip_addr_want - - # Convert the want and have dict to set - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - - # To handle L3 IPV4 configuration - if want.get('ipv4'): - # Get the diff b/w want and have IPV4 - if have.get('ipv4'): - ipv4 = tuple(set(dict(want_dict).get('ipv4')) - set(dict(have_dict).get('ipv4'))) - if ipv4: - ipv4 = ipv4 if self.verify_diff_again(dict(want_dict).get('ipv4'), dict(have_dict).get('ipv4')) else () - else: - diff = want_dict - have_dict - ipv4 = dict(diff).get('ipv4') - if ipv4: - for each in ipv4: - ipv4_dict = dict(each) - if ipv4_dict.get('address') != 'dhcp': - cmd = "ip address {0}".format(ipv4_dict['address']) - if ipv4_dict.get("secondary"): - cmd += " secondary" - elif ipv4_dict.get('address') == 'dhcp': - cmd = "ip address dhcp" - if ipv4_dict.get('dhcp_client') is not None and ipv4_dict.get('dhcp_hostname'): - cmd = "ip address dhcp client-id GigabitEthernet 0/{0} hostname {1}"\ - .format(ipv4_dict.get('dhcp_client'), ipv4_dict.get('dhcp_hostname')) - elif ipv4_dict.get('dhcp_client') and not ipv4_dict.get('dhcp_hostname'): - cmd = "ip address dhcp client-id GigabitEthernet 0/{0}"\ - .format(ipv4_dict.get('dhcp_client')) - elif not ipv4_dict.get('dhcp_client') and ipv4_dict.get('dhcp_hostname'): - cmd = "ip address dhcp hostname {0}".format(ipv4_dict.get('dhcp_client')) - - add_command_to_config_list(interface, cmd, commands) - - # To handle L3 IPV6 configuration - if want.get('ipv6'): - # Get the diff b/w want and have IPV6 - if have.get('ipv6'): - ipv6 = tuple(set(dict(want_dict).get('ipv6')) - set(dict(have_dict).get('ipv6'))) - else: - diff = want_dict - have_dict - ipv6 = dict(diff).get('ipv6') - if ipv6: - for each in ipv6: - ipv6_dict = dict(each) - validate_ipv6(ipv6_dict.get('address'), module) - cmd = "ipv6 address {0}".format(ipv6_dict.get('address')) - add_command_to_config_list(interface, cmd, commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - count = 0 - commands = [] - if want.get('name'): - interface = 'interface ' + want['name'] - else: - interface = 'interface ' + have['name'] - - if have.get('ipv4') and want.get('ipv4'): - for each in have.get('ipv4'): - if each.get('secondary') and not (want.get('ipv4')[count].get('secondary')): - cmd = 'ipv4 address {0} secondary'.format(each.get('address')) - remove_command_from_config_list(interface, cmd, commands) - count += 1 - if have.get('ipv4') and not want.get('ipv4'): - remove_command_from_config_list(interface, 'ip address', commands) - if have.get('ipv6') and not want.get('ipv6'): - remove_command_from_config_list(interface, 'ipv6 address', commands) - return commands diff --git a/lib/ansible/module_utils/network/ios/config/lacp/lacp.py b/lib/ansible/module_utils/network/ios/config/lacp/lacp.py deleted file mode 100644 index 3f6bc0c0eb..0000000000 --- a/lib/ansible/module_utils/network/ios/config/lacp/lacp.py +++ /dev/null @@ -1,189 +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 ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set - - -class Lacp(ConfigBase): - """ - The ios_lacp class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lacp', - ] - - def __init__(self, module): - super(Lacp, self).__init__(module) - - 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} - commands = list() - warnings = 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'] - 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 in ('merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(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 - - 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 - """ - commands = [] - - commands.extend(self._set_config(want, have)) - - return commands - - 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 - """ - commands = [] - - commands.extend(self._set_config(want, have)) - - return commands - - 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 - """ - commands = [] - - if want: - commands.extend(self._clear_config(have)) - else: - commands.extend(self._clear_config(have)) - - return commands - - def _remove_command_from_config_list(self, cmd, commands): - commands.append('no %s' % cmd) - return commands - - def _add_command_to_config_list(self, cmd, commands): - if cmd not in commands: - commands.append(cmd) - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - cmd = 'lacp system-priority {0}'.format(want.get('system').get('priority')) - self._add_command_to_config_list(cmd, commands) - - return commands - - def _clear_config(self, have): - # Delete the interface config based on the want and have config - commands = [] - - if have.get('system').get('priority') and have.get('system').get('priority') != 32768: - cmd = 'lacp system-priority' - self._remove_command_from_config_list(cmd, commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index 71ac96d0c3..0000000000 --- a/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py +++ /dev/null @@ -1,260 +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 ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface - - -class Lacp_Interfaces(ConfigBase): - """ - The ios_lacp_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lacp_interfaces', - ] - - def __init__(self, module): - super(Lacp_Interfaces, self).__init__(module) - - 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} - commands = list() - warnings = 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 - """ - commands = [] - - state = self._module.params['state'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(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 - - 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 - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - 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 - """ - commands = [] - - for each in have: - for interface in want: - if each['name'] == interface['name']: - break - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - interface = dict(name=each['name']) - commands.extend(self._clear_config(interface, each)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - 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 - """ - commands = [] - - for interface in want: - for each in have: - if interface['name'] == each['name']: - break - else: - continue - commands.extend(self._set_config(interface, each)) - - return commands - - 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 - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - interface = dict(name=interface['name']) - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - commands.extend(self._clear_config(dict(), each)) - - return commands - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - interface = 'interface ' + have['name'] - - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - port_priotity = dict(diff).get('port_priority') - max_bundle = dict(diff).get('max_bundle') - fast_switchover = dict(diff).get('fast_switchover') - if port_priotity: - cmd = 'lacp port-priority {0}'.format(port_priotity) - add_command_to_config_list(interface, cmd, commands) - if max_bundle: - cmd = 'lacp max-bundle {0}'.format(max_bundle) - add_command_to_config_list(interface, cmd, commands) - if fast_switchover: - cmd = 'lacp fast-switchover' - add_command_to_config_list(interface, cmd, commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - commands = [] - if want.get('name'): - interface = 'interface ' + want['name'] - else: - interface = 'interface ' + have['name'] - - if have.get('port_priority') and have.get('port_priority') != want.get('port_priority'): - cmd = 'lacp port-priority' - remove_command_from_config_list(interface, cmd, commands) - if have.get('max_bundle') and have.get('max_bundle') != want.get('max_bundle'): - cmd = 'lacp max-bundle' - remove_command_from_config_list(interface, cmd, commands) - if have.get('fast_switchover'): - cmd = 'lacp fast-switchover' - remove_command_from_config_list(interface, cmd, commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py deleted file mode 100644 index c4760c1061..0000000000 --- a/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,296 +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 ios_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 - - -import re -from ansible.module_utils.network.common import utils -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.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface - - -class Lag_interfaces(ConfigBase): - """ - The ios_lag_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lag_interfaces', - ] - - def __init__(self, module): - super(Lag_interfaces, self).__init__(module) - - 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 in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - module = self._module - if state == 'overridden': - commands = self._state_overridden(want, have, module) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged': - commands = self._state_merged(want, have, module) - elif state == 'replaced': - commands = self._state_replaced(want, have, module) - return commands - - def _state_replaced(self, want, have, module): - """ 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: - for each_interface in interface.get('members'): - for each in have: - if each.get('members'): - for every in each.get('members'): - match = False - if every['member'] == each_interface['member']: - match = True - break - else: - continue - if match: - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - elif each.get('name') == each_interface['member']: - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - break - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_overridden(self, want, have, module): - """ 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 interface in want: - for each_interface in interface.get('members'): - for each in have: - if each.get('members'): - for every in each.get('members'): - match = False - if every['member'] == each_interface['member']: - match = True - break - else: - commands.extend(self._clear_config(interface, each)) - continue - if match: - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - elif each.get('name') == each_interface['member']: - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each, module)) - break - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - def _state_merged(self, want, have, module): - """ 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: - for each_interface in interface.get('members'): - for each in have: - if each.get('members'): - for every in each.get('members'): - if every['member'] == each_interface['member']: - break - elif each.get('name') == each_interface['member']: - break - else: - continue - commands.extend(self._set_config(interface, each, module)) - - return commands - - 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 - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each.get('name') == interface['name']: - break - else: - continue - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - commands.extend(self._clear_config(dict(), each)) - - return commands - - def remove_command_from_config_list(self, interface, cmd, commands): - # To delete the passed config - if interface not in commands: - commands.append(interface) - commands.append('no %s' % cmd) - return commands - - def add_command_to_config_list(self, interface, cmd, commands): - # To set the passed config - if interface not in commands: - commands.append(interface) - commands.append(cmd) - return commands - - def _set_config(self, want, have, module): - # Set the interface config based on the want and have config - commands = [] - - # To remove keys with None values from want dict - want = utils.remove_empties(want) - # Get the diff b/w want and have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - # To get the channel-id from lag port-channel name - lag_config = dict(diff).get('members') - channel_name = re.search(r'(\d+)', want.get('name')) - if channel_name: - channel_id = channel_name.group() - else: - module.fail_json(msg="Lag Interface Name is not correct!") - if lag_config: - for each in lag_config: - each = dict(each) - each_interface = 'interface {0}'.format(each.get('member')) - if have.get('name') == want['members'][0]['member'] or have.get('name').lower().startswith('po'): - if each.get('mode'): - cmd = 'channel-group {0} mode {1}'.format(channel_id, each.get('mode')) - self.add_command_to_config_list(each_interface, cmd, commands) - elif each.get('link'): - cmd = 'channel-group {0} link {1}'.format(channel_id, each.get('link')) - self.add_command_to_config_list(each_interface, cmd, commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - commands = [] - - if have.get('members'): - for each in have['members']: - interface = 'interface ' + each['member'] - if want.get('members'): - if each.get('member') and each.get('member') != want['members'][0]['member']: - self.remove_command_from_config_list(interface, 'channel-group', commands) - elif each.get('member'): - self.remove_command_from_config_list(interface, 'channel-group', commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py deleted file mode 100644 index a3f6dd6091..0000000000 --- a/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py +++ /dev/null @@ -1,238 +0,0 @@ -# -# -*- coding: utf-8 -*- -# Copyright 2019 Red Hat Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -""" -The ios_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 its desired end-state is -created -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -from ansible.module_utils.six import iteritems -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.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value - - -class Lldp_global(ConfigBase): - """ - The ios_lldp_global class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lldp_global', - ] - - tlv_select_params = {'four_wire_power_management': '4-wire-power-management', 'mac_phy_cfg': 'mac-phy-cfg', - 'management_address': 'management-address', 'port_description': 'port-description', - 'port_vlan': 'port-vlan', 'power_management': 'power-management', - 'system_capabilities': 'system-capabilities', 'system_description': 'system-description', - 'system_name': 'system-name'} - - 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 moduel execution - """ - result = {'changed': False} - commands = list() - warnings = 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 deisred configuration - """ - want = self._module.params['config'] - 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 deisred configuration - """ - commands = [] - state = self._module.params['state'] - if state in ('merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(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 - - def _state_replaced(self, want, have): - """ The command generator when state is replaced - - :param want: the desired configuration as a dictionary - :param have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the deisred configuration - """ - commands = [] - - have_dict = filter_dict_having_none_value(want, have) - commands.extend(self._clear_config(have_dict)) - commands.extend(self._set_config(want, have)) - - return commands - - def _state_merged(self, want, have): - """ The command generator when state is merged - - :param want: the additive configuration as a dictionary - :param obj_in_have: the current configuration as a dictionary - :rtype: A list - :returns: the commands necessary to merge the provided into - the current configuration - """ - commands = [] - - commands.extend(self._set_config(want, have)) - - return commands - - def _state_deleted(self, want, have): - """ The command generator when state is deleted - - :param want: the objects from which the configuration should be removed - :param obj_in_have: the current configuration as a dictionary - :param interface_type: interface type - :rtype: A list - :returns: the commands necessary to remove the current configuration - of the provided objects - """ - commands = [] - - commands.extend(self._clear_config(have)) - - return commands - - def _remove_command_from_config_list(self, cmd, commands): - if cmd not in commands: - commands.append('no %s' % cmd) - - def add_command_to_config_list(self, cmd, commands): - if cmd not in commands: - commands.append(cmd) - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - - # Get the diff b/w want and have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - diff = dict(diff) - holdtime = diff.get('holdtime') - enabled = diff.get('enabled') - timer = diff.get('timer') - reinit = diff.get('reinit') - tlv_select = diff.get('tlv_select') - - if holdtime: - cmd = 'lldp holdtime {0}'.format(holdtime) - self.add_command_to_config_list(cmd, commands) - if enabled: - cmd = 'lldp run' - self.add_command_to_config_list(cmd, commands) - if timer: - cmd = 'lldp timer {0}'.format(timer) - self.add_command_to_config_list(cmd, commands) - if reinit: - cmd = 'lldp reinit {0}'.format(reinit) - self.add_command_to_config_list(cmd, commands) - if tlv_select: - tlv_selec_dict = dict(tlv_select) - for k, v in iteritems(self.tlv_select_params): - if k in tlv_selec_dict and tlv_selec_dict[k]: - cmd = 'lldp tlv-select {0}'.format(v) - self.add_command_to_config_list(cmd, commands) - - return commands - - def _clear_config(self, have): - # Delete the interface config based on the want and have config - commands = [] - - if have.get('holdtime'): - cmd = 'lldp holdtime' - self._remove_command_from_config_list(cmd, commands) - if have.get('enabled'): - cmd = 'lldp run' - self._remove_command_from_config_list(cmd, commands) - if have.get('timer'): - cmd = 'lldp timer' - self._remove_command_from_config_list(cmd, commands) - if have.get('reinit'): - cmd = 'lldp reinit' - self._remove_command_from_config_list(cmd, commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index 57a6a3cd4c..0000000000 --- a/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py +++ /dev/null @@ -1,270 +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 ios_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 its 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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set -from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list -from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface - - -class Lldp_Interfaces(ConfigBase): - """ - The ios_lldp_interfaces class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'lldp_interfaces', - ] - - def __init__(self, module): - super(Lldp_Interfaces, self).__init__(module) - - 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} - commands = list() - warnings = 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'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(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 - - 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 - """ - commands = [] - - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - 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 - """ - commands = [] - - for each in have: - for interface in want: - if each['name'] == interface['name']: - break - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - interface = dict(name=each['name']) - commands.extend(self._clear_config(interface, each)) - continue - have_dict = filter_dict_having_none_value(interface, each) - commands.extend(self._clear_config(dict(), have_dict)) - commands.extend(self._set_config(interface, each)) - # Remove the duplicate interface call - commands = remove_duplicate_interface(commands) - - return commands - - 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 - """ - commands = [] - - for interface in want: - for each in have: - if interface['name'] == each['name']: - break - else: - continue - commands.extend(self._set_config(interface, each)) - - return commands - - 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 - """ - commands = [] - - if want: - for interface in want: - for each in have: - if each['name'] == interface['name']: - break - else: - continue - interface = dict(name=interface['name']) - commands.extend(self._clear_config(interface, each)) - else: - for each in have: - commands.extend(self._clear_config(dict(), each)) - - return commands - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - - interface = 'interface ' + have['name'] - # Get the diff b/w want and have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - diff = dict(diff) - receive = diff.get('receive') - transmit = diff.get('transmit') - med_tlv_select = diff.get('med_tlv_select') - tlv_select = diff.get('tlv_select') - if receive: - cmd = 'lldp receive' - add_command_to_config_list(interface, cmd, commands) - elif receive is False: - cmd = 'no lldp receive' - add_command_to_config_list(interface, cmd, commands) - if transmit: - cmd = 'lldp transmit' - add_command_to_config_list(interface, cmd, commands) - elif transmit is False: - cmd = 'no lldp transmit' - add_command_to_config_list(interface, cmd, commands) - - if med_tlv_select: - med_tlv_select = dict(med_tlv_select) - if med_tlv_select.get('inventory_management'): - add_command_to_config_list(interface, 'lldp med-tlv-select inventory-management', commands) - if tlv_select: - tlv_select = dict(tlv_select) - if tlv_select.get('power_management'): - add_command_to_config_list(interface, 'lldp tlv-select power-management', commands) - - return commands - - def _clear_config(self, want, have): - # Delete the interface config based on the want and have config - commands = [] - if want.get('name'): - interface = 'interface ' + want['name'] - else: - interface = 'interface ' + have['name'] - - if have.get('receive') and have.get('receive') != want.get('receive'): - cmd = 'lldp receive' - remove_command_from_config_list(interface, cmd, commands) - if have.get('transmit') and have.get('transmit') != want.get('transmit'): - cmd = 'lldp transmit' - remove_command_from_config_list(interface, cmd, commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py deleted file mode 100644 index 0e3eb4a66b..0000000000 --- a/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py +++ /dev/null @@ -1,532 +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 ios_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 copy -from ansible.module_utils.six import iteritems -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.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import new_dict_to_set, validate_n_expand_ipv4, filter_dict_having_none_value - - -class Static_Routes(ConfigBase): - """ - The ios_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} - commands = list() - warnings = 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: - self._connection.edit_config(commands) - 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': - running_config = self._module.params['running_config'] - if not 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=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 - """ - want = self._module.params['config'] - have = existing_static_routes_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 in ('overridden', 'merged', 'replaced', 'rendered') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - commands = [] - if state == 'overridden': - commands = self._state_overridden(want, have) - elif state == 'deleted': - commands = self._state_deleted(want, have) - elif state == 'merged' or 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 - """ - - commands = [] - - # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call - for w in want: - for addr_want in w.get('address_families'): - for route_want in addr_want.get('routes'): - check = False - for h in have: - if h.get('address_families'): - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - if route_want.get('dest') == route_have.get('dest')\ - and addr_want['afi'] == addr_have['afi']: - check = True - have_set = set() - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - new_dict_to_set(addr_have, [], have_set, 0) - # Check if the have dict next_hops value is diff from want dict next_hops - have_dict = filter_dict_having_none_value(route_want.get('next_hops')[0], - route_have.get('next_hops')[0]) - # update the have_dict with forward_router_address - have_dict.update({'forward_router_address': route_have.get('next_hops')[0]. - get('forward_router_address')}) - # updating the have_dict with next_hops val that's not None - new_have_dict = {} - for k, v in have_dict.items(): - if v is not None: - new_have_dict.update({k: v}) - - # Set the new config from the user provided want config - cmd = self._set_config(w, h, addr_want, route_want, route_have, new_hops, have_set) - - if cmd: - # since inplace update isn't allowed for static routes, preconfigured - # static routes needs to be deleted before the new want static routes changes - # are applied - clear_route_have = copy.deepcopy(route_have) - # inplace update is allowed in case of ipv6 static routes, so not deleting it - # before applying the want changes - if ':' not in route_want.get('dest'): - commands.extend(self._clear_config({}, h, {}, addr_have, - {}, clear_route_have)) - commands.extend(cmd) - if check: - break - if check: - break - if not check: - # For configuring any non-existing want config - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set())) - commands = [each for each in commands if 'no' in each] + \ - [each for each in commands if 'no' not in each] - - return commands - - 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 - """ - - commands = [] - # Creating a copy of want, so that want dict is intact even after delete operation - # performed during override want n have comparison - temp_want = copy.deepcopy(want) - - # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call - for h in have: - if h.get('address_families'): - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - check = False - for w in temp_want: - for addr_want in w.get('address_families'): - count = 0 - for route_want in addr_want.get('routes'): - if route_want.get('dest') == route_have.get('dest') \ - and addr_want['afi'] == addr_have['afi']: - check = True - have_set = set() - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - new_dict_to_set(addr_have, [], have_set, 0) - commands.extend(self._clear_config(w, h, addr_want, addr_have, - route_want, route_have)) - commands.extend(self._set_config(w, h, addr_want, - route_want, route_have, new_hops, have_set)) - del addr_want.get('routes')[count] - count += 1 - if check: - break - if check: - break - if not check: - commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have)) - # For configuring any non-existing want config - for w in temp_want: - for addr_want in w.get('address_families'): - for route_want in addr_want.get('routes'): - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set())) - # Arranging the cmds suct that all delete cmds are fired before all set cmds - commands = [each for each in sorted(commands) if 'no' in each] + \ - [each for each in sorted(commands) if 'no' not in each] - - return commands - - 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 - """ - commands = [] - - # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call - for w in want: - for addr_want in w.get('address_families'): - for route_want in addr_want.get('routes'): - check = False - for h in have: - if h.get('address_families'): - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - if route_want.get('dest') == route_have.get('dest')\ - and addr_want['afi'] == addr_have['afi']: - check = True - have_set = set() - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - new_dict_to_set(addr_have, [], have_set, 0) - commands.extend(self._set_config(w, h, addr_want, - route_want, route_have, new_hops, have_set)) - if check: - break - if check: - break - if not check: - # For configuring any non-existing want config - new_hops = [] - for each in route_want.get('next_hops'): - want_set = set() - new_dict_to_set(each, [], want_set, 0) - new_hops.append(want_set) - commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set())) - - return commands - - 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 - """ - commands = [] - - if want: - # Drill each iteration of want n have and then based on dest and afi type comparison fire delete config call - for w in want: - if w.get('address_families'): - for addr_want in w.get('address_families'): - for route_want in addr_want.get('routes'): - check = False - for h in have: - if h.get('address_families'): - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - if route_want.get('dest') == route_have.get('dest') \ - and addr_want['afi'] == addr_have['afi']: - check = True - if route_want.get('next_hops'): - commands.extend(self._clear_config({}, w, {}, addr_want, {}, route_want)) - else: - commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have)) - if check: - break - if check: - break - else: - for h in have: - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - if w.get('vrf') == h.get('vrf'): - commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have)) - else: - # Drill each iteration of have and then based on dest and afi type comparison fire delete config call - for h in have: - for addr_have in h.get('address_families'): - for route_have in addr_have.get('routes'): - commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have)) - - return commands - - def prepare_config_commands(self, config_dict, cmd): - """ - function to parse the input dict and form the prepare the config commands - :rtype: A str - :returns: The command necessary to configure the static routes - """ - - dhcp = config_dict.get('dhcp') - distance_metric = config_dict.get('distance_metric') - forward_router_address = config_dict.get('forward_router_address') - global_route_config = config_dict.get('global') - interface = config_dict.get('interface') - multicast = config_dict.get('multicast') - name = config_dict.get('name') - permanent = config_dict.get('permanent') - tag = config_dict.get('tag') - track = config_dict.get('track') - dest = config_dict.get('dest') - temp_dest = dest.split('/') - if temp_dest and ':' not in dest: - dest = validate_n_expand_ipv4(self._module, {'address': dest}) - - cmd = cmd + dest - if interface: - cmd = cmd + ' {0}'.format(interface) - if forward_router_address: - cmd = cmd + ' {0}'.format(forward_router_address) - if dhcp: - cmd = cmd + ' DHCP' - if distance_metric: - cmd = cmd + ' {0}'.format(distance_metric) - if global_route_config: - cmd = cmd + ' global' - if multicast: - cmd = cmd + ' multicast' - if name: - cmd = cmd + ' name {0}'.format(name) - if permanent: - cmd = cmd + ' permanent' - elif track: - cmd = cmd + ' track {0}'.format(track) - if tag: - cmd = cmd + ' tag {0}'.format(tag) - - return cmd - - def _set_config(self, want, have, addr_want, route_want, route_have, hops, have_set): - """ - Set the interface config based on the want and have config - :rtype: A list - :returns: The commands necessary to configure the static routes - """ - - commands = [] - cmd = None - - vrf_diff = False - topology_diff = False - want_vrf = want.get('vrf') - have_vrf = have.get('vrf') - if want_vrf != have_vrf: - vrf_diff = True - want_topology = want.get('topology') - have_topology = have.get('topology') - if want_topology != have_topology: - topology_diff = True - - have_dest = route_have.get('dest') - if have_dest: - have_set.add(tuple(iteritems({'dest': have_dest}))) - - # configure set cmd for each hops under the same destination - for each in hops: - diff = each - have_set - if vrf_diff: - each.add(tuple(iteritems({'vrf': want_vrf}))) - if topology_diff: - each.add(tuple(iteritems({'topology': want_topology}))) - if diff or vrf_diff or topology_diff: - if want_vrf and not vrf_diff: - each.add(tuple(iteritems({'vrf': want_vrf}))) - if want_topology and not vrf_diff: - each.add(tuple(iteritems({'topology': want_topology}))) - each.add(tuple(iteritems({'afi': addr_want.get('afi')}))) - each.add(tuple(iteritems({'dest': route_want.get('dest')}))) - temp_want = {} - for each_want in each: - temp_want.update(dict(each_want)) - - if temp_want.get('afi') == 'ipv4': - cmd = 'ip route ' - vrf = temp_want.get('vrf') - if vrf: - cmd = cmd + 'vrf {0} '.format(vrf) - cmd = self.prepare_config_commands(temp_want, cmd) - elif temp_want.get('afi') == 'ipv6': - cmd = 'ipv6 route ' - cmd = self.prepare_config_commands(temp_want, cmd) - commands.append(cmd) - - return commands - - def _clear_config(self, want, have, addr_want, addr_have, route_want, route_have): - """ - Delete the interface config based on the want and have config - :rtype: A list - :returns: The commands necessary to configure the static routes - """ - - commands = [] - cmd = None - - vrf_diff = False - topology_diff = False - want_vrf = want.get('vrf') - have_vrf = have.get('vrf') - if want_vrf != have_vrf: - vrf_diff = True - want_topology = want.get('topology') - have_topology = have.get('topology') - if want_topology != have_topology: - topology_diff = True - - want_set = set() - new_dict_to_set(addr_want, [], want_set, 0) - - have_hops = [] - for each in route_have.get('next_hops'): - temp_have_set = set() - new_dict_to_set(each, [], temp_have_set, 0) - have_hops.append(temp_have_set) - - # configure delete cmd for each hops under the same destination - for each in have_hops: - diff = each - want_set - if vrf_diff: - each.add(tuple(iteritems({'vrf': have_vrf}))) - if topology_diff: - each.add(tuple(iteritems({'topology': want_topology}))) - if diff or vrf_diff or topology_diff: - if want_vrf and not vrf_diff: - each.add(tuple(iteritems({'vrf': want_vrf}))) - if want_topology and not vrf_diff: - each.add(tuple(iteritems({'topology': want_topology}))) - if addr_want: - each.add(tuple(iteritems({'afi': addr_want.get('afi')}))) - else: - each.add(tuple(iteritems({'afi': addr_have.get('afi')}))) - if route_want: - each.add(tuple(iteritems({'dest': route_want.get('dest')}))) - else: - each.add(tuple(iteritems({'dest': route_have.get('dest')}))) - temp_want = {} - for each_want in each: - temp_want.update(dict(each_want)) - - if temp_want.get('afi') == 'ipv4': - cmd = 'no ip route ' - vrf = temp_want.get('vrf') - if vrf: - cmd = cmd + 'vrf {0} '.format(vrf) - cmd = self.prepare_config_commands(temp_want, cmd) - elif temp_want.get('afi') == 'ipv6': - cmd = 'no ipv6 route ' - cmd = self.prepare_config_commands(temp_want, cmd) - commands.append(cmd) - - return commands diff --git a/lib/ansible/module_utils/network/ios/config/vlans/vlans.py b/lib/ansible/module_utils/network/ios/config/vlans/vlans.py deleted file mode 100644 index d77e298770..0000000000 --- a/lib/ansible/module_utils/network/ios/config/vlans/vlans.py +++ /dev/null @@ -1,292 +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 ios_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 -from ansible.module_utils.network.ios.facts.facts import Facts -from ansible.module_utils.network.ios.utils.utils import dict_to_set - - -class Vlans(ConfigBase): - """ - The ios_vlans class - """ - - gather_subset = [ - '!all', - '!min', - ] - - gather_network_resources = [ - 'vlans', - ] - - def __init__(self, module): - super(Vlans, self).__init__(module) - - 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('vlans') - 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'] - if state in ('overridden', 'merged', 'replaced') and not want: - self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state)) - - if state == 'overridden': - commands = self._state_overridden(want, have, state) - elif state == 'deleted': - commands = self._state_deleted(want, have, state) - elif state == 'merged': - 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 - """ - commands = [] - - check = False - for each in want: - for every in have: - if every['vlan_id'] == each['vlan_id']: - check = True - break - else: - continue - if check: - commands.extend(self._set_config(each, every)) - else: - commands.extend(self._set_config(each, dict())) - - return commands - - def _state_overridden(self, want, have, state): - """ The command generator when state is overridden - - :rtype: A list - :returns: the commands necessary to migrate the current configuration - to the desired configuration - """ - commands = [] - - want_local = want - for each in have: - count = 0 - for every in want_local: - if each['vlan_id'] == every['vlan_id']: - break - count += 1 - else: - # We didn't find a matching desired state, which means we can - # pretend we received an empty desired state. - commands.extend(self._clear_config(every, each, state)) - continue - commands.extend(self._set_config(every, each)) - # as the pre-existing VLAN are now configured by - # above set_config call, deleting the respective - # VLAN entry from the want_local list - del want_local[count] - - # Iterating through want_local list which now only have new VLANs to be - # configured - for each in want_local: - commands.extend(self._set_config(each, dict())) - - return commands - - 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 - """ - commands = [] - - check = False - for each in want: - for every in have: - if each.get('vlan_id') == every.get('vlan_id'): - check = True - break - else: - continue - if check: - commands.extend(self._set_config(each, every)) - else: - commands.extend(self._set_config(each, dict())) - - return commands - - def _state_deleted(self, want, have, state): - """ 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 want: - check = False - for each in want: - for every in have: - if each.get('vlan_id') == every.get('vlan_id'): - check = True - break - else: - check = False - continue - if check: - commands.extend(self._clear_config(each, every, state)) - else: - for each in have: - commands.extend(self._clear_config(dict(), each, state)) - - return commands - - def remove_command_from_config_list(self, vlan, cmd, commands): - if vlan not in commands and cmd != 'vlan': - commands.insert(0, vlan) - elif cmd == 'vlan': - commands.append('no %s' % vlan) - return commands - commands.append('no %s' % cmd) - return commands - - def add_command_to_config_list(self, vlan_id, cmd, commands): - if vlan_id not in commands: - commands.insert(0, vlan_id) - if cmd not in commands: - commands.append(cmd) - - def _set_config(self, want, have): - # Set the interface config based on the want and have config - commands = [] - vlan = 'vlan {0}'.format(want.get('vlan_id')) - - # Get the diff b/w want n have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) - diff = want_dict - have_dict - - if diff: - name = dict(diff).get('name') - state = dict(diff).get('state') - shutdown = dict(diff).get('shutdown') - mtu = dict(diff).get('mtu') - remote_span = dict(diff).get('remote_span') - if name: - cmd = 'name {0}'.format(name) - self.add_command_to_config_list(vlan, cmd, commands) - if state: - cmd = 'state {0}'.format(state) - self.add_command_to_config_list(vlan, cmd, commands) - if mtu: - cmd = 'mtu {0}'.format(mtu) - self.add_command_to_config_list(vlan, cmd, commands) - if remote_span: - self.add_command_to_config_list(vlan, 'remote-span', commands) - if shutdown == 'enabled': - self.add_command_to_config_list(vlan, 'shutdown', commands) - elif shutdown == 'disabled': - self.add_command_to_config_list(vlan, 'no shutdown', commands) - - return commands - - def _clear_config(self, want, have, state): - # Delete the interface config based on the want and have config - commands = [] - vlan = 'vlan {0}'.format(have.get('vlan_id')) - - if have.get('vlan_id') and 'default' not in have.get('name')\ - and (have.get('vlan_id') != want.get('vlan_id') or state == 'deleted'): - self.remove_command_from_config_list(vlan, 'vlan', commands) - elif 'default' not in have.get('name'): - if have.get('mtu') != want.get('mtu'): - self.remove_command_from_config_list(vlan, 'mtu', commands) - if have.get('remote_span') != want.get('remote_span') and want.get('remote_span'): - self.remove_command_from_config_list(vlan, 'remote-span', commands) - if have.get('shutdown') != want.get('shutdown') and want.get('shutdown'): - self.remove_command_from_config_list(vlan, 'shutdown', commands) - if have.get('state') != want.get('state') and want.get('state'): - self.remove_command_from_config_list(vlan, 'state', commands) - - return commands diff --git a/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py deleted file mode 100644 index c80939aeba..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py +++ /dev/null @@ -1,122 +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 ios_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.ios.utils.utils import get_interface_type -from ansible.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import Acl_InterfacesArgs - - -class Acl_InterfacesFacts(object): - """ The ios_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_acl_interfaces_data(self, connection): - return connection.get('sh running-config | include interface|ip access-group|ipv6 traffic-filter') - - 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 conf - :rtype: dictionary - :returns: facts - """ - objs = [] - - if not data: - data = self.get_acl_interfaces_data(connection) - # operate on a collection of resource x - config = data.split('interface ') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - - facts = {} - if objs: - facts['acl_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - - for cfg in params['config']: - facts['acl_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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - config['name'] = intf - config['access_groups'] = [] - acl_v4_config = {} - acl_v6_config = {} - - def common_iter_code(cmd, conf): - # Common code for IPV4 and IPV6 config parsing - acls = [] - re_cmd = cmd + ' (\\S+.*)' - ip_all = re.findall(re_cmd, conf) - for each in ip_all: - acl = {} - access_grp_config = each.split(' ') - acl['name'] = access_grp_config[0] - acl['direction'] = access_grp_config[1] - acls.append(acl) - return acls - - if 'ip' in conf: - acls = common_iter_code('ip access-group', conf) - acl_v4_config['afi'] = 'ipv4' - acl_v4_config['acls'] = acls - config['access_groups'].append(acl_v4_config) - if 'ipv6' in conf: - acls = common_iter_code('ipv6 traffic-filter', conf) - acl_v6_config['afi'] = 'ipv6' - acl_v6_config['acls'] = acls - config['access_groups'].append(acl_v6_config) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/acls/acls.py b/lib/ansible/module_utils/network/ios/facts/acls/acls.py deleted file mode 100644 index 3b99a18f5c..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/acls/acls.py +++ /dev/null @@ -1,498 +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 ios_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 - - -from copy import deepcopy -import re -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.utils.utils import check_n_return_valid_ipv6_addr -from ansible.module_utils.network.ios.argspec.acls.acls import AclsArgs - - -class AclsFacts(object): - """ The ios_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_acl_data(self, connection): - # Get the access-lists from the ios router - return connection.get('sh 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_acl_data(connection) - # operate on a collection of resource x - config = data.split('\n') - spec = {'acls': list(), 'afi': None} - if config: - objs = self.render_config(spec, config) - # check if rendered config list has only empty dict - if len(objs) == 1 and objs[0] == {}: - objs = [] - 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 create_config_dict(self, config): - """ Function that parse the acls config and convert to module usable config - :param config: config - :rtype: A dict - :returns: the config generated based on have config params - """ - conf = {} - temp_list = [] - access_list_name = '' - count = 0 - if len(config) >= 1 and config[0] != '': - for each in config: - if 'access-list' in each: - temp = each.split('access-list ')[1].split(' ')[0] - if temp == 'extended' or temp == 'standard': - temp = each.split('access-list ')[1] - if not access_list_name: - access_list_name = temp - if 'access-list' not in each: - if 'extended' in temp or 'standard' in temp: - temp_list.append('ipv4 access-list ' + temp + each) - else: - temp_list.append('ipv6 access-list ' + temp + each) - if temp == access_list_name and 'access-list' in each and \ - not ('extended' in access_list_name or 'standard' in access_list_name): - temp_list.append(each) - elif temp != access_list_name: - conf[access_list_name] = temp_list - temp_list = list() - if 'permit' in each or 'deny' in each: - temp_list.append(each) - access_list_name = temp - count += 1 - if len(config) == count: - conf[access_list_name] = temp_list - temp_list = [] - return conf - - def populate_port_protocol(self, source, destination, each_list): - """ Function Populates port portocol wrt to source and destination - :param acls: source config - :param config: destination config - :param each_list: config - :rtype: A list - :returns: the commands generated based on source and destination params - """ - operators = ['eq', 'gt', 'lt', 'neq', 'range'] - for item in operators: - if item in each_list: - index = each_list.index(item) - if source.get('address') or source.get('any') or source.get('host') and not source.get('port_protocol'): - try: - source_index = each_list.index(source.get('address')) - except ValueError: - try: - source_index = each_list.index('any') - except ValueError: - source_index = each_list.index('host') - if source.get('address'): - if (source_index + 2) == index and 'ipv6' not in each_list: - source['port_protocol'] = {item: each_list[index + 1]} - each_list.remove(item) - del each_list[index] - elif (source_index + 1) == index and 'ipv6' in each_list: - source['port_protocol'] = {item: each_list[index + 1]} - each_list.remove(item) - del each_list[source_index] - del each_list[index - 1] - elif source.get('any'): - if (source_index + 1) == index: - source['port_protocol'] = {item: each_list[index + 1]} - each_list.remove(item) - del each_list[index - 1] - del each_list[source_index] - elif source.get('host'): - if (source_index + 1) == index: - source['port_protocol'] = {item: each_list[index + 1]} - each_list.remove(item) - del each_list[index - 1] - del each_list[source_index] - if destination.get('address') or destination.get('any') or destination.get('host'): - try: - destination_index = each_list.index(destination.get('address')) - except ValueError: - try: - destination_index = each_list.index('any') - except ValueError: - destination_index = each_list.index('host') + 1 - index -= 1 - if (destination_index + 1) == index or (destination_index + 2) == index: - destination['port_protocol'] = {item: each_list[index + 1]} - each_list.remove(item) - del each_list[index] - break - if 'eq' in each_list or 'gt' in each_list or 'lt' in each_list or 'neq' in each_list or 'range' in each_list: - self.populate_port_protocol(source, destination, each_list) - - def populate_source_destination(self, each, config, source, destination): - any = [] - if 'any' in each: - any = re.findall('any', each) - if len(any) == 2: - source['any'] = True - destination['any'] = True - elif 'host' in each: - host = re.findall('host', each) - each = each.split(' ') - if len(host) == 2: - host_index = each.index('host') - source['host'] = each[host_index + 1] - del each[host_index] - host_index = each.index('host') - destination['host'] = each[host_index + 1] - else: - ip_n_wildcard_bits = re.findall(r'[0-9]+(?:\.[0-9]+){3}', each) - ip_index = None - if ip_n_wildcard_bits: - ip_index = each.index(ip_n_wildcard_bits[0]) - host_index = each.index('host') - if ip_index: - if host_index < ip_index: - source['host'] = each(host_index + 1) - destination['address'] = ip_n_wildcard_bits[0] - destination['wildcard_bits'] = ip_n_wildcard_bits[1] - elif host_index > ip_index: - destination['host'] = each(host_index + 1) - source['address'] = ip_n_wildcard_bits[0] - source['wildcard_bits'] = ip_n_wildcard_bits[1] - else: - if config['afi'] == 'ipv4': - ip_n_wildcard_bits = re.findall(r'[0-9]+(?:\.[0-9]+){3}', each) - each = each.split(' ') - if len(ip_n_wildcard_bits) == 0 and len(any) == 1: - source['any'] = True - elif len(ip_n_wildcard_bits) == 1: - source['address'] = ip_n_wildcard_bits[0] - elif len(ip_n_wildcard_bits) == 2: - if 'any' in each: - if each.index('any') > each.index(ip_n_wildcard_bits[0]): - source['address'] = ip_n_wildcard_bits[0] - source['wildcard_bits'] = ip_n_wildcard_bits[1] - destination['any'] = True - elif each.index('any') < each.index(ip_n_wildcard_bits[0]): - source['any'] = True - destination['address'] = ip_n_wildcard_bits[0] - destination['wildcard_bits'] = ip_n_wildcard_bits[1] - else: - source['address'] = ip_n_wildcard_bits[0] - source['wildcard_bits'] = ip_n_wildcard_bits[1] - elif len(ip_n_wildcard_bits) == 4: - source['address'] = ip_n_wildcard_bits[0] - source['wildcard_bits'] = ip_n_wildcard_bits[1] - destination['address'] = ip_n_wildcard_bits[2] - destination['wildcard_bits'] = ip_n_wildcard_bits[3] - elif config['afi'] == 'ipv6': - temp_ipv6 = [] - each = each.split(' ') - check_n_return_valid_ipv6_addr(self._module, each, temp_ipv6) - count = 0 - for every in each: - if len(temp_ipv6) == 2: - if temp_ipv6[0] in every or temp_ipv6[1] in every: - temp_ipv6[count] = every - count += 1 - elif len(temp_ipv6) == 1: - if temp_ipv6[0] in every: - temp_ipv6[count] = every - if 'any' in each: - if each.index('any') > each.index(temp_ipv6[0]): - source['address'] = temp_ipv6[0] - destination['any'] = True - elif each.index('any') < each.index(temp_ipv6[0]): - source['any'] = True - destination['address'] = temp_ipv6[0] - elif len(temp_ipv6) == 2: - source['address'] = temp_ipv6[0] - destination['address'] = temp_ipv6[1] - - def parsed_config_facts(self, have_config): - """ - For parsed config have_config is string of commands which - need to be splitted before passing it through render_config - from spec for null values - :param have_config: The configuration - :rtype: list of have config - :returns: The splitted generated config - """ - split_config = re.split('ip|ipv6 access-list', have_config[0]) - temp_config = [] - - # common piece of code for populating the temp_config list - def common_config_code(each, grant, temp_config): - temp = re.split(grant, each) - temp_config.append(temp[0]) - temp_config.extend([grant + item for item in temp if 'access-list' not in item]) - - for each in split_config: - if 'v6' in each: - each = 'ipv6 ' + each.split('v6 ')[1] - if 'permit' in each: - common_config_code(each, 'permit', temp_config) - elif 'deny' in each: - common_config_code(each, 'deny', temp_config) - else: - each = 'ip' + each - if 'permit' in each: - common_config_code(each, 'permit', temp_config) - if 'deny' in each: - common_config_code(each, 'deny', temp_config) - return temp_config - - def render_config(self, spec, have_config): - """ - 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 - """ - - # for parsed scnenario where commands are passed to generate the acls facts - if len(have_config) == 1: - have_config = self.parsed_config_facts(have_config) - - config = deepcopy(spec) - render_config = list() - acls = dict() - aces = list() - temp_name = '' - for each in have_config: - each_list = [val for val in each.split(' ') if val != ''] - if 'IPv6' in each or 'ipv6' in each: - if aces: - config['acls'].append(acls) - ip_config = config - if ip_config.get('acls'): - render_config.append(ip_config) - if not config['afi'] or config['afi'] == 'ipv4': - config = deepcopy(spec) - config['afi'] = 'ipv6' - acls = dict() - aces = list() - elif not config['afi'] and ('IP' in each or 'ip' in each): - config['afi'] = 'ipv4' - if 'access list' in each or 'access-list' in each: - try: - temp_index = each_list.index('list') - name = (each_list[temp_index + 1]) - except ValueError: - name = each_list[-1] - if temp_name != name: - if aces: - config['acls'].append(acls) - acls = dict() - aces = list() - temp_name = name - acls['name'] = name - if 'Extended' in each: - acls['acl_type'] = 'extended' - continue - elif 'Standard' in each: - acls['acl_type'] = 'standard' - continue - ace_options = {} - try: - if config['afi'] == 'ipv4': - if 'deny' in each_list or 'permit' in each_list: - ace_options['sequence'] = int(each_list[0]) - elif config['afi'] == 'ipv6': - if 'sequence' in each_list: - ace_options['sequence'] = int(each_list[each_list.index('sequence') + 1]) - except ValueError: - pass - if utils.parse_conf_arg(each, 'permit'): - ace_options['grant'] = 'permit' - each_list.remove('permit') - elif utils.parse_conf_arg(each, 'deny'): - ace_options['grant'] = 'deny' - each_list.remove('deny') - - protocol_option = ['ahp', 'eigrp', 'esp', 'gre', 'hbh', 'icmp', 'igmp', 'ip', 'ipv6', 'ipinip', 'nos', - 'ospf', 'pcp', 'pim', 'sctp', 'tcp', 'udp'] - tcp_flags = ['ack', 'established', 'fin', 'psh', 'rst', 'syn', 'urg'] - icmp_options = ['administratively_prohibited', 'alternate_address', 'conversion_error', - 'dod_host_prohibited', 'dod_net_prohibited', 'echo', 'echo_reply', - 'general_parameter_problem', 'host_isolated', 'host_precedence_unreachable', - 'host_redirect', 'host_tos_redirect', 'host_tos_unreachable', 'host_unknown', - 'host_unreachable', 'information_reply', 'information_request', 'mask_reply', - 'mask_request', 'mobile_redirect', 'net_redirect', 'net_tos_redirect', - 'net_tos_unreachable', 'net_unreachable', 'network_unknown', 'no_room_for_option', - 'option_missing', 'packet_too_big', 'parameter_problem', 'port_unreachable', - 'precedence_unreachable', 'protocol_unreachable', 'reassembly_timeout', 'redirect', - 'router_advertisement', 'router_solicitation', 'source_quench', 'source_route_failed', - 'time_exceeded', 'timestamp_reply', 'timestamp_request', 'traceroute', 'ttl_exceeded', - 'unreachable'] - igmp_options = ['dvmrp', 'host_query', 'mtrace_resp', 'mtrace_route', 'pim', 'trace', 'v1host_report', - 'v2host_report', 'v2leave_group', 'v3host_report'] - - temp_option = '' - for option in protocol_option: - if option in each_list and 'access' not in each_list[each_list.index(option) + 1]: - temp_option = option - each_list.remove(temp_option) - if temp_option == 'tcp': - temp_flag = [each_flag for each_flag in tcp_flags if each_flag in each] - if temp_flag: - flag = temp_flag[0] - if flag in each_list: - each_list.remove(flag) - temp_flag = flag - if temp_option == 'icmp': - temp_flag = [each_option for each_option in icmp_options if each_option in each] - if temp_flag: - flag = temp_flag[0] - if flag in each_list: - each_list.remove(flag) - temp_flag = flag - if temp_option == 'igmp': - temp_flag = [each_option for each_option in igmp_options if each_option in each] - if temp_flag: - flag = temp_flag[0] - if flag in each_list: - each_list.remove(flag) - temp_flag = flag - break - - dscp = utils.parse_conf_arg(each, 'dscp') - if dscp: - ace_options['dscp'] = dscp.split(' ')[0] - fragments = utils.parse_conf_arg(each, 'fragments') - if fragments: - ace_options['fragments'] = fragments.split(' ')[0] - log = utils.parse_conf_arg(each, 'log') - if log: - ace_options['log'] = log.split(' ')[0] - log_input = utils.parse_conf_arg(each, 'log_input') - if log_input: - ace_options['log_input'] = log_input.split(' ')[0] - option = utils.parse_conf_arg(each, 'option') - if option: - option = option.split(' ')[0] - option_dict = {} - option_dict[option] = True - ace_options['option'] = option_dict - precedence = utils.parse_conf_arg(each, 'precedence') - if precedence: - ace_options['precedence'] = precedence.split(' ')[0] - time_range = utils.parse_conf_arg(each, 'time_range') - if time_range: - ace_options['time_range'] = time_range.split(' ')[0] - tos = utils.parse_conf_arg(each, 'tos') - if tos: - tos_val = dict() - try: - tos_val['service_value'] = int(tos) - except ValueError: - tos = tos.replace('-', '_') - tos_val[tos] = True - ace_options['tos'] = tos_val - ttl = utils.parse_conf_arg(each, 'ttl') - if ttl: - temp_ttl = ttl.split(' ') - ttl = {} - ttl[temp_ttl[0]] = temp_ttl[1] - each_list = [item for item in each_list[:each_list.index('ttl')]] - ace_options['ttl'] = ttl - - source = {} - destination = {} - self.populate_source_destination(each, config, source, destination) - - if source.get('address') and source.get('address') == destination.get('address'): - self._module.fail_json(msg='Source and Destination address cannot be same!') - else: - self.populate_port_protocol(source, destination, each_list) - - if source: - ace_options['source'] = source - if destination: - ace_options['destination'] = destination - if temp_option: - protocol_options = {} - ace_options['protocol'] = temp_option - if temp_option == 'tcp': - tcp = {} - if temp_flag: - tcp[temp_flag] = True - else: - tcp['set'] = True - protocol_options[temp_option] = tcp - elif temp_option == 'icmp': - icmp = dict() - if temp_flag: - icmp[temp_flag] = True - else: - icmp['set'] = True - protocol_options[temp_option] = icmp - elif temp_option == 'igmp': - igmp = dict() - if temp_flag: - igmp[temp_flag] = True - else: - igmp['set'] = True - protocol_options[temp_option] = igmp - else: - protocol_options[temp_option] = True - ace_options['protocol_options'] = protocol_options - if ace_options: - aces.append(ace_options) - acls['aces'] = aces - if acls: - if not config.get('acls'): - config['acls'] = list() - config['acls'].append(acls) - - if config not in render_config: - render_config.append(utils.remove_empties(config)) - # delete the populated config - del config - - return render_config diff --git a/lib/ansible/module_utils/network/ios/facts/facts.py b/lib/ansible/module_utils/network/ios/facts/facts.py deleted file mode 100644 index 8d66e87963..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/facts.py +++ /dev/null @@ -1,79 +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 ios -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.ios.facts.interfaces.interfaces import InterfacesFacts -from ansible.module_utils.network.ios.facts.l2_interfaces.l2_interfaces import L2_InterfacesFacts -from ansible.module_utils.network.ios.facts.vlans.vlans import VlansFacts -from ansible.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts -from ansible.module_utils.network.ios.facts.lacp.lacp import LacpFacts -from ansible.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import Lacp_InterfacesFacts -from ansible.module_utils.network.ios.facts.lldp_global.lldp_global import Lldp_globalFacts -from ansible.module_utils.network.ios.facts.lldp_interfaces.lldp_interfaces import Lldp_InterfacesFacts -from ansible.module_utils.network.ios.facts.l3_interfaces.l3_interfaces import L3_InterfacesFacts -from ansible.module_utils.network.ios.facts.acl_interfaces.acl_interfaces import Acl_InterfacesFacts -from ansible.module_utils.network.ios.facts.static_routes.static_routes import Static_RoutesFacts -from ansible.module_utils.network.ios.facts.acls.acls import AclsFacts -from ansible.module_utils.network.ios.facts.legacy.base import Default, Hardware, Interfaces, Config - - -FACT_LEGACY_SUBSETS = dict( - default=Default, - hardware=Hardware, - interfaces=Interfaces, - config=Config -) - -FACT_RESOURCE_SUBSETS = dict( - interfaces=InterfacesFacts, - l2_interfaces=L2_InterfacesFacts, - vlans=VlansFacts, - lag_interfaces=Lag_interfacesFacts, - lacp=LacpFacts, - lacp_interfaces=Lacp_InterfacesFacts, - lldp_global=Lldp_globalFacts, - lldp_interfaces=Lldp_InterfacesFacts, - l3_interfaces=L3_InterfacesFacts, - acl_interfaces=Acl_InterfacesFacts, - static_routes=Static_RoutesFacts, - acls=AclsFacts, -) - - -class Facts(FactsBase): - """ The fact class for ios - """ - - VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys()) - VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys()) - - def __init__(self, module): - super(Facts, self).__init__(module) - - def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None): - """ Collect the facts for ios - :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/ios/facts/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py deleted file mode 100644 index a6802bd2e8..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py +++ /dev/null @@ -1,97 +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 ios 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.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.interfaces.interfaces import InterfacesArgs - - -class InterfacesFacts(object): - """ The ios 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 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 conf - :rtype: dictionary - :returns: facts - """ - objs = [] - - if not data: - data = connection.get('show running-config | section ^interface') - # operate on a collection of resource x - config = data.split('interface ') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {} - - if objs: - facts['interfaces'] = [] - 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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - # populate the facts from the configuration - config['name'] = normalize_interface(intf) - config['description'] = utils.parse_conf_arg(conf, 'description') - config['speed'] = utils.parse_conf_arg(conf, 'speed') - if utils.parse_conf_arg(conf, 'mtu'): - config['mtu'] = int(utils.parse_conf_arg(conf, 'mtu')) - config['duplex'] = utils.parse_conf_arg(conf, 'duplex') - enabled = utils.parse_conf_cmd_arg(conf, 'shutdown', False) - config['enabled'] = enabled if enabled is not None else True - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py deleted file mode 100644 index 8f6ddf2698..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py +++ /dev/null @@ -1,114 +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 ios 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.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import L2_InterfacesArgs - - -class L2_InterfacesFacts(object): - """ The ios 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 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 conf - :rtype: dictionary - :returns: facts - """ - objs = [] - - if not data: - data = connection.get('show running-config | section ^interface') - # operate on a collection of resource x - config = data.split('interface ') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - - facts = {} - if objs: - facts['l2_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['l2_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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - - if intf.upper()[:2] in ('HU', 'FO', 'TW', 'TE', 'GI', 'FA', 'ET', 'PO'): - # populate the facts from the configuration - config['name'] = normalize_interface(intf) - has_mode = utils.parse_conf_arg(conf, 'switchport mode') - if has_mode: - config['mode'] = has_mode - has_access = utils.parse_conf_arg(conf, 'switchport access vlan') - if has_access: - config["access"] = {"vlan": int(has_access)} - - has_voice = utils.parse_conf_arg(conf, 'switchport voice vlan') - if has_voice: - config["voice"] = {"vlan": int(has_voice)} - - trunk = dict() - trunk["encapsulation"] = utils.parse_conf_arg(conf, 'encapsulation') - native_vlan = utils.parse_conf_arg(conf, 'native vlan') - if native_vlan: - trunk["native_vlan"] = int(native_vlan) - allowed_vlan = utils.parse_conf_arg(conf, 'allowed vlan') - if allowed_vlan: - trunk["allowed_vlans"] = allowed_vlan.split(',') - pruning_vlan = utils.parse_conf_arg(conf, 'pruning vlan') - if pruning_vlan: - trunk['pruning_vlans'] = pruning_vlan.split(',') - - config['trunk'] = trunk - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py deleted file mode 100644 index 5afab57b37..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py +++ /dev/null @@ -1,124 +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 ios_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.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import L3_InterfacesArgs - - -class L3_InterfacesFacts(object): - """ The ios 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 conf - :rtype: dictionary - :returns: facts - """ - objs = [] - - if not data: - data = connection.get('show running-config | section ^interface') - # operate on a collection of resource x - config = data.split('interface ') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {} - - if objs: - facts['l3_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['l3_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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - # populate the facts from the configuration - config['name'] = normalize_interface(intf) - - ipv4 = [] - ipv4_all = re.findall(r"ip address (\S+.*)", conf) - for each in ipv4_all: - each_ipv4 = dict() - if 'secondary' not in each and 'dhcp' not in each: - each_ipv4['address'] = each - elif 'secondary' in each: - each_ipv4['address'] = each.split(' secondary')[0] - each_ipv4['secondary'] = True - elif 'dhcp' in each: - each_ipv4['address'] = 'dhcp' - if 'client-id' in each: - each_ipv4['dhcp_client'] = int(each.split(' hostname ')[0].split('/')[-1]) - if 'hostname' in each: - each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1] - if 'client-id' in each and each_ipv4['dhcp_client'] is None: - each_ipv4['dhcp_client'] = int(each.split('/')[-1]) - if 'hostname' in each and not each_ipv4["dhcp_hostname"]: - each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1] - ipv4.append(each_ipv4) - config['ipv4'] = ipv4 - - # Get the configured IPV6 details - ipv6 = [] - ipv6_all = re.findall(r"ipv6 address (\S+)", conf) - for each in ipv6_all: - each_ipv6 = dict() - if 'autoconfig' in each: - each_ipv6['autoconfig'] = True - if 'dhcp' in each: - each_ipv6['dhcp'] = True - each_ipv6['address'] = each.lower() - ipv6.append(each_ipv6) - config['ipv6'] = ipv6 - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py b/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py deleted file mode 100644 index 455460fc94..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py +++ /dev/null @@ -1,83 +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 ios 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 - - -from copy import deepcopy -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.argspec.lacp.lacp import LacpArgs - - -class LacpFacts(object): - """ The ios 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 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 conf - :rtype: dictionary - :returns: facts - """ - if connection: - pass - - if not data: - data = connection.get('show lacp sys-id') - - obj = {} - if data: - lacp_obj = self.render_config(self.generated_spec, data) - if lacp_obj: - obj = lacp_obj - - ansible_facts['ansible_network_resources'].pop('lacp', None) - facts = {} - - params = utils.validate_config(self.argument_spec, {'config': obj}) - 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'] = int(conf.split(',')[0]) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py deleted file mode 100644 index 722557e269..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py +++ /dev/null @@ -1,102 +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 ios_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.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import Lacp_InterfacesArgs - - -class Lacp_InterfacesFacts(object): - """ The ios_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 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 conf - :rtype: dictionary - :returns: facts - """ - if connection: - pass - - objs = [] - if not data: - data = connection.get('show running-config | section ^interface') - # operate on a collection of resource x - config = data.split('interface ') - - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {} - - if objs: - facts['lacp_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['lacp_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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - if get_interface_type(intf) == 'unknown': - return {} - - config['name'] = normalize_interface(intf) - port_priority = utils.parse_conf_arg(conf, 'lacp port-priority') - max_bundle = utils.parse_conf_arg(conf, 'lacp max-bundle') - if port_priority: - config['port_priority'] = int(port_priority) - if 'lacp fast-switchover' in conf: - config['fast_switchover'] = True - if max_bundle: - config['max_bundle'] = int(max_bundle) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py deleted file mode 100644 index e396bb0b51..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py +++ /dev/null @@ -1,118 +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 ios 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 - - -import re -from copy import deepcopy - -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs - - -class Lag_interfacesFacts(object): - """ The ios_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 interfaces - :param connection: the device connection - :param ansible_facts: Facts dictionary - :param data: previously collected conf - :rtype: dictionary - :returns: facts - """ - objs = [] - - if not data: - data = connection.get('show running-config | section ^interface') - # operate on a collection of resource x - config = data.split('interface ') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - if not obj.get('members'): - obj.update({'members': []}) - objs.append(obj) - - # for appending members configured with same channel-group - for each in range(len(objs)): - if each < (len(objs) - 1): - if objs[each]['name'] == objs[each + 1]['name']: - objs[each]['members'].append(objs[each + 1]['members'][0]) - del objs[each + 1] - facts = {} - - if objs: - facts['lag_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - - for cfg in params['config']: - facts['lag_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) - match = re.search(r'^(\S+)', conf) - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - member_config = {} - channel_group = utils.parse_conf_arg(conf, 'channel-group') - if intf.startswith('Gi'): - config['name'] = intf - config['members'] = [] - if channel_group: - channel_group = channel_group.split(' ') - id = channel_group[0] - config['name'] = 'Port-channel{0}'.format(str(id)) - if 'mode' in channel_group: - mode = channel_group[2] - member_config.update({'mode': mode}) - if 'link' in channel_group: - link = channel_group[2] - member_config.update({'link': link}) - if member_config.get('mode') or member_config.get('link'): - member_config['member'] = normalize_interface(intf) - config['members'].append(member_config) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/legacy/base.py b/lib/ansible/module_utils/network/ios/facts/legacy/base.py deleted file mode 100644 index 75a7e9974d..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/legacy/base.py +++ /dev/null @@ -1,380 +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 ios legacy 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 platform -import re - -from ansible.module_utils.network.ios.ios import run_commands, get_capabilities -from ansible.module_utils.network.ios.ios import normalize_interface -from ansible.module_utils.six import iteritems -from ansible.module_utils.six.moves import zip - - -class FactsBase(object): - - COMMANDS = list() - - def __init__(self, module): - self.module = module - self.facts = dict() - self.warnings = list() - self.responses = None - - def populate(self): - self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False) - - def run(self, cmd): - return run_commands(self.module, commands=cmd, check_rc=False) - - -class Default(FactsBase): - - COMMANDS = ['show version'] - - def populate(self): - super(Default, self).populate() - self.facts.update(self.platform_facts()) - data = self.responses[0] - if data: - self.facts['iostype'] = self.parse_iostype(data) - self.facts['serialnum'] = self.parse_serialnum(data) - self.parse_stacks(data) - - def parse_iostype(self, data): - match = re.search(r'\S+(X86_64_LINUX_IOSD-UNIVERSALK9-M)(\S+)', data) - if match: - return "IOS-XE" - else: - return "IOS" - - def parse_serialnum(self, data): - match = re.search(r'board ID (\S+)', data) - if match: - return match.group(1) - - def parse_stacks(self, data): - match = re.findall(r'^Model [Nn]umber\s+: (\S+)', data, re.M) - if match: - self.facts['stacked_models'] = match - - match = re.findall(r'^System [Ss]erial [Nn]umber\s+: (\S+)', data, re.M) - if match: - self.facts['stacked_serialnums'] = match - - 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', - 'show memory statistics' - ] - - def populate(self): - warnings = list() - super(Hardware, self).populate() - data = self.responses[0] - if data: - self.facts['filesystems'] = self.parse_filesystems(data) - self.facts['filesystems_info'] = self.parse_filesystems_info(data) - - data = self.responses[1] - if data: - if 'Invalid input detected' in data: - warnings.append('Unable to gather memory statistics') - else: - processor_line = [l for l in data.splitlines() - if 'Processor' in l].pop() - match = re.findall(r'\s(\d+)\s', processor_line) - if match: - self.facts['memtotal_mb'] = int(match[0]) / 1024 - self.facts['memfree_mb'] = int(match[3]) / 1024 - - def parse_filesystems(self, data): - return re.findall(r'^Directory of (\S+)/', data, re.M) - - def parse_filesystems_info(self, data): - facts = dict() - fs = '' - for line in data.split('\n'): - match = re.match(r'^Directory of (\S+)/', line) - if match: - fs = match.group(1) - facts[fs] = dict() - continue - match = re.match(r'^(\d+) bytes total \((\d+) bytes free\)', line) - if match: - facts[fs]['spacetotal_kb'] = int(match.group(1)) / 1024 - facts[fs]['spacefree_kb'] = int(match.group(2)) / 1024 - return facts - - -class Config(FactsBase): - - COMMANDS = ['show running-config'] - - def populate(self): - super(Config, self).populate() - data = self.responses[0] - if data: - data = re.sub( - r'^Building configuration...\s+Current configuration : \d+ bytes\n', - '', data, flags=re.MULTILINE) - self.facts['config'] = data - - -class Interfaces(FactsBase): - - COMMANDS = [ - 'show interfaces', - 'show ip interface', - 'show ipv6 interface', - 'show lldp', - 'show cdp' - ] - - def populate(self): - super(Interfaces, self).populate() - - self.facts['all_ipv4_addresses'] = list() - self.facts['all_ipv6_addresses'] = list() - self.facts['neighbors'] = {} - - data = self.responses[0] - if data: - interfaces = self.parse_interfaces(data) - self.facts['interfaces'] = self.populate_interfaces(interfaces) - - data = self.responses[1] - if data: - data = self.parse_interfaces(data) - self.populate_ipv4_interfaces(data) - - data = self.responses[2] - if data: - data = self.parse_interfaces(data) - self.populate_ipv6_interfaces(data) - - data = self.responses[3] - lldp_errs = ['Invalid input', 'LLDP is not enabled'] - - if data and not any(err in data for err in lldp_errs): - neighbors = self.run(['show lldp neighbors detail']) - if neighbors: - self.facts['neighbors'].update(self.parse_neighbors(neighbors[0])) - - data = self.responses[4] - cdp_errs = ['CDP is not enabled'] - - if data and not any(err in data for err in cdp_errs): - cdp_neighbors = self.run(['show cdp neighbors detail']) - if cdp_neighbors: - self.facts['neighbors'].update(self.parse_cdp_neighbors(cdp_neighbors[0])) - - def populate_interfaces(self, interfaces): - facts = dict() - for key, value in iteritems(interfaces): - intf = dict() - intf['description'] = self.parse_description(value) - intf['macaddress'] = self.parse_macaddress(value) - - intf['mtu'] = self.parse_mtu(value) - intf['bandwidth'] = self.parse_bandwidth(value) - intf['mediatype'] = self.parse_mediatype(value) - intf['duplex'] = self.parse_duplex(value) - intf['lineprotocol'] = self.parse_lineprotocol(value) - intf['operstatus'] = self.parse_operstatus(value) - intf['type'] = self.parse_type(value) - - facts[key] = intf - return facts - - def populate_ipv4_interfaces(self, data): - for key, value in data.items(): - self.facts['interfaces'][key]['ipv4'] = list() - primary_address = addresses = [] - primary_address = re.findall(r'Internet address is (.+)$', value, re.M) - addresses = re.findall(r'Secondary address (.+)$', value, re.M) - if len(primary_address) == 0: - continue - addresses.append(primary_address[0]) - for address in addresses: - addr, subnet = address.split("/") - ipv4 = dict(address=addr.strip(), subnet=subnet.strip()) - self.add_ip_address(addr.strip(), 'ipv4') - self.facts['interfaces'][key]['ipv4'].append(ipv4) - - def populate_ipv6_interfaces(self, data): - for key, value in iteritems(data): - try: - self.facts['interfaces'][key]['ipv6'] = list() - except KeyError: - self.facts['interfaces'][key] = dict() - self.facts['interfaces'][key]['ipv6'] = list() - addresses = re.findall(r'\s+(.+), subnet', value, re.M) - subnets = re.findall(r', subnet is (.+)$', value, re.M) - for addr, subnet in zip(addresses, subnets): - ipv6 = dict(address=addr.strip(), subnet=subnet.strip()) - self.add_ip_address(addr.strip(), 'ipv6') - self.facts['interfaces'][key]['ipv6'].append(ipv6) - - 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 parse_neighbors(self, neighbors): - facts = dict() - for entry in neighbors.split('------------------------------------------------'): - if entry == '': - continue - intf = self.parse_lldp_intf(entry) - if intf is None: - return facts - intf = normalize_interface(intf) - if intf not in facts: - facts[intf] = list() - fact = dict() - fact['host'] = self.parse_lldp_host(entry) - fact['port'] = self.parse_lldp_port(entry) - facts[intf].append(fact) - return facts - - def parse_cdp_neighbors(self, neighbors): - facts = dict() - for entry in neighbors.split('-------------------------'): - if entry == '': - continue - intf_port = self.parse_cdp_intf_port(entry) - if intf_port is None: - return facts - intf, port = intf_port - if intf not in facts: - facts[intf] = list() - fact = dict() - fact['host'] = self.parse_cdp_host(entry) - fact['port'] = port - facts[intf].append(fact) - return facts - - def parse_interfaces(self, data): - parsed = dict() - key = '' - for line in data.split('\n'): - if len(line) == 0: - continue - elif line[0] == ' ': - parsed[key] += '\n%s' % line - else: - match = re.match(r'^(\S+)', line) - if match: - key = match.group(1) - parsed[key] = line - return parsed - - def parse_description(self, data): - match = re.search(r'Description: (.+)$', data, re.M) - if match: - return match.group(1) - - def parse_macaddress(self, data): - match = re.search(r'Hardware is (?:.*), address is (\S+)', data) - if match: - return match.group(1) - - def parse_ipv4(self, data): - match = re.search(r'Internet address is (\S+)', data) - if match: - addr, masklen = match.group(1).split('/') - return dict(address=addr, masklen=int(masklen)) - - def parse_mtu(self, data): - match = re.search(r'MTU (\d+)', data) - if match: - return int(match.group(1)) - - def parse_bandwidth(self, data): - match = re.search(r'BW (\d+)', data) - if match: - return int(match.group(1)) - - def parse_duplex(self, data): - match = re.search(r'(\w+) Duplex', data, re.M) - if match: - return match.group(1) - - def parse_mediatype(self, data): - match = re.search(r'media type is (.+)$', data, re.M) - if match: - return match.group(1) - - def parse_type(self, data): - match = re.search(r'Hardware is (.+),', data, re.M) - if match: - return match.group(1) - - def parse_lineprotocol(self, data): - match = re.search(r'line protocol is (\S+)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_operstatus(self, data): - match = re.search(r'^(?:.+) is (.+),', data, re.M) - if match: - return match.group(1) - - def parse_lldp_intf(self, data): - match = re.search(r'^Local Intf: (.+)$', data, re.M) - if match: - return match.group(1) - - def parse_lldp_host(self, data): - match = re.search(r'System Name: (.+)$', data, re.M) - if match: - return match.group(1) - - def parse_lldp_port(self, data): - match = re.search(r'Port id: (.+)$', data, re.M) - if match: - return match.group(1) - - def parse_cdp_intf_port(self, data): - match = re.search(r'^Interface: (.+), Port ID \(outgoing port\): (.+)$', data, re.M) - if match: - return match.group(1), match.group(2) - - def parse_cdp_host(self, data): - match = re.search(r'^Device ID: (.+)$', data, re.M) - if match: - return match.group(1) diff --git a/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py deleted file mode 100644 index 1643d52476..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.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 ios 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 - - -from copy import deepcopy -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.argspec.lldp_global.lldp_global import Lldp_globalArgs - - -class Lldp_globalFacts(object): - """ The ios 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 - """ - objs = dict() - if not data: - data = connection.get('show running-config | section ^lldp') - # operate on a collection of resource x - config = data.split('\n') - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.update(obj) - facts = {} - - if objs: - params = utils.validate_config(self.argument_spec, {'config': utils.remove_empties(objs)}) - facts['lldp_global'] = 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) - - holdtime = utils.parse_conf_arg(conf, 'lldp holdtime') - timer = utils.parse_conf_arg(conf, 'lldp timer') - reinit = utils.parse_conf_arg(conf, 'lldp reinit') - if holdtime: - config['holdtime'] = int(holdtime) - if 'lldp run' in conf: - config['enabled'] = True - if timer: - config['timer'] = int(timer) - if reinit: - config['reinit'] = int(reinit) - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py deleted file mode 100644 index f97f87fbc4..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_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 ios_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.ios.utils.utils import get_interface_type, normalize_interface -from ansible.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import Lldp_InterfacesArgs - - -class Lldp_InterfacesFacts(object): - """ The ios_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 conf - :rtype: dictionary - :returns: facts - """ - if connection: - pass - - objs = [] - if not data: - data = connection.get('show lldp interface') - # operate on a collection of resource x - config = data.split('\n\n') - - for conf in config: - if conf: - obj = self.render_config(self.generated_spec, conf) - if obj: - objs.append(obj) - facts = {} - - if objs: - facts['lldp_interfaces'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - for cfg in params['config']: - facts['lldp_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) - match = re.search(r'^(\S+)(:)', conf) - intf = '' - if match: - intf = match.group(1) - - if get_interface_type(intf) == 'unknown': - return {} - if intf.lower().startswith('gi'): - config['name'] = normalize_interface(intf) - receive = utils.parse_conf_arg(conf, 'Rx:') - transmit = utils.parse_conf_arg(conf, 'Tx:') - - if receive == 'enabled': - config['receive'] = True - elif receive == 'disabled': - config['receive'] = False - if transmit == 'enabled': - config['transmit'] = True - elif transmit == 'disabled': - config['transmit'] = False - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py deleted file mode 100644 index f7ada0b3f5..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.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 ios_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 - - -from copy import deepcopy -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.utils.utils import netmask_to_cidr -from ansible.module_utils.network.ios.argspec.static_routes.static_routes import Static_RoutesArgs - - -class Static_RoutesFacts(object): - """ The ios_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_static_routes_data(self, connection): - return connection.get('sh running-config | include ip route|ipv6 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 - """ - - objs = [] - if not data: - data = self.get_static_routes_data(connection) - # operate on a collection of resource x - config = data.split('\n') - - same_dest = self.populate_destination(config) - for key in same_dest.keys(): - if key: - obj = self.render_config(self.generated_spec, key, same_dest[key]) - if obj: - objs.append(obj) - facts = {} - - # append all static routes address_family with NO VRF together - no_vrf_address_family = { - 'address_families': [each.get('address_families')[0] for each in objs if each.get('vrf') is None] - } - - temp_objs = [each for each in objs if each.get('vrf') is not None] - temp_objs.append(no_vrf_address_family) - objs = temp_objs - - 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 update_netmask_to_cidr(self, filter, pos, del_pos): - netmask = filter.split(' ') - dest = netmask[pos] + '/' + netmask_to_cidr(netmask[del_pos]) - netmask[pos] = dest - del netmask[del_pos] - filter_vrf = ' ' - return filter_vrf.join(netmask), dest - - def populate_destination(self, config): - same_dest = {} - ip_str = '' - for i in sorted(config): - if i: - if '::' in i and 'vrf' in i: - ip_str = 'ipv6 route vrf' - elif '::' in i and 'vrf' not in i: - ip_str = 'ipv6 route' - elif '.' in i and 'vrf' in i: - ip_str = 'ip route vrf' - elif '.' in i and 'vrf' not in i: - ip_str = 'ip route' - - if 'vrf' in i: - filter_vrf = utils.parse_conf_arg(i, ip_str) - if '/' not in filter_vrf and '::' not in filter_vrf: - filter_vrf, dest_vrf = self.update_netmask_to_cidr(filter_vrf, 1, 2) - dest_vrf = dest_vrf + '_vrf' - else: - dest_vrf = filter_vrf.split(' ')[1] - if dest_vrf not in same_dest.keys(): - same_dest[dest_vrf] = [] - same_dest[dest_vrf].append('vrf ' + filter_vrf) - elif 'vrf' not in same_dest[dest_vrf][0]: - same_dest[dest_vrf] = [] - same_dest[dest_vrf].append('vrf ' + filter_vrf) - else: - same_dest[dest_vrf].append(('vrf ' + filter_vrf)) - else: - filter = utils.parse_conf_arg(i, ip_str) - if '/' not in filter and '::' not in filter: - filter, dest = self.update_netmask_to_cidr(filter, 0, 1) - else: - dest = filter.split(' ')[0] - if dest not in same_dest.keys(): - same_dest[dest] = [] - same_dest[dest].append(filter) - elif 'vrf' in same_dest[dest][0]: - same_dest[dest] = [] - same_dest[dest].append(filter) - else: - same_dest[dest].append(filter) - return same_dest - - def render_config(self, spec, conf, conf_val): - """ - 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['address_families'] = [] - route_dict = dict() - final_route = dict() - afi = dict() - final_route['routes'] = [] - next_hops = [] - hops = {} - vrf = '' - address_family = dict() - for each in conf_val: - route = each.split(' ') - if 'vrf' in conf_val[0]: - vrf = route[route.index('vrf') + 1] - route_dict['dest'] = conf.split('_')[0] - else: - route_dict['dest'] = conf - if 'vrf' in conf_val[0]: - hops = {} - if '::' in conf: - hops['forward_router_address'] = route[3] - afi['afi'] = 'ipv6' - elif '.' in conf: - hops['forward_router_address'] = route[3] - afi['afi'] = "ipv4" - else: - hops['interface'] = conf - else: - - if '::' in conf: - hops['forward_router_address'] = route[1] - afi['afi'] = 'ipv6' - elif '.' in conf: - hops['forward_router_address'] = route[1] - afi['afi'] = "ipv4" - else: - hops['interface'] = route[1] - try: - temp_list = each.split(' ') - if 'tag' in temp_list: - del temp_list[temp_list.index('tag') + 1] - if 'track' in temp_list: - del temp_list[temp_list.index('track') + 1] - # find distance metric - dist_metrics = int( - [i for i in temp_list if '.' not in i and ':' not in i and ord(i[0]) > 48 and ord(i[0]) < 57][0] - ) - except IndexError: - dist_metrics = None - if dist_metrics: - hops['distance_metric'] = dist_metrics - if 'name' in route: - hops['name'] = route[route.index('name') + 1] - if 'multicast' in route: - hops['multicast'] = True - if 'dhcp' in route: - hops['dhcp'] = True - if 'global' in route: - hops['global'] = True - if 'permanent' in route: - hops['permanent'] = True - if 'tag' in route: - hops['tag'] = route[route.index('tag') + 1] - if 'track' in route: - hops['track'] = route[route.index('track') + 1] - next_hops.append(hops) - hops = {} - route_dict['next_hops'] = next_hops - if route_dict: - final_route['routes'].append(route_dict) - address_family.update(afi) - address_family.update(final_route) - config['address_families'].append(address_family) - if vrf: - config['vrf'] = vrf - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py b/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py deleted file mode 100644 index b499be5ce9..0000000000 --- a/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py +++ /dev/null @@ -1,144 +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 ios 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 -from ansible.module_utils.network.common import utils -from ansible.module_utils.network.ios.argspec.vlans.vlans import VlansArgs - - -class VlansFacts(object): - """ The ios 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 connection: - pass - - objs = [] - mtu_objs = [] - remote_objs = [] - final_objs = [] - if not data: - data = connection.get('show vlan') - # operate on a collection of resource x - config = data.split('\n') - # Get individual vlan configs separately - vlan_info = '' - for conf in config: - if 'Name' in conf: - vlan_info = 'Name' - elif 'Type' in conf: - vlan_info = 'Type' - elif 'Remote' in conf: - vlan_info = 'Remote' - if conf and ' ' not in filter(None, conf.split('-')): - obj = self.render_config(self.generated_spec, conf, vlan_info) - if 'mtu' in obj: - mtu_objs.append(obj) - elif 'remote_span' in obj: - remote_objs = obj - elif obj: - objs.append(obj) - # Appending MTU value to the retrieved dictionary - for o, m in zip(objs, mtu_objs): - o.update(m) - final_objs.append(o) - - # Appending Remote Span value to related VLAN: - if remote_objs: - if remote_objs.get('remote_span'): - for each in remote_objs.get('remote_span'): - for every in final_objs: - if each == every.get('vlan_id'): - every.update({'remote_span': True}) - break - - facts = {} - if final_objs: - facts['vlans'] = [] - params = utils.validate_config(self.argument_spec, {'config': objs}) - - for cfg in params['config']: - facts['vlans'].append(utils.remove_empties(cfg)) - ansible_facts['ansible_network_resources'].update(facts) - - return ansible_facts - - def render_config(self, spec, conf, vlan_info): - """ - 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) - - if vlan_info == 'Name' and 'Name' not in conf: - conf = list(filter(None, conf.split(' '))) - config['vlan_id'] = int(conf[0]) - config['name'] = conf[1] - if len(conf[2].split('/')) > 1: - if conf[2].split('/')[0] == 'sus': - config['state'] = 'suspend' - elif conf[2].split('/')[0] == 'act': - config['state'] = 'active' - config['shutdown'] = 'enabled' - else: - if conf[2] == 'suspended': - config['state'] = 'suspend' - elif conf[2] == 'active': - config['state'] = 'active' - config['shutdown'] = 'disabled' - elif vlan_info == 'Type' and 'Type' not in conf: - conf = list(filter(None, conf.split(' '))) - config['mtu'] = int(conf[3]) - elif vlan_info == 'Remote': - if len(conf.split(',')) > 1 or conf.isdigit(): - remote_span_vlan = [] - if len(conf.split(',')) > 1: - remote_span_vlan = conf.split(',') - else: - remote_span_vlan.append(conf) - remote_span = [] - for each in remote_span_vlan: - remote_span.append(int(each)) - config['remote_span'] = remote_span - - return utils.remove_empties(config) diff --git a/lib/ansible/module_utils/network/ios/ios.py b/lib/ansible/module_utils/network/ios/ios.py deleted file mode 100644 index 3e1c680aa3..0000000000 --- a/lib/ansible/module_utils/network/ios/ios.py +++ /dev/null @@ -1,183 +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) 2016 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 - -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import env_fallback -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.connection import Connection, ConnectionError - -_DEVICE_CONFIGS = {} - -ios_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(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True), - 'timeout': dict(type='int') -} -ios_argument_spec = { - 'provider': dict(type='dict', options=ios_provider_spec, removed_in_version=2.14), -} - - -def get_provider_argspec(): - return ios_provider_spec - - -def get_connection(module): - if hasattr(module, '_ios_connection'): - return module._ios_connection - - capabilities = get_capabilities(module) - network_api = capabilities.get('network_api') - if network_api == 'cliconf': - module._ios_connection = Connection(module._socket_path) - else: - module.fail_json(msg='Invalid connection type %s' % network_api) - - return module._ios_connection - - -def get_capabilities(module): - if hasattr(module, '_ios_capabilities'): - return module._ios_capabilities - try: - capabilities = Connection(module._socket_path).get_capabilities() - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - module._ios_capabilities = json.loads(capabilities) - return module._ios_capabilities - - -def get_defaults_flag(module): - connection = get_connection(module) - try: - out = connection.get_defaults_flag() - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - return to_text(out, errors='surrogate_then_replace').strip() - - -def get_config(module, flags=None): - flags = to_list(flags) - - section_filter = False - if flags and 'section' in flags[-1]: - section_filter = True - - flag_str = ' '.join(flags) - - try: - return _DEVICE_CONFIGS[flag_str] - except KeyError: - connection = get_connection(module) - try: - out = connection.get_config(flags=flags) - except ConnectionError as exc: - if section_filter: - # Some ios devices don't understand `| section foo` - out = get_config(module, flags=flags[:-1]) - else: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - cfg = to_text(out, errors='surrogate_then_replace').strip() - _DEVICE_CONFIGS[flag_str] = cfg - return cfg - - -def run_commands(module, commands, check_rc=True): - connection = get_connection(module) - try: - return connection.run_commands(commands=commands, check_rc=check_rc) - except ConnectionError as exc: - module.fail_json(msg=to_text(exc)) - - -def load_config(module, commands): - connection = get_connection(module) - - try: - resp = connection.edit_config(commands) - return resp.get('response') - except ConnectionError as exc: - module.fail_json(msg=to_text(exc)) - - -def normalize_interface(name): - """Return the normalized interface name - """ - if not name: - return - - def _get_number(name): - digits = '' - for char in name: - if char.isdigit() or char in '/.': - digits += char - return digits - - if name.lower().startswith('gi'): - if_type = 'GigabitEthernet' - elif name.lower().startswith('te'): - if_type = 'TenGigabitEthernet' - elif name.lower().startswith('fa'): - if_type = 'FastEthernet' - elif name.lower().startswith('fo'): - if_type = 'FortyGigabitEthernet' - elif name.lower().startswith('et'): - if_type = 'Ethernet' - elif name.lower().startswith('vl'): - if_type = 'Vlan' - elif name.lower().startswith('lo'): - if_type = 'loopback' - elif name.lower().startswith('po'): - if_type = 'port-channel' - elif name.lower().startswith('nv'): - if_type = 'nve' - elif name.lower().startswith('twe'): - if_type = 'TwentyFiveGigE' - elif name.lower().startswith('hu'): - if_type = 'HundredGigE' - else: - if_type = None - - number_list = name.split(' ') - if len(number_list) == 2: - if_number = number_list[-1].strip() - else: - if_number = _get_number(name) - - if if_type: - proper_interface = if_type + if_number - else: - proper_interface = name - - return proper_interface diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/base.py b/lib/ansible/module_utils/network/ios/providers/cli/config/base.py deleted file mode 100644 index eade249a09..0000000000 --- a/lib/ansible/module_utils/network/ios/providers/cli/config/base.py +++ /dev/null @@ -1,77 +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.six import iteritems -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.common.config import NetworkConfig - - -class ConfigBase(object): - - argument_spec = {} - - mutually_exclusive = [] - - identifier = () - - def __init__(self, **kwargs): - self.values = {} - self._rendered_configuration = {} - self.active_configuration = None - - for item in self.identifier: - self.values[item] = kwargs.pop(item) - - for key, value in iteritems(kwargs): - if key in self.argument_spec: - setattr(self, key, value) - - for key, value in iteritems(self.argument_spec): - if value.get('default'): - if not getattr(self, key, None): - setattr(self, key, value.get('default')) - - def __getattr__(self, key): - if key in self.argument_spec: - return self.values.get(key) - - def __setattr__(self, key, value): - if key in self.argument_spec: - if key in self.identifier: - raise TypeError('cannot set value') - elif value is not None: - self.values[key] = value - else: - super(ConfigBase, self).__setattr__(key, value) - - def context_config(self, cmd): - if 'context' not in self._rendered_configuration: - self._rendered_configuration['context'] = list() - self._rendered_configuration['context'].extend(to_list(cmd)) - - def global_config(self, cmd): - if 'global' not in self._rendered_configuration: - self._rendered_configuration['global'] = list() - self._rendered_configuration['global'].extend(to_list(cmd)) - - def get_rendered_configuration(self): - config = list() - for section in ('context', 'global'): - config.extend(self._rendered_configuration.get(section, [])) - return config - - def set_active_configuration(self, config): - self.active_configuration = config - - def render(self, config=None): - raise NotImplementedError - - def get_section(self, config, section): - if config is not None: - netcfg = NetworkConfig(indent=1, contents=config) - try: - config = netcfg.get_block_config(to_list(section)) - except ValueError: - config = None - return config diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py deleted file mode 100644 index 366f6413c1..0000000000 --- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py +++ /dev/null @@ -1,140 +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.ios.providers.providers import CliProvider -from ansible.module_utils.network.ios.providers.cli.config.bgp.neighbors import AFNeighbors -from ansible.module_utils.common.network import to_netmask - - -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'] - if item['safi'] != 'unicast': - context += ' %s' % item['safi'] - context_commands = list() - - if config: - context_path = [router_context, context] - context_config = self.get_config_context(config, context_path, indent=1) - - 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-address-family') - - 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'] - cmd = 'network %s' % network - if entry['masklen']: - cmd += ' mask %s' % to_netmask(entry['masklen']) - network += ' mask %s' % to_netmask(entry['masklen']) - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - network += ' route-map %s' % entry['route_map'] - - safe_list.append(network) - - if not config or cmd not in config: - commands.append(cmd) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'network (.*)', 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['id'] and entry['protocol'] in ('ospf', 'ospfv3', 'eigrp'): - cmd += ' %s' % entry['id'] - option += ' %s' % entry['id'] - - if entry['metric']: - cmd += ' metric %s' % entry['metric'] - - 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/ios/providers/cli/config/bgp/neighbors.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py deleted file mode 100644 index 2cee73382a..0000000000 --- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py +++ /dev/null @@ -1,196 +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.ios.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_local_as(self, item, config=None): - cmd = 'neighbor %s local-as %s' % (item['neighbor'], item['local_as']) - if not config or cmd not in config: - return cmd - - def _render_port(self, item, config=None): - cmd = 'neighbor %s port %s' % (item['neighbor'], item['port']) - if not config or cmd not in config: - return cmd - - 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_timers(self, item, config): - """generate bgp timer related configuration - """ - keepalive = item['timers']['keepalive'] - holdtime = item['timers']['holdtime'] - min_neighbor_holdtime = item['timers']['min_neighbor_holdtime'] - neighbor = item['neighbor'] - - if keepalive and holdtime: - cmd = 'neighbor %s timers %s %s' % (neighbor, keepalive, holdtime) - if min_neighbor_holdtime: - cmd += ' %s' % min_neighbor_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_advertisement_interval(self, item, config=None): - cmd = 'neighbor %s advertisement-interval %s' % (item['neighbor'], item['advertisement_interval']) - 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_route_server_client(self, item, config=None): - cmd = 'neighbor %s route-server-client' % item['neighbor'] - if item['route_server_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_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_next_hop_self(self, item, config=None): - cmd = 'neighbor %s next-hop-self' % item['neighbor'] - if item['next_hop_self'] 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_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_maximum_prefix(self, item, config=None): - cmd = 'neighbor %s maximum-prefix %s' % (item['neighbor'], item['maximum_prefix']) - if not config or cmd not in config: - return cmd - - def _render_prefix_list_in(self, item, config=None): - cmd = 'neighbor %s prefix-list %s in' % (item['neighbor'], item['prefix_list_in']) - if not config or cmd not in config: - return cmd - - def _render_prefix_list_out(self, item, config=None): - cmd = 'neighbor %s prefix-list %s out' % (item['neighbor'], item['prefix_list_out']) - if not config or cmd not in config: - return cmd diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py deleted file mode 100644 index d74cf92773..0000000000 --- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py +++ /dev/null @@ -1,140 +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.ios.providers.providers import register_provider -from ansible.module_utils.network.ios.providers.providers import CliProvider -from ansible.module_utils.network.ios.providers.cli.config.bgp.neighbors import Neighbors -from ansible.module_utils.network.ios.providers.cli.config.bgp.address_family import AddressFamily -from ansible.module_utils.common.network import to_netmask - -REDISTRIBUTE_PROTOCOLS = frozenset(['ospf', 'ospfv3', 'eigrp', 'isis', 'static', 'connected', - 'odr', 'lisp', 'mobile', 'rip']) - - -@register_provider('ios', 'ios_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 = 'bgp 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'] - cmd = 'network %s' % network - if entry['masklen'] and entry['masklen'] not in (24, 16, 8): - cmd += ' mask %s' % to_netmask(entry['masklen']) - network += ' mask %s' % to_netmask(entry['masklen']) - - if entry['route_map']: - cmd += ' route-map %s' % entry['route_map'] - network += ' route-map %s' % entry['route_map'] - - safe_list.append(network) - - if not config or cmd not in config: - commands.append(cmd) - - if self.params['operation'] == 'replace': - if config: - matches = re.findall(r'network (.*)', config, re.M) - for entry in set(matches).difference(safe_list): - commands.append('no network %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=None): - 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': - if address_family and root_networks: - for item in address_family: - if item['networks']: - raise ValueError('operation is replace but provided both root level network(s) and network(s) under %s %s address family' - % (item['afi'], item['safi'])) - - if root_networks and 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/ios/providers/module.py b/lib/ansible/module_utils/network/ios/providers/module.py deleted file mode 100644 index 69c6dd9659..0000000000 --- a/lib/ansible/module_utils/network/ios/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.ios.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/ios/providers/providers.py b/lib/ansible/module_utils/network/ios/providers/providers.py deleted file mode 100644 index a466b033d9..0000000000 --- a/lib/ansible/module_utils/network/ios/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=1): - 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/ios/utils/utils.py b/lib/ansible/module_utils/network/ios/utils/utils.py deleted file mode 100644 index cfcfe82dbc..0000000000 --- a/lib/ansible/module_utils/network/ios/utils/utils.py +++ /dev/null @@ -1,328 +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 - -import socket -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.common.utils import is_masklen, to_netmask - - -def remove_command_from_config_list(interface, cmd, commands): - # To delete the passed config - if interface not in commands: - commands.insert(0, interface) - commands.append('no %s' % cmd) - return commands - - -def add_command_to_config_list(interface, cmd, commands): - # To set the passed config - if interface not in commands: - commands.insert(0, interface) - commands.append(cmd) - - -def check_n_return_valid_ipv6_addr(module, input_list, filtered_ipv6_list): - # To verify the valid ipv6 address - try: - for each in input_list: - if '::' in each: - if '/' in each: - each = each.split('/')[0] - if socket.inet_pton(socket.AF_INET6, each): - filtered_ipv6_list.append(each) - return filtered_ipv6_list - except socket.error: - module.fail_json(msg='Incorrect IPV6 address!') - - -def new_dict_to_set(input_dict, temp_list, test_set, count=0): - # recursive function to convert input dict to set for comparision - test_dict = dict() - if isinstance(input_dict, dict): - input_dict_len = len(input_dict) - for k, v in sorted(iteritems(input_dict)): - count += 1 - if isinstance(v, list): - temp_list.append(k) - for each in v: - if isinstance(each, dict): - if [True for i in each.values() if type(i) == list]: - new_dict_to_set(each, temp_list, test_set, count) - else: - new_dict_to_set(each, temp_list, test_set, 0) - else: - if v is not None: - test_dict.update({k: v}) - try: - if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len: - test_set.add(tuple(iteritems(test_dict))) - count = 0 - except TypeError: - temp_dict = {} - - def expand_dict(dict_to_expand): - temp = dict() - for k, v in iteritems(dict_to_expand): - if isinstance(v, dict): - expand_dict(v) - else: - if v is not None: - temp.update({k: v}) - temp_dict.update(tuple(iteritems(temp))) - new_dict = {k: v} - expand_dict(new_dict) - if tuple(iteritems(temp_dict)) not in test_set: - test_set.add(tuple(iteritems(temp_dict))) - - -def dict_to_set(sample_dict): - # Generate a set with passed dictionary for comparison - test_dict = dict() - if isinstance(sample_dict, dict): - for k, v in iteritems(sample_dict): - if v is not None: - if isinstance(v, list): - if isinstance(v[0], dict): - li = [] - for each in v: - for key, value in iteritems(each): - if isinstance(value, list): - each[key] = tuple(value) - li.append(tuple(iteritems(each))) - v = tuple(li) - else: - v = tuple(v) - elif isinstance(v, dict): - li = [] - for key, value in iteritems(v): - if isinstance(value, list): - v[key] = tuple(value) - li.extend(tuple(iteritems(v))) - v = tuple(li) - test_dict.update({k: v}) - return_set = set(tuple(iteritems(test_dict))) - else: - return_set = set(sample_dict) - return return_set - - -def filter_dict_having_none_value(want, have): - # Generate dict with have dict value which is None in want dict - test_dict = dict() - name = want.get('name') - if name: - test_dict['name'] = name - diff_ip = False - for k, v in iteritems(want): - if isinstance(v, dict): - for key, value in iteritems(v): - test_key_dict = dict() - if value is None: - dict_val = have.get(k).get(key) - test_key_dict.update({key: dict_val}) - elif k == 'ipv6' and value.lower() != have.get(k)[0].get(key).lower(): - # as multiple IPV6 address can be configured on same - # interface, for replace state in place update will - # actually create new entry, which isn't as expected - # for replace state, so in case of IPV6 address - # every time 1st delete the existing IPV6 config and - # then apply the new change - dict_val = have.get(k)[0].get(key) - test_key_dict.update({key: dict_val}) - if test_key_dict: - test_dict.update({k: test_key_dict}) - if isinstance(v, list): - for key, value in iteritems(v[0]): - test_key_dict = dict() - if value is None: - dict_val = have.get(k).get(key) - test_key_dict.update({key: dict_val}) - elif k == 'ipv6' and value.lower() != have.get(k)[0].get(key).lower(): - dict_val = have.get(k)[0].get(key) - test_key_dict.update({key: dict_val}) - if test_key_dict: - test_dict.update({k: test_key_dict}) - # below conditions checks are added to check if - # secondary IP is configured, if yes then delete - # the already configured IP if want and have IP - # is different else if it's same no need to delete - for each in v: - if each.get('secondary'): - want_ip = each.get('address').split('/') - have_ip = have.get('ipv4') - if len(want_ip) > 1 and have_ip and have_ip[0].get('secondary'): - have_ip = have_ip[0]['address'].split(' ')[0] - if have_ip != want_ip[0]: - diff_ip = True - if each.get('secondary') and diff_ip is True: - test_key_dict.update({'secondary': True}) - test_dict.update({'ipv4': test_key_dict}) - if v is None: - val = have.get(k) - test_dict.update({k: val}) - return test_dict - - -def remove_duplicate_interface(commands): - # Remove duplicate interface from commands - set_cmd = [] - for each in commands: - if 'interface' in each: - if each not in set_cmd: - set_cmd.append(each) - else: - set_cmd.append(each) - - return set_cmd - - -def validate_ipv4(value, module): - if value: - address = value.split('/') - if len(address) != 2: - module.fail_json(msg='address format is <ipv4 address>/<mask>, got invalid format {0}'.format(value)) - - if not is_masklen(address[1]): - module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-32'.format(address[1])) - - -def validate_ipv6(value, module): - if value: - address = value.split('/') - if len(address) != 2: - module.fail_json(msg='address format is <ipv6 address>/<mask>, got invalid format {0}'.format(value)) - else: - if not 0 <= int(address[1]) <= 128: - module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-128'.format(address[1])) - - -def validate_n_expand_ipv4(module, want): - # Check if input IPV4 is valid IP and expand IPV4 with its subnet mask - ip_addr_want = want.get('address') - if len(ip_addr_want.split(' ')) > 1: - return ip_addr_want - validate_ipv4(ip_addr_want, module) - ip = ip_addr_want.split('/') - if len(ip) == 2: - ip_addr_want = '{0} {1}'.format(ip[0], to_netmask(ip[1])) - - return ip_addr_want - - -def netmask_to_cidr(netmask): - bit_range = [128, 64, 32, 16, 8, 4, 2, 1] - count = 0 - cidr = 0 - netmask_list = netmask.split('.') - netmask_calc = [i for i in netmask_list if int(i) != 255 and int(i) != 0] - if netmask_calc: - netmask_calc_index = netmask_list.index(netmask_calc[0]) - elif sum(list(map(int, netmask_list))) == 0: - return '32' - else: - return '24' - for each in bit_range: - if cidr == int(netmask.split('.')[2]): - if netmask_calc_index == 1: - return str(8 + count) - elif netmask_calc_index == 2: - return str(8 * 2 + count) - elif netmask_calc_index == 3: - return str(8 * 3 + count) - break - cidr += each - count += 1 - - -def normalize_interface(name): - """Return the normalized interface name - """ - if not name: - return - - def _get_number(name): - digits = '' - for char in name: - if char.isdigit() or char in '/.': - digits += char - return digits - - if name.lower().startswith('gi'): - if_type = 'GigabitEthernet' - elif name.lower().startswith('te'): - if_type = 'TenGigabitEthernet' - elif name.lower().startswith('fa'): - if_type = 'FastEthernet' - elif name.lower().startswith('fo'): - if_type = 'FortyGigabitEthernet' - elif name.lower().startswith('long'): - if_type = 'LongReachEthernet' - elif name.lower().startswith('et'): - if_type = 'Ethernet' - elif name.lower().startswith('vl'): - if_type = 'Vlan' - elif name.lower().startswith('lo'): - if_type = 'loopback' - elif name.lower().startswith('po'): - if_type = 'Port-channel' - elif name.lower().startswith('nv'): - if_type = 'nve' - elif name.lower().startswith('twe'): - if_type = 'TwentyFiveGigE' - elif name.lower().startswith('hu'): - if_type = 'HundredGigE' - else: - if_type = None - - number_list = name.split(' ') - if len(number_list) == 2: - number = number_list[-1].strip() - else: - number = _get_number(name) - - if if_type: - proper_interface = if_type + number - else: - proper_interface = name - - return proper_interface - - -def get_interface_type(interface): - """Gets the type of interface - """ - - if interface.upper().startswith('GI'): - return 'GigabitEthernet' - elif interface.upper().startswith('TE'): - return 'TenGigabitEthernet' - elif interface.upper().startswith('FA'): - return 'FastEthernet' - elif interface.upper().startswith('FO'): - return 'FortyGigabitEthernet' - elif interface.upper().startswith('LON'): - return 'LongReachEthernet' - elif interface.upper().startswith('ET'): - return 'Ethernet' - elif interface.upper().startswith('VL'): - return 'Vlan' - elif interface.upper().startswith('LO'): - return 'loopback' - elif interface.upper().startswith('PO'): - return 'Port-channel' - elif interface.upper().startswith('NV'): - return 'nve' - elif interface.upper().startswith('TWE'): - return 'TwentyFiveGigE' - elif interface.upper().startswith('HU'): - return 'HundredGigE' - else: - return 'unknown' |