summaryrefslogtreecommitdiff
path: root/lib/ansible/module_utils/network/iosxr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/module_utils/network/iosxr')
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py88
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/acls/acls.py644
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/facts/facts.py24
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/interfaces/interfaces.py47
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py57
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py51
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/lacp/lacp.py67
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py79
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py87
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py82
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py70
-rw-r--r--lib/ansible/module_utils/network/iosxr/argspec/static_routes/static_routes.py121
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py317
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/acls/acls.py440
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/interfaces/interfaces.py265
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py305
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py323
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/lacp/lacp.py172
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py264
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py386
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/lldp_global/lldp_global.py188
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py247
-rw-r--r--lib/ansible/module_utils/network/iosxr/config/static_routes/static_routes.py560
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py104
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/acls/acls.py380
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/facts.py77
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/interfaces/interfaces.py102
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py125
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py117
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/lacp/lacp.py82
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py104
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py128
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/legacy/base.py259
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/lldp_global/lldp_global.py91
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py96
-rw-r--r--lib/ansible/module_utils/network/iosxr/facts/static_routes/static_routes.py176
-rw-r--r--lib/ansible/module_utils/network/iosxr/iosxr.py565
-rw-r--r--lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py114
-rw-r--r--lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py125
-rw-r--r--lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/process.py97
-rw-r--r--lib/ansible/module_utils/network/iosxr/providers/module.py62
-rw-r--r--lib/ansible/module_utils/network/iosxr/providers/providers.py120
-rw-r--r--lib/ansible/module_utils/network/iosxr/utils/utils.py355
43 files changed, 0 insertions, 8163 deletions
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index ca3035f742..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the iosxr_acl_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Acl_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_acl_interfaces module
- """
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'running_config': {
- 'type': 'str'
- },
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'access_groups': {
- 'elements': 'dict',
- 'options': {
- 'acls': {
- 'elements': 'dict',
- 'options': {
- 'direction': {
- 'choices': ['in', 'out'],
- 'type': 'str',
- 'required': True
- },
- 'name': {
- 'type': 'str',
- 'required': True
- }
- },
- 'type': 'list'
- },
- 'afi': {
- 'choices': ['ipv4', 'ipv6'],
- 'type': 'str',
- 'required': True
- }
- },
- 'type': 'list'
- },
- 'name': {
- 'type': 'str',
- 'required': True
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': [
- 'merged', 'replaced', 'overridden', 'deleted', 'gathered',
- 'parsed', 'rendered'
- ],
- 'default':
- 'merged',
- 'type':
- 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/acls/acls.py b/lib/ansible/module_utils/network/iosxr/argspec/acls/acls.py
deleted file mode 100644
index 2a2fa6b261..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/acls/acls.py
+++ /dev/null
@@ -1,644 +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 iosxr_acls module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class AclsArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_acls module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'running_config': {
- 'type': 'str'
- },
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'acls': {
- 'elements': 'dict',
- 'options': {
- 'name': {
- 'type': 'str'
- },
- 'aces': {
- 'elements': 'dict',
- 'mutually_exclusive': [['grant', 'remark', 'line']],
- 'options': {
- 'destination': {
- 'mutually_exclusive': [['address', 'any', 'host', 'prefix'], ['wildcard_bits', 'any', 'host', 'prefix']],
- 'options': {
- 'host': {
- 'type': 'str'
- },
- 'address': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'prefix': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'mutually_exclusive': [['eq', 'gt', 'lt', 'neq', 'range']],
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'str'
- },
- 'start': {
- 'type': 'str'
- }
- },
- 'required_together': [['start', 'end']],
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'wildcard_bits': {
- 'type': 'str'
- }
- },
- 'required_together': [['address', 'wildcard_bits']],
- 'type': 'dict'
- },
- 'dscp': {
- 'mutually_exclusive': [['eq', 'gt', 'lt', 'neq', 'range']],
- 'type': 'dict',
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'str'
- },
- 'start': {
- 'type': 'str'
- }
- },
- 'required_together': [['start', 'end']],
- 'type': 'dict'
- }
- },
- },
- 'fragments': {
- 'type': 'bool'
- },
- 'capture': {
- 'type': 'bool'
- },
- 'destopts': {
- 'type': 'bool'
- },
- 'authen': {
- 'type': 'bool'
- },
- 'routing': {
- 'type': 'bool'
- },
- 'hop_by_hop': {
- 'type': 'bool'
- },
- 'grant': {
- 'type': 'str',
- 'choices': ['permit', 'deny'],
- },
- 'icmp_off': {
- 'type': 'bool'
- },
- 'log': {
- 'type': 'bool'
- },
- 'log_input': {
- 'type': 'bool'
- },
- 'line': {
- 'type': 'str',
- 'aliases': ['ace']
- },
- 'packet_length': {
- 'mutually_exclusive': [['eq', 'lt', 'neq', 'range'], ['eq', 'gt', 'neq', 'range']],
- 'options': {
- 'eq': {
- 'type': 'int'
- },
- 'gt': {
- 'type': 'int'
- },
- 'lt': {
- 'type': 'int'
- },
- 'neq': {
- 'type': 'int'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'int'
- },
- 'start': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- }
- },
- 'type':
- 'dict'
- },
- 'precedence': {
- 'type': 'str'
- },
- 'protocol': {
- 'type': 'str'
- },
- 'protocol_options': {
- 'mutually_exclusive': [['icmp', 'tcp', 'igmp', 'icmpv6']],
- 'options': {
- 'icmpv6': {
- 'type': 'dict',
- 'options': {
- 'address_unreachable': {
- 'type': 'bool'
- },
- 'administratively_prohibited':
- {
- 'type': 'bool'
- },
- 'beyond_scope_of_source_address':
- {
- 'type': 'bool'
- },
- 'destination_unreachable': {
- 'type': 'bool'
- },
- 'echo': {
- 'type': 'bool'
- },
- 'echo_reply': {
- 'type': 'bool'
- },
- 'erroneous_header_field': {
- 'type': 'bool'
- },
- 'group_membership_query': {
- 'type': 'bool'
- },
- 'group_membership_report': {
- 'type': 'bool'
- },
- 'group_membership_termination':
- {
- 'type': 'bool'
- },
- 'host_unreachable': {
- 'type': 'bool'
- },
- 'nd_na': {
- 'type': 'bool'
- },
- 'nd_ns': {
- 'type': 'bool'
- },
- 'neighbor_redirect': {
- 'type': 'bool'
- },
- 'no_route_to_destination': {
- 'type': 'bool'
- },
- 'node_information_request_is_refused':
- {
- 'type': 'bool'
- },
- 'node_information_successful_reply':
- {
- 'type': 'bool'
- },
- 'packet_too_big': {
- 'type': 'bool'
- },
- 'parameter_problem': {
- 'type': 'bool'
- },
- 'port_unreachable': {
- 'type': 'bool'
- },
- 'query_subject_is_IPv4address':
- {
- 'type': 'bool'
- },
- 'query_subject_is_IPv6address':
- {
- 'type': 'bool'
- },
- 'query_subject_is_domainname': {
- 'type': 'bool'
- },
- 'reassembly_timeout': {
- 'type': 'bool'
- },
- 'redirect': {
- 'type': 'bool'
- },
- 'router_advertisement': {
- 'type': 'bool'
- },
- 'router_renumbering': {
- 'type': 'bool'
- },
- 'router_solicitation': {
- 'type': 'bool'
- },
- 'rr_command': {
- 'type': 'bool'
- },
- 'rr_result': {
- 'type': 'bool'
- },
- 'rr_seqnum_reset': {
- 'type': 'bool'
- },
- 'time_exceeded': {
- 'type': 'bool'
- },
- 'ttl_exceeded': {
- 'type': 'bool'
- },
- 'unknown_query_type': {
- 'type': 'bool'
- },
- 'unreachable': {
- 'type': 'bool'
- },
- 'unrecognized_next_header': {
- 'type': 'bool'
- },
- 'unrecognized_option': {
- 'type': 'bool'
- },
- 'whoareyou_reply': {
- 'type': 'bool'
- },
- 'whoareyou_request': {
- 'type': 'bool'
- }
- }
- },
- 'icmp': {
- 'options': {
- 'administratively_prohibited':
- {
- 'type': 'bool'
- },
- 'alternate_address': {
- 'type': 'bool'
- },
- 'conversion_error': {
- 'type': 'bool'
- },
- 'dod_host_prohibited': {
- 'type': 'bool'
- },
- 'dod_net_prohibited': {
- 'type': 'bool'
- },
- 'echo': {
- 'type': 'bool'
- },
- 'echo_reply': {
- 'type': 'bool'
- },
- 'general_parameter_problem': {
- 'type': 'bool'
- },
- 'host_isolated': {
- 'type': 'bool'
- },
- 'host_precedence_unreachable':
- {
- 'type': 'bool'
- },
- 'host_redirect': {
- 'type': 'bool'
- },
- 'host_tos_redirect': {
- 'type': 'bool'
- },
- 'host_tos_unreachable': {
- 'type': 'bool'
- },
- 'host_unknown': {
- 'type': 'bool'
- },
- 'host_unreachable': {
- 'type': 'bool'
- },
- 'information_reply': {
- 'type': 'bool'
- },
- 'information_request': {
- 'type': 'bool'
- },
- 'mask_reply': {
- 'type': 'bool'
- },
- 'mask_request': {
- 'type': 'bool'
- },
- 'mobile_redirect': {
- 'type': 'bool'
- },
- 'net_redirect': {
- 'type': 'bool'
- },
- 'net_tos_redirect': {
- 'type': 'bool'
- },
- 'net_tos_unreachable': {
- 'type': 'bool'
- },
- 'net_unreachable': {
- 'type': 'bool'
- },
- 'network_unknown': {
- 'type': 'bool'
- },
- 'no_room_for_option': {
- 'type': 'bool'
- },
- 'option_missing': {
- 'type': 'bool'
- },
- 'packet_too_big': {
- 'type': 'bool'
- },
- 'parameter_problem': {
- 'type': 'bool'
- },
- 'port_unreachable': {
- 'type': 'bool'
- },
- 'precedence_unreachable': {
- 'type': 'bool'
- },
- 'protocol_unreachable': {
- 'type': 'bool'
- },
- 'reassembly_timeout': {
- 'type': 'bool'
- },
- 'redirect': {
- 'type': 'bool'
- },
- 'router_advertisement': {
- 'type': 'bool'
- },
- 'router_solicitation': {
- 'type': 'bool'
- },
- 'source_quench': {
- 'type': 'bool'
- },
- 'source_route_failed': {
- 'type': 'bool'
- },
- 'time_exceeded': {
- 'type': 'bool'
- },
- 'timestamp_reply': {
- 'type': 'bool'
- },
- 'timestamp_request': {
- 'type': 'bool'
- },
- 'traceroute': {
- 'type': 'bool'
- },
- 'ttl_exceeded': {
- 'type': 'bool'
- },
- 'unreachable': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'igmp': {
- 'options': {
- 'dvmrp': {
- 'type': 'bool'
- },
- 'host_query': {
- 'type': 'bool'
- },
- 'host_report': {
- 'type': 'bool'
- },
- 'mtrace': {
- 'type': 'bool'
- },
- 'mtrace_response': {
- 'type': 'bool'
- },
- 'pim': {
- 'type': 'bool'
- },
- 'trace': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- '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'
- }
- },
- 'type': 'dict'
- },
- 'remark': {
- 'type': 'str'
- },
- 'sequence': {
- 'type': 'int'
- },
- 'source': {
- 'mutually_exclusive': [['address', 'any', 'host', 'prefix'], ['wildcard_bits', 'any', 'host', 'prefix']],
- 'options': {
- 'host': {
- 'type': 'str'
- },
- 'address': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'prefix': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'mutually_exclusive': [['eq', 'gt', 'lt', 'neq', 'range']],
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'str'
- },
- 'start': {
- 'type': 'str'
- }
- },
- 'required_together': [['start', 'end']],
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'wildcard_bits': {
- 'type': 'str'
- }
- },
- 'required_together': [['address', 'wildcard_bits']],
- 'type': 'dict'
- },
- 'ttl': {
- 'mutually_exclusive': [['eq', 'gt', 'lt', 'neq', 'range']],
- 'options': {
- 'eq': {
- 'type': 'int'
- },
- 'gt': {
- 'type': 'int'
- },
- 'lt': {
- 'type': 'int'
- },
- 'neq': {
- 'type': 'int'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'int'
- },
- 'start': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'list'
- },
- },
- 'type': 'list'
- },
- 'afi': {
- 'choices': ['ipv4', 'ipv6'],
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': [
- 'merged', 'replaced', 'overridden', 'deleted', 'gathered',
- 'rendered', 'parsed'
- ],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/facts/facts.py b/lib/ansible/module_utils/network/iosxr/argspec/facts/facts.py
deleted file mode 100644
index dabc6a5322..0000000000
--- a/lib/ansible/module_utils/network/iosxr/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 iosxr facts module.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class FactsArgs(object): # pylint: disable=R0903
- """ The arg spec for the iosxr 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/iosxr/argspec/interfaces/interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/interfaces/interfaces.py
deleted file mode 100644
index 3e67c7bd16..0000000000
--- a/lib/ansible/module_utils/network/iosxr/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': 'int'},
- 'mtu': {'type': 'int'},
- 'duplex': {'type': 'str', 'choices': ['full', 'half']}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index dbf4b0756b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/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 iosxr_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},
- 'native_vlan': {'type': 'int'},
- 'l2transport': {'type': 'bool'},
- 'l2protocol': {'element': 'dict',
- 'type': 'list',
- 'options': {'cdp': {'type': 'str',
- 'choices': ['drop', 'forward', 'tunnel']},
- 'pvst': {'type': 'str',
- 'choices': ['drop', 'forward', 'tunnel']},
- 'stp': {'type': 'str',
- 'choices': ['drop', 'forward', 'tunnel']},
- 'vtp': {'type': 'str',
- 'choices': ['drop', 'forward', 'tunnel']},
- }},
- 'q_vlan': {'type': 'list'},
- 'propagate': {'type': 'bool'}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 0de627ad91..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the 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'}}},
- '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/iosxr/argspec/lacp/lacp.py b/lib/ansible/module_utils/network/iosxr/argspec/lacp/lacp.py
deleted file mode 100644
index 57d8090d7c..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/lacp/lacp.py
+++ /dev/null
@@ -1,67 +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 iosxr_lacp module
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class LacpArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_lacp module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'options': {
- 'system': {
- 'options': {
- 'mac': {
- 'type': 'dict',
- 'options': {
- 'address': {
- 'type': 'str'
- }
- }
- },
- 'priority': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index f8a0070a5d..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.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)
-
-#############################################
-# 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 iosxr_lacp_interfaces module
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lacp_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_lacp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'churn_logging': {
- 'choices': ['actor', 'partner', 'both'],
- 'type': 'str'
- },
- 'collector_max_delay': {
- 'type': 'int'
- },
- 'name': {
- 'type': 'str'
- },
- 'period': {
- 'type': 'int'
- },
- 'switchover_suppress_flaps': {
- 'type': 'int'
- },
- 'system': {
- 'options': {
- 'mac': {
- 'type': 'str'
- },
- 'priority': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index d5799ee764..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,87 +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 iosxr_lag_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lag_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_lag_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'links': {
- 'options': {
- 'max_active': {
- 'type': 'int'
- },
- 'min_active': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- },
- 'load_balancing_hash': {
- 'choices': ['dst-ip', 'src-ip'],
- 'type': 'str'
- },
- 'members': {
- 'elements': 'dict',
- 'options': {
- 'member': {
- 'type': 'str'
- },
- 'mode': {
- 'choices': ['on', 'active', 'passive', 'inherit'],
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'mode': {
- 'choices': ['on', 'active', 'passive'],
- 'type': 'str'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py
deleted file mode 100644
index 920c5a655e..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,82 +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 iosxr_lldp_global module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lldp_globalArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_lldp module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'options': {
- 'holdtime': {
- 'type': 'int'
- },
- 'reinit': {
- 'type': 'int'
- },
- 'subinterfaces': {
- 'type': 'bool'
- },
- 'timer': {
- 'type': 'int'
- },
- 'tlv_select': {
- 'options': {
- 'management_address': {
- 'type': 'bool'
- },
- 'port_description': {
- 'type': 'bool'
- },
- 'system_capabilities': {
- 'type': 'bool'
- },
- 'system_description': {
- 'type': 'bool'
- },
- 'system_name': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 1f5632efa0..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,70 +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 iosxr_lldp_interfaces module
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lldp_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_lldp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'destination': {
- 'type': 'dict',
- 'options': {
- 'mac_address': {
- 'type': 'str',
- 'choices': ['ieee-nearest-bridge', 'ieee-nearest-non-tmpr-bridge'],
- }
- }
- },
- 'name': {
- 'type': 'str'
- },
- 'receive': {
- 'type': 'bool'
- },
- 'transmit': {
- 'type': 'bool'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/argspec/static_routes/static_routes.py b/lib/ansible/module_utils/network/iosxr/argspec/static_routes/static_routes.py
deleted file mode 100644
index 030515b877..0000000000
--- a/lib/ansible/module_utils/network/iosxr/argspec/static_routes/static_routes.py
+++ /dev/null
@@ -1,121 +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 iosxr_static_routes module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Static_routesArgs(object): # pylint: disable=R0903
- """The arg spec for the iosxr_static_routes module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'vrf': {
- 'type': 'str'
- },
- 'address_families': {
- 'elements': 'dict',
- 'options': {
- 'afi': {
- 'choices': ['ipv4', 'ipv6'],
- 'required': True,
- 'type': 'str'
- },
- 'safi': {
- 'choices': ['unicast', 'multicast'],
- 'required': True,
- 'type': 'str'
- },
- 'routes': {
- 'elements': 'dict',
- 'options': {
- 'dest': {
- 'required': True,
- 'type': 'str'
- },
- 'next_hops': {
- 'elements': 'dict',
- 'options': {
- 'admin_distance': {
- 'type': 'int'
- },
- 'description': {
- 'type': 'str'
- },
- 'dest_vrf': {
- 'type': 'str'
- },
- 'forward_router_address': {
- 'type': 'str'
- },
- 'interface': {
- 'type': 'str'
- },
- 'metric': {
- 'type': 'int'
- },
- 'tag': {
- 'type': 'int'
- },
- 'track': {
- 'type': 'str'
- },
- 'tunnel_id': {
- 'type': 'int'
- },
- 'vrflabel': {
- 'type': 'int'
- }
- },
- 'type': 'list'
- }
- },
- 'type': 'list'
- },
- },
- 'type': 'list'
- },
- },
- 'type': 'list'
- },
- 'running_config': {
- 'type': 'str'
- },
- 'state': {
- 'choices': [
- 'merged', 'replaced', 'overridden', 'deleted', 'gathered', 'rendered', 'parsed'
- ],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index 02b1ea738b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,317 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.iosxr.utils.utils import normalize_interface, diff_list_of_dicts, pad_commands
-from ansible.module_utils.network.common.utils \
- import (
- to_list,
- search_obj_in_list,
- remove_empties
- )
-
-
-class Acl_interfaces(ConfigBase):
- """
- The iosxr_acl_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'acl_interfaces',
- ]
-
- def __init__(self, module):
- super(Acl_interfaces, self).__init__(module)
-
- def get_acl_interfaces_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(
- self.gather_subset, self.gather_network_resources, data=data)
- acl_interfaces_facts = facts['ansible_network_resources'].get(
- 'acl_interfaces')
- if not acl_interfaces_facts:
- return []
- return acl_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- commands = list()
-
- 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)
-
- if self.state in self.ACTION_STATES:
- result["before"] = existing_acl_interfaces_facts
- if result["changed"]:
- result["after"] = changed_acl_interfaces_facts
-
- elif self.state == "gathered":
- result["gathered"] = changed_acl_interfaces_facts
-
- result["warnings"] = warnings
- return result
-
- def set_config(self, existing_acl_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- if want:
- for item in want:
- item['name'] = normalize_interface(item['name'])
- if 'members' in want and want['members']:
- for item in want['members']:
- item.update({
- 'member':
- normalize_interface(item['member']),
- 'mode':
- item['mode']
- })
- have = existing_acl_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- commands = []
-
- 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.extend(self._state_overridden(want, have))
-
- elif state == 'deleted':
- if not want:
- for intf in have:
- commands.extend(self._state_deleted({}, intf))
- else:
- for item in want:
- obj_in_have = search_obj_in_list(item['name'], have) or {}
- commands.extend(
- self._state_deleted(remove_empties(item), obj_in_have))
-
- else:
- # Instead of passing entire want and have
- # list of dictionaries to the respective
- # _state_* methods we are passing the want
- # and have dictionaries per interface
- for item in want:
- name = item['name']
- obj_in_have = search_obj_in_list(name, have) or {}
-
- if state == 'merged' or state == 'rendered':
- commands.extend(self._state_merged(item, obj_in_have))
-
- elif state == 'replaced':
- commands.extend(self._state_replaced(item, obj_in_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 = []
-
- want = remove_empties(want)
-
- delete_commands = []
- for have_afi in have.get('access_groups', []):
- want_afi = search_obj_in_list(have_afi['afi'],
- want.get('access_groups', []),
- key='afi') or {}
- afi = have_afi.get('afi')
-
- for acl in have_afi.get('acls', []):
- if acl not in want_afi.get('acls', []):
- delete_commands.extend(
- self._compute_commands(afi, [acl], remove=True))
-
- if delete_commands:
- pad_commands(delete_commands, want['name'])
- commands.extend(delete_commands)
-
- merged_commands = self._state_merged(want, have)
- if merged_commands and delete_commands:
- del merged_commands[0]
-
- commands.extend(merged_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 have_intf in have:
- want_intf = search_obj_in_list(have_intf['name'], want) or {}
- if not want_intf:
- commands.extend(self._state_deleted(want_intf, have_intf))
-
- for want_intf in want:
- have_intf = search_obj_in_list(want_intf['name'], have) or {}
- commands.extend(self._state_replaced(want_intf, have_intf))
-
- 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 = []
-
- want = remove_empties(want)
-
- for want_afi in want.get('access_groups', []):
- have_afi = search_obj_in_list(want_afi['afi'],
- have.get('access_groups', []),
- key='afi') or {}
- delta = diff_list_of_dicts(want_afi['acls'],
- have_afi.get('acls', []),
- key='direction')
- commands.extend(self._compute_commands(want_afi['afi'], delta))
-
- if commands:
- pad_commands(commands, want['name'])
-
- 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 = []
-
- # This handles deletion for both empty/no config
- # and just interface name provided.
- if 'access_groups' not in want:
- for x in have.get('access_groups', []):
- afi = x.get('afi')
- for have_acl in x.get('acls', []):
- commands.extend(
- self._compute_commands(afi, [have_acl], remove=True))
-
- else:
- for want_afi in want['access_groups']:
- have_afi = search_obj_in_list(want_afi['afi'],
- have.get('access_groups', []),
- key='afi') or {}
- afi = have_afi.get('afi')
-
- # If only the AFI has be specified, we
- # delete all the access-groups for that AFI
- if 'acls' not in want_afi:
- for have_acl in have_afi.get('acls', []):
- commands.extend(
- self._compute_commands(afi, [have_acl],
- remove=True))
-
- # If one or more acl has been explicitly specified, we
- # delete that and leave the rest untouched
- else:
- for acl in want_afi['acls']:
- if acl in have_afi.get('acls', []):
- commands.extend(
- self._compute_commands(afi, [acl],
- remove=True))
-
- if commands:
- pad_commands(commands, have['name'])
-
- return commands
-
- def _compute_commands(self, afi, delta, remove=False):
- updates = []
- map_dir = {'in': 'ingress', 'out': 'egress'}
-
- for x in delta:
- cmd = "{0} access-group {1} {2}".format(afi, x['name'],
- map_dir[x['direction']])
- if remove:
- cmd = "no " + cmd
- updates.append(cmd)
-
- return updates
diff --git a/lib/ansible/module_utils/network/iosxr/config/acls/acls.py b/lib/ansible/module_utils/network/iosxr/config/acls/acls.py
deleted file mode 100644
index 43dd015ece..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/acls/acls.py
+++ /dev/null
@@ -1,440 +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 iosxr_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
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.iosxr.utils.utils \
- import (
- flatten_dict,
- prefix_to_address_wildcard,
- is_ipv4_address
- )
-from ansible.module_utils.network.common.utils \
- import (
- to_list,
- search_obj_in_list,
- dict_diff,
- remove_empties,
- )
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.iosxr.facts.facts import Facts
-
-
-class Acls(ConfigBase):
- """
- The iosxr_acls class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'acls',
- ]
-
- def __init__(self, module):
- super(Acls, self).__init__(module)
-
- def get_acls_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(
- self.gather_subset, self.gather_network_resources, data=data)
- acls_facts = facts["ansible_network_resources"].get("acls")
- if not acls_facts:
- return []
- return acls_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- commands = list()
-
- if self.state in self.ACTION_STATES:
- existing_acls_facts = self.get_acls_facts()
- else:
- existing_acls_facts = []
-
- if self.state in self.ACTION_STATES or self.state == "rendered":
- commands.extend(self.set_config(existing_acls_facts))
-
- if commands and self.state in self.ACTION_STATES:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result["changed"] = True
-
- if self.state in self.ACTION_STATES:
- result["commands"] = commands
-
- if self.state in self.ACTION_STATES or self.state == "gathered":
- changed_acls_facts = self.get_acls_facts()
-
- elif self.state == "rendered":
- 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_acls_facts(data=running_config)
-
- if self.state in self.ACTION_STATES:
- result["before"] = existing_acls_facts
- if result["changed"]:
- result["after"] = changed_acls_facts
-
- elif self.state == "gathered":
- result["gathered"] = changed_acls_facts
-
- result["warnings"] = warnings
- return result
-
- def set_config(self, existing_acls_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_acls_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']
- commands = []
-
- 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.extend(self._state_overridden(want, have))
-
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
-
- else:
- # Instead of passing entire want and have
- # list of dictionaries to the respective
- # _state_* methods we are passing the want
- # and have dictionaries per AFI
- for item in want:
- afi = item['afi']
- obj_in_have = search_obj_in_list(afi, have, key='afi')
-
- if state == 'merged' or self.state == 'rendered':
- commands.extend(
- self._state_merged(remove_empties(item), obj_in_have))
-
- elif state == 'replaced':
- commands.extend(
- self._state_replaced(remove_empties(item),
- obj_in_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 want_acl in want['acls']:
- have_acl = search_obj_in_list(want_acl['name'], have['acls']) or {}
- acl_updates = []
-
- for have_ace in have_acl.get('aces', []):
- want_ace = search_obj_in_list(have_ace['sequence'], want_acl['aces'], key='sequence') or {}
- if not want_ace:
- acl_updates.append('no {0}'.format(have_ace['sequence']))
-
- for want_ace in want_acl.get('aces', []):
- have_ace = search_obj_in_list(want_ace.get('sequence'), have_acl.get('aces', []), key='sequence') or {}
- set_cmd = self._set_commands(want_ace, have_ace)
- if set_cmd:
- acl_updates.append(set_cmd)
-
- if acl_updates:
- acl_updates.insert(0, '{0} access-list {1}'.format(want['afi'], want_acl['name']))
- commands.extend(acl_updates)
-
- 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 = []
-
- # Remove extraneous AFI that are present in config but not
- # specified in `want`
- for have_afi in have:
- want_afi = search_obj_in_list(have_afi['afi'], want, key='afi') or {}
- if not want_afi:
- for acl in have_afi.get('acls', []):
- commands.append('no {0} access-list {1}'.format(have_afi['afi'], acl['name']))
-
- # First we remove the extraneous ACLs from the AFIs that
- # are present both in `want` and in `have` and then
- # we call `_state_replaced` to update the ACEs within those ACLs
- for want_afi in want:
- want_afi = remove_empties(want_afi)
- have_afi = search_obj_in_list(want_afi['afi'], have, key='afi') or {}
- if have_afi:
- for have_acl in have_afi.get('acls', []):
- want_acl = search_obj_in_list(have_acl['name'], want_afi.get('acls', [])) or {}
- if not want_acl:
- commands.append('no {0} access-list {1}'.format(have_afi['afi'], have_acl['name']))
-
- commands.extend(self._state_replaced(want_afi, have_afi))
-
- 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 = []
- if not have:
- have = {}
-
- for want_acl in want['acls']:
- have_acl = search_obj_in_list(want_acl['name'], have.get('acls', {})) or {}
-
- acl_updates = []
- for want_ace in want_acl['aces']:
- have_ace = search_obj_in_list(want_ace.get('sequence'), have_acl.get('aces', []), key='sequence') or {}
- set_cmd = self._set_commands(want_ace, have_ace)
- if set_cmd:
- acl_updates.append(set_cmd)
-
- if acl_updates:
- acl_updates.insert(0, '{0} access-list {1}'.format(want['afi'], want_acl['name']))
- commands.extend(acl_updates)
-
- 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 not want:
- want = [{'afi': 'ipv4'}, {'afi': 'ipv6'}]
-
- for item in want:
- item = remove_empties(item)
- have_item = search_obj_in_list(item['afi'], have, key='afi') or {}
- if 'acls' not in item:
- if have_item:
- for acl in have_item['acls']:
- commands.append('no {0} access-list {1}'.format(have_item['afi'], acl['name']))
- else:
- for want_acl in item['acls']:
- have_acl = search_obj_in_list(want_acl['name'], have_item.get('acls', [])) or {}
- if have_acl:
- if 'aces' not in want_acl:
- commands.append('no {0} access-list {1}'.format(have_item['afi'], have_acl['name']))
- else:
- acl_updates = []
- for want_ace in want_acl['aces']:
- have_ace = search_obj_in_list(want_ace.get('sequence'), have_acl.get('aces', []), key='sequence') or {}
- if have_ace:
- acl_updates.append('no {0}'.format(have_ace['sequence']))
-
- if acl_updates:
- acl_updates.insert(0, '{0} access-list {1}'.format(have_item['afi'], have_acl['name']))
- commands.extend(acl_updates)
-
- return commands
-
- def _compute_commands(self, want_ace):
- """This command creates an ACE line from an ACE dictionary
-
- :rtype: A string
- :returns: An ACE generated from a structured ACE dictionary
- """
- def __compute_src_dest(dir_dict):
- cmd = ""
- if 'any' in dir_dict:
- cmd += 'any '
- elif 'host' in dir_dict:
- cmd += 'host {0} '.format(dir_dict['host'])
- elif 'prefix' in dir_dict:
- cmd += '{0} '.format(dir_dict['prefix'])
- else:
- cmd += '{0} {1} '.format(dir_dict['address'],
- dir_dict['wildcard_bits'])
-
- if 'port_protocol' in dir_dict:
- protocol_range = dir_dict['port_protocol'].get('range')
- if protocol_range:
- cmd += 'range {0} {1} '.format(protocol_range['start'],
- protocol_range['end'])
- else:
- for key, value in iteritems(dir_dict['port_protocol']):
- cmd += '{0} {1} '.format(key, value)
-
- return cmd
-
- def __compute_protocol_options(protocol_dict):
- cmd = ""
- for value in protocol_options.values():
- for subkey, subvalue in iteritems(value):
- if subvalue:
- cmd += '{0} '.format(subkey.replace('_', '-'))
- return cmd
-
- def __compute_match_options(want_ace):
- cmd = ""
-
- if 'precedence' in want_ace:
- cmd += 'precedence {0} '.format(want_ace['precedence'])
-
- for x in ['dscp', 'packet_length', 'ttl']:
- if x in want_ace:
- opt_range = want_ace[x].get('range')
- if opt_range:
- cmd += '{0} range {1} {2} '.format(
- x.replace('_', '-'), opt_range['start'],
- opt_range['end'])
- else:
- for key, value in iteritems(want_ace[x]):
- cmd += '{0} {1} {2} '.format(
- x.replace('_', '-'), key, value)
-
- for x in ('authen', 'capture', 'fragments', 'routing', 'log',
- 'log_input', 'icmp_off', 'destopts', 'hop_by_hop'):
- if x in want_ace:
- cmd += '{0} '.format(x.replace('_', '-'))
-
- return cmd
-
- cmd = ""
- if 'sequence' in want_ace:
- cmd += '{0} '.format(want_ace['sequence'])
-
- if 'remark' in want_ace:
- cmd += 'remark {0}'.format(want_ace['remark'])
-
- elif 'line' in want_ace:
- cmd += want_ace['line']
-
- else:
- cmd += '{0} '.format(want_ace['grant'])
- if 'protocol' in want_ace:
- cmd += '{0} '.format(want_ace['protocol'])
-
- cmd += __compute_src_dest(want_ace['source'])
- cmd += __compute_src_dest(want_ace['destination'])
-
- protocol_options = want_ace.get('protocol_options', {})
- if protocol_options:
- cmd += __compute_protocol_options(protocol_options)
-
- cmd += __compute_match_options(want_ace)
-
- return cmd.strip()
-
- def _set_commands(self, want_ace, have_ace):
- """A helped method that checks if there is
- a delta between the `have_ace` and `want_ace`.
- If there is a delta then it calls `_compute_commands`
- to create the ACE line.
-
- :rtype: A string
- :returns: An ACE generated from a structured ACE dictionary
- via a call to `_compute_commands`
- """
-
- if 'line' in want_ace:
- if want_ace['line'] != have_ace.get('line'):
- return self._compute_commands(want_ace)
-
- else:
- if ('prefix' in want_ace.get('source', {})) or ('prefix' in want_ace.get('destination', {})):
- self._prepare_for_diff(want_ace)
-
- protocol_opt_delta = {}
- delta = dict_diff(have_ace, want_ace)
-
- # `dict_diff` doesn't work properly for `protocol_options` diff,
- # so we need to handle it separately
- if want_ace.get('protocol_options', {}):
- protocol_opt_delta = set(flatten_dict(have_ace.get('protocol_options', {}))) ^ \
- set(flatten_dict(want_ace.get('protocol_options', {})))
-
- if delta or protocol_opt_delta:
- want_ace = self._dict_merge(have_ace, want_ace)
- return self._compute_commands(want_ace)
-
- def _prepare_for_diff(self, ace):
- """This method prepares the want ace dict
- for diff calculation against the have ace dict.
-
- :param ace: The want ace to prepare for diff calculation
- """
- # Convert prefixes to "address wildcard bits" format for IPv4 addresses
- # Not valid for IPv6 addresses because those can only be specified as prefixes
- # and are always rendered in running-config as prefixes too
- for x in ['source', 'destination']:
- prefix = ace.get(x, {}).get('prefix')
- if prefix and is_ipv4_address(prefix):
- del ace[x]['prefix']
- ace[x]['address'], ace[x]['wildcard_bits'] = prefix_to_address_wildcard(prefix)
-
- def _dict_merge(self, have_ace, want_ace):
- for x in want_ace:
- have_ace[x] = want_ace[x]
- return have_ace
diff --git a/lib/ansible/module_utils/network/iosxr/config/interfaces/interfaces.py b/lib/ansible/module_utils/network/iosxr/config/interfaces/interfaces.py
deleted file mode 100644
index 076ae017b7..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/interfaces/interfaces.py
+++ /dev/null
@@ -1,265 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.iosxr.utils.utils import get_interface_type, dict_to_set
-from ansible.module_utils.network.iosxr.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.iosxr.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class Interfaces(ConfigBase):
- """
- The iosxr_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 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
- """
- 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
- elif interface['name'] in each['name']:
- break
- else:
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- want = dict()
- commands.extend(self._clear_config(want, 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
- elif interface['name'] in each['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)
- want = dict()
- commands.extend(self._clear_config(want, 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 each['name'] == interface['name']:
- break
- elif interface['name'] in 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
- 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 _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/iosxr/config/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index a842026609..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,305 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.iosxr.utils.utils import normalize_interface, dict_to_set
-from ansible.module_utils.network.iosxr.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.iosxr.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class L2_Interfaces(ConfigBase):
- """
- The iosxr_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'l2_interfaces',
- ]
-
- def get_l2_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- l2_interfaces_facts = facts['ansible_network_resources'].get('l2_interfaces')
-
- if not l2_interfaces_facts:
- return []
- return l2_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
- commands.extend(self.set_config(existing_l2_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_l2_interfaces_facts = self.get_l2_interfaces_facts()
-
- result['before'] = existing_l2_interfaces_facts
- if result['changed']:
- result['after'] = changed_l2_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_l2_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_l2_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- 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:
- interface['name'] = normalize_interface(interface['name'])
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- commands.extend(self._set_config(interface, {}, 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 = []
- not_in_have = set()
- in_have = set()
- for each in have:
- for interface in want:
- interface['name'] = normalize_interface(interface['name'])
- if each['name'] == interface['name']:
- in_have.add(interface['name'])
- break
- elif interface['name'] != each['name']:
- not_in_have.add(interface['name'])
- 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, module))
- # Add the want interface that's not already configured in have interface
- for each in (not_in_have - in_have):
- for every in want:
- interface = 'interface {0}'.format(every['name'])
- if each and interface not in commands:
- commands.extend(self._set_config(every, {}, 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:
- interface['name'] = normalize_interface(interface['name'])
- for each in have:
- if each['name'] == interface['name']:
- break
- elif interface['name'] in each['name']:
- break
- else:
- commands.extend(self._set_config(interface, {}, 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:
- interface['name'] = normalize_interface(interface['name'])
- 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 _set_config(self, want, have, module):
- # Set the interface config based on the want and have config
- commands = []
- interface = 'interface ' + want['name']
- l2_protocol_bool = False
-
- # 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:
- # For merging with already configured l2protocol
- if have.get('l2protocol') and len(have.get('l2protocol')) > 1:
- l2_protocol_diff = []
- for each in want.get('l2protocol'):
- for every in have.get('l2protocol'):
- if every == each:
- break
- if each not in have.get('l2protocol'):
- l2_protocol_diff.append(each)
- l2_protocol_bool = True
- l2protocol = tuple(l2_protocol_diff)
- else:
- l2protocol = {}
-
- diff = dict(diff)
- wants_native = diff.get('native_vlan')
- l2transport = diff.get('l2transport')
- q_vlan = diff.get('q_vlan')
- propagate = diff.get('propagate')
- if l2_protocol_bool is False:
- l2protocol = diff.get('l2protocol')
-
- if wants_native:
- cmd = 'dot1q native vlan {0}'.format(wants_native)
- add_command_to_config_list(interface, cmd, commands)
-
- if l2transport or l2protocol:
- for each in l2protocol:
- each = dict(each)
- if isinstance(each, dict):
- cmd = 'l2transport l2protocol {0} {1}'.format(list(each.keys())[0], list(each.values())[0])
- add_command_to_config_list(interface, cmd, commands)
- if propagate and not have.get('propagate'):
- cmd = 'l2transport propagate remote-status'
- add_command_to_config_list(interface, cmd, commands)
- elif want.get('l2transport') is False and (want.get('l2protocol') or want.get('propagate')):
- module.fail_json(msg='L2transport L2protocol or Propagate can only be configured when '
- 'L2transport set to True!')
-
- if q_vlan and '.' in interface:
- q_vlans = (" ".join(map(str, want.get('q_vlan'))))
- if q_vlans != have.get('q_vlan'):
- cmd = 'dot1q vlan {0}'.format(q_vlans)
- 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('native_vlan'):
- remove_command_from_config_list(interface, 'dot1q native vlan', commands)
-
- if have.get('q_vlan'):
- remove_command_from_config_list(interface, 'encapsulation dot1q', commands)
-
- if have.get('l2protocol') and (want.get('l2protocol') is None or want.get('propagate') is None):
- if 'no l2transport' not in commands:
- remove_command_from_config_list(interface, 'l2transport', commands)
- elif have.get('l2transport') and have.get('l2transport') != want.get('l2transport'):
- if 'no l2transport' not in commands:
- remove_command_from_config_list(interface, 'l2transport', commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 555933ad85..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,323 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.iosxr.utils.utils import normalize_interface, dict_to_set
-from ansible.module_utils.network.iosxr.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.iosxr.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-from ansible.module_utils.network.iosxr.utils.utils import validate_n_expand_ipv4, validate_ipv6
-
-
-class L3_Interfaces(ConfigBase):
- """
- The iosxr_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:
- interface['name'] = normalize_interface(interface['name'])
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- 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 = []
- not_in_have = set()
- in_have = set()
-
- for each in have:
- for interface in want:
- interface['name'] = normalize_interface(interface['name'])
- if each['name'] == interface['name']:
- in_have.add(interface['name'])
- break
- elif interface['name'] != each['name']:
- not_in_have.add(interface['name'])
- 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))
- # Add the want interface that's not already configured in have interface
- for each in (not_in_have - in_have):
- for every in want:
- interface = 'interface {0}'.format(every['name'])
- if each and interface not in commands:
- commands.extend(self._set_config(every, {}, 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:
- interface['name'] = normalize_interface(interface['name'])
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- 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:
- interface['name'] = normalize_interface(interface['name'])
- 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('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
-
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
-
- # To handle L3 IPV4 configuration
- want_ipv4 = dict(want_dict).get('ipv4')
- have_ipv4 = dict(have_dict).get('ipv4')
- if want_ipv4:
- if have_ipv4:
- diff_ipv4 = set(want_ipv4) - set(dict(have_dict).get('ipv4'))
- if diff_ipv4:
- diff_ipv4 = diff_ipv4 if self.verify_diff_again(want_ipv4, have_ipv4) else ()
- else:
- diff_ipv4 = set(want_ipv4)
- for each in diff_ipv4:
- ipv4_dict = dict(each)
- if ipv4_dict.get('address') != 'dhcp':
- cmd = "ipv4 address {0}".format(ipv4_dict['address'])
- if ipv4_dict.get("secondary"):
- cmd += " secondary"
- add_command_to_config_list(interface, cmd, commands)
-
- # To handle L3 IPV6 configuration
- want_ipv6 = dict(want_dict).get('ipv6')
- have_ipv6 = dict(have_dict).get('ipv6')
- if want_ipv6:
- if have_ipv6:
- diff_ipv6 = set(want_ipv6) - set(have_ipv6)
- else:
- diff_ipv6 = set(want_ipv6)
- for each in diff_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, 'ipv4 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/iosxr/config/lacp/lacp.py b/lib/ansible/module_utils/network/iosxr/config/lacp/lacp.py
deleted file mode 100644
index 51acdb90f3..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/lacp/lacp.py
+++ /dev/null
@@ -1,172 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.common.utils import dict_diff
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import remove_empties
-from ansible.module_utils.network.iosxr. \
- utils.utils import flatten_dict
-
-
-class Lacp(ConfigBase):
- """
- The iosxr_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.get('config')
- if not want:
- want = {}
- 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
-
- @staticmethod
- def _state_replaced(want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- commands.extend(
- Lacp._state_deleted(want, have)
- )
-
- commands.extend(
- Lacp._state_merged(want, have)
- )
-
- return commands
-
- @staticmethod
- def _state_merged(want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- updates = dict_diff(have, want)
- if updates:
- for key, value in iteritems(flatten_dict(remove_empties(updates['system']))):
- commands.append('lacp system {0} {1}'.format(key.replace('address', 'mac'), value))
-
- return commands
-
- @staticmethod
- def _state_deleted(want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- for x in [k for k in have.get('system', {}) if k not in remove_empties(want.get('system', {}))]:
- commands.append('no lacp system {0}'.format(x))
-
- return commands
diff --git a/lib/ansible/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 34e137269b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,264 +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 iosxr_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.iosxr.facts.facts import Facts
-from ansible.module_utils.network.common.utils import dict_diff, remove_empties
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import search_obj_in_list
-from ansible.module_utils.network.iosxr.utils.utils import dict_delete, pad_commands, flatten_dict
-
-
-class Lacp_interfaces(ConfigBase):
- """
- The iosxr_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.extend(
- Lacp_interfaces._state_overridden(
- want, have
- )
- )
-
- elif state == 'deleted':
- if not want:
- for intf in have:
- commands.extend(
- Lacp_interfaces._state_deleted(
- {'name': intf['name']},
- intf
- )
- )
- else:
- for item in want:
- obj_in_have = search_obj_in_list(item['name'], have)
- commands.extend(
- Lacp_interfaces._state_deleted(
- item, obj_in_have
- )
- )
-
- else:
- for item in want:
- name = item['name']
- obj_in_have = search_obj_in_list(name, have)
-
- if state == 'merged':
- commands.extend(
- Lacp_interfaces._state_merged(
- item, obj_in_have
- )
- )
-
- elif state == 'replaced':
- commands.extend(
- Lacp_interfaces._state_replaced(
- item, obj_in_have
- )
- )
-
- return commands
-
- @staticmethod
- def _state_replaced(want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
- replaced_commands = []
- merged_commands = []
-
- if have:
- replaced_commands = Lacp_interfaces._state_deleted(want, have)
-
- merged_commands = Lacp_interfaces._state_merged(want, have)
-
- if merged_commands and replaced_commands:
- del merged_commands[0]
-
- commands.extend(replaced_commands)
- commands.extend(merged_commands)
-
- return commands
-
- @staticmethod
- def _state_overridden(want, have):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
- for intf in have:
- intf_in_want = search_obj_in_list(intf['name'], want)
- if not intf_in_want:
- commands.extend(Lacp_interfaces._state_deleted({'name': intf['name']}, intf))
-
- for intf in want:
- intf_in_have = search_obj_in_list(intf['name'], have)
- commands.extend(Lacp_interfaces._state_replaced(intf, intf_in_have))
-
- return commands
-
- @staticmethod
- def _state_merged(want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- if not have:
- have = {'name': want['name']}
-
- for key, value in iteritems(flatten_dict(remove_empties(dict_diff(have, want)))):
- commands.append(Lacp_interfaces._compute_commands(key, value))
-
- if commands:
- pad_commands(commands, want['name'])
-
- return commands
-
- @staticmethod
- def _state_deleted(want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- for key, value in iteritems(flatten_dict(dict_delete(have, remove_empties(want)))):
- commands.append(Lacp_interfaces._compute_commands(key, value, remove=True))
-
- if commands:
- pad_commands(commands, have['name'])
-
- return commands
-
- @staticmethod
- def _compute_commands(key, value, remove=False):
- if key == "churn_logging":
- cmd = "lacp churn logging {0}".format(value)
-
- elif key == "collector_max_delay":
- cmd = "lacp collector-max-delay {0}".format(value)
-
- elif key == "period":
- cmd = "lacp period {0}".format(value)
-
- elif key == "switchover_suppress_flaps":
- cmd = "lacp switchover suppress-flaps {0}".format(value)
-
- elif key == 'mac':
- cmd = "lacp system mac {0}".format(value)
-
- elif key == 'priority':
- cmd = "lacp system priority {0}".format(value)
-
- if remove:
- cmd = "no " + cmd
-
- return cmd
diff --git a/lib/ansible/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index 432fcd52a0..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,386 +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 iosxr_lag_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from copy import deepcopy
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.iosxr.facts.facts import Facts
-from ansible.module_utils.network.common.utils \
- import (
- to_list,
- dict_diff,
- remove_empties,
- search_obj_in_list,
- param_list_to_dict
- )
-from ansible.module_utils.network.iosxr.utils.utils \
- import (
- diff_list_of_dicts,
- pad_commands,
- flatten_dict,
- dict_delete,
- normalize_interface
- )
-
-
-class Lag_interfaces(ConfigBase):
- """
- The iosxr_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}
- warnings = list()
- commands = 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']
- if want:
- for item in want:
- item['name'] = normalize_interface(item['name'])
- if 'members' in want and want['members']:
- for item in want['members']:
- item.update({
- 'member': normalize_interface(item['member']),
- 'mode': item['mode']
- })
- 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']
- commands = []
-
- 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.extend(self._state_overridden(want, have))
-
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
-
- else:
- # Instead of passing entire want and have
- # list of dictionaries to the respective
- # _state_* methods we are passing the want
- # and have dictionaries per interface
- for item in want:
- name = item['name']
- obj_in_have = search_obj_in_list(name, have)
-
- if state == 'merged':
- commands.extend(self._state_merged(item, obj_in_have))
-
- elif state == 'replaced':
- commands.extend(self._state_replaced(item, obj_in_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 = []
- if have:
- commands.extend(self._render_bundle_del_commands(want, have))
- commands.extend(self._render_bundle_updates(want, have))
-
- if commands or have == {}:
- pad_commands(commands, want['name'])
-
- if have:
- commands.extend(self._render_interface_del_commands(want, have))
- commands.extend(self._render_interface_updates(want, have))
-
- 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 have_intf in have:
- intf_in_want = search_obj_in_list(have_intf['name'], want)
- if not intf_in_want:
- commands.extend(self._purge_attribs(have_intf))
-
- for intf in want:
- intf_in_have = search_obj_in_list(intf['name'], have)
- commands.extend(self._state_replaced(intf, intf_in_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._render_bundle_updates(want, have))
-
- if commands or have == {}:
- pad_commands(commands, want['name'])
-
- commands.extend(self._render_interface_updates(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 not want:
- for item in have:
- commands.extend(self._purge_attribs(intf=item))
- else:
- for item in want:
- name = item['name']
- obj_in_have = search_obj_in_list(name, have)
- if not obj_in_have:
- self._module.fail_json(
- msg=('interface {0} does not exist'.format(name)))
- commands.extend(self._purge_attribs(intf=obj_in_have))
-
- return commands
-
- def _render_bundle_updates(self, want, have):
- """ The command generator for updates to bundles
- :rtype: A list
- :returns: the commands necessary to update bundles
- """
- commands = []
- if not have:
- have = {'name': want['name']}
-
- want_copy = deepcopy(want)
- have_copy = deepcopy(have)
-
- want_copy.pop('members', [])
- have_copy.pop('members', [])
-
- bundle_updates = dict_diff(have_copy, want_copy)
-
- if bundle_updates:
- for key, value in iteritems(
- flatten_dict(remove_empties(bundle_updates))):
- commands.append(self._compute_commands(key=key, value=value))
-
- return commands
-
- def _render_interface_updates(self, want, have):
- """ The command generator for updates to member
- interfaces
- :rtype: A list
- :returns: the commands necessary to update member
- interfaces
- """
- commands = []
-
- if not have:
- have = {'name': want['name']}
-
- member_diff = diff_list_of_dicts(want['members'],
- have.get('members', []))
-
- for diff in member_diff:
- diff_cmd = []
- bundle_cmd = 'bundle id {0}'.format(
- want['name'].split('Bundle-Ether')[1])
- if diff.get('mode'):
- bundle_cmd += ' mode {0}'.format(diff.get('mode'))
- diff_cmd.append(bundle_cmd)
- pad_commands(diff_cmd, diff['member'])
- commands.extend(diff_cmd)
-
- return commands
-
- def _render_bundle_del_commands(self, want, have):
- """ The command generator for delete commands
- w.r.t bundles
- :rtype: A list
- :returns: the commands necessary to update member
- interfaces
- """
- commands = []
- if not want:
- want = {'name': have['name']}
-
- want_copy = deepcopy(want)
- have_copy = deepcopy(have)
- want_copy.pop('members', [])
- have_copy.pop('members', [])
-
- to_delete = dict_delete(have_copy, remove_empties(want_copy))
- if to_delete:
- for key, value in iteritems(flatten_dict(
- remove_empties(to_delete))):
- commands.append(
- self._compute_commands(key=key, value=value, remove=True))
-
- return commands
-
- def _render_interface_del_commands(self, want, have):
- """ The command generator for delete commands
- w.r.t member interfaces
- :rtype: A list
- :returns: the commands necessary to update member
- interfaces
- """
- commands = []
- if not want:
- want = {}
- have_members = have.get('members')
-
- if have_members:
- have_members = param_list_to_dict(deepcopy(have_members), unique_key='member')
- want_members = param_list_to_dict(deepcopy(want).get('members', []), unique_key='member')
-
- for key in have_members:
- if key not in want_members:
- member_cmd = ['no bundle id']
- pad_commands(member_cmd, key)
- commands.extend(member_cmd)
-
- return commands
-
- def _purge_attribs(self, intf):
- """ The command generator for purging attributes
- :rtype: A list
- :returns: the commands necessary to purge attributes
- """
- commands = []
- have_copy = deepcopy(intf)
- members = have_copy.pop('members', [])
-
- to_delete = dict_delete(have_copy, remove_empties({'name': have_copy['name']}))
- if to_delete:
- for key, value in iteritems(flatten_dict(remove_empties(to_delete))):
- commands.append(self._compute_commands(key=key, value=value, remove=True))
-
- if commands:
- pad_commands(commands, intf['name'])
-
- if members:
- members = param_list_to_dict(deepcopy(members), unique_key='member')
- for key in members:
- member_cmd = ['no bundle id']
- pad_commands(member_cmd, key)
- commands.extend(member_cmd)
-
- return commands
-
- def _compute_commands(self, key, value, remove=False):
- """ The method generates LAG commands based on the
- key, value passed. When remove is set to True,
- the command is negated.
- :rtype: str
- :returns: a command based on the `key`, `value` pair
- passed and the value of `remove`
- """
- if key == "mode":
- cmd = "lacp mode {0}".format(value)
-
- elif key == "load_balancing_hash":
- cmd = "bundle load-balancing hash {0}".format(value)
-
- elif key == "max_active":
- cmd = "bundle maximum-active links {0}".format(value)
-
- elif key == "min_active":
- cmd = "bundle minimum-active links {0}".format(value)
-
- if remove:
- cmd = "no {0}".format(cmd)
-
- return cmd
diff --git a/lib/ansible/module_utils/network/iosxr/config/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/iosxr/config/lldp_global/lldp_global.py
deleted file mode 100644
index 812daad5ed..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,188 +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 iosxr_lldp_global class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, dict_diff, remove_empties
-from ansible.module_utils.network.iosxr.facts.facts import Facts
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.iosxr. \
- utils.utils import flatten_dict, dict_delete
-
-
-class Lldp_global(ConfigBase):
- """
- The iosxr_lldp class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lldp_global',
- ]
-
- def __init__(self, module):
- super(Lldp_global, self).__init__(module)
-
- def get_lldp_global_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lldp_facts = facts['ansible_network_resources'].get('lldp_global')
- if not lldp_facts:
- return {}
- return lldp_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- commands = list()
-
- existing_lldp_global_facts = self.get_lldp_global_facts()
- commands.extend(self.set_config(existing_lldp_global_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lldp_global_facts = self.get_lldp_global_facts()
-
- result['before'] = existing_lldp_global_facts
- if result['changed']:
- result['after'] = changed_lldp_global_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_lldp_global_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- if not want and self._module.params['state'] == 'deleted':
- want = {}
- have = existing_lldp_global_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state 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._state_deleted(want, have)
- )
-
- commands.extend(
- self._state_merged(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 = []
- updates = dict_diff(have, want)
- if updates:
- for key, value in iteritems(flatten_dict(remove_empties(updates))):
- commands.append(self._compute_commands(key, value))
-
- 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 = []
- for key, value in iteritems(flatten_dict(dict_delete(have, remove_empties(want)))):
- cmd = self._compute_commands(key, value, remove=True)
- if cmd:
- commands.append(cmd)
-
- return commands
-
- def _compute_commands(self, key, value=None, remove=False):
- if key in ['holdtime', 'reinit', 'timer']:
- cmd = 'lldp {0} {1}'.format(key, value)
- if remove:
- return 'no {0}'.format(cmd)
- else:
- return cmd
-
- elif key == 'subinterfaces':
- cmd = 'lldp subinterfaces enable'
- if (value and not remove):
- return cmd
- elif (not value and not remove) or (value and remove):
- return 'no {0}'.format(cmd)
-
- else:
- cmd = 'lldp tlv-select {0} disable'.format(key.replace('_', '-'))
- if (not value and not remove):
- return cmd
- elif (value and not remove) or (not value and remove):
- return 'no {0}'.format(cmd)
diff --git a/lib/ansible/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 2938b3c026..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,247 +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 iosxr_lldp_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, search_obj_in_list, dict_diff, remove_empties
-from ansible.module_utils.network.iosxr.facts.facts import Facts
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.iosxr.utils.utils import dict_delete, pad_commands, flatten_dict
-
-
-class Lldp_interfaces(ConfigBase):
- """
- The iosxr_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}
- warnings = list()
- commands = list()
-
- existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
- commands.extend(self.set_config(existing_lldp_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
-
- result['before'] = existing_lldp_interfaces_facts
- if result['changed']:
- result['after'] = changed_lldp_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_lldp_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_lldp_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- commands = []
- 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.extend(
- self._state_overridden(
- want, have
- )
- )
-
- elif state == 'deleted':
- if not want:
- for intf in have:
- commands.extend(
- self._state_deleted(
- {'name': intf['name']},
- intf
- )
- )
- else:
- for item in want:
- obj_in_have = search_obj_in_list(item['name'], have)
- commands.extend(
- self._state_deleted(
- item, obj_in_have
- )
- )
-
- else:
- for item in want:
- name = item['name']
- obj_in_have = search_obj_in_list(name, have)
-
- if state == 'merged':
- commands.extend(
- self._state_merged(
- item, obj_in_have
- )
- )
-
- elif state == 'replaced':
- commands.extend(
- self._state_replaced(
- item, obj_in_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 = []
- replaced_commands = []
- merged_commands = []
-
- if have:
- replaced_commands = self._state_deleted(want, have)
-
- merged_commands = self._state_merged(want, have)
-
- if merged_commands and replaced_commands:
- del merged_commands[0]
-
- commands.extend(replaced_commands)
- commands.extend(merged_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 intf in have:
- intf_in_want = search_obj_in_list(intf['name'], want)
- if not intf_in_want:
- commands.extend(self._state_deleted({'name': intf['name']}, intf))
-
- for intf in want:
- intf_in_have = search_obj_in_list(intf['name'], have)
- commands.extend(self._state_replaced(intf, intf_in_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 = []
- if not have:
- have = {'name': want['name']}
-
- for key, value in iteritems(flatten_dict(remove_empties(dict_diff(have, want)))):
- commands.append(self._compute_commands(key, value))
-
- if commands:
- pad_commands(commands, want['name'])
-
- 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 = []
-
- for key, value in iteritems(flatten_dict(dict_delete(have, remove_empties(want)))):
- commands.append(self._compute_commands(key, value, remove=True))
-
- if commands:
- pad_commands(commands, have['name'])
-
- return commands
-
- def _compute_commands(self, key, value=None, remove=False):
- if key == 'mac_address':
- cmd = 'lldp destination mac-address {0}'.format(value)
- if remove:
- return 'no {0}'.format(cmd)
- else:
- return cmd
-
- else:
- cmd = 'lldp {0} disable'.format(key)
- if (not value and not remove):
- return cmd
- elif (value and not remove) or (not value and remove):
- return 'no {0}'.format(cmd)
diff --git a/lib/ansible/module_utils/network/iosxr/config/static_routes/static_routes.py b/lib/ansible/module_utils/network/iosxr/config/static_routes/static_routes.py
deleted file mode 100644
index 1c843b9166..0000000000
--- a/lib/ansible/module_utils/network/iosxr/config/static_routes/static_routes.py
+++ /dev/null
@@ -1,560 +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 iosxr_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
-
-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.iosxr.facts.facts import Facts
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import (
- search_obj_in_list,
- remove_empties,
- dict_diff,
- dict_merge,
-)
-
-
-class Static_routes(ConfigBase):
- """
- The iosxr_static_routes class
- """
-
- gather_subset = [
- "!all",
- "!min",
- ]
-
- gather_network_resources = [
- "static_routes",
- ]
-
- def __init__(self, module):
- super(Static_routes, self).__init__(module)
-
- def get_static_routes_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(
- self.gather_subset, self.gather_network_resources, data=data
- )
- static_routes_facts = facts["ansible_network_resources"].get("static_routes")
- if not static_routes_facts:
- return []
- return static_routes_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {"changed": False}
- warnings = list()
- commands = list()
-
- if self.state in self.ACTION_STATES:
- existing_static_routes_facts = self.get_static_routes_facts()
- else:
- existing_static_routes_facts = []
-
- if self.state in self.ACTION_STATES or self.state == "rendered":
- commands.extend(self.set_config(existing_static_routes_facts))
-
- if commands and self.state in self.ACTION_STATES:
- if not self._module.check_mode:
- 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)
-
- 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"]
- commands = []
-
- 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.extend(self._state_overridden(want, have))
-
- elif state == "deleted":
- if not want:
- if len(have) >= 1:
- return "no router static"
-
- else:
- for w_item in want:
- obj_in_have = self._find_vrf(w_item, have)
- if obj_in_have:
- commands.extend(
- self._state_deleted(remove_empties(w_item), obj_in_have)
- )
-
- else:
- for w_item in want:
- obj_in_have = self._find_vrf(w_item, have)
- if state == "merged" or self.state == "rendered":
- commands.extend(
- self._state_merged(remove_empties(w_item), obj_in_have)
- )
-
- elif state == "replaced":
- commands.extend(
- self._state_replaced(remove_empties(w_item), obj_in_have)
- )
-
- if commands:
- commands.insert(0, "router static")
-
- 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 want_afi in want.get("address_families", []):
- have_afi = (
- self.find_af_context(want_afi, have.get("address_families", [])) or {}
- )
- update_commands = []
- for want_route in want_afi.get("routes", []):
- have_route = (
- search_obj_in_list(
- want_route["dest"], have_afi.get("routes", []), key="dest"
- )
- or {}
- )
-
- rotated_have_next_hops = self.rotate_next_hops(
- have_route.get("next_hops", {})
- )
- rotated_want_next_hops = self.rotate_next_hops(
- want_route.get("next_hops", {})
- )
-
- for key in rotated_have_next_hops.keys():
- if key not in rotated_want_next_hops:
- cmd = "no {0}".format(want_route["dest"])
- for item in key:
- if "." in item or ":" in item or "/" in item:
- cmd += " {0}".format(item)
- else:
- cmd += " vrf {0}".format(item)
- update_commands.append(cmd)
-
- for key, value in iteritems(rotated_want_next_hops):
- if key in rotated_have_next_hops:
- existing = True
- have_exit_point_attribs = rotated_have_next_hops[key]
-
- else:
- existing = False
- have_exit_point_attribs = {}
-
- updates = dict_diff(have_exit_point_attribs, value)
-
- if updates or not existing:
- update_commands.append(
- self._compute_commands(
- dest=want_route["dest"], next_hop=key, updates=updates
- )
- )
-
- if update_commands:
- update_commands.insert(
- 0,
- "address-family {0} {1}".format(want_afi["afi"], want_afi["safi"]),
- )
- commands.extend(update_commands)
-
- if "vrf" in want and update_commands:
- commands.insert(0, "vrf {0}".format(want["vrf"]))
-
- 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 = []
-
- # Iterate through all the entries, i.e., VRFs and Global entry in have
- # and fully remove the ones that are not present in want and then call
- # replaced
-
- for h_item in have:
- w_item = self._find_vrf(h_item, want)
-
- # Delete all the top-level keys (VRFs/Global Route Entry) that are
- # not specified in want.
- if not w_item:
- if "vrf" in h_item:
- commands.append("no vrf {0}".format(h_item["vrf"]))
- else:
- for have_afi in h_item.get("address_families", []):
- commands.append(
- "no address-family {0} {1}".format(
- have_afi["afi"], have_afi["safi"]
- )
- )
-
- # For VRFs/Global Entry present in want, we also need to delete extraneous routes
- # from them. We cannot reuse `_state_replaced` for this purpose since its scope is
- # limited to replacing a single `dest`.
- else:
- del_cmds = []
- for have_afi in h_item.get("address_families", []):
- want_afi = (
- self.find_af_context(
- have_afi, w_item.get("address_families", [])
- )
- or {}
- )
- update_commands = []
- for h_route in have_afi.get("routes", []):
- w_route = (
- search_obj_in_list(
- h_route["dest"], want_afi.get("routes", []), key="dest"
- )
- or {}
- )
- if not w_route:
- update_commands.append("no {0}".format(h_route["dest"]))
-
- if update_commands:
- update_commands.insert(
- 0,
- "address-family {0} {1}".format(
- want_afi["afi"], want_afi["safi"]
- ),
- )
- del_cmds.extend(update_commands)
-
- if "vrf" in want and update_commands:
- del_cmds.insert(0, "vrf {0}".format(want["vrf"]))
-
- commands.extend(del_cmds)
-
- # We finally call `_state_replaced` to replace exiting `dest` entries
- # or add new ones as specified in want.
- for w_item in want:
- h_item = self._find_vrf(w_item, have)
- commands.extend(self._state_replaced(remove_empties(w_item), h_item))
-
- 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 want_afi in want.get("address_families", []):
- have_afi = (
- self.find_af_context(want_afi, have.get("address_families", [])) or {}
- )
-
- update_commands = []
- for want_route in want_afi.get("routes", []):
- have_route = (
- search_obj_in_list(
- want_route["dest"], have_afi.get("routes", []), key="dest"
- )
- or {}
- )
-
- # convert the next_hops list of dictionaries to dictionary of
- # dictionaries with (`dest_vrf`, `forward_router_address`, `interface`) tuple
- # being the key for each dictionary.
- # a combination of these 3 attributes uniquely identifies a route entry.
- # in case `dest_vrf` is not specified, `forward_router_address` and `interface`
- # become the unique identifier
- rotated_have_next_hops = self.rotate_next_hops(
- have_route.get("next_hops", {})
- )
- rotated_want_next_hops = self.rotate_next_hops(
- want_route.get("next_hops", {})
- )
-
- # for every dict in the want next_hops dictionaries, if the key
- # is present in `rotated_have_next_hops`, we set `existing` to True,
- # which means the the given want exit point exists and we run dict_diff
- # on `value` which is basically all the other attributes of the exit point
- # if the key is not present, it means that this is a new exit point
- for key, value in iteritems(rotated_want_next_hops):
- if key in rotated_have_next_hops:
- existing = True
- have_exit_point_attribs = rotated_have_next_hops[key]
-
- else:
- existing = False
- have_exit_point_attribs = {}
-
- updates = dict_diff(have_exit_point_attribs, value)
- if updates or not existing:
- update_commands.append(
- self._compute_commands(
- dest=want_route["dest"],
- next_hop=key,
- # dict_merge() is necessary to make sure that we
- # don't end up overridding the entry and also to
- # allow incremental updates
- updates=dict_merge(
- rotated_have_next_hops.get(key, {}), updates
- ),
- )
- )
-
- if update_commands:
- update_commands.insert(
- 0,
- "address-family {0} {1}".format(want_afi["afi"], want_afi["safi"]),
- )
- commands.extend(update_commands)
-
- if "vrf" in want and update_commands:
- commands.insert(0, "vrf {0}".format(want["vrf"]))
-
- 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 "address_families" not in want:
- return ["no vrf {0}".format(want["vrf"])]
-
- else:
- for want_afi in want.get("address_families", []):
- update_commands = []
- have_afi = (
- self.find_af_context(want_afi, have.get("address_families", []))
- or {}
- )
- if have_afi:
- if "routes" not in want_afi:
- commands.append(
- "no address-family {0} {1}".format(
- have_afi["afi"], have_afi["safi"]
- )
- )
- else:
- for want_route in want_afi.get("routes", []):
- have_route = (
- search_obj_in_list(
- want_route["dest"],
- have_afi.get("routes", []),
- key="dest",
- )
- or {}
- )
- if have_route:
- if "next_hops" not in want_route:
- update_commands.append(
- "no {0}".format(want_route["dest"])
- )
- else:
- rotated_have_next_hops = self.rotate_next_hops(
- have_route.get("next_hops", {})
- )
- rotated_want_next_hops = self.rotate_next_hops(
- want_route.get("next_hops", {})
- )
-
- for key in rotated_want_next_hops.keys():
- if key in rotated_have_next_hops:
- cmd = "no {0}".format(want_route["dest"])
- for item in key:
- if (
- "." in item
- or ":" in item
- or "/" in item
- ):
- cmd += " {0}".format(item)
- else:
- cmd += " vrf {0}".format(item)
- update_commands.append(cmd)
-
- if update_commands:
- update_commands.insert(
- 0,
- "address-family {0} {1}".format(
- want_afi["afi"], want_afi["safi"]
- ),
- )
- commands.extend(update_commands)
-
- if "vrf" in want and commands:
- commands.insert(0, "vrf {0}".format(want["vrf"]))
-
- return commands
-
- def _find_vrf(self, item, entries):
- """ This method iterates through the items
- in `entries` and returns the object that
- matches `item`.
-
- :rtype: A dict
- :returns: the obj in `entries` that matches `item`
- """
- obj = {}
- afi = item.get("vrf")
-
- if afi:
- obj = search_obj_in_list(afi, entries, key="vrf") or {}
- else:
- for x in entries:
- if "vrf" not in remove_empties(x):
- obj = x
- break
- return obj
-
- def find_af_context(self, want_af_context, have_address_families):
- """ This method iterates through the have AFs
- and returns the one that matches the want AF
-
- :rtype: A dict
- :returns: the corresponding AF in have AFs
- that matches the want AF
- """
- for have_af in have_address_families:
- if (
- have_af["afi"] == want_af_context["afi"]
- and have_af["safi"] == want_af_context["safi"]
- ):
- return have_af
-
- def rotate_next_hops(self, next_hops):
- """ This method iterates through the list of
- next hops for a given destination network
- and converts it to a dictionary of dictionaries.
- Each dictionary has a primary key indicated by the
- tuple of `dest_vrf`, `forward_router_address` and
- `interface` and the value of this key is a dictionary
- that contains all the other attributes of the next hop.
-
- :rtype: A dict
- :returns: A next_hops list in a dictionary of dictionaries format
- """
- next_hops_dict = {}
-
- for entry in next_hops:
- entry = entry.copy()
- key_list = []
-
- for x in ["dest_vrf", "forward_router_address", "interface"]:
- if entry.get(x):
- key_list.append(entry.pop(x))
-
- key = tuple(key_list)
- next_hops_dict[key] = entry
-
- return next_hops_dict
-
- def _compute_commands(self, dest, next_hop, updates=None):
- """ This method computes a static route entry command
- from the specified `dest`, `next_hop` and `updates`
-
- :rtype: A str
- :returns: A platform specific static routes command
- """
- if not updates:
- updates = {}
-
- command = dest
-
- for x in next_hop:
- if "." in x or ":" in x or "/" in x:
- command += " {0}".format(x)
- else:
- command += " vrf {0}".format(x)
-
- for key in sorted(updates):
- if key == "admin_distance":
- command += " {0}".format(updates[key])
- else:
- command += " {0} {1}".format(key, updates[key])
-
- return command
diff --git a/lib/ansible/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index 93aa174b16..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,104 +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 iosxr 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.six import iteritems
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.iosxr.argspec.acl_interfaces.acl_interfaces import Acl_interfacesArgs
-
-
-class Acl_interfacesFacts(object):
- """ The iosxr 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 populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for acl_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
-
- if not data:
- data = connection.get_config(flags='interface')
-
- interfaces = data.split('interface ')
-
- objs = []
- for interface in interfaces:
- obj = self.render_config(self.generated_spec, interface)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('acl_interfaces', None)
- facts = {}
- 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)
- config['access_groups'] = []
- map_dir = {'ingress': 'in', 'egress': 'out'}
-
- match = re.search(r'(?:preconfigure)*(?:\s*)(\S+)', conf, re.M)
- if match:
- config['name'] = match.group(1)
- acls = {'ipv4': [], 'ipv6': []}
- for item in conf.split('\n'):
- item = item.strip()
- if item.startswith('ipv4 access-group'):
- acls['ipv4'].append(item)
- elif item.startswith('ipv6 access-group'):
- acls['ipv6'].append(item)
-
- for key, value in iteritems(acls):
- if value:
- entry = {'afi': key, 'acls': []}
- for item in value:
- entry['acls'].append({'name': item.split()[2], 'direction': map_dir[item.split()[3]]})
- config['access_groups'].append(entry)
-
- config['access_groups'] = sorted(config['access_groups'], key=lambda i: i['afi'])
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/acls/acls.py b/lib/ansible/module_utils/network/iosxr/facts/acls/acls.py
deleted file mode 100644
index 685bb67a94..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/acls/acls.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 iosxr 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
-
-from collections import deque
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.iosxr.argspec.acls.acls import AclsArgs
-from ansible.module_utils.network.iosxr.utils.utils import isipaddress
-
-PROTOCOL_OPTIONS = {
- 'tcp': (
- 'ack',
- 'fin',
- 'psh',
- 'rst',
- 'syn',
- 'urg',
- 'established',
- ),
- 'igmp': ('dvmrp', 'host_query', 'host_report', 'mtrace', 'mtrace_response',
- 'pim', 'trace', 'v2_leave', 'v2_report', 'v3_report'),
- 'icmp':
- ('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'),
- 'icmpv6':
- ('address_unreachable', 'administratively_prohibited',
- 'beyond_scope_of_source_address', 'destination_unreachable', 'echo',
- 'echo_reply', 'erroneous_header_field', 'group_membership_query',
- 'group_membership_report', 'group_membership_termination',
- 'host_unreachable', 'nd_na', 'nd_ns', 'neighbor_redirect',
- 'no_route_to_destination', 'node_information_request_is_refused',
- 'node_information_successful_reply', 'packet_too_big',
- 'parameter_problem', 'port_unreachable', 'query_subject_is_IPv4address',
- 'query_subject_is_IPv6address', 'query_subject_is_domainname',
- 'reassembly_timeout', 'redirect', 'router_advertisement',
- 'router_renumbering', 'router_solicitation', 'rr_command', 'rr_result',
- 'rr_seqnum_reset', 'time_exceeded', 'ttl_exceeded', 'unknown_query_type',
- 'unreachable', 'unrecognized_next_header', 'unrecognized_option',
- 'whoareyou_reply', 'whoareyou_request')
-}
-
-
-class AclsFacts(object):
- """ The iosxr acls fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = AclsArgs.argument_spec
- spec = deepcopy(self.argument_spec)
-
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_device_data(self, connection):
- return connection.get('show access-lists afi-all')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for acls
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if not data:
- data = self.get_device_data(connection)
-
- objs = []
-
- acl_lines = data.splitlines()
-
- # We iterate through the data and create a list of ACLs
- # where each ACL is a dictionary in the following format:
- # {'afi': 'ipv4', 'name': 'acl_1', 'aces': ['10 permit 172.16.0.0 0.0.255.255', '20 deny 192.168.34.0 0.0.0.255']}
- if acl_lines:
- acl, acls = {}, []
- for line in acl_lines:
- if line.startswith('ip'):
- if acl:
- acls.append(acl)
- acl = {'aces': []}
- acl['afi'], acl['name'] = line.split()[0], line.split()[2]
- else:
- acl['aces'].append(line.strip())
- acls.append(acl)
-
- # Here we group the ACLs based on AFI
- # {
- # 'ipv6': [{'aces': ['10 permit ipv6 2000::/12 any'], 'name': 'acl_2'}],
- # 'ipv4': [{'aces': ['10 permit 172.16.0.0 0.0.255.255', '20 deny 192.168.34.0 0.0.0.255'], 'name': 'acl_1'},
- # {'aces': ['20 deny 10.0.0.0/8 log'], 'name': 'acl_3'}]
- # }
-
- grouped_acls = {'ipv4': [], 'ipv6': []}
- for acl in acls:
- acl_copy = deepcopy(acl)
- del acl_copy['afi']
- grouped_acls[acl['afi']].append(acl_copy)
-
- # Now that we have the ACLs in a fairly structured format,
- # we pass it on to render_config to convert it to model spec
- for key, value in iteritems(grouped_acls):
- obj = self.render_config(self.generated_spec, value)
- if obj:
- obj['afi'] = key
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('acls', None)
- facts = {}
-
- facts['acls'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['acls'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- config['acls'] = []
-
- for item in conf:
- acl = {'name': item['name']}
- aces = item.get('aces', [])
- if aces:
- acl['aces'] = []
- for ace in aces:
- acl['aces'].append(self._render_ace(ace))
- config['acls'].append(acl)
-
- return utils.remove_empties(config)
-
- def _render_ace(self, ace):
- """
- Parses an Access Control Entry (ACE) and converts it
- into model spec
-
- :param ace: An ACE in device specific format
- :rtype: dictionary
- :returns: The ACE in structured format
- """
-
- def __parse_src_dest(rendered_ace, ace_queue, direction):
- """
- Parses the ACE queue and populates address, wildcard_bits,
- host or any keys in the source/destination dictionary of
- ace dictionary, i.e., `rendered_ace`.
-
- :param rendered_ace: The dictionary containing the ACE in structured format
- :param ace_queue: The ACE queue
- :param direction: Specifies whether to populate `source` or `destination`
- dictionary
- """
- element = ace_queue.popleft()
- if element == 'host':
- rendered_ace[direction] = {'host': ace_queue.popleft()}
-
- elif element == 'any':
- rendered_ace[direction] = {'any': True}
-
- elif '/' in element:
- rendered_ace[direction] = {
- 'prefix': element
- }
-
- elif isipaddress(element):
- rendered_ace[direction] = {
- 'address': element,
- 'wildcard_bits': ace_queue.popleft()
- }
-
- def __parse_port_protocol(rendered_ace, ace_queue, direction):
- """
- Parses the ACE queue and populates `port_protocol` dictionary in the
- ACE dictionary, i.e., `rendered_ace`.
-
- :param rendered_ace: The dictionary containing the ACE in structured format
- :param ace_queue: The ACE queue
- :param direction: Specifies whether to populate `source` or `destination`
- dictionary
- """
- if len(ace_queue) > 0 and ace_queue[0] in ('eq', 'gt', 'lt', 'neq',
- 'range'):
- element = ace_queue.popleft()
- port_protocol = {}
-
- if element == 'range':
- port_protocol['range'] = {
- 'start': ace_queue.popleft(),
- 'end': ace_queue.popleft()
- }
- else:
- port_protocol[element] = ace_queue.popleft()
-
- rendered_ace[direction]['port_protocol'] = port_protocol
-
- def __parse_protocol_options(rendered_ace, ace_queue, protocol):
- """
- Parses the ACE queue and populates protocol specific options
- of the required dictionary and updates the ACE dictionary, i.e.,
- `rendered_ace`.
-
- :param rendered_ace: The dictionary containing the ACE in structured format
- :param ace_queue: The ACE queue
- :param protocol: Specifies the protocol that will be populated under
- `protocol_options` dictionary
- """
- if len(ace_queue) > 0:
- protocol_options = {protocol: {}}
-
- for match_bit in PROTOCOL_OPTIONS.get(protocol, ()):
- if match_bit.replace('_', '-') in ace_queue:
- protocol_options[protocol][match_bit] = True
- ace_queue.remove(match_bit.replace('_', '-'))
-
- rendered_ace['protocol_options'] = protocol_options
-
- def __parse_match_options(rendered_ace, ace_queue):
- """
- Parses the ACE queue and populates remaining options in the ACE dictionary,
- i.e., `rendered_ace`
-
- :param rendered_ace: The dictionary containing the ACE in structured format
- :param ace_queue: The ACE queue
- """
- if len(ace_queue) > 0:
- # We deepcopy the actual queue and iterate through the
- # copied queue. However, we pop off the elements from
- # the actual queue. Then, in every pass we update the copied
- # queue with the current state of the original queue.
- # This is done because a queue cannot be mutated during iteration.
- copy_ace_queue = deepcopy(ace_queue)
-
- for element in copy_ace_queue:
- if element == 'precedence':
- ace_queue.popleft()
- rendered_ace['precedence'] = ace_queue.popleft()
-
- elif element == 'dscp':
- ace_queue.popleft()
- dscp = {}
- operation = ace_queue.popleft()
-
- if operation in ('eq', 'gt', 'neq', 'lt', 'range'):
- if operation == 'range':
- dscp['range'] = {
- 'start': ace_queue.popleft(),
- 'end': ace_queue.popleft()
- }
- else:
- dscp[operation] = ace_queue.popleft()
- else:
- # `dscp` can be followed by either the dscp value itself or
- # the same thing can be represented using "dscp eq <dscp_value>".
- # In both cases, it would show up as {'dscp': {'eq': "dscp_value"}}.
- dscp['eq'] = operation
-
- rendered_ace['dscp'] = dscp
-
- elif element in ('packet-length', 'ttl'):
- ace_queue.popleft()
- element_dict = {}
- operation = ace_queue.popleft()
-
- if operation == 'range':
- element_dict['range'] = {
- 'start': ace_queue.popleft(),
- 'end': ace_queue.popleft()
- }
- else:
- element_dict[operation] = ace_queue.popleft()
-
- rendered_ace[element.replace('-', '_')] = element_dict
-
- elif element in ('log', 'log-input', 'fragments',
- 'icmp-off', 'capture', 'destopts',
- 'authen', 'routing', 'hop-by-hop'):
- rendered_ace[element.replace('-', '_')] = True
- ace_queue.remove(element)
-
- copy_ace_queue = deepcopy(ace_queue)
-
- rendered_ace = {}
- split_ace = ace.split()
-
- # Create a queue with each word in the ace
- # We parse each element and pop it off the queue
- ace_queue = deque(split_ace)
-
- # An ACE will always have a sequence number, even if
- # it is not explicitly provided while configuring
- sequence = int(ace_queue.popleft())
- rendered_ace['sequence'] = sequence
- operation = ace_queue.popleft()
-
- if operation == 'remark':
- rendered_ace['remark'] = ' '.join(split_ace[2:])
-
- else:
- rendered_ace['grant'] = operation
-
- # If the entry is a non-remark entry, the third element
- # will always be the protocol specified. By default, it's
- # the AFI.
- rendered_ace['protocol'] = ace_queue.popleft()
-
- # Populate source dictionary
- __parse_src_dest(rendered_ace, ace_queue, direction='source')
- # Populate port_protocol key in source dictionary
- __parse_port_protocol(rendered_ace, ace_queue, direction='source')
- # Populate destination dictionary
- __parse_src_dest(rendered_ace, ace_queue, direction='destination')
- # Populate port_protocol key in destination dictionary
- __parse_port_protocol(rendered_ace,
- ace_queue,
- direction='destination')
- # Populate protocol_options dictionary
- __parse_protocol_options(rendered_ace,
- ace_queue,
- protocol=rendered_ace['protocol'])
- # Populate remaining match options' dictionaries
- __parse_match_options(rendered_ace, ace_queue)
-
- # At this stage the queue should be empty
- # If the queue is not empty, it means that
- # we haven't been able to parse the entire ACE
- # In this case, we add the whole unprocessed ACE
- # to a key called `line` and send it back
- if len(ace_queue) > 0:
- rendered_ace = {
- 'sequence': sequence,
- 'line': ' '.join(split_ace[1:])
- }
-
- return utils.remove_empties(rendered_ace)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/facts.py b/lib/ansible/module_utils/network/iosxr/facts/facts.py
deleted file mode 100644
index 109a813a59..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/facts.py
+++ /dev/null
@@ -1,77 +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 iosxr
-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.iosxr.facts.legacy.base import Default, Hardware, Interfaces, Config
-from ansible.module_utils.network.iosxr.facts.lacp.lacp import LacpFacts
-from ansible.module_utils.network.iosxr.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts
-from ansible.module_utils.network.iosxr.facts.lldp_global.lldp_global import Lldp_globalFacts
-from ansible.module_utils.network.iosxr.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts
-from ansible.module_utils.network.iosxr.facts.interfaces.interfaces import InterfacesFacts
-from ansible.module_utils.network.iosxr.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
-from ansible.module_utils.network.iosxr.facts.l2_interfaces.l2_interfaces import L2_InterfacesFacts
-from ansible.module_utils.network.iosxr.facts.l3_interfaces.l3_interfaces import L3_InterfacesFacts
-from ansible.module_utils.network.iosxr.facts.acl_interfaces.acl_interfaces import Acl_interfacesFacts
-from ansible.module_utils.network.iosxr.facts.acls.acls import AclsFacts
-from ansible.module_utils.network.iosxr.facts.static_routes.static_routes import Static_routesFacts
-
-
-FACT_LEGACY_SUBSETS = dict(
- default=Default,
- hardware=Hardware,
- interfaces=Interfaces,
- config=Config,
-)
-FACT_RESOURCE_SUBSETS = dict(
- lacp=LacpFacts,
- lacp_interfaces=Lacp_interfacesFacts,
- lldp_global=Lldp_globalFacts,
- lldp_interfaces=Lldp_interfacesFacts,
- interfaces=InterfacesFacts,
- l2_interfaces=L2_InterfacesFacts,
- lag_interfaces=Lag_interfacesFacts,
- l3_interfaces=L3_InterfacesFacts,
- acl_interfaces=Acl_interfacesFacts,
- acls=AclsFacts,
- static_routes=Static_routesFacts
-)
-
-
-class Facts(FactsBase):
- """ The fact class for iosxr
- """
-
- 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 iosxr
-
- :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/iosxr/facts/interfaces/interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/interfaces/interfaces.py
deleted file mode 100644
index 8ec4258d0b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/interfaces/interfaces.py
+++ /dev/null
@@ -1,102 +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 iosxr 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.iosxr.utils.utils import get_interface_type
-from ansible.module_utils.network.iosxr.argspec.interfaces.interfaces import InterfacesArgs
-
-
-class InterfacesFacts(object):
- """ The iosxr 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 module: the module instance
- :param connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get('show running-config 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 match.group(1).lower() == "preconfigure":
- match = re.search(r'^(\S+) (.*)', conf)
- if match:
- intf = match.group(2)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- # populate the facts from the configuration
- config['name'] = intf
- config['description'] = utils.parse_conf_arg(conf, 'description')
- if utils.parse_conf_arg(conf, 'speed'):
- config['speed'] = int(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/iosxr/facts/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index dd77172da4..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,125 +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 iosxr l2_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.iosxr.utils.utils import get_interface_type
-from ansible.module_utils.network.iosxr.argspec.l2_interfaces.l2_interfaces import L2_InterfacesArgs
-
-
-class L2_InterfacesFacts(object):
- """ The iosxr 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 l2_interfaces
- :param module: the module instance
- :param connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get('show running-config 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 match.group(1).lower() == "preconfigure":
- match = re.search(r'^(\S+) (.*)', conf)
- if match:
- intf = match.group(2)
-
- if get_interface_type(intf) == 'unknown':
- return {}
-
- if intf.lower().startswith('gi'):
- config['name'] = intf
-
- # populate the facts from the configuration
- native_vlan = re.search(r"dot1q native vlan (\d+)", conf)
- if native_vlan:
- config["native_vlan"] = int(native_vlan.group(1))
-
- dot1q = utils.parse_conf_arg(conf, 'encapsulation dot1q')
- config['q_vlan'] = []
- if dot1q:
- config['q_vlan'].append(int(dot1q.split(' ')[0]))
- if len(dot1q.split(' ')) > 1:
- config['q_vlan'].append(int(dot1q.split(' ')[2]))
-
- if utils.parse_conf_cmd_arg(conf, 'l2transport', True):
- config['l2transport'] = True
- if utils.parse_conf_arg(conf, 'propagate'):
- config['propagate'] = True
- config['l2protocol'] = []
-
- cdp = utils.parse_conf_arg(conf, 'l2protocol cdp')
- pvst = utils.parse_conf_arg(conf, 'l2protocol pvst')
- stp = utils.parse_conf_arg(conf, 'l2protocol stp')
- vtp = utils.parse_conf_arg(conf, 'l2protocol vtp')
- if cdp:
- config['l2protocol'].append({'cdp': cdp})
- if pvst:
- config['l2protocol'].append({'pvst': pvst})
- if stp:
- config['l2protocol'].append({'stp': stp})
- if vtp:
- config['l2protocol'].append({'vtp': vtp})
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 5e610701bd..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,117 +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 iosxr_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.iosxr.utils.utils import get_interface_type
-from ansible.module_utils.network.iosxr.argspec.l3_interfaces.l3_interfaces import L3_InterfacesArgs
-
-
-class L3_InterfacesFacts(object):
- """ The iosxr_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 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 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 match.group(1).lower() == "preconfigure":
- match = re.search(r'^(\S+) (.*)', conf)
- if match:
- intf = match.group(2)
-
- if get_interface_type(intf) == 'unknown':
- return {}
-
- # populate the facts from the configuration
- config['name'] = intf
-
- # Get the configured IPV4 details
- ipv4 = []
- ipv4_all = re.findall(r"ipv4 address (\S+.*)", conf)
- for each in ipv4_all:
- each_ipv4 = dict()
- if 'secondary' in each:
- each_ipv4['address'] = each.split(' secondary')[0]
- each_ipv4['secondary'] = True
- else:
- each_ipv4['address'] = each
- 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()
- each_ipv6['address'] = each
- ipv6.append(each_ipv6)
- config['ipv6'] = ipv6
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/lacp/lacp.py b/lib/ansible/module_utils/network/iosxr/facts/lacp/lacp.py
deleted file mode 100644
index 54226dca8b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/lacp/lacp.py
+++ /dev/null
@@ -1,82 +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 iosxr 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.iosxr.argspec.lacp.lacp import LacpArgs
-
-
-class LacpFacts(object):
- """ The iosxr 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 not data:
- data = connection.get_config(flags='lacp')
-
- 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)
-
- system_priority = utils.parse_conf_arg(conf, 'priority')
- config['system']['priority'] = int(system_priority) if system_priority else system_priority
- config['system']['mac']['address'] = utils.parse_conf_arg(conf, 'mac')
-
- return config
diff --git a/lib/ansible/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index d7744c6ad2..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,104 +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 iosxr 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.iosxr.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
-from ansible.module_utils.six import iteritems
-
-
-class Lacp_interfacesFacts(object):
- """ The iosxr 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 not data:
- data = connection.get_config(flags='interface')
- interfaces = data.split('interface ')
-
- objs = []
- for interface in interfaces:
- obj = self.render_config(self.generated_spec, interface)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('lacp_interfaces', None)
- 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'(GigabitEthernet|Bundle-Ether|TenGigE|FortyGigE|HundredGigE)(\S+)', conf, re.M)
- if match:
- config['name'] = match.group(1) + match.group(2)
-
- temp = {
- 'churn_logging': 'lacp churn logging',
- 'switchover_suppress_flaps': 'lacp switchover suppress-flaps',
- 'collector_max_delay': 'lacp collector-max-delay',
- 'period': 'lacp period'
- }
-
- for key, value in iteritems(temp):
- config[key] = utils.parse_conf_arg(
- conf, value)
-
- for key in config['system'].keys():
- config['system'][key] = utils.parse_conf_arg(
- conf, 'lacp system {0}'.format(key))
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index 212232cfea..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,128 +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 iosxr 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.iosxr.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
-
-
-class Lag_interfacesFacts(object):
- """ The iosxr lag_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Lag_interfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lag_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
-
- if not data:
- data = connection.get_config(flags='interface')
- interfaces = data.split('interface ')
-
- objs = []
-
- for interface in interfaces:
- if interface.startswith("Bundle-Ether"):
- obj = self.render_config(self.generated_spec, interface, interfaces)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('lag_interfaces', None)
- facts = {}
-
- 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, data):
- """
- 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'(Bundle-Ether)(\d+)', conf, re.M)
- if match:
- config['name'] = match.group(1) + match.group(2)
- config['load_balancing_hash'] = utils.parse_conf_arg(
- conf, 'bundle load-balancing hash')
- config['mode'] = utils.parse_conf_arg(conf, 'lacp mode')
- config['links']['max_active'] = utils.parse_conf_arg(
- conf, 'bundle maximum-active links')
- config['links']['min_active'] = utils.parse_conf_arg(
- conf, 'bundle minimum-active links')
- config['members'] = self.parse_members(match.group(2), data)
-
- return utils.remove_empties(config)
-
- def parse_members(self, bundle_id, interfaces):
- """
- Renders a list of member interfaces for every bundle
- present in running-config.
-
- :param bundle_id: The Bundle-Ether ID fetched from running-config
- :param interfaces: Data of all interfaces present in running-config
- :rtype: list
- :returns: A list of member interfaces
- """
- def _parse_interface(name):
- if name.startswith('preconfigure'):
- return name.split()[1]
- else:
- return name.split()[0]
-
- members = []
- for interface in interfaces:
- if not interface.startswith('Bu'):
- match = re.search(r'bundle id (\d+) mode (\S+)', interface, re.M)
- if match:
- if bundle_id == match.group(1):
- members.append(
- {
- 'member': _parse_interface(interface),
- 'mode': match.group(2)
- }
- )
-
- return members
diff --git a/lib/ansible/module_utils/network/iosxr/facts/legacy/base.py b/lib/ansible/module_utils/network/iosxr/facts/legacy/base.py
deleted file mode 100644
index cbcee0bb50..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/legacy/base.py
+++ /dev/null
@@ -1,259 +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 iosxr 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.iosxr.iosxr import run_commands, get_capabilities
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six.moves import zip
-
-
-class FactsBase(object):
-
- COMMANDS = frozenset()
-
- 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, list(self.COMMANDS), check_rc=False)
-
-
-class Default(FactsBase):
-
- def populate(self):
- self.facts.update(self.platform_facts())
-
- def platform_facts(self):
- platform_facts = {}
-
- resp = get_capabilities(self.module)
- device_info = resp['device_info']
-
- platform_facts['system'] = device_info['network_os']
-
- for item in ('model', 'image', 'version', 'platform', 'hostname'):
- val = device_info.get('network_os_%s' % item)
- if val:
- platform_facts[item] = val
-
- platform_facts['api'] = resp['network_api']
- platform_facts['python_version'] = platform.python_version()
-
- return platform_facts
-
-
-class Hardware(FactsBase):
-
- COMMANDS = [
- 'dir /all',
- 'show memory summary'
- ]
-
- def populate(self):
- super(Hardware, self).populate()
- data = self.responses[0]
- self.facts['filesystems'] = self.parse_filesystems(data)
-
- data = self.responses[1]
- match = re.search(r'Physical Memory: (\d+)M total \((\d+)', data)
- if match:
- self.facts['memtotal_mb'] = match.group(1)
- self.facts['memfree_mb'] = match.group(2)
-
- def parse_filesystems(self, data):
- return re.findall(r'^Directory of (\S+)', data, re.M)
-
-
-class Config(FactsBase):
-
- COMMANDS = [
- 'show running-config'
- ]
-
- def populate(self):
- super(Config, self).populate()
- self.facts['config'] = self.responses[0]
-
-
-class Interfaces(FactsBase):
-
- COMMANDS = [
- 'show interfaces',
- 'show ipv6 interface',
- 'show lldp',
- 'show lldp neighbors detail'
- ]
-
- def populate(self):
- super(Interfaces, self).populate()
- self.facts['all_ipv4_addresses'] = list()
- self.facts['all_ipv6_addresses'] = list()
-
- interfaces = self.parse_interfaces(self.responses[0])
- self.facts['interfaces'] = self.populate_interfaces(interfaces)
-
- data = self.responses[1]
- if len(data) > 0:
- data = self.parse_interfaces(data)
- self.populate_ipv6_interfaces(data)
-
- if 'LLDP is not enabled' not in self.responses[2]:
- neighbors = self.responses[3]
- self.facts['neighbors'] = self.parse_neighbors(neighbors)
-
- 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)
-
- ipv4 = self.parse_ipv4(value)
- intf['ipv4'] = self.parse_ipv4(value)
- if ipv4:
- self.add_ip_address(ipv4['address'], 'ipv4')
-
- intf['mtu'] = self.parse_mtu(value)
- intf['bandwidth'] = self.parse_bandwidth(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_ipv6_interfaces(self, data):
- for key, value in iteritems(data):
- if key in ['No', 'RPF'] or key.startswith('IP'):
- continue
- 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()
- nbors = neighbors.split('------------------------------------------------')
- for entry in nbors[1:]:
- if entry == '':
- continue
- intf = self.parse_lldp_intf(entry)
- if intf not in facts:
- facts[intf] = list()
- fact = dict()
- fact['host'] = self.parse_lldp_host(entry)
- fact['remote_description'] = self.parse_lldp_remote_desc(entry)
- fact['port'] = self.parse_lldp_port(entry)
- 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'address is (\S+)', data)
- if match:
- return match.group(1)
-
- def parse_ipv4(self, data):
- match = re.search(r'Internet address is (\S+)/(\d+)', data)
- if match:
- addr = match.group(1)
- masklen = int(match.group(2))
- return dict(address=addr, masklen=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+)(?: D|-d)uplex', 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+?$', 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 Interface: (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lldp_remote_desc(self, data):
- match = re.search(r'Port Description: (.+)$', 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)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/iosxr/facts/lldp_global/lldp_global.py
deleted file mode 100644
index bbaa1f6ee4..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,91 +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 iosxr lldp 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.iosxr.argspec.lldp_global.lldp_global import Lldp_globalArgs
-
-
-class Lldp_globalFacts(object):
- """ The iosxr lldp 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
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if not data:
- data = connection.get_config(flags='lldp')
-
- obj = {}
- if data:
- lldp_obj = self.render_config(self.generated_spec, data)
- if lldp_obj:
- obj = lldp_obj
-
- ansible_facts['ansible_network_resources'].pop('lldp_global', None)
- facts = {}
-
- params = utils.validate_config(self.argument_spec, {'config': obj})
- 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)
-
- for key in spec.keys():
- if key == 'subinterfaces':
- config[key] = True if 'subinterfaces enable' in conf else None
-
- elif key == 'tlv_select':
- for item in ['system_name', 'port_description', 'management_address', 'system_description', 'system_capabilities']:
- config[key][item] = False if ('{0} disable'.format(item.replace('_', '-'))) in conf else None
-
- else:
- value = utils.parse_conf_arg(conf, key)
- config[key] = int(value) if value else value
-
- return config
diff --git a/lib/ansible/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 292493175b..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,96 +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 iosxr 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.iosxr.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
-
-
-class Lldp_interfacesFacts(object):
- """ The iosxr 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 not data:
- data = connection.get_config(flags='interface')
- interfaces = data.split('interface ')
-
- objs = []
- for interface in interfaces:
- obj = self.render_config(self.generated_spec, interface)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('lldp_interfaces', None)
- 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'(GigabitEthernet|Bundle-Ether|TenGigE|FortyGigE|HundredGigE)(\S+)', conf, re.M)
- if match:
- config['name'] = match.group(1) + match.group(2)
-
- for key in ['receive', 'transmit']:
- config[key] = False if ('{0} disable'.format(key)) in conf else None
-
- for x in ['ieee-nearest-bridge', 'ieee-nearest-non-tmpr-bridge']:
- if x in conf:
- config['destination']['mac_address'] = x
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/iosxr/facts/static_routes/static_routes.py b/lib/ansible/module_utils/network/iosxr/facts/static_routes/static_routes.py
deleted file mode 100644
index 3485cc7813..0000000000
--- a/lib/ansible/module_utils/network/iosxr/facts/static_routes/static_routes.py
+++ /dev/null
@@ -1,176 +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 iosxr static_routes fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-import re
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.iosxr.argspec.static_routes.static_routes import Static_routesArgs
-
-
-class Static_routesFacts(object):
- """ The iosxr static_routes fact class
- """
-
- def __init__(self, module, subspec="config", options="options"):
- self._module = module
- self.argument_spec = Static_routesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_device_data(self, connection):
- return connection.get_config(flags="router static")
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for static_routes
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if not data:
- data = self.get_device_data(connection)
-
- objs = []
-
- if "No such configuration" not in data:
- for entry in re.compile(r"(\s) vrf").split(data):
- obj = self.render_config(self.generated_spec, entry)
- if obj:
- objs.append(obj)
-
- ansible_facts["ansible_network_resources"].pop("static_routes", None)
- facts = {}
-
- facts["static_routes"] = []
- params = utils.validate_config(self.argument_spec, {"config": objs})
- for cfg in params["config"]:
- facts["static_routes"].append(utils.remove_empties(cfg))
-
- ansible_facts["ansible_network_resources"].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- entry_list = conf.split(" address-family")
- config["address_families"] = []
-
- if "router static" not in entry_list[0]:
- config["vrf"] = entry_list[0].replace("!", "").strip()
-
- for item in entry_list[1:]:
- routes = []
- address_family = {"routes": []}
- address_family["afi"], address_family["safi"] = self.parse_af(item)
-
- destinations = re.findall(r"((?:\S+)/(?:\d+)) (?:.*)", item, re.M)
- for dest in set(destinations):
- route = {"next_hops": []}
- route["dest"] = dest
-
- regex = r"%s .+$" % dest
- cfg = re.findall(regex, item, re.M)
-
- for route_entry in cfg:
- exit_point = {}
- exit_point["forward_router_address"] = self.parse_faddr(route_entry)
- exit_point["interface"] = self.parse_intf(route_entry)
- exit_point["admin_distance"] = self.parse_admin_distance(route_entry)
-
- for x in [
- "tag",
- "tunnel-id",
- "metric",
- "description",
- "track",
- "vrflabel",
- "dest_vrf",
- ]:
- exit_point[x.replace("-", "_")] = self.parse_attrib(
- route_entry, x.replace("dest_vrf", "vrf")
- )
-
- route["next_hops"].append(exit_point)
-
- routes.append(route)
- address_family["routes"] = sorted(routes, key=lambda i: i["dest"])
- config["address_families"].append(address_family)
-
- return utils.remove_empties(config)
-
- def parse_af(self, item):
- match = re.search(r"(?:\s*)(\w+)(?:\s*)(\w+)", item, re.M)
- if match:
- return match.group(1), match.group(2)
-
- def parse_faddr(self, item):
- for x in item.split(" "):
- if (":" in x or "." in x) and "/" not in x:
- return x
-
- def parse_intf(self, item):
- match = re.search(r" ((\w+)((?:\d)/(?:\d)/(?:\d)/(?:\d+)))", item)
- if match:
- return match.group(1)
-
- def parse_attrib(self, item, attrib):
- match = re.search(r" %s (\S+)" % attrib, item)
- if match:
- val = match.group(1).strip("'")
- if attrib in ["tunnel-id", "vrflabel", "tag", "metric"]:
- val = int(val)
- return val
-
- def parse_admin_distance(self, item):
- split_item = item.split(" ")
- for item in [
- "vrf",
- "metric",
- "tunnel-id",
- "vrflabel",
- "track",
- "tag",
- "description",
- ]:
- try:
- del split_item[split_item.index(item) + 1]
- del split_item[split_item.index(item)]
- except ValueError:
- continue
- try:
- return [
- i for i in split_item if "." not in i and ":" not in i and ord(i[0]) > 48 and ord(i[0]) < 57
- ][0]
- except IndexError:
- return None
diff --git a/lib/ansible/module_utils/network/iosxr/iosxr.py b/lib/ansible/module_utils/network/iosxr/iosxr.py
deleted file mode 100644
index 361716a07c..0000000000
--- a/lib/ansible/module_utils/network/iosxr/iosxr.py
+++ /dev/null
@@ -1,565 +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.
-#
-# Copyright (c) 2015 Peter Sprygada, <psprygada@ansible.com>
-# Copyright (c) 2017 Red Hat Inc.
-#
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-import json
-import re
-from difflib import Differ
-
-from ansible.module_utils._text import to_text, to_bytes
-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
-from ansible.module_utils.network.common.netconf import NetconfConnection
-
-try:
- from ncclient.xml_ import to_xml
- HAS_NCCLIENT = True
-except ImportError:
- HAS_NCCLIENT = False
-
-try:
- from lxml import etree
- HAS_XML = True
-except ImportError:
- HAS_XML = False
-
-_EDIT_OPS = frozenset(['merge', 'create', 'replace', 'delete'])
-
-BASE_1_0 = "{urn:ietf:params:xml:ns:netconf:base:1.0}"
-
-NS_DICT = {
- 'BASE_NSMAP': {"xc": "urn:ietf:params:xml:ns:netconf:base:1.0"},
- 'BANNERS_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg"},
- 'INTERFACES_NSMAP': {None: "http://openconfig.net/yang/interfaces"},
- 'INSTALL_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-installmgr-admin-oper"},
- 'HOST-NAMES_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-shellutil-cfg"},
- 'M:TYPE_NSMAP': {"idx": "urn:ietf:params:xml:ns:yang:iana-if-type"},
- 'ETHERNET_NSMAP': {None: "http://openconfig.net/yang/interfaces/ethernet"},
- 'CETHERNET_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-drivers-media-eth-cfg"},
- 'INTERFACE-CONFIGURATIONS_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg"},
- 'INFRA-STATISTICS_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-statsd-oper"},
- 'INTERFACE-PROPERTIES_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-oper"},
- 'IP-DOMAIN_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ip-domain-cfg"},
- 'SYSLOG_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-syslog-cfg"},
- 'AAA_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg"},
- 'AAA_LOCALD_NSMAP': {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-cfg"},
-}
-
-iosxr_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'),
- 'timeout': dict(type='int'),
- 'transport': dict(type='str', default='cli', choices=['cli', 'netconf']),
-}
-
-iosxr_argument_spec = {
- 'provider': dict(type='dict', options=iosxr_provider_spec, removed_in_version=2.14)
-}
-
-command_spec = {
- 'command': dict(),
- 'prompt': dict(default=None),
- 'answer': dict(default=None)
-}
-
-CONFIG_MISPLACED_CHILDREN = [
- re.compile(r'^end-\s*(.+)$')
-]
-
-# Objects defined in Route-policy Language guide of IOS_XR.
-# Reconfiguring these objects replace existing configurations.
-# Hence these objects should be played direcly from candidate
-# configurations
-CONFIG_BLOCKS_FORCED_IN_DIFF = [
- {
- 'start': re.compile(r'route-policy'),
- 'end': re.compile(r'end-policy')
- },
- {
- 'start': re.compile(r'prefix-set'),
- 'end': re.compile(r'end-set')
- },
- {
- 'start': re.compile(r'as-path-set'),
- 'end': re.compile(r'end-set')
- },
- {
- 'start': re.compile(r'community-set'),
- 'end': re.compile(r'end-set')
- },
- {
- 'start': re.compile(r'rd-set'),
- 'end': re.compile(r'end-set')
- },
- {
- 'start': re.compile(r'extcommunity-set'),
- 'end': re.compile(r'end-set')
- }
-]
-
-
-def get_provider_argspec():
- return iosxr_provider_spec
-
-
-def get_connection(module):
- if hasattr(module, 'connection'):
- return module.connection
-
- capabilities = get_capabilities(module)
- network_api = capabilities.get('network_api')
- if network_api == 'cliconf':
- module.connection = Connection(module._socket_path)
- elif network_api == 'netconf':
- module.connection = NetconfConnection(module._socket_path)
- else:
- module.fail_json(msg='Invalid connection type {0!s}'.format(network_api))
-
- return module.connection
-
-
-def get_capabilities(module):
- if hasattr(module, 'capabilities'):
- return module.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.capabilities = json.loads(capabilities)
-
- return module.capabilities
-
-
-def build_xml_subtree(container_ele, xmap, param=None, opcode=None):
- sub_root = container_ele
- meta_subtree = list()
-
- for key, meta in xmap.items():
- candidates = meta.get('xpath', "").split("/")
- if container_ele.tag == candidates[-2]:
- parent = container_ele
- elif sub_root.tag == candidates[-2]:
- parent = sub_root
- else:
- parent = sub_root.find(".//" + meta.get('xpath', "").split(sub_root.tag + '/', 1)[1].rsplit('/', 1)[0])
-
- if ((opcode in ('delete', 'merge') and meta.get('operation', 'unknown') == 'edit') or
- meta.get('operation', None) is None):
-
- if meta.get('tag', False) is True:
- if parent.tag == container_ele.tag:
- if meta.get('ns', False) is True:
- child = etree.Element(candidates[-1], nsmap=NS_DICT[key.upper() + "_NSMAP"])
- else:
- child = etree.Element(candidates[-1])
- meta_subtree.append(child)
- sub_root = child
- else:
- if meta.get('ns', False) is True:
- child = etree.SubElement(parent, candidates[-1], nsmap=NS_DICT[key.upper() + "_NSMAP"])
- else:
- child = etree.SubElement(parent, candidates[-1])
-
- if meta.get('attrib', None) is not None and opcode in ('delete', 'merge'):
- child.set(BASE_1_0 + meta.get('attrib'), opcode)
-
- continue
-
- text = None
- param_key = key.split(":")
- if param_key[0] == 'a':
- if param is not None and param.get(param_key[1], None) is not None:
- text = param.get(param_key[1])
- elif param_key[0] == 'm':
- if meta.get('value', None) is not None:
- text = meta.get('value')
-
- if text:
- if meta.get('ns', False) is True:
- child = etree.SubElement(parent, candidates[-1], nsmap=NS_DICT[key.upper() + "_NSMAP"])
- else:
- child = etree.SubElement(parent, candidates[-1])
- child.text = text
-
- if meta.get('attrib', None) is not None and opcode in ('delete', 'merge'):
- child.set(BASE_1_0 + meta.get('attrib'), opcode)
-
- if len(meta_subtree) > 1:
- for item in meta_subtree:
- container_ele.append(item)
-
- if sub_root == container_ele:
- return None
- else:
- return sub_root
-
-
-def build_xml(container, xmap=None, params=None, opcode=None):
- """
- Builds netconf xml rpc document from meta-data
-
- Args:
- container: the YANG container within the namespace
- xmap: meta-data map to build xml tree
- params: Input params that feed xml tree values
- opcode: operation to be performed (merge, delete etc.)
-
- Example:
- Module inputs:
- banner_params = [{'banner':'motd', 'text':'Ansible banner example', 'state':'present'}]
-
- Meta-data definition:
- bannermap = collections.OrderedDict()
- bannermap.update([
- ('banner', {'xpath' : 'banners/banner', 'tag' : True, 'attrib' : "operation"}),
- ('a:banner', {'xpath' : 'banner/banner-name'}),
- ('a:text', {'xpath' : 'banner/banner-text', 'operation' : 'edit'})
- ])
-
- Fields:
- key: exact match to the key in arg_spec for a parameter
- (prefixes --> a: value fetched from arg_spec, m: value fetched from meta-data)
- xpath: xpath of the element (based on YANG model)
- tag: True if no text on the element
- attrib: attribute to be embedded in the element (e.g. xc:operation="merge")
- operation: if edit --> includes the element in edit_config() query else ignores for get() queries
- value: if key is prefixed with "m:", value is required in meta-data
-
- Output:
- <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
- <banners xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg">
- <banner xc:operation="merge">
- <banner-name>motd</banner-name>
- <banner-text>Ansible banner example</banner-text>
- </banner>
- </banners>
- </config>
- :returns: xml rpc document as a string
- """
- if opcode == 'filter':
- root = etree.Element("filter", type="subtree")
- elif opcode in ('delete', 'merge'):
- root = etree.Element("config", nsmap=NS_DICT['BASE_NSMAP'])
-
- container_ele = etree.SubElement(root, container, nsmap=NS_DICT[container.upper() + "_NSMAP"])
-
- if xmap is not None:
- if params is None:
- build_xml_subtree(container_ele, xmap, opcode=opcode)
- else:
- subtree_list = list()
- for param in to_list(params):
- subtree_ele = build_xml_subtree(container_ele, xmap, param=param, opcode=opcode)
- if subtree_ele is not None:
- subtree_list.append(subtree_ele)
-
- for item in subtree_list:
- container_ele.append(item)
-
- return etree.tostring(root, encoding='unicode')
-
-
-def etree_find(root, node):
- try:
- root = etree.fromstring(to_bytes(root))
- except (ValueError, etree.XMLSyntaxError):
- pass
-
- return root.find('.//%s' % node.strip())
-
-
-def etree_findall(root, node):
- try:
- root = etree.fromstring(to_bytes(root))
- except (ValueError, etree.XMLSyntaxError):
- pass
-
- return root.findall('.//%s' % node.strip())
-
-
-def is_cliconf(module):
- capabilities = get_capabilities(module)
- return (capabilities.get('network_api') == 'cliconf')
-
-
-def is_netconf(module):
- capabilities = get_capabilities(module)
- network_api = capabilities.get('network_api')
- if network_api == 'netconf':
- if not HAS_NCCLIENT:
- module.fail_json(msg='ncclient is not installed')
- if not HAS_XML:
- module.fail_json(msg='lxml is not installed')
- return True
-
- return False
-
-
-def get_config_diff(module, running=None, candidate=None):
- conn = get_connection(module)
-
- if is_cliconf(module):
- try:
- response = conn.get('show commit changes diff')
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- return response
- elif is_netconf(module):
- if running and candidate:
- # ignore rpc-reply root node and diff from data element onwards
- running_data_ele = etree.fromstring(to_bytes(running.strip())).getchildren()[0]
- candidate_data_ele = etree.fromstring(to_bytes(candidate.strip())).getchildren()[0]
-
- running_data = to_text(etree.tostring(running_data_ele)).strip()
- candidate_data = to_text(etree.tostring(candidate_data_ele)).strip()
- if running_data != candidate_data:
- d = Differ()
- diff = list(d.compare(running_data.splitlines(), candidate_data.splitlines()))
- return '\n'.join(diff).strip()
-
- return None
-
-
-def discard_config(module):
- conn = get_connection(module)
- try:
- if is_netconf(module):
- conn.discard_changes(remove_ns=True)
- else:
- conn.discard_changes()
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
-
-def commit_config(module, comment=None, confirmed=False, confirm_timeout=None,
- persist=False, check=False, label=None):
- conn = get_connection(module)
- reply = None
- try:
- if is_netconf(module):
- if check:
- reply = conn.validate(remove_ns=True)
- else:
- reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist, remove_ns=True)
- elif is_cliconf(module):
- if check:
- module.fail_json(msg="Validate configuration is not supported with network_cli connection type")
- else:
- reply = conn.commit(comment=comment, label=label)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return reply
-
-
-def get_oper(module, filter=None):
- conn = get_connection(module)
-
- if filter is not None:
- try:
- if is_netconf(module):
- response = conn.get(filter=filter, remove_ns=True)
- else:
- response = conn.get(filter)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- else:
- return None
-
- return to_bytes(etree.tostring(response), errors='surrogate_then_replace').strip()
-
-
-def get_config(module, config_filter=None, source='running'):
- conn = get_connection(module)
-
- # Note: Does not cache config in favour of latest config on every get operation.
- try:
- if is_netconf(module):
- out = to_xml(conn.get_config(source=source, filter=config_filter, remove_ns=True))
- elif is_cliconf(module):
- out = conn.get_config(source=source, flags=config_filter)
- cfg = out.strip()
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- return cfg
-
-
-def check_existing_commit_labels(conn, label):
- out = conn.get(command='show configuration history detail | include %s' % label)
- label_exist = re.search(label, out, re.M)
- if label_exist:
- return True
- else:
- return False
-
-
-def load_config(module, command_filter, commit=False, replace=False,
- comment=None, admin=False, exclusive=False, running=None, nc_get_filter=None,
- label=None):
-
- conn = get_connection(module)
-
- diff = None
- if is_netconf(module):
- # FIXME: check for platform behaviour and restore this
- # conn.lock(target = 'candidate')
- # conn.discard_changes()
-
- try:
- for filter in to_list(command_filter):
- conn.edit_config(config=filter, remove_ns=True)
-
- candidate = get_config(module, source='candidate', config_filter=nc_get_filter)
- diff = get_config_diff(module, running, candidate)
-
- if commit and diff:
- commit_config(module)
- else:
- discard_config(module)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- finally:
- # conn.unlock(target = 'candidate')
- pass
-
- elif is_cliconf(module):
- try:
- if label:
- old_label = check_existing_commit_labels(conn, label)
- if old_label:
- module.fail_json(
- msg='commit label {%s} is already used for'
- ' an earlier commit, please choose a different label'
- ' and rerun task' % label
- )
-
- response = conn.edit_config(candidate=command_filter, commit=commit, admin=admin,
- exclusive=exclusive, replace=replace, comment=comment, label=label)
- if module._diff:
- diff = response.get('diff')
-
- # Overwrite the default diff by the IOS XR commit diff.
- # See plugins/cliconf/iosxr.py for this key set: show_commit_config_diff
- diff = response.get('show_commit_config_diff')
-
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return diff
-
-
-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 copy_file(module, src, dst, proto='scp'):
- conn = get_connection(module)
- try:
- conn.copy_file(source=src, destination=dst, proto=proto)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
-
-def get_file(module, src, dst, proto='scp'):
- conn = get_connection(module)
- try:
- conn.get_file(source=src, destination=dst, proto=proto)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
-
-# A list of commands like {end-set, end-policy, ...} are part of configuration
-# block like { prefix-set, as-path-set , ... } but they are not indented properly
-# to be included with their parent. sanitize_config will add indentation to
-# end-* commands so they are included with their parents
-def sanitize_config(config, force_diff_prefix=None):
- conf_lines = config.split('\n')
- for regex in CONFIG_MISPLACED_CHILDREN:
- for index, line in enumerate(conf_lines):
- m = regex.search(line)
- if m and m.group(0):
- if force_diff_prefix:
- conf_lines[index] = ' ' + m.group(0) + force_diff_prefix
- else:
- conf_lines[index] = ' ' + m.group(0)
- conf = ('\n').join(conf_lines)
- return conf
-
-
-def mask_config_blocks_from_diff(config, candidate, force_diff_prefix):
- conf_lines = config.split('\n')
- candidate_lines = candidate.split('\n')
-
- for regex in CONFIG_BLOCKS_FORCED_IN_DIFF:
- block_index_start_end = []
- for index, line in enumerate(candidate_lines):
- startre = regex['start'].search(line)
- if startre and startre.group(0):
- start_index = index
- else:
- endre = regex['end'].search(line)
- if endre and endre.group(0):
- end_index = index
- new_block = True
- for prev_start, prev_end in block_index_start_end:
- if start_index == prev_start:
- # This might be end-set of another regex
- # otherwise we would be having new start
- new_block = False
- break
- if new_block:
- block_index_start_end.append((start_index, end_index))
-
- for start, end in block_index_start_end:
- diff = False
- if candidate_lines[start] in conf_lines:
- run_conf_start_index = conf_lines.index(candidate_lines[start])
- else:
- diff = False
- continue
- for i in range(start, end + 1):
- if conf_lines[run_conf_start_index] == candidate_lines[i]:
- run_conf_start_index = run_conf_start_index + 1
- else:
- diff = True
- break
- if diff:
- run_conf_start_index = conf_lines.index(candidate_lines[start])
- for i in range(start, end + 1):
- conf_lines[run_conf_start_index] = conf_lines[run_conf_start_index] + force_diff_prefix
- run_conf_start_index = run_conf_start_index + 1
-
- conf = ('\n').join(conf_lines)
- return conf
diff --git a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py b/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py
deleted file mode 100644
index 2005615d97..0000000000
--- a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py
+++ /dev/null
@@ -1,114 +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.iosxr.providers.providers import CliProvider
-
-
-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 %s' % (item['afi'], 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')
-
- safe_list.append(context)
-
- 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_networks(self, item, config=None):
- commands = list()
- safe_list = list()
-
- for entry in item['networks']:
- network = entry['prefix']
- if entry['masklen']:
- network = '%s/%s' % (entry['prefix'], entry['masklen'])
- safe_list.append(network)
-
- cmd = 'network %s' % network
-
- if entry['route_map']:
- cmd += ' route-policy %s' % entry['route_map']
-
- if not config or cmd not in config:
- commands.append(cmd)
-
- if config and self.params['operation'] == 'replace':
- matches = re.findall(r'network (\S+)', config, re.M)
- for entry in set(matches).difference(safe_list):
- commands.append('no network %s' % entry)
-
- return commands
-
- def _render_redistribute(self, item, config=None):
- commands = list()
- safe_list = list()
-
- for entry in item['redistribute']:
- option = entry['protocol']
-
- cmd = 'redistribute %s' % entry['protocol']
-
- if entry['id'] and entry['protocol'] in ('ospf', 'eigrp', 'isis', 'ospfv3'):
- cmd += ' %s' % entry['id']
- option += ' %s' % entry['id']
-
- if entry['metric']:
- cmd += ' metric %s' % entry['metric']
-
- if entry['route_map']:
- cmd += ' route-policy %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
diff --git a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py b/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py
deleted file mode 100644
index 137691e3e1..0000000000
--- a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py
+++ /dev/null
@@ -1,125 +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
-import socket
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.iosxr.providers.providers import CliProvider
-
-
-class Neighbors(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.neighbors'):
- context_commands = list()
-
- neighbor = item['neighbor']
-
- try:
- socket.inet_aton(neighbor)
- context = 'neighbor %s' % neighbor
- except socket.error:
- context = 'neighbor-group %s' % neighbor
-
- 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')
-
- safe_list.append(context)
-
- 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_remote_as(self, item, config=None):
- cmd = 'remote-as %s' % item['remote_as']
- if not config or cmd not in config:
- return cmd
-
- def _render_description(self, item, config=None):
- cmd = 'description %s' % item['description']
- if not config or cmd not in config:
- return cmd
-
- def _render_enabled(self, item, config=None):
- cmd = 'shutdown'
- if item['enabled'] is True:
- cmd = 'no %s' % cmd
- if not config or cmd not in config:
- return cmd
-
- def _render_update_source(self, item, config=None):
- cmd = 'update-source %s' % item['update_source'].replace(' ', '')
- if not config or cmd not in config:
- return cmd
-
- def _render_password(self, item, config=None):
- cmd = 'password %s' % item['password']
- if not config or cmd not in config:
- return cmd
-
- def _render_ebgp_multihop(self, item, config=None):
- cmd = 'ebgp-multihop %s' % item['ebgp_multihop']
- if not config or cmd not in config:
- return cmd
-
- def _render_tcp_mss(self, item, config=None):
- cmd = 'tcp mss %s' % item['tcp_mss']
- if not config or cmd not in config:
- return cmd
-
- def _render_advertisement_interval(self, item, config=None):
- cmd = 'advertisement-interval %s' % item['advertisement_interval']
- if not config or cmd not in config:
- return cmd
-
- def _render_neighbor_group(self, item, config=None):
- cmd = 'use neighbor-group %s' % item['neighbor_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']
-
- if keepalive and holdtime:
- cmd = 'timers %s %s' % (keepalive, holdtime)
- if min_neighbor_holdtime:
- cmd += ' %s' % min_neighbor_holdtime
- if not config or cmd not in config:
- return cmd
- else:
- raise ValueError("required both options for timers: keepalive and holdtime")
diff --git a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/process.py b/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/process.py
deleted file mode 100644
index 470d586a64..0000000000
--- a/lib/ansible/module_utils/network/iosxr/providers/cli/config/bgp/process.py
+++ /dev/null
@@ -1,97 +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.iosxr.providers.providers import register_provider
-from ansible.module_utils.network.iosxr.providers.providers import CliProvider
-from ansible.module_utils.network.iosxr.providers.cli.config.bgp.neighbors import Neighbors
-from ansible.module_utils.network.iosxr.providers.cli.config.bgp.address_family import AddressFamily
-
-REDISTRIBUTE_PROTOCOLS = frozenset(['ospf', 'ospfv3', 'eigrp', 'isis', 'static',
- 'connected', 'lisp', 'mobile', 'rip',
- 'subscriber'])
-
-
-@register_provider('iosxr', 'iosxr_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:
- if operation == 'replace':
- if existing_as and int(existing_as) != self.get_value('config.bgp_as'):
- # The negate command has to be committed before new BGP AS is used.
- self.connection.edit_config('no router bgp %s' % existing_as)
- config = None
-
- elif operation == 'override':
- if existing_as:
- # The negate command has to be committed before new BGP AS is used.
- self.connection.edit_config('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 '%s detail' % cmd
- elif log_neighbor_changes is False:
- if config and cmd in config:
- return '%s disable' % cmd
-
- 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)
diff --git a/lib/ansible/module_utils/network/iosxr/providers/module.py b/lib/ansible/module_utils/network/iosxr/providers/module.py
deleted file mode 100644
index 2c4d97a337..0000000000
--- a/lib/ansible/module_utils/network/iosxr/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.iosxr.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/iosxr/providers/providers.py b/lib/ansible/module_utils/network/iosxr/providers/providers.py
deleted file mode 100644
index a466b033d9..0000000000
--- a/lib/ansible/module_utils/network/iosxr/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/iosxr/utils/utils.py b/lib/ansible/module_utils/network/iosxr/utils/utils.py
deleted file mode 100644
index 73589601ab..0000000000
--- a/lib/ansible/module_utils/network/iosxr/utils/utils.py
+++ /dev/null
@@ -1,355 +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
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.compat import ipaddress
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import dict_diff, is_masklen, to_netmask, search_obj_in_list
-
-
-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 dict_to_set(sample_dict):
- # Generate a set with passed dictionary for comparison
- test_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()
- test_key_dict = dict()
- name = want.get('name')
- if name:
- test_dict['name'] = name
- diff_ip = False
- want_ip = ''
- for k, v in iteritems(want):
- if isinstance(v, dict):
- for key, value in iteritems(v):
- if value is None:
- dict_val = have.get(k).get(key)
- test_key_dict.update({key: dict_val})
- test_dict.update({k: test_key_dict})
- if isinstance(v, list) and isinstance(v[0], dict):
- for key, value in iteritems(v[0]):
- if value is None:
- dict_val = have.get(k).get(key)
- test_key_dict.update({key: dict_val})
- 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')
- for each in have_ip:
- if len(want_ip) > 1 and each.get('secondary'):
- have_ip = each.get('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})
- # Checks if want doesn't have secondary IP but have has secondary IP set
- elif have.get('ipv4'):
- if [
- True for each_have in have.get('ipv4')
- if 'secondary' in each_have
- ]:
- test_dict.update({'ipv4': {'secondary': True}})
- if k == 'l2protocol':
- if want[k] != have.get('l2protocol') and have.get('l2protocol'):
- test_dict.update({k: v})
- 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 flatten_dict(x):
- result = {}
- if not isinstance(x, dict):
- return result
-
- for key, value in iteritems(x):
- if isinstance(value, dict):
- result.update(flatten_dict(value))
- else:
- result[key] = value
-
- return result
-
-
-def dict_delete(base, comparable):
- """
-
- This function generates a dict containing key, value pairs for keys
- that are present in the `base` dict but not present in the `comparable`
- dict.
-
- :param base: dict object to base the diff on
- :param comparable: dict object to compare against base
-
- :returns: new dict object with key, value pairs that needs to be deleted.
-
- """
- to_delete = dict()
-
- for key in base:
- if isinstance(base[key], dict):
- sub_diff = dict_delete(base[key], comparable.get(key, {}))
- if sub_diff:
- to_delete[key] = sub_diff
- else:
- if key not in comparable:
- to_delete[key] = base[key]
-
- return to_delete
-
-
-def pad_commands(commands, interface):
- commands.insert(0, 'interface {0}'.format(interface))
-
-
-def diff_list_of_dicts(w, h, key='member'):
- """
- Returns a list containing diff between
- two list of dictionaries
- """
- if not w:
- w = []
- if not h:
- h = []
-
- diff = []
- for w_item in w:
- h_item = search_obj_in_list(w_item[key], h, key=key) or {}
- d = dict_diff(h_item, w_item)
- if d:
- if key not in d.keys():
- d[key] = w_item[key]
- diff.append(d)
-
- return diff
-
-
-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 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('fa'):
- if_type = 'FastEthernet'
- elif name.lower().startswith('fo'):
- if_type = 'FortyGigE'
- elif name.lower().startswith('te'):
- if_type = 'TenGigE'
- elif name.lower().startswith('twe'):
- if_type = 'TwentyFiveGigE'
- elif name.lower().startswith('hu'):
- if_type = 'HundredGigE'
- elif name.lower().startswith('vl'):
- if_type = 'Vlan'
- elif name.lower().startswith('lo'):
- if_type = 'Loopback'
- elif name.lower().startswith('be'):
- if_type = 'Bundle-Ether'
- elif name.lower().startswith('bp'):
- if_type = 'Bundle-POS'
- 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('FA'):
- return 'FastEthernet'
- elif interface.upper().startswith('FO'):
- return 'FortyGigE'
- elif interface.upper().startswith('ET'):
- return 'Ethernet'
- elif interface.upper().startswith('LO'):
- return 'Loopback'
- elif interface.upper().startswith('BE'):
- return 'Bundle-Ether'
- elif interface.upper().startswith('NV'):
- return 'nve'
- elif interface.upper().startswith('TWE'):
- return 'TwentyFiveGigE'
- elif interface.upper().startswith('HU'):
- return 'HundredGigE'
- elif interface.upper().startswith('PRE'):
- return 'preconfigure'
- else:
- return 'unknown'
-
-
-def isipaddress(data):
- """
- Checks if the passed string is
- a valid IPv4 or IPv6 address
- """
- isipaddress = True
-
- try:
- ipaddress.ip_address(data)
- except ValueError:
- isipaddress = False
-
- return isipaddress
-
-
-def is_ipv4_address(data):
- """
- Checks if the passed string is
- a valid IPv4 address
- """
- if '/' in data:
- data = data.split('/')[0]
-
- if not isipaddress(to_text(data)):
- raise ValueError('{0} is not a valid IP address'.format(data))
-
- return (ipaddress.ip_address(to_text(data)).version == 4)
-
-
-def prefix_to_address_wildcard(prefix):
- """ Converts a IPv4 prefix into address and
- wildcard mask
-
- :returns: IPv4 address and wildcard mask
- """
- wildcard = []
-
- subnet = to_text(ipaddress.IPv4Network(to_text(prefix)).netmask)
-
- for x in subnet.split('.'):
- component = 255 - int(x)
- wildcard.append(str(component))
-
- wildcard = '.'.join(wildcard)
-
- return prefix.split('/')[0], wildcard