summaryrefslogtreecommitdiff
path: root/lib/ansible/module_utils/network/nxos
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/module_utils/network/nxos')
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/acl_interfaces/acl_interfaces.py91
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/acls/acls.py425
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/bfd_interfaces/bfd_interfaces.py56
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/facts/facts.py21
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/hsrp_interfaces/hsrp_interfaces.py54
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/interfaces/interfaces.py80
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/l2_interfaces/l2_interfaces.py77
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/l3_interfaces/l3_interfaces.py90
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/lacp/lacp.py69
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/lacp_interfaces/lacp_interfaces.py90
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/lag_interfaces/lag_interfaces.py49
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/lldp_global/lldp_global.py109
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/lldp_interfaces/lldp_interfaces.py75
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/telemetry/telemetry.py90
-rw-r--r--lib/ansible/module_utils/network/nxos/argspec/vlans/vlans.py51
-rw-r--r--lib/ansible/module_utils/network/nxos/cmdref/telemetry/telemetry.py145
-rw-r--r--lib/ansible/module_utils/network/nxos/config/acl_interfaces/acl_interfaces.py303
-rw-r--r--lib/ansible/module_utils/network/nxos/config/acls/acls.py690
-rw-r--r--lib/ansible/module_utils/network/nxos/config/bfd_interfaces/bfd_interfaces.py264
-rw-r--r--lib/ansible/module_utils/network/nxos/config/hsrp_interfaces/hsrp_interfaces.py248
-rw-r--r--lib/ansible/module_utils/network/nxos/config/interfaces/interfaces.py379
-rw-r--r--lib/ansible/module_utils/network/nxos/config/l2_interfaces/l2_interfaces.py301
-rw-r--r--lib/ansible/module_utils/network/nxos/config/l3_interfaces/l3_interfaces.py488
-rw-r--r--lib/ansible/module_utils/network/nxos/config/lacp/lacp.py203
-rw-r--r--lib/ansible/module_utils/network/nxos/config/lacp_interfaces/lacp_interfaces.py284
-rw-r--r--lib/ansible/module_utils/network/nxos/config/lag_interfaces/lag_interfaces.py273
-rw-r--r--lib/ansible/module_utils/network/nxos/config/lldp_global/lldp_global.py240
-rw-r--r--lib/ansible/module_utils/network/nxos/config/lldp_interfaces/lldp_interfaces.py304
-rw-r--r--lib/ansible/module_utils/network/nxos/config/telemetry/telemetry.py503
-rw-r--r--lib/ansible/module_utils/network/nxos/config/vlans/vlans.py290
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/acl_interfaces/acl_interfaces.py119
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/acls/acls.py236
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/bfd_interfaces/bfd_interfaces.py97
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/facts.py82
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/hsrp_interfaces/hsrp_interfaces.py89
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/interfaces/interfaces.py151
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/l2_interfaces/l2_interfaces.py94
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/l3_interfaces/l3_interfaces.py126
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/lacp/lacp.py84
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/lacp_interfaces/lacp_interfaces.py108
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/lag_interfaces/lag_interfaces.py124
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/legacy/base.py756
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/lldp_global/lldp_global.py105
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/lldp_interfaces/lldp_interfaces.py121
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/telemetry/telemetry.py163
-rw-r--r--lib/ansible/module_utils/network/nxos/facts/vlans/vlans.py172
-rw-r--r--lib/ansible/module_utils/network/nxos/nxos.py1310
-rw-r--r--lib/ansible/module_utils/network/nxos/utils/telemetry/telemetry.py250
-rw-r--r--lib/ansible/module_utils/network/nxos/utils/utils.py138
49 files changed, 0 insertions, 10667 deletions
diff --git a/lib/ansible/module_utils/network/nxos/argspec/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index baa1a70a28..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/acl_interfaces/acl_interfaces.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)
-
-#############################################
-# 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 nxos_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 nxos_acl_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'access_groups': {
- 'elements': 'dict',
- 'options': {
- 'acls': {
- 'elements': 'dict',
- 'options': {
- 'direction': {
- 'choices': ['in', 'out'],
- 'required': True,
- 'type': 'str'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'port': {
- 'type': 'bool'
- }
- },
- 'type': 'list'
- },
- 'afi': {
- 'choices': ['ipv4', 'ipv6'],
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'running_config': {
- 'type': 'str'
- },
- 'state': {
- 'choices': [
- 'deleted', 'gathered', 'merged', 'overridden', 'rendered',
- 'replaced', 'parsed'
- ],
- 'default':
- 'merged',
- 'type':
- 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/acls/acls.py b/lib/ansible/module_utils/network/nxos/argspec/acls/acls.py
deleted file mode 100644
index 01e13f1893..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/acls/acls.py
+++ /dev/null
@@ -1,425 +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 nxos_acls module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class AclsArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_acls module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'acls': {
- 'elements': 'dict',
- 'options': {
- 'aces': {
- 'elements': 'dict',
- 'mutually_exclusive': [['grant', 'remark']],
- 'options': {
- 'destination': {
- 'mutually_exclusive':
- [['address', 'any', 'host', 'prefix'],
- [
- 'wildcard_bits', 'any', 'host',
- 'prefix'
- ]],
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'host': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'mutually_exclusive': [[
- 'eq', 'lt', 'neq', 'gt',
- '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'
- },
- 'prefix': {
- 'type': 'str'
- },
- 'wildcard_bits': {
- 'type': 'str'
- }
- },
- 'required_together':
- [['address', 'wildcard_bits']],
- 'type': 'dict'
- },
- 'dscp': {
- 'type': 'str'
- },
- 'fragments': {
- 'type': 'bool'
- },
- 'grant': {
- 'choices': ['permit', 'deny'],
- 'type': 'str'
- },
- 'log': {
- 'type': 'bool'
- },
- 'precedence': {
- 'type': 'str'
- },
- 'protocol': {
- 'type': 'str'
- },
- 'protocol_options': {
- 'mutually_exclusive':
- [['icmp', 'igmp', 'tcp']],
- 'options': {
- 'icmp': {
- 'options': {
- 'administratively_prohibited':
- {
- 'type': 'bool'
- },
- 'alternate_address': {
- 'type': 'bool'
- },
- 'conversion_error': {
- 'type': 'bool'
- },
- 'dod_host_prohibited': {
- 'type': 'bool'
- },
- 'dod_net_prohibited': {
- 'type': 'bool'
- },
- 'echo': {
- 'type': 'bool'
- },
- 'echo_reply': {
- 'type': 'bool'
- },
- 'general_parameter_problem': {
- 'type': 'bool'
- },
- 'host_isolated': {
- 'type': 'bool'
- },
- 'host_precedence_unreachable':
- {
- 'type': 'bool'
- },
- 'host_redirect': {
- 'type': 'bool'
- },
- 'host_tos_redirect': {
- 'type': 'bool'
- },
- 'host_tos_unreachable': {
- 'type': 'bool'
- },
- 'host_unknown': {
- 'type': 'bool'
- },
- 'host_unreachable': {
- 'type': 'bool'
- },
- 'information_reply': {
- 'type': 'bool'
- },
- 'information_request': {
- 'type': 'bool'
- },
- 'mask_reply': {
- 'type': 'bool'
- },
- 'mask_request': {
- 'type': 'bool'
- },
- 'message_code': {
- 'type': 'int'
- },
- 'message_type': {
- 'type': 'int'
- },
- 'mobile_redirect': {
- 'type': 'bool'
- },
- 'net_redirect': {
- 'type': 'bool'
- },
- 'net_tos_redirect': {
- 'type': 'bool'
- },
- 'net_tos_unreachable': {
- 'type': 'bool'
- },
- 'net_unreachable': {
- 'type': 'bool'
- },
- 'network_unknown': {
- 'type': 'bool'
- },
- 'no_room_for_option': {
- 'type': 'bool'
- },
- 'option_missing': {
- 'type': 'bool'
- },
- 'packet_too_big': {
- 'type': 'bool'
- },
- 'parameter_problem': {
- 'type': 'bool'
- },
- 'port_unreachable': {
- 'type': 'bool'
- },
- 'precedence_unreachable': {
- 'type': 'bool'
- },
- 'protocol_unreachable': {
- 'type': 'bool'
- },
- 'reassembly_timeout': {
- 'type': 'bool'
- },
- 'redirect': {
- 'type': 'bool'
- },
- 'router_advertisement': {
- 'type': 'bool'
- },
- 'router_solicitation': {
- 'type': 'bool'
- },
- 'source_quench': {
- 'type': 'bool'
- },
- 'source_route_failed': {
- 'type': 'bool'
- },
- 'time_exceeded': {
- 'type': 'bool'
- },
- 'timestamp_reply': {
- 'type': 'bool'
- },
- 'timestamp_request': {
- 'type': 'bool'
- },
- 'traceroute': {
- 'type': 'bool'
- },
- 'ttl_exceeded': {
- 'type': 'bool'
- },
- 'unreachable': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'igmp': {
- 'mutually_exclusive': [[
- 'dvmrp', 'host_query',
- 'host_report'
- ]],
- 'options': {
- 'dvmrp': {
- 'type': 'bool'
- },
- 'host_query': {
- 'type': 'bool'
- },
- 'host_report': {
- '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', 'host', 'any',
- 'prefix'
- ]],
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'host': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'mutually_exclusive':
- [['eq', 'lt', 'neq', 'range'],
- ['eq', 'gt', 'neq', 'range']],
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'options': {
- 'end': {
- 'type': 'str'
- },
- 'start': {
- 'type': 'str'
- }
- },
- 'type': 'dict'
- }
- },
- 'type':
- 'dict'
- },
- 'prefix': {
- 'type': 'str'
- },
- 'wildcard_bits': {
- 'type': 'str'
- }
- },
- 'required_together':
- [['address', 'wildcard_bits']],
- 'type':
- 'dict'
- }
- },
- 'type': 'list'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'afi': {
- 'choices': ['ipv4', 'ipv6'],
- 'required': True,
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'running_config': {
- 'type': 'str'
- },
- 'state': {
- 'choices': [
- 'deleted', 'gathered', 'merged', 'overridden', 'rendered',
- 'replaced', 'parsed'
- ],
- 'default':
- 'merged',
- 'type':
- 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/bfd_interfaces/bfd_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/bfd_interfaces/bfd_interfaces.py
deleted file mode 100644
index 3c41030fe9..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/bfd_interfaces/bfd_interfaces.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# 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.
-#
-#############################################
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-"""
-The arg spec for the nxos_bfd_interfaces module
-"""
-
-
-class Bfd_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_bfd_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'name': {'type': 'str'},
- 'bfd': {
- 'choices': ['enable', 'disable'], 'type': 'str'},
- 'echo': {
- 'choices': ['enable', 'disable'], 'type': 'str'},
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/facts/facts.py b/lib/ansible/module_utils/network/nxos/argspec/facts/facts.py
deleted file mode 100644
index 889ae5f34b..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/facts/facts.py
+++ /dev/null
@@ -1,21 +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 nxos facts module.
-"""
-
-
-class FactsArgs(object):
- """ The arg spec for the nxos 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/nxos/argspec/hsrp_interfaces/hsrp_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/hsrp_interfaces/hsrp_interfaces.py
deleted file mode 100644
index 5183ce7ac8..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/hsrp_interfaces/hsrp_interfaces.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# 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.
-#
-#############################################
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-"""
-The arg spec for the nxos_hsrp_interfaces module
-"""
-
-
-class Hsrp_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_hsrp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'type': 'list',
- 'elements': 'dict',
- 'options': {
- 'name': {'type': 'str'},
- 'bfd': {
- 'choices': ['enable', 'disable'], 'type': 'str'},
- },
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/interfaces/interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/interfaces/interfaces.py
deleted file mode 100644
index 1d9b7d0ead..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/interfaces/interfaces.py
+++ /dev/null
@@ -1,80 +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 nxos_interfaces module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class InterfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'description': {
- 'type': 'str'
- },
- 'duplex': {
- 'choices': ['full', 'half', 'auto'],
- 'type': 'str'
- },
- 'enabled': {
- 'type': 'bool'
- },
- 'fabric_forwarding_anycast_gateway': {
- 'type': 'bool'
- },
- 'ip_forward': {
- 'type': 'bool'
- },
- 'mode': {
- 'choices': ['layer2', 'layer3'],
- 'type': 'str'
- },
- 'mtu': {
- 'type': 'str'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'speed': {
- 'type': 'str'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index db723be790..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/l2_interfaces/l2_interfaces.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)
-
-#############################################
-# 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 nxos_l2_interfaces module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class L2_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_l2_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'access': {
- 'options': {
- 'vlan': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- },
- 'mode': {
- 'type': 'str',
- 'choices': ['access', 'trunk']
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'trunk': {
- 'options': {
- 'allowed_vlans': {
- 'type': 'str'
- },
- 'native_vlan': {
- '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/nxos/argspec/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index d6f2098bd6..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# 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 nxos_l3_interfaces module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class L3_interfacesArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_l3_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'dot1q': {
- 'type': 'int'
- },
- 'ipv4': {
- 'elements': 'dict',
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'secondary': {
- 'type': 'bool'
- },
- 'tag': {
- 'type': 'int'
- }
- },
- 'type': 'list'
- },
- 'ipv6': {
- 'elements': 'dict',
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'tag': {
- 'type': 'int'
- }
- },
- 'type': 'list'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'redirects': {
- 'type': 'bool',
- },
- 'unreachables': {
- '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/nxos/argspec/lacp/lacp.py b/lib/ansible/module_utils/network/nxos/argspec/lacp/lacp.py
deleted file mode 100644
index b63c10f471..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/lacp/lacp.py
+++ /dev/null
@@ -1,69 +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 nxos_lacp module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class LacpArgs(object):
- """The arg spec for the nxos_lacp module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'options': {
- 'system': {
- 'options': {
- 'mac': {
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'role': {
- 'choices': ['primary', 'secondary'],
- 'type': 'str'
- }
- },
- 'type': 'dict'
- },
- 'priority': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/nxos/argspec/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 5f72f21a1b..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# 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 nxos_lacp_interfaces module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lacp_interfacesArgs(object):
- """The arg spec for the nxos_lacp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'convergence': {
- 'options': {
- 'graceful': {
- 'type': 'bool'
- },
- 'vpc': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'links': {
- 'options': {
- 'max': {
- 'type': 'int'
- },
- 'min': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- },
- 'mode': {
- 'choices': ['delay'],
- 'type': 'str'
- },
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'port_priority': {
- 'type': 'int'
- },
- 'rate': {
- 'choices': ['fast', 'normal'],
- 'type': 'str'
- },
- 'suspend_individual': {
- 'type': 'bool'
- }
- },
- 'type': 'list'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/nxos/argspec/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index dd200c177d..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the nxos_lag_interfaces module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lag_interfacesArgs(object):
- """The arg spec for the nxos_lag_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'members': {'elements': 'dict',
- 'options': {'member': {'type': 'str'},
- 'mode': {'type': 'str',
- 'choices': ['active', 'on', 'passive']},
- 'force': {'type': 'bool'}},
- 'type': 'list'},
- '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/nxos/argspec/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/nxos/argspec/lldp_global/lldp_global.py
deleted file mode 100644
index d3289fbf39..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,109 +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 nxos_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 nxos_lldp_global module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'options': {
- 'holdtime': {
- 'type': 'int'
- },
- 'port_id': {
- 'choices': [0, 1],
- 'type': 'int'
- },
- 'reinit': {
- 'type': 'int'
- },
- 'timer': {
- 'type': 'int'
- },
- 'tlv_select': {
- 'options': {
- 'dcbxp': {
- 'type': 'bool'
- },
- 'management_address': {
- 'options': {
- 'v4': {
- 'type': 'bool'
- },
- 'v6': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'port': {
- 'options': {
- 'description': {
- 'type': 'bool'
- },
- 'vlan': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'power_management': {
- 'type': 'bool'
- },
- 'system': {
- 'options': {
- 'capabilities': {
- 'type': 'bool'
- },
- 'description': {
- 'type': 'bool'
- },
- 'name': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- }
- },
- 'type': 'dict'
- },
- 'state': {
- 'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/nxos/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/nxos/argspec/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index ee223eafe5..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,75 +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 nxos_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 nxos_lldp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'receive': {
- 'type': 'bool'
- },
- 'tlv_set': {
- 'options': {
- 'management_address': {
- 'type': 'str'
- },
- 'vlan': {
- 'type': 'int'
- }
- },
- 'type': 'dict'
- },
- 'transmit': {
- 'type': 'bool'
- }
- },
- 'type': 'list'
- },
- 'running_config': {
- 'type': 'str'
- },
- 'state': {
- 'choices': ['deleted', 'gathered', 'merged', 'overridden', 'rendered',
- 'replaced', 'parsed'],
- 'default': 'merged',
- 'type': 'str'
- }
- } # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/telemetry/telemetry.py b/lib/ansible/module_utils/network/nxos/argspec/telemetry/telemetry.py
deleted file mode 100644
index fd9753e245..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/telemetry/telemetry.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# 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 nxos_telemetry module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class TelemetryArgs(object): # pylint: disable=R0903
- """The arg spec for the nxos_telemetry module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'options': {
- 'certificate': {
- 'options': {
- 'hostname': {'type': 'str'},
- 'key': {'type': 'str'}},
- 'type': 'dict'},
- 'compression': {'choices': ['gzip'], 'type': 'str'},
- 'source_interface': {'type': 'str'},
- 'vrf': {'type': 'str'},
- 'destination_groups': {
- 'options': {
- 'destination': {
- 'options': {
- 'encoding': {'choices': ['GPB', 'JSON'],
- 'type': 'str'},
- 'ip': {'type': 'str'},
- 'port': {'type': 'int'},
- 'protocol': {'choices': ['HTTP', 'TCP', 'UDP', 'gRPC'],
- 'type': 'str'}},
- 'type': 'dict'},
- 'id': {'type': 'int'}},
- 'type': 'list'},
- 'sensor_groups': {
- 'options': {
- 'data_source': {'choices': ['NX-API', 'DME', 'YANG'],
- 'type': 'str'},
- 'id': {'type': 'int'},
- 'path': {
- 'options': {
- 'depth': {'type': 'str'},
- 'filter_condition': {'type': 'str'},
- 'name': {'type': 'str'},
- 'query_condition': {'type': 'str'}},
- 'type': 'dict'}},
- 'type': 'list'},
- 'subscriptions': {
- 'options': {
- 'destination_group': {'type': 'int'},
- 'id': {'type': 'int'},
- 'sensor_group': {
- 'options': {
- 'id': {'type': 'int'},
- 'sample_interval': {'type': 'int'}},
- 'type': 'dict'}},
- 'type': 'list'}},
- 'type': 'dict'},
- 'state': {
- 'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}} # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/nxos/argspec/vlans/vlans.py b/lib/ansible/module_utils/network/nxos/argspec/vlans/vlans.py
deleted file mode 100644
index e323c5dd4d..0000000000
--- a/lib/ansible/module_utils/network/nxos/argspec/vlans/vlans.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 nxos_vlans module
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class VlansArgs(object):
- """The arg spec for the nxos_vlans module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'enabled': {'type': 'bool'},
- 'mapped_vni': {'type': 'int'},
- 'mode': {'choices': ['ce', 'fabricpath'],
- 'type': 'str'},
- 'name': {'type': 'str'},
- 'vlan_id': {'required': True, 'type': 'int'},
- 'state': {'choices': ['active', 'suspend'],
- 'type': 'str'}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/nxos/cmdref/telemetry/telemetry.py b/lib/ansible/module_utils/network/nxos/cmdref/telemetry/telemetry.py
deleted file mode 100644
index 39f3604518..0000000000
--- a/lib/ansible/module_utils/network/nxos/cmdref/telemetry/telemetry.py
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-# Telemetry Command Reference File
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-TMS_GLOBAL = '''
-# The cmd_ref is a yaml formatted list of module commands.
-# A leading underscore denotes a non-command variable; e.g. _template.
-# TMS does not have convenient global json data so this cmd_ref uses raw cli configs.
----
-_template: # _template holds common settings for all commands
- # Enable feature telemetry if disabled
- feature: telemetry
- # Common get syntax for TMS commands
- get_command: show run telemetry all
- # Parent configuration for TMS commands
- context:
- - telemetry
-certificate:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- kind: dict
- getval: certificate (?P<key>\\S+) (?P<hostname>\\S+)$
- setval: certificate {key} {hostname}
- default:
- key: ~
- hostname: ~
-compression:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- kind: str
- getval: use-compression (\\S+)$
- setval: 'use-compression {0}'
- default: ~
- context: &dpcontext
- - telemetry
- - destination-profile
-source_interface:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- kind: str
- getval: source-interface (\\S+)$
- setval: 'source-interface {0}'
- default: ~
- context: *dpcontext
-vrf:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- kind: str
- getval: use-vrf (\\S+)$
- setval: 'use-vrf {0}'
- default: ~
- context: *dpcontext
-'''
-
-TMS_DESTGROUP = '''
-# The cmd_ref is a yaml formatted list of module commands.
-# A leading underscore denotes a non-command variable; e.g. _template.
-# TBD: Use Structured Where Possible
----
-_template: # _template holds common settings for all commands
- # Enable feature telemetry if disabled
- feature: telemetry
- # Common get syntax for TMS commands
- get_command: show run telemetry all
- # Parent configuration for TMS commands
- context:
- - telemetry
-destination:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- multiple: true
- kind: dict
- getval: ip address (?P<ip>\\S+) port (?P<port>\\S+) protocol (?P<protocol>\\S+) encoding (?P<encoding>\\S+)
- setval: ip address {ip} port {port} protocol {protocol} encoding {encoding}
- default:
- ip: ~
- port: ~
- protocol: ~
- encoding: ~
-'''
-
-TMS_SENSORGROUP = '''
-# The cmd_ref is a yaml formatted list of module commands.
-# A leading underscore denotes a non-command variable; e.g. _template.
-# TBD: Use Structured Where Possible
----
-_template: # _template holds common settings for all commands
- # Enable feature telemetry if disabled
- feature: telemetry
- # Common get syntax for TMS commands
- get_command: show run telemetry all
- # Parent configuration for TMS commands
- context:
- - telemetry
-data_source:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- kind: str
- getval: data-source (\\S+)$
- setval: 'data-source {0}'
- default: ~
-path:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- multiple: true
- kind: dict
- getval: path (?P<name>(\\S+|".*"))( depth (?P<depth>\\S+))?( query-condition (?P<query_condition>\\S+))?( filter-condition (?P<filter_condition>\\S+))?$
- setval: path {name} depth {depth} query-condition {query_condition} filter-condition {filter_condition}
- default:
- name: ~
- depth: ~
- query_condition: ~
- filter_condition: ~
-'''
-
-TMS_SUBSCRIPTION = '''
-# The cmd_ref is a yaml formatted list of module commands.
-# A leading underscore denotes a non-command variable; e.g. _template.
-# TBD: Use Structured Where Possible
----
-_template: # _template holds common settings for all commands
- # Enable feature telemetry if disabled
- feature: telemetry
- # Common get syntax for TMS commands
- get_command: show run telemetry all
- # Parent configuration for TMS commands
- context:
- - telemetry
-destination_group:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- multiple: true
- kind: int
- getval: dst-grp (\\S+)$
- setval: 'dst-grp {0}'
- default: ~
-sensor_group:
- _exclude: ['N3K', 'N5K', 'N6k', 'N7k']
- multiple: true
- kind: dict
- getval: snsr-grp (?P<id>\\S+) sample-interval (?P<sample_interval>\\S+)$
- setval: snsr-grp {id} sample-interval {sample_interval}
- default:
- id: ~
- sample_interval: ~
-'''
diff --git a/lib/ansible/module_utils/network/nxos/config/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/nxos/config/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index e5b56f82b1..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,303 +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 nxos_acl_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, remove_empties, dict_diff
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list, get_interface_type, normalize_interface
-
-
-class Acl_interfaces(ConfigBase):
- """
- The nxos_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 edit_config(self, commands):
- """Wrapper method for `_connection.edit_config()`
- This exists solely to allow the unit test framework to mock device connection calls.
- """
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- commands = list()
- state = self._module.params['state']
- action_states = ['merged', 'replaced', 'deleted', 'overridden']
-
- if state == 'gathered':
- result['gathered'] = self.get_acl_interfaces_facts()
- elif state == 'rendered':
- result['rendered'] = self.set_config({})
- # no need to fetch facts for rendered
- elif state == 'parsed':
- result['parsed'] = self.set_config({})
- # no need to fetch facts for parsed
- else:
- existing_acl_interfaces_facts = self.get_acl_interfaces_facts()
- commands.extend(self.set_config(existing_acl_interfaces_facts))
- if commands and state in action_states:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['before'] = existing_acl_interfaces_facts
- result['commands'] = commands
-
- changed_acl_interfaces_facts = self.get_acl_interfaces_facts()
- if result['changed']:
- result['after'] = 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
- """
- config = self._module.params['config']
- want = []
- if config:
- for w in config:
- if get_interface_type(w['name']) == 'loopback':
- self._module.fail_json(
- msg='This module works with ethernet, management or port-channe')
- w.update({'name': normalize_interface(w['name'])})
- want.append(remove_empties(w))
- 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 == 'overridden':
- commands = (self._state_overridden(want, have))
- elif state == 'deleted':
- commands = (self._state_deleted(want, have))
- elif state == 'rendered':
- commands = self._state_rendered(want)
- elif state == 'parsed':
- want = self._module.params['running_config']
- commands = self._state_parsed(want)
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- return commands
-
- def _state_parsed(self, want):
- return self.get_acl_interfaces_facts(want)
-
- def _state_rendered(self, want):
- commands = []
- for w in want:
- commands.extend(self.set_commands(w, {}))
- 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
- """
- new_commands = []
- del_dict = {'name': want['name'], 'access_groups': []}
- obj_in_have = search_obj_in_list(want['name'], have, 'name')
- if obj_in_have != want:
- commands = []
- if obj_in_have and 'access_groups' in obj_in_have.keys():
- for ag in obj_in_have['access_groups']:
- want_afi = []
- if want.get('access_groups'):
- want_afi = search_obj_in_list(
- ag['afi'], want['access_groups'], 'afi')
- if not want_afi:
- # whatever in have is not in want
- del_dict['access_groups'].append(ag)
- else:
- del_acl = []
- for acl in ag['acls']:
- if want_afi.get('acls'):
- if acl not in want_afi['acls']:
- del_acl.append(acl)
- else:
- del_acl.append(acl)
- afi = want_afi['afi']
- del_dict['access_groups'].append(
- {'afi': afi, 'acls': del_acl})
-
- commands.extend(self._state_deleted([del_dict], have))
- commands.extend(self._state_merged(want, have))
- new_commands.append(commands[0])
- commands = [commands[i]
- for i in range(1, len(commands)) if commands[i] != commands[0]]
- new_commands.extend(commands)
- return new_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 = []
- want_intf = [w['name'] for w in want]
- for h in have:
- if h['name'] not in want_intf:
- commands.extend(self._state_deleted([h], have))
- for w in want:
- commands.extend(self._state_replaced(w, 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
- """
- return self.set_commands(want, have)
-
- def set_commands(self, want, have, deleted=False):
- commands = []
- have_name = search_obj_in_list(want['name'], have, 'name')
- if have_name and have_name.get('access_groups'):
- if want.get('access_groups'):
- for w_afi in want['access_groups']:
- ip = 'ipv6'
- if w_afi['afi'] == 'ipv4':
- ip = 'ip'
- have_afi = search_obj_in_list(
- w_afi['afi'], have_name['access_groups'], 'afi')
- if have_afi:
- new_acls = []
- if deleted:
- if w_afi.get('acls') and have_afi.get('acls'):
- new_acls = [
- acl for acl in w_afi.get('acls') if acl in have_afi.get('acls')]
- elif 'acls' not in w_afi.keys():
- new_acls = have_afi.get('acls')
- else:
- if w_afi.get('acls'):
- new_acls = [
- acl for acl in w_afi['acls'] if acl not in have_afi['acls']]
- commands.extend(self.process_acl(
- new_acls, ip, deleted))
- else:
- if not deleted:
- if w_afi.get('acls'):
- commands.extend(
- self.process_acl(w_afi['acls'], ip))
- else:
- # only name is given to delete
- if deleted and 'access_groups' in have_name.keys():
- commands.extend(self.process_access_group(have_name, True))
- else:
- if not deleted: # and 'access_groups' in have_name.keys():
- commands.extend(self.process_access_group(want))
-
- if len(commands) > 0:
- commands.insert(0, 'interface ' + want['name'])
- return commands
-
- def process_access_group(self, item, deleted=False):
- commands = []
- for ag in item['access_groups']:
- ip = 'ipv6'
- if ag['afi'] == 'ipv4':
- ip = 'ip'
- if ag.get('acls'):
- commands.extend(self.process_acl(
- ag['acls'], ip, deleted))
- return commands
-
- def process_acl(self, acls, ip, deleted=False):
- commands = []
- no = ''
- if deleted:
- no = 'no '
- for acl in acls:
- port = ''
- if acl.get('port'):
- port = ' port'
- ag = ' access-group '
- if ip == 'ipv6':
- ag = ' traffic-filter '
- commands.append(no + ip + port + ag +
- acl['name'] + ' ' + acl['direction'])
- return commands
-
- def _state_deleted(self, main_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 main_want:
- for want in main_want:
- commands.extend(self.set_commands(want, have, deleted=True))
- else:
- for h in have:
- commands.extend(self.set_commands(h, have, deleted=True))
-
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/acls/acls.py b/lib/ansible/module_utils/network/nxos/config/acls/acls.py
deleted file mode 100644
index 37c8b3d23a..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/acls/acls.py
+++ /dev/null
@@ -1,690 +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 nxos_acls class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import socket
-import re
-from copy import deepcopy
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, remove_empties, dict_diff
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.argspec.acls.acls import AclsArgs
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list, get_interface_type, normalize_interface
-
-
-class Acls(ConfigBase):
- """
- The nxos_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 edit_config(self, commands):
- """Wrapper method for `_connection.edit_config()`
- This exists solely to allow the unit test framework to mock device connection calls.
- """
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- commands = list()
- state = self._module.params['state']
- action_states = ['merged', 'replaced', 'deleted', 'overridden']
-
- if state == 'gathered':
- result['gathered'] = self.get_acls_facts()
- elif state == 'rendered':
- result['rendered'] = self.set_config({})
- elif state == 'parsed':
- result['parsed'] = self.set_config({})
- else:
- existing_acls_facts = self.get_acls_facts()
- commands.extend(self.set_config(existing_acls_facts))
- if commands and state in action_states:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['before'] = existing_acls_facts
- result['commands'] = commands
-
- changed_acls_facts = self.get_acls_facts()
- if result['changed']:
- result['after'] = changed_acls_facts
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_acls_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- config = self._module.params['config']
- want = []
- if config:
- for w in config:
- want.append(remove_empties(w))
- have = existing_acls_facts
- if want:
- want = self.convert_values(want)
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def convert_values(self, want):
- '''
- This method is used to map and convert the user given values with what will actually be present in the device configuation
- '''
- port_protocol = {
- 515: 'lpd',
- 517: 'talk',
- 7: 'echo',
- 9: 'discard',
- 12: 'exec',
- 13: 'login',
- 14: 'cmd',
- 109: 'pop2',
- 19: 'chargen',
- 20: 'ftp-data',
- 21: 'ftp',
- 23: 'telnet',
- 25: 'smtp',
- 540: 'uucp',
- 543: 'klogin',
- 544: 'kshell',
- 37: 'time',
- 43: 'whois',
- 49: 'tacacs',
- 179: 'bgp',
- 53: 'domain',
- 194: 'irc',
- 70: 'gopher',
- 79: 'finger',
- 80: 'www',
- 101: 'hostname',
- 3949: 'drip',
- 110: 'pop3',
- 111: 'sunrpc',
- 496: 'pim-auto-rp',
- 113: 'ident',
- 119: 'nntp'
- }
- protocol = {
- 1: 'icmp',
- 2: 'igmp',
- 4: 'ip',
- 6: 'tcp',
- 103: 'pim',
- 108: 'pcp',
- 47: 'gre',
- 17: 'udp',
- 50: 'esp',
- 51: 'ahp',
- 88: 'eigrp',
- 89: 'ospf',
- 94: 'nos'
- }
- precedence = {
- 0: 'routine',
- 1: 'priority',
- 2: 'immediate',
- 3: 'flash',
- 4: 'flash-override',
- 5: 'critical',
- 6: 'internet',
- 7: 'network'
- }
- dscp = {
- 10: 'AF11',
- 12: 'AF12',
- 14: 'AF13',
- 18: 'AF21',
- 20: 'AF22',
- 22: 'AF23',
- 26: 'AF31',
- 28: 'AF32',
- 30: 'AF33',
- 34: 'AF41',
- 36: 'AF42',
- 38: 'AF43',
- 8: 'CS1',
- 16: 'CS2',
- 24: 'CS3',
- 32: 'CS4',
- 40: 'CS5',
- 48: 'CS6',
- 56: 'CS7',
- 0: 'Default',
- 46: 'EF'
- }
- # port_pro_num = list(protocol.keys())
- for afi in want:
- if 'acls' in afi.keys():
- for acl in afi['acls']:
- if 'aces' in acl.keys():
- for ace in acl['aces']:
- if 'dscp' in ace.keys():
- if ace['dscp'].isdigit():
- ace['dscp'] = dscp[int(ace['dscp'])]
- ace['dscp'] = ace['dscp'].lower()
- if 'precedence' in ace.keys():
- if ace['precedence'].isdigit():
- ace['precedence'] = precedence[int(
- ace['precedence'])]
- if 'protocol' in ace.keys(
- ) and ace['protocol'].isdigit() and int(
- ace['protocol']) in protocol.keys():
- ace['protocol'] = protocol[int(
- ace['protocol'])]
- # convert number to name
- if 'protocol' in ace.keys(
- ) and ace['protocol'] in ['tcp', 'udp']:
- for end in ['source', 'destination']:
- if 'port_protocol' in ace[end].keys():
- key = list(ace[end]
- ['port_protocol'].keys())[0]
- # key could be eq,gt,lt,neq or range
- if key != 'range':
- val = ace[end]['port_protocol'][
- key]
- if val.isdigit() and int(val) in port_protocol.keys(
- ):
- ace[end]['port_protocol'][
- key] = port_protocol[int(
- val)]
- else:
- st = int(ace[end]['port_protocol']
- ['range']['start'])
-
- end = int(ace[end]['port_protocol']
- ['range']['end'])
-
- if st in port_protocol.keys():
- ace[end]['port_protocol'][
- 'range'][
- 'start'] = port_protocol[
- st]
- if end in port_protocol.keys():
- ace[end]['port_protocol'][
- 'range'][
- 'end'] = port_protocol[
- end]
- return want
-
- 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 == 'overridden':
- commands = (self._state_overridden(want, have))
- elif state == 'deleted':
- commands = (self._state_deleted(want, have))
- elif state == 'rendered':
- commands = self._state_rendered(want)
- elif state == 'parsed':
- want = self._module.params['running_config']
- commands = self._state_parsed(want)
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- if state != 'parsed':
- commands = [c.strip() for c in commands]
- return commands
-
- def _state_parsed(self, want):
- return self.get_acls_facts(want)
-
- def _state_rendered(self, want):
- commands = []
- for w in want:
- commands.extend(self.set_commands(w, {}))
- 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 = []
- have_afi = search_obj_in_list(want['afi'], have, 'afi')
- del_dict = {'acls': []}
- want_names = []
- if have_afi != want:
- if have_afi:
- del_dict.update({'afi': have_afi['afi'], 'acls': []})
- if want.get('acls'):
- want_names = [w['name'] for w in want['acls']]
- have_names = [h['name'] for h in have_afi['acls']]
- want_acls = want.get('acls')
- for w in want_acls:
- acl_commands = []
- if w['name'] not in have_names:
- # creates new ACL in replaced state
- merge_dict = {'afi': want['afi'], 'acls': [w]}
- commands.extend(
- self._state_merged(merge_dict, have))
- else:
- # acl in want exists in have
- have_name = search_obj_in_list(
- w['name'], have_afi['acls'], 'name')
- have_aces = have_name.get('aces') if have_name.get(
- 'aces') else []
- merge_aces = []
- del_aces = []
- w_aces = w.get('aces') if w.get('aces') else []
-
- for ace in have_aces:
- if ace not in w_aces:
- del_aces.append(ace)
- for ace in w_aces:
- if ace not in have_aces:
- merge_aces.append(ace)
- merge_dict = {
- 'afi': want['afi'],
- 'acls': [{
- 'name': w['name'],
- 'aces': merge_aces
- }]
- }
- del_dict = {
- 'afi': want['afi'],
- 'acls': [{
- 'name': w['name'],
- 'aces': del_aces
- }]
- }
- if del_dict['acls']:
- acl_commands.extend(
- self._state_deleted([del_dict], have))
- acl_commands.extend(
- self._state_merged(merge_dict, have))
-
- for i in range(1, len(acl_commands)):
- if acl_commands[i] == acl_commands[0]:
- acl_commands[i] = ''
- commands.extend(acl_commands)
- else:
- acls = []
- # no acls given in want, so delete all have acls
- for acl in have_afi['acls']:
- acls.append({'name': acl['name']})
- del_dict['acls'] = acls
- if del_dict['acls']:
- commands.extend(self._state_deleted([del_dict], have))
-
- else:
- # want_afi is not present in have
- commands.extend(self._state_merged(want, have))
-
- commands = list(filter(None, 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 = []
- want_afi = [w['afi'] for w in want]
- for h in have:
- if h['afi'] in want_afi:
- w = search_obj_in_list(h['afi'], want, 'afi')
- for h_acl in h['acls']:
- w_acl = search_obj_in_list(h_acl['name'], w['acls'],
- 'name')
- if not w_acl:
- del_dict = {
- 'afi': h['afi'],
- 'acls': [{
- 'name': h_acl['name']
- }]
- }
- commands.extend(self._state_deleted([del_dict], have))
- else:
- # if afi is not in want
- commands.extend(self._state_deleted([{'afi': h['afi']}], have))
- for w in want:
- commands.extend(self._state_replaced(w, 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
- """
- return self.set_commands(want, have)
-
- 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: # and have != want:
- for w in want:
- ip = 'ipv6' if w['afi'] == 'ipv6' else 'ip'
- acl_names = []
- have_afi = search_obj_in_list(w['afi'], have, 'afi')
- # if want['afi] not in have, ignore
- if have_afi:
- if w.get('acls'):
- for acl in w['acls']:
- if 'aces' in acl.keys():
- have_name = search_obj_in_list(
- acl['name'], have_afi['acls'], 'name')
- if have_name:
- ace_commands = []
- flag = 0
- for ace in acl['aces']:
- if list(ace.keys()) == ['sequence']:
- # only sequence number is specified to be deleted
- if 'aces' in have_name.keys():
- for h_ace in have_name['aces']:
- if h_ace[
- 'sequence'] == ace[
- 'sequence']:
- ace_commands.append(
- 'no ' +
- str(ace['sequence']
- ))
- flag = 1
- else:
- if 'aces' in have_name.keys():
- for h_ace in have_name['aces']:
- # when want['ace'] does not have seq number
- if 'sequence' not in ace.keys(
- ):
- del h_ace['sequence']
- if ace == h_ace:
- ace_commands.append(
- 'no ' +
- self.process_ace(
- ace))
- flag = 1
- if flag:
- ace_commands.insert(
- 0,
- ip + ' access-list ' + acl['name'])
- commands.extend(ace_commands)
- else:
- # only name given
- for h in have_afi['acls']:
- if h['name'] == acl['name']:
- acl_names.append(acl['name'])
- for name in acl_names:
- commands.append('no ' + ip + ' access-list ' +
- name)
-
- else:
- # 'only afi is given'
- if have_afi.get('acls'):
- for h in have_afi['acls']:
- acl_names.append(h['name'])
- for name in acl_names:
- commands.append('no ' + ip + ' access-list ' +
- name)
- else:
- v6 = []
- v4 = []
- v6_local = v4_local = None
- for h in have:
- if h['afi'] == 'ipv6':
- v6 = (acl['name'] for acl in h['acls'])
- if 'match_local_traffic' in h.keys():
- v6_local = True
- else:
- v4 = (acl['name'] for acl in h['acls'])
- if 'match_local_traffic' in h.keys():
- v4_local = True
-
- self.no_commands(v4, commands, v4_local, 'ip')
- self.no_commands(v6, commands, v6_local, 'ipv6')
-
- for name in v6:
- commands.append('no ipv6 access-list ' + name)
- if v4_local:
- commands.append('no ipv6 access-list match-local-traffic')
-
- return commands
-
- def no_commands(self, v_list, commands, match_local, ip):
- for name in v_list:
- commands.append('no ' + ip + ' access-list ' + name)
- if match_local:
- commands.append('no ' + ip + ' access-list match-local-traffic')
-
- def set_commands(self, want, have):
- commands = []
- have_afi = search_obj_in_list(want['afi'], have, 'afi')
- ip = ''
- if 'v6' in want['afi']:
- ip = 'ipv6 '
- else:
- ip = 'ip '
-
- if have_afi:
- if want.get('acls'):
- for w_acl in want['acls']:
- have_acl = search_obj_in_list(w_acl['name'],
- have_afi['acls'], 'name')
- name = w_acl['name']
- flag = 0
- ace_commands = []
- if have_acl != w_acl:
- if have_acl:
- ace_list = []
- if w_acl.get('aces') and have_acl.get('aces'):
- # case 1 --> sequence number not given in want --> new ace
- # case 2 --> new sequence number in want --> new ace
- # case 3 --> existing sequence number given --> update rule (only for merged state.
- # For replaced and overridden, rule is deleted in the state's config)
-
- ace_list = [
- item for item in w_acl['aces']
- if 'sequence' not in item.keys()
- ] # case 1
-
- want_seq = [
- item['sequence'] for item in w_acl['aces']
- if 'sequence' in item.keys()
- ]
-
- have_seq = [
- item['sequence']
- for item in have_acl['aces']
- ]
-
- new_seq = list(set(want_seq) - set(have_seq))
- common_seq = list(
- set(want_seq).intersection(set(have_seq)))
-
- temp_list = [
- item for item in w_acl['aces']
- if 'sequence' in item.keys()
- and item['sequence'] in new_seq
- ] # case 2
- ace_list.extend(temp_list)
- for w in w_acl['aces']:
- self.argument_spec = AclsArgs.argument_spec
- params = utils.validate_config(
- self.argument_spec, {
- 'config': [{
- 'afi':
- want['afi'],
- 'acls': [{
- 'name': name,
- 'aces': ace_list
- }]
- }]
- })
- if 'sequence' in w.keys(
- ) and w['sequence'] in common_seq:
- temp_obj = search_obj_in_list(
- w['sequence'], have_acl['aces'],
- 'sequence') # case 3
- if temp_obj != w:
- for key, val in w.items():
- temp_obj[key] = val
- ace_list.append(temp_obj)
- if self._module.params[
- 'state'] == 'merged':
- ace_commands.append(
- 'no ' + str(w['sequence']))
- # remove existing rule to update it
- elif w_acl.get('aces'):
- # 'have' has ACL defined without any ACE
- ace_list = [item for item in w_acl['aces']]
- for w_ace in ace_list:
- ace_commands.append(
- self.process_ace(w_ace).strip())
- flag = 1
-
- if flag:
- ace_commands.insert(0,
- ip + 'access-list ' + name)
-
- else:
- commands.append(ip + 'access-list ' + name)
- if 'aces' in w_acl.keys():
- for w_ace in w_acl['aces']:
- commands.append(
- self.process_ace(w_ace).strip())
- commands.extend(ace_commands)
- else:
- if want.get('acls'):
- for w_acl in want['acls']:
- name = w_acl['name']
- commands.append(ip + 'access-list ' + name)
- if 'aces' in w_acl.keys():
- for w_ace in w_acl['aces']:
- commands.append(self.process_ace(w_ace).strip())
-
- return commands
-
- def process_ace(self, w_ace):
- command = ''
- ace_keys = w_ace.keys()
- if 'remark' in ace_keys:
- command += 'remark ' + w_ace['remark'] + ' '
- else:
- command += w_ace['grant'] + ' '
- if 'protocol' in ace_keys:
- command += w_ace['protocol'] + ' '
- src = self.get_address(w_ace['source'], w_ace['protocol'])
- dest = self.get_address(w_ace['destination'],
- w_ace['protocol'])
- command += src + dest
- if 'protocol_options' in ace_keys:
- pro = list(w_ace['protocol_options'].keys())[0]
- if pro != w_ace['protocol']:
- self._module.fail_json(
- msg='protocol and protocol_options mismatch')
- flags = ''
- for k in w_ace['protocol_options'][pro].keys():
- k = re.sub('_', '-', k)
- flags += k + ' '
- command += flags
- if 'dscp' in ace_keys:
- command += 'dscp ' + w_ace['dscp'] + ' '
- if 'fragments' in ace_keys:
- command += 'fragments '
- if 'precedence' in ace_keys:
- command += 'precedence ' + w_ace['precedence'] + ' '
- if 'log' in ace_keys:
- command += 'log '
- if 'sequence' in ace_keys:
- command = str(w_ace['sequence']) + ' ' + command
- return command
-
- def get_address(self, endpoint, pro=''):
- ret_addr = ''
- keys = list(endpoint.keys())
- if 'address' in keys:
- if 'wildcard_bits' not in keys:
- self._module.fail_json(
- msg='wildcard bits not specified for address')
- else:
- ret_addr = endpoint['address'] + \
- ' ' + endpoint['wildcard_bits'] + ' '
- elif 'any' in keys:
- ret_addr = 'any '
- elif 'host' in keys:
- ret_addr = 'host ' + endpoint['host'] + ' '
- elif 'prefix' in keys:
- ret_addr = endpoint['prefix'] + ' '
-
- if pro in ['tcp', 'udp']:
- if 'port_protocol' in keys:
- options = self.get_options(endpoint['port_protocol'])
- ret_addr += options
- return ret_addr
-
- def get_options(self, item):
- com = ''
- subkey = list(item.keys())
- if 'range' in subkey:
- com = 'range ' + item['range']['start'] + \
- ' ' + item['range']['end'] + ' '
- else:
- com = subkey[0] + ' ' + item[subkey[0]] + ' '
- return com
diff --git a/lib/ansible/module_utils/network/nxos/config/bfd_interfaces/bfd_interfaces.py b/lib/ansible/module_utils/network/nxos/config/bfd_interfaces/bfd_interfaces.py
deleted file mode 100644
index 3b0d2e7af7..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/bfd_interfaces/bfd_interfaces.py
+++ /dev/null
@@ -1,264 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-nxos_bfd_interfaces class
-This class creates a command set to bring the current device configuration
-to a desired end-state. The command set is based on a comparison of the
-current configuration (as dict) and the provided configuration (as dict).
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import dict_diff, to_list
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list
-
-
-class Bfd_interfaces(ConfigBase):
- """
- The nxos_bfd_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
- gather_network_resources = [
- 'bfd_interfaces',
- ]
- # exclude_params = []
-
- def __init__(self, module):
- super(Bfd_interfaces, self).__init__(module)
-
- def get_bfd_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :returns: A list of interface configs and a platform string
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- bfd_interfaces_facts = facts['ansible_network_resources'].get('bfd_interfaces', [])
- platform = facts.get('ansible_net_platform', '')
- return bfd_interfaces_facts, platform
-
- def edit_config(self, commands):
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- cmds = list()
-
- existing_bfd_interfaces_facts, platform = self.get_bfd_interfaces_facts()
- cmds.extend(self.set_config(existing_bfd_interfaces_facts, platform))
- if cmds:
- if not self._module.check_mode:
- self.edit_config(cmds)
- result['changed'] = True
- result['commands'] = cmds
-
- changed_bfd_interfaces_facts, platform = self.get_bfd_interfaces_facts()
- result['before'] = existing_bfd_interfaces_facts
- if result['changed']:
- result['after'] = changed_bfd_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_bfd_interfaces_facts, platform):
- """ 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
- """
- if re.search('N[56]K', platform):
- # Some platforms do not support the 'bfd' interface keyword;
- # remove the 'bfd' key from each want/have interface.
- orig_want = self._module.params['config']
- want = []
- for w in orig_want:
- del w['bfd']
- want.append(w)
- orig_have = existing_bfd_interfaces_facts
- have = []
- for h in orig_have:
- del h['bfd']
- have.append(h)
- else:
- want = self._module.params['config']
- have = existing_bfd_interfaces_facts
-
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- cmds = list()
- if state == 'overridden':
- cmds.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- cmds.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- cmds.extend(self._state_merged(flatten_dict(w), have))
- elif state == 'replaced':
- cmds.extend(self._state_replaced(flatten_dict(w), have))
- return cmds
-
- 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
- """
- cmds = []
- obj_in_have = search_obj_in_list(want['name'], have, 'name')
- if obj_in_have:
- diff = dict_diff(want, obj_in_have)
- else:
- diff = want
- merged_cmds = self.set_commands(want, have)
- if 'name' not in diff:
- diff['name'] = want['name']
-
- replaced_cmds = []
- if obj_in_have:
- replaced_cmds = self.del_attribs(diff)
- if replaced_cmds or merged_cmds:
- for cmd in set(replaced_cmds).intersection(set(merged_cmds)):
- merged_cmds.remove(cmd)
- cmds.extend(replaced_cmds)
- cmds.extend(merged_cmds)
- return cmds
-
- 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
- """
- cmds = []
- for h in have:
- # Clean up bfd attrs for any interfaces not listed in the play
- h = flatten_dict(h)
- obj_in_want = flatten_dict(search_obj_in_list(h['name'], want, 'name'))
- if obj_in_want:
- # Let the 'want' loop handle all vals for this interface
- continue
- cmds.extend(self.del_attribs(h))
- for w in want:
- # Update any want attrs if needed. The overridden state considers
- # the play as the source of truth for the entire device, therefore
- # set any unspecified attrs to their default state.
- w = self.set_none_vals_to_defaults(flatten_dict(w))
- cmds.extend(self.set_commands(w, have))
- return cmds
-
- 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
- """
- return self.set_commands(want, have)
-
- 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
- """
- if not (want or have):
- return []
- cmds = []
- if want:
- for w in want:
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- cmds.extend(self.del_attribs(obj_in_have))
- else:
- for h in have:
- cmds.extend(self.del_attribs(flatten_dict(h)))
- return cmds
-
- def del_attribs(self, obj):
- if not obj or len(obj.keys()) == 1:
- return []
- cmds = []
- # 'bfd' and 'bfd echo' are enabled by default so the handling is
- # counter-intuitive; we are enabling them to remove them. The end result
- # is that they are removed from the interface config on the device.
- if 'bfd' in obj and 'disable' in obj['bfd']:
- cmds.append('bfd')
- if 'echo' in obj and 'disable' in obj['echo']:
- cmds.append('bfd echo')
- if cmds:
- cmds.insert(0, 'interface ' + obj['name'])
- return cmds
-
- def set_none_vals_to_defaults(self, want):
- # Set dict None values to default states
- if 'bfd' in want and want['bfd'] is None:
- want['bfd'] = 'enable'
- if 'echo' in want and want['echo'] is None:
- want['echo'] = 'enable'
- return want
-
- def diff_of_dicts(self, want, obj_in_have):
- diff = set(want.items()) - set(obj_in_have.items())
- diff = dict(diff)
- if diff and want['name'] == obj_in_have['name']:
- diff.update({'name': want['name']})
- return diff
-
- def add_commands(self, want):
- if not want:
- return []
- cmds = []
- if 'bfd' in want and want['bfd'] is not None:
- cmd = 'bfd' if want['bfd'] == 'enable' else 'no bfd'
- cmds.append(cmd)
- if 'echo' in want and want['echo'] is not None:
- cmd = 'bfd echo' if want['echo'] == 'enable' else 'no bfd echo'
- cmds.append(cmd)
-
- if cmds:
- cmds.insert(0, 'interface ' + want['name'])
- return cmds
-
- def set_commands(self, want, have):
- cmds = []
- obj_in_have = flatten_dict(search_obj_in_list(want['name'], have, 'name'))
- if not obj_in_have:
- cmds = self.add_commands(want)
- else:
- diff = self.diff_of_dicts(want, obj_in_have)
- cmds = self.add_commands(diff)
- return cmds
diff --git a/lib/ansible/module_utils/network/nxos/config/hsrp_interfaces/hsrp_interfaces.py b/lib/ansible/module_utils/network/nxos/config/hsrp_interfaces/hsrp_interfaces.py
deleted file mode 100644
index e3ef78e540..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/hsrp_interfaces/hsrp_interfaces.py
+++ /dev/null
@@ -1,248 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos hsrp_interfaces class
-This class creates a command set to bring the current device configuration
-to a desired end-state. The command set is based on a comparison of the
-current configuration (as dict) and the provided configuration (as dict).
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import dict_diff, to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, get_interface_type, normalize_interface, search_obj_in_list, vlan_range_to_list
-
-
-class Hsrp_interfaces(ConfigBase):
- """
- The nxos_hsrp_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'hsrp_interfaces',
- ]
-
- def __init__(self, module):
- super(Hsrp_interfaces, self).__init__(module)
-
- def get_hsrp_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)
- hsrp_interfaces_facts = facts['ansible_network_resources'].get('hsrp_interfaces', [])
- return hsrp_interfaces_facts
-
- def edit_config(self, commands):
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- warnings = list()
- cmds = list()
-
- existing_hsrp_interfaces_facts = self.get_hsrp_interfaces_facts()
- cmds.extend(self.set_config(existing_hsrp_interfaces_facts))
- if cmds:
- if not self._module.check_mode:
- self.edit_config(cmds)
- result['changed'] = True
- result['commands'] = cmds
- changed_hsrp_interfaces_facts = self.get_hsrp_interfaces_facts()
-
- result['before'] = existing_hsrp_interfaces_facts
- if result['changed']:
- result['after'] = changed_hsrp_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_hsrp_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
- """
- config = self._module.params['config']
- want = []
- if config:
- for w in config:
- w.update({'name': normalize_interface(w['name'])})
- want.append(w)
- have = existing_hsrp_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']
- # check for 'config' keyword in play
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- cmds = list()
- if state == 'overridden':
- cmds.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- cmds.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- cmds.extend(self._state_merged(flatten_dict(w), have))
- elif state == 'replaced':
- cmds.extend(self._state_replaced(flatten_dict(w), have))
- return cmds
-
- 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
- """
- cmds = []
- obj_in_have = search_obj_in_list(want['name'], have, 'name')
- if obj_in_have:
- diff = dict_diff(want, obj_in_have)
- else:
- diff = want
- merged_cmds = self.set_commands(want, have)
- if 'name' not in diff:
- diff['name'] = want['name']
-
- replaced_cmds = []
- if obj_in_have:
- replaced_cmds = self.del_attribs(diff)
- if replaced_cmds or merged_cmds:
- for cmd in set(replaced_cmds).intersection(set(merged_cmds)):
- merged_cmds.remove(cmd)
- cmds.extend(replaced_cmds)
- cmds.extend(merged_cmds)
- return cmds
-
- 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
- """
- cmds = []
- for h in have:
- # Check existing states, set to default if not in want or different than want
- h = flatten_dict(h)
- obj_in_want = search_obj_in_list(h['name'], want, 'name')
- if obj_in_want:
- # Let the 'want' loop handle all vals for this interface
- continue
- cmds.extend(self.del_attribs(h))
- for w in want:
- # Update any want attrs if needed. The overridden state considers
- # the play as the source of truth for the entire device, therefore
- # set any unspecified attrs to their default state.
- w = self.set_none_vals_to_defaults(flatten_dict(w))
- cmds.extend(self.set_commands(w, have))
- return cmds
-
- 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
- """
- return self.set_commands(want, have)
-
- 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
- """
- if not (want or have):
- return []
- cmds = []
- if want:
- for w in want:
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- cmds.extend(self.del_attribs(obj_in_have))
- else:
- for h in have:
- cmds.extend(self.del_attribs(flatten_dict(h)))
- return cmds
-
- def del_attribs(self, obj):
- if not obj or len(obj.keys()) == 1:
- return []
- cmds = []
- if 'bfd' in obj:
- cmds.append('no hsrp bfd')
- if cmds:
- cmds.insert(0, 'interface ' + obj['name'])
- return cmds
-
- def set_none_vals_to_defaults(self, want):
- # Set dict None values to default states
- if 'bfd' in want and want['bfd'] is None:
- want['bfd'] = 'disable'
- return want
-
- def diff_of_dicts(self, want, obj_in_have):
- diff = set(want.items()) - set(obj_in_have.items())
- diff = dict(diff)
- if diff and want['name'] == obj_in_have['name']:
- diff.update({'name': want['name']})
- return diff
-
- def add_commands(self, want, obj_in_have):
- if not want:
- return []
- cmds = []
- if 'bfd' in want and want['bfd'] is not None:
- if want['bfd'] == 'enable':
- cmd = 'hsrp bfd'
- cmds.append(cmd)
- elif want['bfd'] == 'disable' and obj_in_have and obj_in_have.get('bfd') == 'enable':
- cmd = 'no hsrp bfd'
- cmds.append(cmd)
-
- if cmds:
- cmds.insert(0, 'interface ' + want['name'])
- return cmds
-
- def set_commands(self, want, have):
- cmds = []
- obj_in_have = search_obj_in_list(want['name'], have, 'name')
- if not obj_in_have:
- cmds = self.add_commands(want, obj_in_have)
- else:
- diff = self.diff_of_dicts(want, obj_in_have)
- cmds = self.add_commands(diff, obj_in_have)
- return cmds
diff --git a/lib/ansible/module_utils/network/nxos/config/interfaces/interfaces.py b/lib/ansible/module_utils/network/nxos/config/interfaces/interfaces.py
deleted file mode 100644
index 0082b376b7..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/interfaces/interfaces.py
+++ /dev/null
@@ -1,379 +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 nxos_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
-import re
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import dict_diff, to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import normalize_interface, search_obj_in_list
-from ansible.module_utils.network.nxos.utils.utils import remove_rsvd_interfaces
-from ansible.module_utils.network.nxos.nxos import default_intf_enabled
-
-
-class Interfaces(ConfigBase):
- """
- The nxos_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'interfaces',
- ]
-
- exclude_params = [
- 'description',
- 'mtu',
- 'speed',
- 'duplex',
- ]
-
- def __init__(self, module):
- super(Interfaces, self).__init__(module)
-
- def get_interfaces_facts(self, get_default_interfaces=False):
- """ Get the 'facts' (the current configuration)
-
- :get_default_interfaces: boolean - when True include a list of existing-but-default interface names in the facts dict.
- - The defaults list is primarily used to detect non-existent virtual interfaces.
- :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')
- interfaces_facts = remove_rsvd_interfaces(interfaces_facts)
- if get_default_interfaces:
- default_interfaces = facts['ansible_network_resources'].get('default_interfaces', [])
- interfaces_facts.append(default_interfaces)
-
- self.intf_defs = facts.get('intf_defs', {})
- return interfaces_facts
-
- def edit_config(self, commands):
- """Wrapper method for `_connection.edit_config()`
- This method exists solely to allow the unit test framework to mock device connection calls.
- """
- return self._connection.edit_config(commands)
-
- 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(get_default_interfaces=True)
- default_intf_list = existing_interfaces_facts.pop()
- commands.extend(self.set_config(existing_interfaces_facts, default_intf_list))
- if commands:
- if not self._module.check_mode:
- self.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, default_intf_list):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- config = self._module.params.get('config')
- want = []
- if config:
- for w in config:
- w.update({'name': normalize_interface(w['name'])})
- want.append(remove_empties(w))
- have = deepcopy(existing_interfaces_facts)
- for i in want:
- # 'have' does not include objects from the default_interfaces list.
- # Add any 'want' names from default_interfaces to the 'have' list.
- if i['name'] in default_intf_list:
- have.append({'name': i['name']})
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- commands = list()
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- return commands
-
- def _state_replaced(self, w, 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 = []
- name = w['name']
- obj_in_have = search_obj_in_list(name, have, 'name')
- if obj_in_have:
- # If 'w' does not specify mode then intf may need to change to its
- # default mode, however default mode may depend on sysdef.
- if not w.get('mode') and re.search('Ethernet|port-channel', name):
- sysdefs = self.intf_defs['sysdefs']
- sysdef_mode = sysdefs['mode']
- if obj_in_have.get('mode') != sysdef_mode:
- w['mode'] = sysdef_mode
- diff = dict_diff(w, obj_in_have)
- else:
- diff = w
-
- merged_commands = self.set_commands(w, have)
- if merged_commands:
- # merged_commands:
- # - These commands are changes specified by the playbook.
- # - merged_commands apply to both existing and new objects
- # replaced_commands:
- # - These are the unspecified commands, used to reset any params
- # that are not already set to default states
- # - replaced_commands should only be used on 'have' objects
- # (interfaces that already exist)
- if obj_in_have:
- if 'name' not in diff:
- diff['name'] = name
- wkeys = w.keys()
- dkeys = diff.keys()
- for k in wkeys:
- if k in self.exclude_params and k in dkeys:
- del diff[k]
- replaced_commands = self.del_attribs(diff)
- cmds = set(replaced_commands).intersection(set(merged_commands))
- for cmd in cmds:
- merged_commands.remove(cmd)
- 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
- """
- # overridden is the same as replaced behavior except for the scope.
- cmds = []
- existing_interfaces = []
- for h in have:
- existing_interfaces.append(h['name'])
- obj_in_want = search_obj_in_list(h['name'], want, 'name')
- if obj_in_want:
- if h != obj_in_want:
- replaced_cmds = self._state_replaced(obj_in_want, [h])
- if replaced_cmds:
- cmds.extend(replaced_cmds)
- else:
- cmds.extend(self.del_attribs(h))
-
- for w in want:
- if w['name'] not in existing_interfaces:
- # This is an object that was excluded from the 'have' list
- # because all of its params are currently set to default states
- # -OR- it's a new object that does not exist on the device yet.
- cmds.extend(self.add_commands(w))
- return cmds
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- return self.set_commands(w, have)
-
- 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 w in want:
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- commands.extend(self.del_attribs(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_attribs(h))
- return commands
-
- def default_enabled(self, want=None, have=None, action=''):
- # 'enabled' default state depends on the interface type and L2 state.
- # Note that the current default could change when changing L2/L3 modes.
- if want is None:
- want = {}
- if have is None:
- have = {}
- name = have.get('name')
- if name is None:
- return None
-
- sysdefs = self.intf_defs['sysdefs']
- sysdef_mode = sysdefs['mode']
-
- # Get the default enabled state for this interface. This was collected
- # during Facts gathering.
- intf_def_enabled = self.intf_defs.get(name)
-
- have_mode = have.get('mode', sysdef_mode)
- if action == 'delete' and not want:
- want_mode = sysdef_mode
- else:
- want_mode = want.get('mode', have_mode)
- if (want_mode and have_mode) is None or (want_mode != have_mode) or intf_def_enabled is None:
- # L2-L3 is changing or this is a new virtual intf. Get new default.
- intf_def_enabled = default_intf_enabled(name=name, sysdefs=sysdefs, mode=want_mode)
-
- return intf_def_enabled
-
- def del_attribs(self, obj):
- commands = []
- if not obj or len(obj.keys()) == 1:
- return commands
- # mode/switchport changes should occur before other changes
- sysdef_mode = self.intf_defs['sysdefs']['mode']
- if 'mode' in obj and obj['mode'] != sysdef_mode:
- no_cmd = 'no ' if sysdef_mode == 'layer3' else ''
- commands.append(no_cmd + 'switchport')
- if 'description' in obj:
- commands.append('no description')
- if 'speed' in obj:
- commands.append('no speed')
- if 'duplex' in obj:
- commands.append('no duplex')
- if 'enabled' in obj:
- sysdef_enabled = self.default_enabled(have=obj, action='delete')
- if obj['enabled'] is False and sysdef_enabled is True:
- commands.append('no shutdown')
- elif obj['enabled'] is True and sysdef_enabled is False:
- commands.append('shutdown')
- if 'mtu' in obj:
- commands.append('no mtu')
- if 'ip_forward' in obj and obj['ip_forward'] is True:
- commands.append('no ip forward')
- if 'fabric_forwarding_anycast_gateway' in obj and obj['fabric_forwarding_anycast_gateway'] is True:
- commands.append('no fabric forwarding mode anycast-gateway')
- if commands:
- commands.insert(0, 'interface ' + obj['name'])
-
- return commands
-
- def diff_of_dicts(self, w, obj):
- diff = set(w.items()) - set(obj.items())
- diff = dict(diff)
- if diff and w['name'] == obj['name']:
- diff.update({'name': w['name']})
- return diff
-
- def add_commands(self, d, obj_in_have=None):
- commands = []
- if not d:
- return commands
- if obj_in_have is None:
- obj_in_have = {}
- # mode/switchport changes should occur before other changes
- if 'mode' in d:
- sysdef_mode = self.intf_defs['sysdefs']['mode']
- have_mode = obj_in_have.get('mode', sysdef_mode)
- want_mode = d['mode']
- if have_mode == 'layer2':
- if want_mode == 'layer3':
- commands.append('no switchport')
- elif want_mode == 'layer2':
- commands.append('switchport')
- if 'description' in d:
- commands.append('description ' + d['description'])
- if 'speed' in d:
- commands.append('speed ' + str(d['speed']))
- if 'duplex' in d:
- commands.append('duplex ' + d['duplex'])
- if 'enabled' in d:
- have_enabled = obj_in_have.get('enabled', self.default_enabled(d, obj_in_have))
- if d['enabled'] is False and have_enabled is True:
- commands.append('shutdown')
- elif d['enabled'] is True and have_enabled is False:
- commands.append('no shutdown')
- if 'mtu' in d:
- commands.append('mtu ' + str(d['mtu']))
- if 'ip_forward' in d:
- if d['ip_forward'] is True:
- commands.append('ip forward')
- else:
- commands.append('no ip forward')
- if 'fabric_forwarding_anycast_gateway' in d:
- if d['fabric_forwarding_anycast_gateway'] is True:
- commands.append('fabric forwarding mode anycast-gateway')
- else:
- commands.append('no fabric forwarding mode anycast-gateway')
- if commands or not obj_in_have:
- commands.insert(0, 'interface' + ' ' + d['name'])
- return commands
-
- def set_commands(self, w, have):
- commands = []
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- if not obj_in_have:
- commands = self.add_commands(w)
- else:
- diff = self.diff_of_dicts(w, obj_in_have)
- commands = self.add_commands(diff, obj_in_have)
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/nxos/config/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index dba9afc981..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,301 +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 nxos_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 dict_diff, to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, normalize_interface, search_obj_in_list, vlan_range_to_list
-
-
-class L2_interfaces(ConfigBase):
- """
- The nxos_l2_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'l2_interfaces',
- ]
-
- exclude_params = [
- 'vlan',
- 'allowed_vlans',
- 'native_vlans',
- ]
-
- def __init__(self, module):
- super(L2_interfaces, self).__init__(module)
-
- 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
- """
- config = self._module.params.get('config')
- want = []
- if config:
- for w in config:
- w.update({'name': normalize_interface(w['name'])})
- self.expand_trunk_allowed_vlans(w)
- want.append(remove_empties(w))
- have = existing_l2_interfaces_facts
- for h in have:
- self.expand_trunk_allowed_vlans(h)
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def expand_trunk_allowed_vlans(self, d):
- if not d:
- return None
- if 'trunk' in d and d['trunk']:
- if 'allowed_vlans' in d['trunk']:
- allowed_vlans = vlan_range_to_list(d['trunk']['allowed_vlans'])
- vlans_list = [str(l) for l in sorted(allowed_vlans)]
- d['trunk']['allowed_vlans'] = ",".join(vlans_list)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- commands = list()
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(flatten_dict(w), have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(flatten_dict(w), have))
- return commands
-
- def _state_replaced(self, w, 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 = []
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- if obj_in_have:
- diff = dict_diff(w, obj_in_have)
- else:
- diff = w
- merged_commands = self.set_commands(w, have, True)
- if 'name' not in diff:
- diff['name'] = w['name']
-
- dkeys = diff.keys()
- for k in w.copy():
- if k in self.exclude_params and k in dkeys:
- del diff[k]
- replaced_commands = self.del_attribs(diff)
-
- if merged_commands:
- cmds = set(replaced_commands).intersection(set(merged_commands))
- for cmd in cmds:
- merged_commands.remove(cmd)
- 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 h in have:
- h = flatten_dict(h)
- obj_in_want = flatten_dict(search_obj_in_list(h['name'], want, 'name'))
- if h == obj_in_want:
- continue
- for w in want:
- w = flatten_dict(w)
- if h['name'] == w['name']:
- wkeys = w.keys()
- hkeys = h.keys()
- for k in wkeys:
- if k in self.exclude_params and k in hkeys:
- del h[k]
- commands.extend(self.del_attribs(h))
- for w in want:
- commands.extend(self.set_commands(flatten_dict(w), have, True))
- return commands
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- return self.set_commands(w, have)
-
- 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 w in want:
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- commands.extend(self.del_attribs(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_attribs(flatten_dict(h)))
- return commands
-
- def del_attribs(self, obj):
- commands = []
- if not obj or len(obj.keys()) == 1:
- return commands
-
- cmd = 'no switchport '
- if 'vlan' in obj:
- commands.append(cmd + 'access vlan')
- if 'mode' in obj:
- commands.append(cmd + 'mode')
- if 'allowed_vlans' in obj:
- commands.append(cmd + 'trunk allowed vlan')
- if 'native_vlan' in obj:
- commands.append(cmd + 'trunk native vlan')
- if commands:
- commands.insert(0, 'interface ' + obj['name'])
- return commands
-
- def diff_of_dicts(self, w, obj):
- diff = set(w.items()) - set(obj.items())
- diff = dict(diff)
- if diff and w['name'] == obj['name']:
- diff.update({'name': w['name']})
- return diff
-
- def add_commands(self, d, vlan_exists=False):
- commands = []
- if not d:
- return commands
-
- cmd = 'switchport '
- if 'mode' in d:
- commands.append(cmd + 'mode {0}'.format(d['mode']))
- if 'vlan' in d:
- commands.append(cmd + 'access vlan ' + str(d['vlan']))
- if 'allowed_vlans' in d:
- if vlan_exists:
- commands.append(cmd + 'trunk allowed vlan add ' + str(d['allowed_vlans']))
- else:
- commands.append(cmd + 'trunk allowed vlan ' + str(d['allowed_vlans']))
- if 'native_vlan' in d:
- commands.append(cmd + 'trunk native vlan ' + str(d['native_vlan']))
- if commands:
- commands.insert(0, 'interface ' + d['name'])
- return commands
-
- def set_commands(self, w, have, replace=False):
- commands = []
-
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- if not obj_in_have:
- commands = self.add_commands(w)
- else:
- diff = self.diff_of_dicts(w, obj_in_have)
- if diff and not replace:
- if 'mode' in diff.keys() and diff['mode']:
- commands = self.add_commands(diff)
- if "allowed_vlans" in diff.keys() and diff["allowed_vlans"]:
- vlan_tobe_added = diff["allowed_vlans"].split(',')
- vlan_list = vlan_tobe_added[:]
- if obj_in_have.get("allowed_vlans"):
- have_vlans = obj_in_have["allowed_vlans"].split(',')
- else:
- have_vlans = []
- for w_vlans in vlan_list:
- if w_vlans in have_vlans:
- vlan_tobe_added.pop(vlan_tobe_added.index(w_vlans))
- if vlan_tobe_added:
- diff.update({"allowed_vlans": ','.join(vlan_tobe_added)})
- if have_vlans:
- commands = self.add_commands(diff, True)
- else:
- commands = self.add_commands(diff)
- return commands
- commands = self.add_commands(diff)
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/nxos/config/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 6febab96d7..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,488 +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 nxos_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
-
-import re
-
-from copy import deepcopy
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import normalize_interface, search_obj_in_list
-from ansible.module_utils.network.nxos.utils.utils import remove_rsvd_interfaces, get_interface_type
-
-
-class L3_interfaces(ConfigBase):
- """
- The nxos_l3_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'l3_interfaces',
- ]
-
- exclude_params = [
- ]
-
- def __init__(self, module):
- super(L3_interfaces, self).__init__(module)
-
- 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 []
-
- self.platform = self.get_platform_type()
- return remove_rsvd_interfaces(l3_interfaces_facts)
-
- def get_platform_type(self):
- default, _warnings = Facts(self._module).get_facts(legacy_facts_type=['default'])
- return default.get('ansible_net_platform', '')
-
- def edit_config(self, commands):
- return self._connection.edit_config(commands)
-
- 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.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
- """
- config = self._module.params.get('config')
- want = []
- if config:
- for w in config:
- w.update({'name': normalize_interface(w['name'])})
- if get_interface_type(w['name']) == 'management':
- self._module.fail_json(msg="The 'management' interface is not allowed to be managed by this module")
- want.append(remove_empties(w))
- have = deepcopy(existing_l3_interfaces_facts)
- self.init_check_existing(have)
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- commands = list()
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
- Scope is limited to interface objects defined in the playbook.
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- cmds = []
- name = want['name']
- obj_in_have = search_obj_in_list(want['name'], have, 'name')
-
- have_v4 = obj_in_have.pop('ipv4', []) if obj_in_have else []
- have_v6 = obj_in_have.pop('ipv6', []) if obj_in_have else []
-
- # Process lists of dicts separately
- v4_cmds = self._v4_cmds(want.pop('ipv4', []), have_v4, state='replaced')
- v6_cmds = self._v6_cmds(want.pop('ipv6', []), have_v6, state='replaced')
-
- # Process remaining attrs
- if obj_in_have:
- # Find 'want' changes first
- diff = self.diff_of_dicts(want, obj_in_have)
- rmv = {'name': name}
- haves_not_in_want = set(obj_in_have.keys()) - set(want.keys()) - set(diff.keys())
- for i in haves_not_in_want:
- rmv[i] = obj_in_have[i]
- cmds.extend(self.generate_delete_commands(rmv))
- else:
- diff = want
-
- cmds.extend(self.add_commands(diff, name=name))
- cmds.extend(v4_cmds)
- cmds.extend(v6_cmds)
- self.cmd_order_fixup(cmds, name)
- return cmds
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
- Scope includes all interface objects on the device.
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- # overridden behavior is the same as replaced except for scope.
- cmds = []
- existing_vlans = []
- for i in have:
- obj_in_want = search_obj_in_list(i['name'], want, 'name')
- if obj_in_want:
- if i != obj_in_want:
- v4_cmds = self._v4_cmds(obj_in_want.pop('ipv4', []), i.pop('ipv4', []), state='overridden')
- replaced_cmds = self._state_replaced(obj_in_want, [i])
- replaced_cmds.extend(v4_cmds)
- self.cmd_order_fixup(replaced_cmds, obj_in_want['name'])
- cmds.extend(replaced_cmds)
- else:
- deleted_cmds = self.generate_delete_commands(i)
- self.cmd_order_fixup(deleted_cmds, i['name'])
- cmds.extend(deleted_cmds)
-
- for i in want:
- if [item for item in have if i['name'] == item['name']]:
- continue
- cmds.extend(self.add_commands(i, name=i['name']))
-
- return cmds
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- return self.set_commands(w, have)
-
- def _v4_cmds(self, want, have, state=None):
- """Helper method for processing ipv4 changes.
- This is needed to handle primary/secondary address changes, which require a specific sequence when changing.
- """
- # The ip address cli does not allow removing primary addresses while
- # secondaries are present, but it does allow changing a primary to a
- # new address as long as the address is not a current secondary.
- # Be aware of scenarios where a secondary is taking over
- # the role of the primary, which must be changed in sequence.
- # In general, primaries/secondaries should change in this order:
- # Step 1. Remove secondaries that are being changed or removed
- # Step 2. Change the primary if needed
- # Step 3. Merge secondaries
-
- # Normalize inputs (add tag key if not present)
- for i in want:
- i['tag'] = i.get('tag')
- for i in have:
- i['tag'] = i.get('tag')
-
- merged = True if state == 'merged' else False
- replaced = True if state == 'replaced' else False
- overridden = True if state == 'overridden' else False
-
- # Create secondary and primary wants/haves
- sec_w = [i for i in want if i.get('secondary')]
- sec_h = [i for i in have if i.get('secondary')]
- pri_w = [i for i in want if not i.get('secondary')]
- pri_h = [i for i in have if not i.get('secondary')]
- pri_w = pri_w[0] if pri_w else {}
- pri_h = pri_h[0] if pri_h else {}
- cmds = []
-
- # Remove all addrs when no primary is specified in want (pri_w)
- if pri_h and not pri_w and (replaced or overridden):
- cmds.append('no ip address')
- return cmds
-
- # 1. Determine which secondaries are changing and remove them. Need a have/want
- # diff instead of want/have because a have sec addr may be changing to a pri.
- sec_to_rmv = []
- sec_diff = self.diff_list_of_dicts(sec_h, sec_w)
- for i in sec_diff:
- if overridden or [w for w in sec_w if w['address'] == i['address']]:
- sec_to_rmv.append(i['address'])
-
- # Check if new primary is currently a secondary
- if pri_w and [h for h in sec_h if h['address'] == pri_w['address']]:
- if not overridden:
- sec_to_rmv.append(pri_w['address'])
-
- # Remove the changing secondaries
- cmds.extend(['no ip address %s secondary' % i for i in sec_to_rmv])
-
- # 2. change primary
- if pri_w:
- diff = dict(set(pri_w.items()) - set(pri_h.items()))
- if diff:
- cmd = 'ip address %s' % diff['address']
- tag = diff.get('tag')
- cmd += ' tag %s' % tag if tag else ''
- cmds.append(cmd)
-
- # 3. process remaining secondaries last
- sec_w_to_chg = self.diff_list_of_dicts(sec_w, sec_h)
- for i in sec_w_to_chg:
- cmd = 'ip address %s secondary' % i['address']
- cmd += ' tag %s' % i['tag'] if i['tag'] else ''
- cmds.append(cmd)
-
- return cmds
-
- def _v6_cmds(self, want, have, state=''):
- """Helper method for processing ipv6 changes.
- This is needed to avoid unnecessary churn on the device when removing or changing multiple addresses.
- """
- # Normalize inputs (add tag key if not present)
- for i in want:
- i['tag'] = i.get('tag')
- for i in have:
- i['tag'] = i.get('tag')
-
- cmds = []
- # items to remove (items in 'have' only)
- if state == 'replaced':
- for i in self.diff_list_of_dicts(have, want):
- want_addr = [w for w in want if w['address'] == i['address']]
- if not want_addr:
- cmds.append('no ipv6 address %s' % i['address'])
- elif i['tag'] and not want_addr[0]['tag']:
- # Must remove entire cli when removing tag
- cmds.append('no ipv6 address %s' % i['address'])
-
- # items to merge/add
- for i in self.diff_list_of_dicts(want, have):
- addr = i['address']
- tag = i['tag']
- if not tag and state == 'merged':
- # When want is IP-no-tag and have is IP+tag it will show up in diff,
- # but for merged nothing has changed, so ignore it for idempotence.
- have_addr = [h for h in have if h['address'] == addr]
- if have_addr and have_addr[0].get('tag'):
- continue
- cmd = 'ipv6 address %s' % i['address']
- cmd += ' tag %s' % tag if tag else ''
- cmds.append(cmd)
-
- return cmds
-
- 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 w in want:
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- commands.extend(self.del_all_attribs(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_all_attribs(h))
- return commands
-
- def del_all_attribs(self, obj):
- commands = []
- if not obj or len(obj.keys()) == 1:
- return commands
- commands = self.generate_delete_commands(obj)
- self.cmd_order_fixup(commands, obj['name'])
- return commands
-
- def generate_delete_commands(self, obj):
- """Generate CLI commands to remove non-default settings.
- obj: dict of attrs to remove
- """
- commands = []
- name = obj.get('name')
- if 'dot1q' in obj:
- commands.append('no encapsulation dot1q')
- if 'redirects' in obj:
- if not self.check_existing(name, 'has_secondary') or re.match('N[3567]', self.platform):
- # device auto-enables redirects when secondaries are removed;
- # auto-enable may fail on legacy platforms so always do explicit enable
- commands.append('ip redirects')
- if 'unreachables' in obj:
- commands.append('no ip unreachables')
- if 'ipv4' in obj:
- commands.append('no ip address')
- if 'ipv6' in obj:
- commands.append('no ipv6 address')
- return commands
-
- def init_check_existing(self, have):
- """Creates a class var dict for easier access to existing states
- """
- self.existing_facts = dict()
- have_copy = deepcopy(have)
- for intf in have_copy:
- name = intf['name']
- self.existing_facts[name] = intf
- # Check for presence of secondaries; used for ip redirects logic
- if [i for i in intf.get('ipv4', []) if i.get('secondary')]:
- self.existing_facts[name]['has_secondary'] = True
-
- def check_existing(self, name, query):
- """Helper method to lookup existing states on an interface.
- This is needed for attribute changes that have additional dependencies;
- e.g. 'ip redirects' may auto-enable when all secondary ip addrs are removed.
- """
- if name:
- have = self.existing_facts.get(name, {})
- if 'has_secondary' in query:
- return have.get('has_secondary', False)
- if 'redirects' in query:
- return have.get('redirects', True)
- if 'unreachables' in query:
- return have.get('unreachables', False)
- return None
-
- def diff_of_dicts(self, w, obj):
- diff = set(w.items()) - set(obj.items())
- diff = dict(diff)
- if diff and w['name'] == obj['name']:
- diff.update({'name': w['name']})
- return diff
-
- def diff_list_of_dicts(self, w, h):
- diff = []
- set_w = set(tuple(sorted(d.items())) for d in w) if w else set()
- set_h = set(tuple(sorted(d.items())) for d in h) if h else set()
- difference = set_w.difference(set_h)
- for element in difference:
- diff.append(dict((x, y) for x, y in element))
- return diff
-
- def add_commands(self, diff, name=''):
- commands = []
- if not diff:
- return commands
- if 'dot1q' in diff:
- commands.append('encapsulation dot1q ' + str(diff['dot1q']))
- if 'redirects' in diff:
- # Note: device will auto-disable redirects when secondaries are present
- if diff['redirects'] != self.check_existing(name, 'redirects'):
- no_cmd = 'no ' if diff['redirects'] is False else ''
- commands.append(no_cmd + 'ip redirects')
- self.cmd_order_fixup(commands, name)
- if 'unreachables' in diff:
- if diff['unreachables'] != self.check_existing(name, 'unreachables'):
- no_cmd = 'no ' if diff['unreachables'] is False else ''
- commands.append(no_cmd + 'ip unreachables')
- if 'ipv4' in diff:
- commands.extend(self.generate_afi_commands(diff['ipv4']))
- if 'ipv6' in diff:
- commands.extend(self.generate_afi_commands(diff['ipv6']))
- self.cmd_order_fixup(commands, name)
-
- return commands
-
- def generate_afi_commands(self, diff):
- cmds = []
- for i in diff:
- cmd = 'ipv6 address ' if re.search('::', i['address']) else 'ip address '
- cmd += i['address']
- if i.get('secondary'):
- cmd += ' secondary'
- if i.get('tag'):
- cmd += ' tag ' + str(i['tag'])
- cmds.append(cmd)
- return cmds
-
- def set_commands(self, w, have):
- commands = []
- name = w['name']
- obj_in_have = search_obj_in_list(name, have, 'name')
- if not obj_in_have:
- commands = self.add_commands(w, name=name)
- else:
- # lists of dicts must be processed separately from non-list attrs
- v4_cmds = self._v4_cmds(w.pop('ipv4', []), obj_in_have.pop('ipv4', []), state='merged')
- v6_cmds = self._v6_cmds(w.pop('ipv6', []), obj_in_have.pop('ipv6', []), state='merged')
-
- # diff remaining attrs
- diff = self.diff_of_dicts(w, obj_in_have)
- commands = self.add_commands(diff, name=name)
- commands.extend(v4_cmds)
- commands.extend(v6_cmds)
-
- self.cmd_order_fixup(commands, name)
- return commands
-
- def cmd_order_fixup(self, cmds, name):
- """Inserts 'interface <name>' config at the beginning of populated command list; reorders dependent commands that must process after others.
- """
- if cmds:
- if name and not [item for item in cmds if item.startswith('interface')]:
- cmds.insert(0, 'interface ' + name)
-
- redirects = [item for item in cmds if re.match('(no )*ip redirects', item)]
- if redirects:
- # redirects should occur after ipv4 commands, just move to end of list
- redirects = redirects.pop()
- cmds.remove(redirects)
- cmds.append(redirects)
diff --git a/lib/ansible/module_utils/network/nxos/config/lacp/lacp.py b/lib/ansible/module_utils/network/nxos/config/lacp/lacp.py
deleted file mode 100644
index ebed250184..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/lacp/lacp.py
+++ /dev/null
@@ -1,203 +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 nxos_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 dict_diff, to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-
-
-class Lacp(ConfigBase):
- """
- The nxos_lacp class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lacp',
- ]
-
- exclude_params = [
- 'priority',
- 'mac',
- ]
-
- 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 = remove_empties(self._module.params['config'])
- have = existing_lacp_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- commands = list()
-
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- elif state == 'merged':
- commands.extend(self._state_merged(want, have))
- elif state == 'replaced':
- commands.extend(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 = []
- diff = dict_diff(want, have)
- wkeys = want.keys()
- dkeys = diff.keys()
- for k in wkeys:
- if k in self.exclude_params and k in dkeys:
- del diff[k]
- deleted_commands = self.del_all(diff)
- merged_commands = self._state_merged(want, have)
-
- commands.extend(deleted_commands)
- if merged_commands:
- commands.extend(merged_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
- """
- return self.set_commands(want, have)
-
- 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 have:
- return commands
- commands.extend(self.del_all(have))
- return commands
-
- def get_diff(self, comparable, base):
- diff = {}
- if not base:
- diff = comparable
- else:
- diff = dict_diff(base, comparable)
- return diff
-
- def del_all(self, diff):
- commands = []
- base = 'no lacp system-'
- diff = diff.get('system')
- if diff:
- if 'priority' in diff:
- commands.append(base + 'priority')
- if 'mac' in diff:
- commands.append(base + 'mac')
- return commands
-
- def add_commands(self, diff):
- commands = []
- base = 'lacp system-'
- diff = diff.get('system')
- if diff and 'priority' in diff:
- cmd = base + 'priority' + ' ' + str(diff['priority'])
- commands.append(cmd)
- if diff and 'mac' in diff:
- cmd = ''
- if 'address' in diff['mac']:
- cmd += base + 'mac' + ' ' + diff['mac']['address']
- if 'role' in diff['mac']:
- cmd += ' ' + 'role' + ' ' + diff['mac']['role']
- if cmd:
- commands.append(cmd)
-
- return commands
-
- def set_commands(self, want, have):
- if not want:
- return []
- diff = self.get_diff(want, have)
- return self.add_commands(diff)
diff --git a/lib/ansible/module_utils/network/nxos/config/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/nxos/config/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 891d2466c8..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,284 +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 nxos_lacp_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, dict_diff, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list, get_interface_type, normalize_interface
-
-
-class Lacp_interfaces(ConfigBase):
- """
- The nxos_lacp_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lacp_interfaces',
- ]
-
- exclude_params = [
- 'port_priority',
- 'rate',
- 'min',
- 'max',
- ]
-
- 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
- """
- config = self._module.params.get('config')
- want = []
- if config:
- for w in config:
- if get_interface_type(w['name']) not in ('portchannel', 'ethernet'):
- self._module.fail_json(msg='This module works with either portchannel or ethernet')
- w.update({'name': normalize_interface(w['name'])})
- want.append(remove_empties(w))
- have = existing_lacp_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
- commands = list()
-
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(flatten_dict(w), have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(flatten_dict(w), have))
- return commands
-
- def _state_replaced(self, w, 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 = []
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- diff = dict_diff(w, obj_in_have)
- merged_commands = self.set_commands(w, have)
- if 'name' not in diff:
- diff['name'] = w['name']
- wkeys = w.keys()
- dkeys = diff.keys()
- for k in wkeys:
- if k in self.exclude_params and k in dkeys:
- del diff[k]
- replaced_commands = self.del_attribs(diff)
-
- if merged_commands:
- cmds = set(replaced_commands).intersection(set(merged_commands))
- for cmd in cmds:
- merged_commands.remove(cmd)
- 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 h in have:
- h = flatten_dict(h)
- obj_in_want = flatten_dict(search_obj_in_list(h['name'], want, 'name'))
- if h == obj_in_want:
- continue
- for w in want:
- w = flatten_dict(w)
- if h['name'] == w['name']:
- wkeys = w.keys()
- hkeys = h.keys()
- for k in wkeys:
- if k in self.exclude_params and k in hkeys:
- del h[k]
- commands.extend(self.del_attribs(h))
- for w in want:
- commands.extend(self.set_commands(flatten_dict(w), have))
- return commands
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- return self.set_commands(w, have)
-
- 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 w in want:
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- commands.extend(self.del_attribs(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_attribs(flatten_dict(h)))
- return commands
-
- def del_attribs(self, obj):
- commands = []
- if not obj or len(obj.keys()) == 1:
- return commands
- commands.append('interface ' + obj['name'])
- if 'graceful' in obj:
- commands.append('lacp graceful-convergence')
- if 'vpc' in obj:
- commands.append('no lacp vpn-convergence')
- if 'suspend_individual' in obj:
- commands.append('lacp suspend_individual')
- if 'mode' in obj:
- commands.append('no lacp mode ' + obj['mode'])
- if 'max' in obj:
- commands.append('no lacp max-bundle')
- if 'min' in obj:
- commands.append('no lacp min-links')
- if 'port_priority' in obj:
- commands.append('no lacp port-priority')
- if 'rate' in obj:
- commands.append('no lacp rate')
- return commands
-
- def diff_of_dicts(self, w, obj):
- diff = set(w.items()) - set(obj.items())
- diff = dict(diff)
- if diff and w['name'] == obj['name']:
- diff.update({'name': w['name']})
- return diff
-
- def add_commands(self, d):
- commands = []
- if not d:
- return commands
- commands.append('interface' + ' ' + d['name'])
-
- if 'port_priority' in d:
- commands.append('lacp port-priority ' + str(d['port_priority']))
- if 'rate' in d:
- commands.append('lacp rate ' + str(d['rate']))
- if 'min' in d:
- commands.append('lacp min-links ' + str(d['min']))
- if 'max' in d:
- commands.append('lacp max-bundle ' + str(d['max']))
- if 'mode' in d:
- commands.append('lacp mode ' + d['mode'])
- if 'suspend_individual' in d:
- if d['suspend_individual'] is True:
- commands.append('lacp suspend-individual')
- else:
- commands.append('no lacp suspend-individual')
- if 'graceful' in d:
- if d['graceful'] is True:
- commands.append('lacp graceful-convergence')
- else:
- commands.append('no lacp graceful-convergence')
- if 'vpc' in d:
- if d['vpc'] is True:
- commands.append('lacp vpc-convergence')
- else:
- commands.append('no lacp vpc-convergence')
- return commands
-
- def set_commands(self, w, have):
- commands = []
- obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name'))
- if not obj_in_have:
- commands = self.add_commands(w)
- else:
- diff = self.diff_of_dicts(w, obj_in_have)
- commands = self.add_commands(diff)
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/nxos/config/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index ed000f5467..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,273 +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 junos_lag_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list, remove_empties, dict_diff, search_obj_in_list
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import normalize_interface
-
-
-class Lag_interfaces(ConfigBase):
- """
- The nxos_lag_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lag_interfaces',
- ]
-
- def __init__(self, module):
- super(Lag_interfaces, self).__init__(module)
-
- def get_lag_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lag_interfaces_facts = facts['ansible_network_resources'].get('lag_interfaces')
- if not lag_interfaces_facts:
- return []
- return lag_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
- commands.extend(self.set_config(existing_lag_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- resp = self._connection.edit_config(commands)
- if 'response' in resp:
- for item in resp['response']:
- if item:
- err_str = item
- if err_str.lower().startswith('cannot add'):
- self._module.fail_json(msg=err_str)
- 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.get('config')
- if want:
- for w in want:
- w.update(remove_empties(w))
- if 'members' in w and w['members']:
- for item in w['members']:
- item.update({'member': normalize_interface(item['member'])})
- 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 = list()
-
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- if state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- return commands
-
- def _state_replaced(self, w, 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 = []
- merged_commands = self.set_commands(w, have)
- replaced_commands = self.del_intf_commands(w, have)
- if merged_commands:
- 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 h in have:
- obj_in_want = search_obj_in_list(h['name'], want, 'name')
- if obj_in_want:
- diff = self.diff_list_of_dicts(h['members'], obj_in_want['members'])
- if not diff:
- continue
- commands.extend(self.del_all_commands(h))
- for w in want:
- commands.extend(self.set_commands(w, have))
- return commands
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- return self.set_commands(w, have)
-
- 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 w in want:
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- commands.extend(self.del_all_commands(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_all_commands(h))
- return commands
-
- def diff_list_of_dicts(self, want, have):
- if not want:
- want = []
-
- if not have:
- have = []
-
- diff = []
- for w_item in want:
- h_item = search_obj_in_list(w_item['member'], have, key='member') or {}
- delta = dict_diff(h_item, w_item)
- if delta:
- if h_item:
- if 'mode' in delta.keys() and delta['mode'] == 'on' and 'mode' not in h_item.keys():
- # mode = on will not be displayed in running-config
- continue
- if 'member' not in delta.keys():
- delta['member'] = w_item['member']
- diff.append(delta)
-
- return diff
-
- def intersect_list_of_dicts(self, w, h):
- intersect = []
- wmem = []
- hmem = []
- for d in w:
- wmem.append({'member': d['member']})
- for d in h:
- hmem.append({'member': d['member']})
- set_w = set(tuple(sorted(d.items())) for d in wmem)
- set_h = set(tuple(sorted(d.items())) for d in hmem)
- intersection = set_w.intersection(set_h)
- for element in intersection:
- intersect.append(dict((x, y) for x, y in element))
- return intersect
-
- def add_commands(self, diff, name):
- commands = []
- name = name.strip('port-channel')
- for d in diff:
- commands.append('interface' + ' ' + d['member'])
- cmd = ''
- group_cmd = 'channel-group {0}'.format(name)
- if 'force' in d:
- cmd = group_cmd + ' force ' + d['force']
- if 'mode' in d:
- if cmd:
- cmd = cmd + ' mode ' + d['mode']
- else:
- cmd = group_cmd + ' mode ' + d['mode']
- if not cmd:
- cmd = group_cmd
- commands.append(cmd)
- return commands
-
- def set_commands(self, w, have):
- commands = []
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- if not obj_in_have:
- commands = self.add_commands(w['members'], w['name'])
- else:
- diff = self.diff_list_of_dicts(w['members'], obj_in_have['members'])
- commands = self.add_commands(diff, w['name'])
- return commands
-
- def del_all_commands(self, obj_in_have):
- commands = []
- if not obj_in_have:
- return commands
- for m in obj_in_have['members']:
- commands.append('interface' + ' ' + m['member'])
- commands.append('no channel-group')
- return commands
-
- def del_intf_commands(self, w, have):
- commands = []
- obj_in_have = search_obj_in_list(w['name'], have, 'name')
- if obj_in_have:
- lst_to_del = self.intersect_list_of_dicts(w['members'], obj_in_have['members'])
- if lst_to_del:
- for item in lst_to_del:
- commands.append('interface' + ' ' + item['member'])
- commands.append('no channel-group')
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/nxos/config/lldp_global/lldp_global.py
deleted file mode 100644
index 75f0d753ff..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,240 +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 nxos_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 remove_empties, dict_diff
-from ansible.module_utils.network.nxos.facts.facts import Facts
-
-
-class Lldp_global(ConfigBase):
- """
- The nxos_lldp_global class
- """
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lldp_global',
- ]
-
- def __init__(self, module):
- super(Lldp_global, self).__init__(module)
-
- def get_lldp_global_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(
- self.gather_subset, self.gather_network_resources)
- lldp_global_facts = facts['ansible_network_resources'].get(
- 'lldp_global')
- if not lldp_global_facts:
- return {}
- return lldp_global_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lldp_global_facts = self.get_lldp_global_facts()
- commands.extend(self.set_config(existing_lldp_global_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lldp_global_facts = self.get_lldp_global_facts()
-
- result['before'] = dict(existing_lldp_global_facts)
- if result['changed']:
- result['after'] = dict(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']
- have = existing_lldp_global_facts
- resp = self.set_state(remove_empties(want), have)
- return resp
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state == 'deleted':
- commands = self._state_deleted(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 = []
- merge_dict = dict_diff(have, want)
- # merge_dict will contain new and unique values in want
- delete_dict = self.find_delete_params(have, want)
- self._module.params['state'] = 'deleted'
- commands.extend(self._state_deleted(delete_dict)) # delete
- self._module.params['state'] = 'merged'
- commands.extend(self.set_commands(merge_dict)) # merge
- self._module.params['state'] = 'replaced'
- return commands
-
- def delete_nested_dict(self, have, want):
- """
- Returns tlv_select nested dict that needs to be defaulted
- """
- outer_dict = {}
- for key, val in have.items():
- inner_dict = {}
- if not isinstance(val, dict):
- if key not in want.keys():
- inner_dict.update({key: val})
- return inner_dict
- else:
- if key in want.keys():
- outer_dict.update(
- {key: self.delete_nested_dict(val, want[key])})
- else:
- outer_dict.update({key: val})
- return outer_dict
-
- def find_delete_params(self, have, want):
- """
- Returns parameters that are present in have and not in want, that need to be defaulted
- """
- delete_dict = {}
- for key, val in have.items():
- if key not in want.keys():
- delete_dict.update({key: val})
- else:
- if key == 'tlv_select':
- delete_dict.update({key: self.delete_nested_dict(
- have['tlv_select'], want['tlv_select'])})
- return delete_dict
-
- 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 = []
- diff = dict_diff(have, want)
- commands.extend(self.set_commands(diff))
- return commands
-
- def _state_deleted(self, 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 have:
- for key, val in have.items():
- if 'tlv_select' in key:
- commands.extend(self.process_nested_dict(val))
- else:
- if key == 'port_id':
- key = 'portid-subtype'
- commands.append('no lldp ' + key + ' ' + str(val))
-
- return commands
-
- def set_commands(self, diff):
- commands = []
- for key, val in diff.items():
- commands.extend(self.add_commands(key, val))
- return commands
-
- def add_commands(self, key, val):
- command = []
- if 'port_id' in key:
- command.append('lldp portid-subtype ' + str(val))
- elif 'tlv_select' in key:
- command.extend(self.process_nested_dict(val))
- else:
- if val:
- command.append('lldp ' + key + ' ' + str(val))
- return command
-
- def process_nested_dict(self, val):
- nested_commands = []
- for k, v in val.items():
- if isinstance(v, dict):
- for k1, v1 in v.items():
- com1 = 'lldp tlv-select '
- com2 = ''
- if 'system' in k:
- com2 = 'system-' + k1
- elif 'management_address' in k:
- com2 = 'management-address ' + k1
- elif 'port' in k:
- com2 = 'port-' + k1
-
- com1 += com2
- com1 = self.negate_command(com1, v1)
- nested_commands.append(com1)
- else:
- com1 = 'lldp tlv-select '
- if 'power_management' in k:
- com1 += 'power-management'
- else:
- com1 += k
-
- com1 = self.negate_command(com1, v)
- nested_commands.append(com1)
- return nested_commands
-
- def negate_command(self, command, val):
- # for merged, replaced vals need to be checked to add 'no'
- if self._module.params['state'] == 'merged':
- if not val:
- command = 'no ' + command
- return command
diff --git a/lib/ansible/module_utils/network/nxos/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/nxos/config/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 37e29ae5c6..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,304 +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 nxos_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, remove_empties, dict_diff
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import flatten_dict, search_obj_in_list, get_interface_type, normalize_interface
-
-
-class Lldp_interfaces(ConfigBase):
- """
- The nxos_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, 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)
- lldp_interfaces_facts = facts['ansible_network_resources'].get(
- 'lldp_interfaces')
- if not lldp_interfaces_facts:
- return []
- return lldp_interfaces_facts
-
- def edit_config(self, commands):
- """Wrapper method for `_connection.edit_config()`
- This exists solely to allow the unit test framework to mock device connection calls.
- """
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
- state = self._module.params['state']
- action_states = ['merged', 'replaced', 'deleted', 'overridden']
-
- if state == 'gathered':
- result['gathered'] = self.get_lldp_interfaces_facts()
- elif state == 'rendered':
- result['rendered'] = self.set_config({})
- elif state == 'parsed':
- result['parsed'] = self.set_config({})
- else:
- existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
- commands.extend(self.set_config(existing_lldp_interfaces_facts))
- if commands and state in action_states:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['before'] = existing_lldp_interfaces_facts
- result['commands'] = commands
- result['commands'] = commands
-
- changed_lldp_interfaces_facts = self.get_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
- """
- config = self._module.params['config']
- want = []
- if config:
- for w in config:
- if get_interface_type(w['name']) not in ('management',
- 'ethernet'):
- self._module.fail_json(
- msg='This module works with either management or ethernet')
- w.update({'name': normalize_interface(w['name'])})
- want.append(remove_empties(w))
- 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
- """
- commands = []
- state = self._module.params['state']
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'rendered':
- commands = self._state_rendered(want)
- elif state == 'parsed':
- want = self._module.params['running_config']
- commands = self._state_parsed(want)
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(flatten_dict(w), have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(
- flatten_dict(w), have))
- return commands
-
- def _state_parsed(self, want):
- return self.get_lldp_interfaces_facts(want)
-
- def _state_rendered(self, want):
- commands = []
- for w in want:
- commands.extend(self.set_commands(w, {}))
- return commands
-
- def _state_gathered(self, have):
- """ The command generator when state is gathered
-
- :rtype: A list
- :returns: the commands necessary to reproduce the current configuration
- """
- commands = []
- want = {}
- commands.append(self.set_commands(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 = []
- del_commands = []
- delete_dict = {}
- obj_in_have = flatten_dict(
- search_obj_in_list(want['name'], have, 'name'))
- for k1 in obj_in_have.keys():
- if k1 not in want.keys():
- delete_dict.update({k1: obj_in_have[k1]})
-
- if delete_dict:
- delete_dict.update({'name': want['name']})
- del_commands = self.del_commands(delete_dict)
- merged_commands = self.set_commands(want, have)
-
- if merged_commands:
- cmds = set(del_commands).intersection(set(merged_commands))
- for cmd in cmds:
- merged_commands.remove(cmd)
-
- commands.extend(del_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 = []
- want_intfs = [w['name'] for w in want]
- for h in have:
- h = flatten_dict(h)
- delete_dict = {}
- if h['name'] in want_intfs:
- for w in want:
- if w['name'] == h['name']:
- delete_keys = list(set(h) - set(flatten_dict(w)))
- for k in delete_keys:
- delete_dict.update({k: h[k]})
- delete_dict.update({'name': h['name']})
- break
- else:
- delete_dict.update(h)
- commands.extend(self.del_commands(delete_dict))
- for w in want:
- commands.extend(self.set_commands(flatten_dict(w), 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
- """
- return self.set_commands(want, have)
-
- 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 w in want:
- obj_in_have = flatten_dict(
- search_obj_in_list(w['name'], have, 'name'))
- commands.extend(self.del_commands(obj_in_have))
- else:
- if not have:
- return commands
- for h in have:
- commands.extend(self.del_commands(flatten_dict(h)))
- return commands
-
- def set_commands(self, want, have):
- commands = []
- obj_in_have = flatten_dict(
- search_obj_in_list(want['name'], have, 'name'))
- if not obj_in_have:
- commands = self.add_commands(flatten_dict(want))
- else:
- diff = dict_diff(obj_in_have, want)
- if diff:
- diff.update({'name': want['name']})
- commands = self.add_commands(diff)
- return commands
-
- def add_commands(self, d):
- commands = []
- if not d:
- return commands
- commands.append('interface ' + d['name'])
- if 'transmit' in d:
- if (d['transmit']):
- commands.append('lldp transmit')
- else:
- commands.append('no lldp transmit')
- if 'receive' in d:
- if (d['receive']):
- commands.append('lldp receive')
- else:
- commands.append('no lldp receive')
- if 'management_address' in d:
- commands.append('lldp tlv-set management-address ' +
- d['management_address'])
- if 'vlan' in d:
- commands.append('lldp tlv-set vlan ' + str(d['vlan']))
-
- return commands
-
- def del_commands(self, obj):
- commands = []
- if not obj or len(obj.keys()) == 1:
- return commands
- commands.append('interface ' + obj['name'])
- if 'transmit' in obj:
- commands.append('lldp transmit')
- if 'receive' in obj:
- commands.append('lldp receive')
- if 'management_address' in obj:
- commands.append('no lldp tlv-set management-address ' +
- obj['management_address'])
- if 'vlan' in obj:
- commands.append('no lldp tlv-set vlan ' + str(obj['vlan']))
-
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/telemetry/telemetry.py b/lib/ansible/module_utils/network/nxos/config/telemetry/telemetry.py
deleted file mode 100644
index dac91b232c..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/telemetry/telemetry.py
+++ /dev/null
@@ -1,503 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos_telemetry 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.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.cmdref.telemetry.telemetry import TMS_GLOBAL, TMS_DESTGROUP, TMS_SENSORGROUP, TMS_SUBSCRIPTION
-from ansible.module_utils.network.nxos.utils.telemetry.telemetry import normalize_data, remove_duplicate_context
-from ansible.module_utils.network.nxos.utils.telemetry.telemetry import valiate_input, get_setval_path, massage_data
-from ansible.module_utils.network.nxos.utils.telemetry.telemetry import get_module_params_subsection, remove_duplicate_commands
-from ansible.module_utils.network.nxos.utils.utils import normalize_interface
-from ansible.module_utils.network.nxos.nxos import NxosCmdRef
-
-
-class Telemetry(ConfigBase):
- """
- The nxos_telemetry class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'telemetry',
- ]
-
- def __init__(self, module):
- super(Telemetry, self).__init__(module)
-
- def get_telemetry_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)
- telemetry_facts = facts['ansible_network_resources'].get('telemetry')
- if not telemetry_facts:
- return {}
- return telemetry_facts
-
- def edit_config(self, commands):
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- state = self._module.params['state']
- if 'overridden' in state:
- self._module.fail_json(msg='State <overridden> is invalid for this module.')
- # When state is 'deleted', the module_params should not contain data
- # under the 'config' key
- if 'deleted' in state and self._module.params.get('config'):
- self._module.fail_json(msg='Remove config key from playbook when state is <deleted>')
-
- if self._module.params['config'] is None:
- self._module.params['config'] = {}
- # Normalize interface name.
- int = self._module.params['config'].get('source_interface')
- if int:
- self._module.params['config']['source_interface'] = normalize_interface(int)
-
- existing_telemetry_facts = self.get_telemetry_facts()
- commands.extend(self.set_config(existing_telemetry_facts))
- if commands:
- if not self._module.check_mode:
- self.edit_config(commands)
- # TODO: edit_config is only available for network_cli. Once we
- # add support for httpapi, we will need to switch to load_config
- # or add support to httpapi for edit_config
- #
- # self._connection.load_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_telemetry_facts = self.get_telemetry_facts()
-
- result['before'] = existing_telemetry_facts
- if result['changed']:
- result['after'] = changed_telemetry_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_tms_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
- """
- config = self._module.params['config']
- want = dict((k, v) for k, v in config.items() if v is not None)
- have = existing_tms_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']
-
- # The deleted case is very simple since we purge all telemetry config
- # and does not require any processing using NxosCmdRef objects.
- if state == 'deleted':
- return self._state_deleted(want, have)
- elif state == 'replaced':
- if want == have:
- return []
- return self._state_replaced(want, have)
-
- # Save off module params
- ALL_MP = self._module.params['config']
-
- cmd_ref = {}
- cmd_ref['TMS_GLOBAL'] = {}
- cmd_ref['TMS_DESTGROUP'] = {}
- cmd_ref['TMS_SENSORGROUP'] = {}
- cmd_ref['TMS_SUBSCRIPTION'] = {}
-
- # Build Telemetry Global NxosCmdRef Object
- cmd_ref['TMS_GLOBAL']['ref'] = []
- self._module.params['config'] = get_module_params_subsection(ALL_MP, 'TMS_GLOBAL')
- cmd_ref['TMS_GLOBAL']['ref'].append(NxosCmdRef(self._module, TMS_GLOBAL))
- ref = cmd_ref['TMS_GLOBAL']['ref'][0]
- ref.set_context()
- ref.get_existing()
- ref.get_playvals()
- device_cache = ref.cache_existing
-
- def build_cmdref_objects(td):
- cmd_ref[td['type']]['ref'] = []
- saved_ids = []
- if want.get(td['name']):
- for playvals in want[td['name']]:
- valiate_input(playvals, td['name'], self._module)
- if playvals['id'] in saved_ids:
- continue
- saved_ids.append(playvals['id'])
- resource_key = td['cmd'].format(playvals['id'])
- # Only build the NxosCmdRef object for the td['name'] module parameters.
- self._module.params['config'] = get_module_params_subsection(ALL_MP, td['type'], playvals['id'])
- cmd_ref[td['type']]['ref'].append(NxosCmdRef(self._module, td['obj']))
- ref = cmd_ref[td['type']]['ref'][-1]
- ref.set_context([resource_key])
- if td['type'] == 'TMS_SENSORGROUP' and get_setval_path(self._module):
- # Sensor group path setting can contain optional values.
- # Call get_setval_path helper function to process any
- # optional setval keys.
- ref._ref['path']['setval'] = get_setval_path(self._module)
- ref.get_existing(device_cache)
- ref.get_playvals()
- if td['type'] == 'TMS_DESTGROUP':
- normalize_data(ref)
-
- # Build Telemetry Destination Group NxosCmdRef Objects
- td = {'name': 'destination_groups', 'type': 'TMS_DESTGROUP',
- 'obj': TMS_DESTGROUP, 'cmd': 'destination-group {0}'}
- build_cmdref_objects(td)
-
- # Build Telemetry Sensor Group NxosCmdRef Objects
- td = {'name': 'sensor_groups', 'type': 'TMS_SENSORGROUP',
- 'obj': TMS_SENSORGROUP, 'cmd': 'sensor-group {0}'}
- build_cmdref_objects(td)
-
- # Build Telemetry Subscription NxosCmdRef Objects
- td = {'name': 'subscriptions', 'type': 'TMS_SUBSCRIPTION',
- 'obj': TMS_SUBSCRIPTION, 'cmd': 'subscription {0}'}
- build_cmdref_objects(td)
-
- if state == 'merged':
- if want == have:
- return []
- commands = self._state_merged(cmd_ref)
- 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 = []
- massaged_have = massage_data(have)
- massaged_want = massage_data(want)
-
- ref = {}
- ref['tms_global'] = NxosCmdRef([], TMS_GLOBAL, ref_only=True)
- ref['tms_destgroup'] = NxosCmdRef([], TMS_DESTGROUP, ref_only=True)
- ref['tms_sensorgroup'] = NxosCmdRef([], TMS_SENSORGROUP, ref_only=True)
- ref['tms_subscription'] = NxosCmdRef([], TMS_SUBSCRIPTION, ref_only=True)
-
- # Order matters for state replaced.
- # First remove all subscriptions, followed by sensor-groups and destination-groups.
- # Second add all destination-groups, followed by sensor-groups and subscriptions
- add = {'TMS_GLOBAL': [], 'TMS_DESTGROUP': [], 'TMS_SENSORGROUP': [], 'TMS_SUBSCRIPTION': []}
- delete = {'TMS_DESTGROUP': [], 'TMS_SENSORGROUP': [], 'TMS_SUBSCRIPTION': []}
-
- # Process Telemetry Global Want and Have Values
- # Possible states:
- # - want and have are (set) (equal: no action, not equal: replace with want)
- # - want (set) have (not set) (add want)
- # - want (not set) have (set) (delete have)
- # - want (not set) have (not set) (no action)
- # global_ctx = ref['tms_global']._ref['_template']['context']
- # property_ctx = ref['tms_global']._ref['certificate'].get('context')
- # setval = ref['tms_global']._ref['certificate']['setval']
- #
- all_global_properties = ['certificate', 'compression', 'source_interface', 'vrf']
- dest_profile_properties = ['compression', 'source_interface', 'vrf']
- dest_profile_remote_commands = []
- for property in all_global_properties:
- cmd = None
- global_ctx = ref['tms_global']._ref['_template']['context']
- property_ctx = ref['tms_global']._ref[property].get('context')
- setval = ref['tms_global']._ref[property]['setval']
- kind = ref['tms_global']._ref[property]['kind']
- if want.get(property) is not None:
- if have.get(property) is not None:
- if want.get(property) != have.get(property):
- if kind == 'dict':
- cmd = [setval.format(**want.get(property))]
- else:
- cmd = [setval.format(want.get(property))]
- elif have.get(property) is None:
- if kind == 'dict':
- cmd = [setval.format(**want.get(property))]
- else:
- cmd = [setval.format(want.get(property))]
- elif want.get(property) is None:
- if have.get(property) is not None:
- if kind == 'dict':
- cmd = ['no ' + setval.format(**have.get(property))]
- else:
- cmd = ['no ' + setval.format(have.get(property))]
- if property in dest_profile_properties:
- dest_profile_remote_commands.extend(cmd)
-
- if cmd is not None:
- ctx = global_ctx
- if property_ctx is not None:
- ctx.extend(property_ctx)
- add['TMS_GLOBAL'].extend(ctx)
- add['TMS_GLOBAL'].extend(cmd)
-
- add['TMS_GLOBAL'] = remove_duplicate_commands(add['TMS_GLOBAL'])
- # If all destination profile commands are being removed then just
- # remove the config context instead.
- if len(dest_profile_remote_commands) == 3:
- for item in dest_profile_remote_commands:
- add['TMS_GLOBAL'].remove(item)
- add['TMS_GLOBAL'].remove('destination-profile')
- add['TMS_GLOBAL'].extend(['no destination-profile'])
-
- # Process Telemetry destination_group, sensor_group and subscription Want and Have Values
- # Possible states:
- # - want (not set) have (set) (delete have)
- # - want and have are (set) (equal: no action, not equal: replace with want)
- # - want (set) have (not set) (add want)
- # - want (not set) have (not set) (no action)
- tms_resources = ['TMS_DESTGROUP', 'TMS_SENSORGROUP', 'TMS_SUBSCRIPTION']
- for resource in tms_resources:
- if resource == 'TMS_DESTGROUP':
- name = 'destination-group'
- cmd_property = 'destination'
- global_ctx = ref['tms_destgroup']._ref['_template']['context']
- setval = ref['tms_destgroup']._ref['destination']['setval']
- want_resources = massaged_want.get('destination_groups')
- have_resources = massaged_have.get('destination_groups')
- if resource == 'TMS_SENSORGROUP':
- name = 'sensor-group'
- global_ctx = ref['tms_sensorgroup']._ref['_template']['context']
- setval = {}
- setval['data_source'] = ref['tms_sensorgroup']._ref['data_source']['setval']
- setval['path'] = ref['tms_sensorgroup']._ref['path']['setval']
- want_resources = massaged_want.get('sensor_groups')
- have_resources = massaged_have.get('sensor_groups')
- if resource == 'TMS_SUBSCRIPTION':
- name = 'subscription'
- global_ctx = ref['tms_subscription']._ref['_template']['context']
- setval = {}
- setval['destination_group'] = ref['tms_subscription']._ref['destination_group']['setval']
- setval['sensor_group'] = ref['tms_subscription']._ref['sensor_group']['setval']
- want_resources = massaged_want.get('subscriptions')
- have_resources = massaged_have.get('subscriptions')
-
- if not want_resources and have_resources:
- # want not and have not set so delete have
- for key in have_resources.keys():
- remove_context = ['{0} {1} {2}'.format('no', name, key)]
- delete[resource].extend(global_ctx)
- if remove_context[0] not in delete[resource]:
- delete[resource].extend(remove_context)
- else:
- # want and have are set.
- # process wants:
- for want_key in want_resources.keys():
- if want_key not in have_resources.keys():
- # Want resource key not in have resource key so add it
- property_ctx = ['{0} {1}'.format(name, want_key)]
- for item in want_resources[want_key]:
- if resource == 'TMS_DESTGROUP':
- cmd = [setval.format(**item[cmd_property])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- add[resource].extend(cmd)
- if resource == 'TMS_SENSORGROUP':
- cmd = {}
- if item.get('data_source'):
- cmd['data_source'] = [setval['data_source'].format(item['data_source'])]
- if item.get('path'):
- setval['path'] = get_setval_path(item.get('path'))
- cmd['path'] = [setval['path'].format(**item['path'])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- if cmd.get('data_source'):
- add[resource].extend(cmd['data_source'])
- if cmd.get('path'):
- add[resource].extend(cmd['path'])
- if resource == 'TMS_SUBSCRIPTION':
- cmd = {}
- if item.get('destination_group'):
- cmd['destination_group'] = [setval['destination_group'].format(item['destination_group'])]
- if item.get('sensor_group'):
- cmd['sensor_group'] = [setval['sensor_group'].format(**item['sensor_group'])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- if cmd.get('destination_group'):
- add[resource].extend(cmd['destination_group'])
- if cmd.get('sensor_group'):
- add[resource].extend(cmd['sensor_group'])
-
- elif want_key in have_resources.keys():
- # Want resource key exists in have resource keys but we need to
- # inspect the individual items under the resource key
- # for differences
- for item in want_resources[want_key]:
- if item not in have_resources[want_key]:
- if item is None:
- continue
- # item wanted but does not exist so add it
- property_ctx = ['{0} {1}'.format(name, want_key)]
- if resource == 'TMS_DESTGROUP':
- cmd = [setval.format(**item[cmd_property])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- add[resource].extend(cmd)
- if resource == 'TMS_SENSORGROUP':
- cmd = {}
- if item.get('data_source'):
- cmd['data_source'] = [setval['data_source'].format(item['data_source'])]
- if item.get('path'):
- setval['path'] = get_setval_path(item.get('path'))
- cmd['path'] = [setval['path'].format(**item['path'])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- if cmd.get('data_source'):
- add[resource].extend(cmd['data_source'])
- if cmd.get('path'):
- add[resource].extend(cmd['path'])
- if resource == 'TMS_SUBSCRIPTION':
- cmd = {}
- if item.get('destination_group'):
- cmd['destination_group'] = [setval['destination_group'].format(item['destination_group'])]
- if item.get('sensor_group'):
- cmd['sensor_group'] = [setval['sensor_group'].format(**item['sensor_group'])]
- add[resource].extend(global_ctx)
- if property_ctx[0] not in add[resource]:
- add[resource].extend(property_ctx)
- if cmd.get('destination_group'):
- add[resource].extend(cmd['destination_group'])
- if cmd.get('sensor_group'):
- add[resource].extend(cmd['sensor_group'])
-
- # process haves:
- for have_key in have_resources.keys():
- if have_key not in want_resources.keys():
- # Want resource key is not in have resource keys so remove it
- cmd = ['no ' + '{0} {1}'.format(name, have_key)]
- delete[resource].extend(global_ctx)
- delete[resource].extend(cmd)
- elif have_key in want_resources.keys():
- # Have resource key exists in want resource keys but we need to
- # inspect the individual items under the resource key
- # for differences
- for item in have_resources[have_key]:
- if item not in want_resources[have_key]:
- if item is None:
- continue
- # have item not wanted so remove it
- property_ctx = ['{0} {1}'.format(name, have_key)]
- if resource == 'TMS_DESTGROUP':
- cmd = ['no ' + setval.format(**item[cmd_property])]
- delete[resource].extend(global_ctx)
- if property_ctx[0] not in delete[resource]:
- delete[resource].extend(property_ctx)
- delete[resource].extend(cmd)
- if resource == 'TMS_SENSORGROUP':
- cmd = {}
- if item.get('data_source'):
- cmd['data_source'] = ['no ' + setval['data_source'].format(item['data_source'])]
- if item.get('path'):
- setval['path'] = get_setval_path(item.get('path'))
- cmd['path'] = ['no ' + setval['path'].format(**item['path'])]
- delete[resource].extend(global_ctx)
- if property_ctx[0] not in delete[resource]:
- delete[resource].extend(property_ctx)
- if cmd.get('data_source'):
- delete[resource].extend(cmd['data_source'])
- if cmd.get('path'):
- delete[resource].extend(cmd['path'])
- if resource == 'TMS_SUBSCRIPTION':
- cmd = {}
- if item.get('destination_group'):
- cmd['destination_group'] = ['no ' + setval['destination_group'].format(item['destination_group'])]
- if item.get('sensor_group'):
- cmd['sensor_group'] = ['no ' + setval['sensor_group'].format(**item['sensor_group'])]
- delete[resource].extend(global_ctx)
- if property_ctx[0] not in delete[resource]:
- delete[resource].extend(property_ctx)
- if cmd.get('destination_group'):
- delete[resource].extend(cmd['destination_group'])
- if cmd.get('sensor_group'):
- delete[resource].extend(cmd['sensor_group'])
-
- add[resource] = remove_duplicate_context(add[resource])
- delete[resource] = remove_duplicate_context(delete[resource])
-
- commands.extend(delete['TMS_SUBSCRIPTION'])
- commands.extend(delete['TMS_SENSORGROUP'])
- commands.extend(delete['TMS_DESTGROUP'])
- commands.extend(add['TMS_DESTGROUP'])
- commands.extend(add['TMS_SENSORGROUP'])
- commands.extend(add['TMS_SUBSCRIPTION'])
- commands.extend(add['TMS_GLOBAL'])
- commands = remove_duplicate_context(commands)
-
- return commands
-
- @staticmethod
- def _state_merged(cmd_ref):
- """ The command generator when state is merged
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = cmd_ref['TMS_GLOBAL']['ref'][0].get_proposed()
-
- if cmd_ref['TMS_DESTGROUP'].get('ref'):
- for cr in cmd_ref['TMS_DESTGROUP']['ref']:
- commands.extend(cr.get_proposed())
-
- if cmd_ref['TMS_SENSORGROUP'].get('ref'):
- for cr in cmd_ref['TMS_SENSORGROUP']['ref']:
- commands.extend(cr.get_proposed())
-
- if cmd_ref['TMS_SUBSCRIPTION'].get('ref'):
- for cr in cmd_ref['TMS_SUBSCRIPTION']['ref']:
- commands.extend(cr.get_proposed())
-
- return remove_duplicate_context(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 = []
- if want != have:
- commands = ['no telemetry']
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/config/vlans/vlans.py b/lib/ansible/module_utils/network/nxos/config/vlans/vlans.py
deleted file mode 100644
index 16a8cfa856..0000000000
--- a/lib/ansible/module_utils/network/nxos/config/vlans/vlans.py
+++ /dev/null
@@ -1,290 +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 nxos_vlans class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import dict_diff, to_list, remove_empties
-from ansible.module_utils.network.nxos.facts.facts import Facts
-from ansible.module_utils.network.nxos.utils.utils import search_obj_in_list
-
-
-class Vlans(ConfigBase):
- """
- The nxos_vlans class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'vlans',
- ]
-
- def __init__(self, module):
- super(Vlans, self).__init__(module)
-
- def get_vlans_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- vlans_facts = facts['ansible_network_resources'].get('vlans')
- if not vlans_facts:
- return []
-
- # Remove vlan 1 from facts list
- vlans_facts = [i for i in vlans_facts if (int(i['vlan_id'])) != 1]
- return vlans_facts
-
- def edit_config(self, commands):
- """Wrapper method for `_connection.edit_config()`
- This exists solely to allow the unit test framework to mock device connection calls.
- """
- return self._connection.edit_config(commands)
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_vlans_facts = self.get_vlans_facts()
- commands.extend(self.set_config(existing_vlans_facts))
- if commands:
- if not self._module.check_mode:
- self.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_vlans_facts = self.get_vlans_facts()
-
- result['before'] = existing_vlans_facts
- if result['changed']:
- result['after'] = changed_vlans_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_vlans_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- config = self._module.params.get('config')
- want = []
- if config:
- for w in config:
- if int(w['vlan_id']) == 1:
- self._module.fail_json(msg="Vlan 1 is not allowed to be managed by this module")
- want.append(remove_empties(w))
- have = existing_vlans_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='config is required for state {0}'.format(state))
-
- commands = list()
- if state == 'overridden':
- commands.extend(self._state_overridden(want, have))
- elif state == 'deleted':
- commands.extend(self._state_deleted(want, have))
- else:
- for w in want:
- if state == 'merged':
- commands.extend(self._state_merged(w, have))
- elif state == 'replaced':
- commands.extend(self._state_replaced(w, have))
- return commands
-
- def remove_default_states(self, obj):
- """Removes non-empty but default states from the obj.
- """
- default_states = {
- 'enabled': True,
- 'state': 'active',
- 'mode': 'ce',
- }
- for k in default_states.keys():
- if obj[k] == default_states[k]:
- obj.pop(k, None)
- return obj
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced.
- Scope is limited to vlan objects defined in the playbook.
- :rtype: A list
- :returns: The minimum command set required to migrate the current
- configuration to the desired configuration.
- """
- obj_in_have = search_obj_in_list(want['vlan_id'], have, 'vlan_id')
- if obj_in_have:
- # ignore states that are already reset, then diff what's left
- obj_in_have = self.remove_default_states(obj_in_have)
- diff = dict_diff(want, obj_in_have)
- # Remove merge items from diff; what's left will be used to
- # remove states not specified in the playbook
- for k in dict(set(want.items()) - set(obj_in_have.items())).keys():
- diff.pop(k, None)
- else:
- diff = want
-
- # merged_cmds: 'want' cmds to update 'have' states that don't match
- # replaced_cmds: remaining 'have' cmds that need to be reset to default
- merged_cmds = self.set_commands(want, have)
- replaced_cmds = []
- if obj_in_have:
- # Remaining diff items are used to reset states to default
- replaced_cmds = self.del_attribs(diff)
- cmds = []
- if replaced_cmds or merged_cmds:
- cmds += ['vlan %s' % str(want['vlan_id'])]
- cmds += merged_cmds + replaced_cmds
- return cmds
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden.
- Scope includes all vlan objects on the device.
- :rtype: A list
- :returns: the minimum command set required to migrate the current
- configuration to the desired configuration.
- """
- # overridden behavior is the same as replaced except for scope.
- cmds = []
- existing_vlans = []
- for h in have:
- existing_vlans.append(h['vlan_id'])
- obj_in_want = search_obj_in_list(h['vlan_id'], want, 'vlan_id')
- if obj_in_want:
- if h != obj_in_want:
- replaced_cmds = self._state_replaced(obj_in_want, [h])
- if replaced_cmds:
- cmds.extend(replaced_cmds)
- else:
- cmds.append('no vlan %s' % h['vlan_id'])
-
- # Add wanted vlans that don't exist on the device yet
- for w in want:
- if w['vlan_id'] not in existing_vlans:
- new_vlan = ['vlan %s' % w['vlan_id']]
- cmds.extend(new_vlan + self.add_commands(w))
- return cmds
-
- def _state_merged(self, w, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- cmds = self.set_commands(w, have)
- if cmds:
- cmds.insert(0, 'vlan %s' % str(w['vlan_id']))
- return(cmds)
-
- 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 w in want:
- obj_in_have = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
- if obj_in_have:
- commands.append('no vlan ' + str(obj_in_have['vlan_id']))
- else:
- if not have:
- return commands
- for h in have:
- commands.append('no vlan ' + str(h['vlan_id']))
- return commands
-
- def del_attribs(self, obj):
- """Returns a list of commands to reset states to default
- """
- commands = []
- if not obj:
- return commands
- default_cmds = {
- 'name': 'no name',
- 'state': 'no state',
- 'enabled': 'no shutdown',
- 'mode': 'mode ce',
- 'mapped_vni': 'no vn-segment',
- }
- for k in obj:
- commands.append(default_cmds[k])
- return commands
-
- def diff_of_dicts(self, w, obj):
- diff = set(w.items()) - set(obj.items())
- diff = dict(diff)
- if diff and w['vlan_id'] == obj['vlan_id']:
- diff.update({'vlan_id': w['vlan_id']})
- return diff
-
- def add_commands(self, d):
- commands = []
- if not d:
- return commands
- if 'name' in d:
- commands.append('name ' + d['name'])
- if 'state' in d:
- commands.append('state ' + d['state'])
- if 'enabled' in d:
- if d['enabled'] is True:
- commands.append('no shutdown')
- else:
- commands.append('shutdown')
- if 'mode' in d:
- commands.append('mode ' + d['mode'])
- if 'mapped_vni' in d:
- commands.append('vn-segment %s' % d['mapped_vni'])
-
- return commands
-
- def set_commands(self, w, have):
- commands = []
- obj_in_have = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
- if not obj_in_have:
- commands = self.add_commands(w)
- else:
- diff = self.diff_of_dicts(w, obj_in_have)
- commands = self.add_commands(diff)
- return commands
diff --git a/lib/ansible/module_utils/network/nxos/facts/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index 87d522df67..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,119 +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 nxos acl_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.acl_interfaces.acl_interfaces import Acl_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import normalize_interface
-
-
-class Acl_interfacesFacts(object):
- """ The nxos acl_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Acl_interfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_device_data(self, connection):
- return connection.get('show running-config | section interface')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for acl_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if not data:
- data = self.get_device_data(connection)
- data = data.split('interface')
-
- resources = []
- for i in range(len(data)):
- intf = data[i].split('\n')
- for l in range(1, len(intf)):
- if not re.search('ip(v6)?( port)? (access-group|traffic-filter)', intf[l]):
- intf[l] = ''
- intf = list(filter(None, intf))
- resources.append(intf)
-
- objs = []
- for resource in resources:
- if resource:
- obj = self.render_config(self.generated_spec, resource)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('acl_interfaces', None)
- facts = {}
- if objs:
- params = utils.validate_config(
- self.argument_spec, {'config': objs})
- params = utils.remove_empties(params)
- facts['acl_interfaces'] = 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)
- name = conf[0].strip()
- config['name'] = normalize_interface(name)
- config['access_groups'] = []
- v4 = {'afi': 'ipv4', 'acls': []}
- v6 = {'afi': 'ipv6', 'acls': []}
- for c in conf[1:]:
- if c:
- acl4 = re.search(r'ip( port)? access-group (\w*) (\w*)', c)
- acl6 = re.search(r'ipv6( port)? traffic-filter (\w*) (\w*)', c)
- if acl4:
- acl = {'name': acl4.group(2).strip(
- ), 'direction': acl4.group(3).strip()}
- if acl4.group(1):
- acl.update({'port': True})
- v4['acls'].append(acl)
- elif acl6:
- acl = {'name': acl6.group(2), 'direction': acl6.group(3)}
- if acl6.group(1):
- acl.update({'port': True})
- v6['acls'].append(acl)
-
- if len(v4['acls']) > 0:
- config['access_groups'].append(v4)
- if len(v6['acls']) > 0:
- config['access_groups'].append(v6)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/acls/acls.py b/lib/ansible/module_utils/network/nxos/facts/acls/acls.py
deleted file mode 100644
index e9b97b2456..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/acls/acls.py
+++ /dev/null
@@ -1,236 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos acls fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.acls.acls import AclsArgs
-
-
-class AclsFacts(object):
- """ The nxos acls fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = AclsArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_device_data(self, connection):
- return connection.get(
- "show running-config | section 'ip(v6)* access-list'")
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for acls
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if not data:
- data = self.get_device_data(connection)
- data = re.split('\nip', data)
- v6 = []
- v4 = []
-
- for i in range(len(data)):
- if str(data[i]):
- if 'v6' in str(data[i]).split()[0]:
- v6.append(data[i])
- else:
- v4.append(data[i])
-
- resources = []
- resources.append(v6)
- resources.append(v4)
- objs = []
- for resource in resources:
- if resource:
- obj = self.render_config(self.generated_spec, resource)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('acls', None)
- facts = {}
- if objs:
- params = utils.validate_config(self.argument_spec,
- {'config': objs})
- params = utils.remove_empties(params)
- facts['acls'] = params['config']
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def get_endpoint(self, ace, pro):
- ret_dict = {}
- option = ace.split()[0]
- if option == 'any':
- ret_dict.update({'any': True})
- else:
- # it could be a.b.c.d or a.b.c.d/x or a.b.c.d/32
- if '/' in option: # or 'host' in option:
- ip = re.search(r'(.*)/(\d+)', option)
- if int(ip.group(2)) < 32 or 32 < int(ip.group(2)) < 128:
- ret_dict.update({'prefix': option})
- else:
- ret_dict.update({'host': ip.group(1)})
- else:
- ret_dict.update({'address': option})
- wb = ace.split()[1]
- ret_dict.update({'wildcard_bits': wb})
- ace = re.sub('{0}'.format(wb), '', ace, 1)
- ace = re.sub(option, '', ace, 1)
- if pro in ['tcp', 'udp']:
- keywords = ['eq', 'lt', 'gt', 'neq', 'range']
- if len(ace.split()) and ace.split()[0] in keywords:
- port_protocol = {}
- port_pro = re.search(r'(eq|lt|gt|neq) (\w*)', ace)
- if port_pro:
- port_protocol.update(
- {port_pro.group(1): port_pro.group(2)})
- ace = re.sub(port_pro.group(1), '', ace, 1)
- ace = re.sub(port_pro.group(2), '', ace, 1)
- else:
- limit = re.search(r'(range) (\w*) (\w*)', ace)
- if limit:
- port_protocol.update({
- 'range': {
- 'start': limit.group(2),
- 'end': limit.group(3)
- }
- })
- ace = re.sub(limit.group(2), '', ace, 1)
- ace = re.sub(limit.group(3), '', ace, 1)
- if port_protocol:
- ret_dict.update({'port_protocol': port_protocol})
- return ace, ret_dict
-
- 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)
- protocol_options = {
- 'tcp': ['fin', 'established', 'psh', 'rst', 'syn', 'urg', 'ack'],
- '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'
- ],
- 'igmp': ['dvmrp', 'host_query', 'host_report'],
- }
- if conf:
- if 'v6' in conf[0].split()[0]:
- config['afi'] = 'ipv6'
- else:
- config['afi'] = 'ipv4'
- config['acls'] = []
- for acl in conf:
- acls = {}
- if 'match-local-traffic' in acl:
- config['match_local_traffic'] = True
- continue
- acl = acl.split('\n')
- acl = [a.strip() for a in acl]
- acl = list(filter(None, acl))
- acls['name'] = re.match(r'(ip)?(v6)?\s?access-list (.*)',
- acl[0]).group(3)
- acls['aces'] = []
- for ace in list(filter(None, acl[1:])):
- if re.search(r'ip(.*)access-list.*', ace):
- break
- entry = {}
- ace = ace.strip()
- seq = re.match(r'(\d*)', ace).group(0)
- entry.update({'sequence': seq})
- ace = re.sub(seq, '', ace, 1)
- grant = ace.split()[0]
- rem = ''
- if grant != 'remark':
- entry.update({'grant': grant})
- else:
- rem = re.match('.*remark (.*)', ace).group(1)
- entry.update({'remark': rem})
-
- if not rem:
- ace = re.sub(grant, '', ace, 1)
- pro = ace.split()[0]
- entry.update({'protocol': pro})
- ace = re.sub(pro, '', ace, 1)
- ace, source = self.get_endpoint(ace, pro)
- entry.update({'source': source})
- ace, dest = self.get_endpoint(ace, pro)
- entry.update({'destination': dest})
-
- dscp = re.search(r'dscp (\w*)', ace)
- if dscp:
- entry.update({'dscp': dscp.group(1)})
-
- frag = re.search(r'fragments', ace)
- if frag:
- entry.update({'fragments': True})
-
- prec = re.search(r'precedence (\w*)', ace)
- if prec:
- entry.update({'precedence': prec.group(1)})
-
- log = re.search('log', ace)
- if log:
- entry.update({'log': True})
-
- if pro == 'tcp' or pro == 'icmp' or pro == 'igmp':
- pro_options = {}
- options = {}
- for option in protocol_options[pro]:
- option = re.sub('_', '-', option)
- if option in ace:
- option = re.sub('-', '_', option)
- options.update({option: True})
- if options:
- pro_options.update({pro: options})
- if pro_options:
- entry.update({'protocol_options': pro_options})
- acls['aces'].append(entry)
- config['acls'].append(acls)
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/bfd_interfaces/bfd_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/bfd_interfaces/bfd_interfaces.py
deleted file mode 100644
index ad1c63a859..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/bfd_interfaces/bfd_interfaces.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-"""
-The nxos bfd_interfaces fact class
-Populate the facts tree based on the current device configuration.
-"""
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.bfd_interfaces.bfd_interfaces import Bfd_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class Bfd_interfacesFacts(object):
- """ The nxos_bfd_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Bfd_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 bfd_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get("show running-config | section '^interface|^feature bfd'")
-
- # Some of the bfd attributes
- if 'feature bfd' in data.split('\n'):
- resources = data.split('interface ')
- resources.pop(0)
- else:
- resources = []
- for resource in resources:
- if resource:
- obj = self.render_config(self.generated_spec, resource)
- if obj and len(obj.keys()) > 1:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('bfd_interfaces', None)
- facts = {}
- if objs:
- facts['bfd_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['bfd_interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- # 'bfd'/'bfd echo' do not nvgen when enabled thus set to 'enable' when None.
- # 'bfd' is not supported on some platforms
- config['bfd'] = utils.parse_conf_cmd_arg(conf, 'bfd', 'enable', 'disable') or 'enable'
- config['echo'] = utils.parse_conf_cmd_arg(conf, 'bfd echo', 'enable', 'disable') or 'enable'
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/facts.py b/lib/ansible/module_utils/network/nxos/facts/facts.py
deleted file mode 100644
index 301652b385..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/facts.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 facts class for nxos
-this file validates each subset of facts and selectively
-calls the appropriate facts gathering function
-"""
-
-from ansible.module_utils.network.common.facts.facts import FactsBase
-from ansible.module_utils.network.nxos.facts.legacy.base import Default, Legacy, Hardware, Config, Interfaces, Features
-from ansible.module_utils.network.nxos.facts.bfd_interfaces.bfd_interfaces import Bfd_interfacesFacts
-from ansible.module_utils.network.nxos.facts.hsrp_interfaces.hsrp_interfaces import Hsrp_interfacesFacts
-from ansible.module_utils.network.nxos.facts.interfaces.interfaces import InterfacesFacts
-from ansible.module_utils.network.nxos.facts.l2_interfaces.l2_interfaces import L2_interfacesFacts
-from ansible.module_utils.network.nxos.facts.lacp.lacp import LacpFacts
-from ansible.module_utils.network.nxos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts
-from ansible.module_utils.network.nxos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
-from ansible.module_utils.network.nxos.facts.telemetry.telemetry import TelemetryFacts
-from ansible.module_utils.network.nxos.facts.vlans.vlans import VlansFacts
-from ansible.module_utils.network.nxos.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts
-from ansible.module_utils.network.nxos.facts.lldp_global.lldp_global import Lldp_globalFacts
-from ansible.module_utils.network.nxos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts
-from ansible.module_utils.network.nxos.facts.acl_interfaces.acl_interfaces import Acl_interfacesFacts
-from ansible.module_utils.network.nxos.facts.acls.acls import AclsFacts
-
-
-FACT_LEGACY_SUBSETS = dict(
- default=Default,
- legacy=Legacy,
- hardware=Hardware,
- interfaces=Interfaces,
- config=Config,
- features=Features,
-)
-FACT_RESOURCE_SUBSETS = dict(
- bfd_interfaces=Bfd_interfacesFacts,
- hsrp_interfaces=Hsrp_interfacesFacts,
- lag_interfaces=Lag_interfacesFacts,
- lldp_global=Lldp_globalFacts,
- telemetry=TelemetryFacts,
- vlans=VlansFacts,
- lacp=LacpFacts,
- lacp_interfaces=Lacp_interfacesFacts,
- interfaces=InterfacesFacts,
- l3_interfaces=L3_interfacesFacts,
- l2_interfaces=L2_interfacesFacts,
- lldp_interfaces=Lldp_interfacesFacts,
- acl_interfaces=Acl_interfacesFacts,
- acls=AclsFacts,
-)
-
-
-class Facts(FactsBase):
- """ The fact class for nxos
- """
-
- 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 nxos
- :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/nxos/facts/hsrp_interfaces/hsrp_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/hsrp_interfaces/hsrp_interfaces.py
deleted file mode 100644
index b63eca4afd..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/hsrp_interfaces/hsrp_interfaces.py
+++ /dev/null
@@ -1,89 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-"""
-The nxos hsrp_interfaces fact class
-Populate the facts tree based on the current device configuration.
-"""
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.hsrp_interfaces.hsrp_interfaces import Hsrp_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class Hsrp_interfacesFacts(object):
- """ The nxos hsrp_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Hsrp_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 hsrp_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
-
- resources = data.split('interface ')
- for resource in resources:
- if resource:
- obj = self.render_config(self.generated_spec, resource)
- if obj and len(obj.keys()) > 1:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('hsrp_interfaces', None)
- facts = {}
- if objs:
- facts['hsrp_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['hsrp_interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- config['bfd'] = utils.parse_conf_cmd_arg(conf, 'hsrp bfd', 'enable', 'disable')
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/interfaces/interfaces.py b/lib/ansible/module_utils/network/nxos/facts/interfaces/interfaces.py
deleted file mode 100644
index 59a49376cc..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/interfaces/interfaces.py
+++ /dev/null
@@ -1,151 +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)#!/usr/bin/python
-"""
-The nxos 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.nxos.argspec.interfaces.interfaces import InterfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-from ansible.module_utils.network.nxos.nxos import default_intf_enabled
-
-
-class InterfacesFacts(object):
- """ The nxos interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for interfaces
- :param connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get("show running-config all | incl 'system default switchport'")
- data += connection.get('show running-config | section ^interface')
-
- # Collect device defaults & per-intf defaults
- self.render_system_defaults(data)
- intf_defs = {'sysdefs': self.sysdefs}
-
- config = data.split('interface ')
- default_interfaces = []
- for conf in config:
- conf = conf.strip()
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- intf_defs[obj['name']] = obj.pop('enabled_def', None)
- if len(obj.keys()) > 1:
- objs.append(obj)
- elif len(obj.keys()) == 1:
- # Existing-but-default interfaces are not included in the
- # objs list; however a list of default interfaces is
- # necessary to prevent idempotence issues and to help
- # with virtual interfaces that haven't been created yet.
- default_interfaces.append(obj['name'])
-
- ansible_facts['ansible_network_resources'].pop('interfaces', None)
- facts = {}
- facts['interfaces'] = []
- if objs:
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- ansible_facts['ansible_network_resources']['default_interfaces'] = default_interfaces
- ansible_facts['intf_defs'] = intf_defs
- return ansible_facts
-
- def _device_info(self):
- return self._module._capabilities.get('device_info', {})
-
- def render_system_defaults(self, config):
- """Collect user-defined-default states for 'system default switchport' configurations.
- These configurations determine default L2/L3 modes and enabled/shutdown
- states. The default values for user-defined-default configurations may
- be different for legacy platforms.
- Notes:
- - L3 enabled default state is False on N9K,N7K but True for N3K,N6K
- - Changing L2-L3 modes may change the default enabled value.
- - '(no) system default switchport shutdown' only applies to L2 interfaces.
- """
- platform = self._device_info().get('network_os_platform', '')
- L3_enabled = True if re.search('N[356]K', platform) else False
- sysdefs = {
- 'mode': None,
- 'L2_enabled': None,
- 'L3_enabled': L3_enabled
- }
- pat = '(no )*system default switchport$'
- m = re.search(pat, config, re.MULTILINE)
- if m:
- sysdefs['mode'] = 'layer3' if 'no ' in m.groups() else 'layer2'
-
- pat = '(no )*system default switchport shutdown$'
- m = re.search(pat, config, re.MULTILINE)
- if m:
- sysdefs['L2_enabled'] = True if 'no ' in m.groups() else False
-
- self.sysdefs = sysdefs
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- config['description'] = utils.parse_conf_arg(conf, 'description')
- config['speed'] = utils.parse_conf_arg(conf, 'speed')
- config['mtu'] = utils.parse_conf_arg(conf, 'mtu')
- config['duplex'] = utils.parse_conf_arg(conf, 'duplex')
- config['mode'] = utils.parse_conf_cmd_arg(conf, 'switchport', 'layer2', 'layer3')
-
- config['enabled'] = utils.parse_conf_cmd_arg(conf, 'shutdown', False, True)
-
- # Capture the default 'enabled' state, which may be interface-specific
- config['enabled_def'] = default_intf_enabled(name=intf, sysdefs=self.sysdefs, mode=config['mode'])
-
- config['fabric_forwarding_anycast_gateway'] = utils.parse_conf_cmd_arg(conf, 'fabric forwarding mode anycast-gateway', True)
- config['ip_forward'] = utils.parse_conf_cmd_arg(conf, 'ip forward', True)
-
- interfaces_cfg = utils.remove_empties(config)
- return interfaces_cfg
diff --git a/lib/ansible/module_utils/network/nxos/facts/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index 2063dd495e..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,94 +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)#!/usr/bin/python
-"""
-The nxos 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
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class L2_interfacesFacts(object):
- """The nxos 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 connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get('show running-config | section ^interface')
-
- config = data.split('interface ')
- for conf in config:
- conf = conf.strip()
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj and len(obj.keys()) > 1:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('l2_interfaces', None)
- facts = {}
- if objs:
- facts['l2_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['l2_interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
-
- config['name'] = intf
- config['mode'] = utils.parse_conf_arg(conf, 'switchport mode')
- config['ip_forward'] = utils.parse_conf_arg(conf, 'ip forward')
- config['access']['vlan'] = utils.parse_conf_arg(conf, 'switchport access vlan')
- config['trunk']['allowed_vlans'] = utils.parse_conf_arg(conf, 'switchport trunk allowed vlan')
- config['trunk']['native_vlan'] = utils.parse_conf_arg(conf, 'switchport trunk native vlan')
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index c5be39a4dc..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,126 +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)#!/usr/bin/python
-"""
-The nxos 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
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.l3_interfaces.l3_interfaces import L3_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class L3_interfacesFacts(object):
- """ The nxos l3_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = L3_interfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for l3_interfaces
- :param connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get('show running-config | section ^interface')
-
- config = data.split('interface ')
- for conf in config:
- conf = conf.strip()
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj and len(obj.keys()) > 1:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('l3_interfaces', None)
- facts = {}
- if objs:
- facts['l3_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['l3_interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- config['dot1q'] = utils.parse_conf_arg(conf, 'encapsulation dot1[qQ]')
- config['redirects'] = utils.parse_conf_cmd_arg(conf, 'no ip redirects', False, True)
- config['unreachables'] = utils.parse_conf_cmd_arg(conf, 'ip unreachables', True, False)
- ipv4_match = re.compile(r'\n ip address (.*)')
- matches = ipv4_match.findall(conf)
- if matches:
- if matches[0]:
- config['ipv4'] = []
- for m in matches:
- ipv4_conf = m.split()
- addr = ipv4_conf[0]
- if addr:
- config_dict = {'address': addr}
- if len(ipv4_conf) > 1:
- d = ipv4_conf[1]
- if d == 'secondary':
- config_dict.update({'secondary': True})
- if len(ipv4_conf) == 4:
- if ipv4_conf[2] == 'tag':
- config_dict.update({'tag': int(ipv4_conf[-1])})
- elif d == 'tag':
- config_dict.update({'tag': int(ipv4_conf[-1])})
- config['ipv4'].append(config_dict)
-
- ipv6_match = re.compile(r'\n ipv6 address (.*)')
- matches = ipv6_match.findall(conf)
- if matches:
- if matches[0]:
- config['ipv6'] = []
- for m in matches:
- ipv6_conf = m.split()
- addr = ipv6_conf[0]
- if addr:
- config_dict = {'address': addr}
- if len(ipv6_conf) > 1:
- d = ipv6_conf[1]
- if d == 'tag':
- config_dict.update({'tag': int(ipv6_conf[-1])})
- config['ipv6'].append(config_dict)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/lacp/lacp.py b/lib/ansible/module_utils/network/nxos/facts/lacp/lacp.py
deleted file mode 100644
index 90524503db..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/lacp/lacp.py
+++ /dev/null
@@ -1,84 +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 nxos lacp fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.lacp.lacp import LacpArgs
-
-
-class LacpFacts(object):
- """ The nxos 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("show running-config | include lacp")
- resources = data.strip()
- objs = self.render_config(self.generated_spec, resources)
- ansible_facts['ansible_network_resources'].pop('lacp', None)
- facts = {}
- if objs:
- params = utils.validate_config(self.argument_spec, {'config': objs})
- facts['lacp'] = utils.remove_empties(params['config'])
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- p_match = re.search(r'lacp system-priority (\d+)', conf, re.M)
- if p_match:
- config['system']['priority'] = p_match.group(1)
-
- a_match = re.search(r'lacp system-mac (\S+)', conf, re.M)
- if a_match:
- address = a_match.group(1)
- config['system']['mac']['address'] = address
- r_match = re.search(r'lacp system-mac {0} role (\S+)'.format(address), conf, re.M)
- if r_match:
- config['system']['mac']['role'] = r_match.group(1)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 000e1de72b..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos 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.nxos.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class Lacp_interfacesFacts(object):
- """ The nxos 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
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
-
- resources = data.split('interface ')
- for resource in resources:
- if resource and re.search(r'lacp', resource):
- obj = self.render_config(self.generated_spec, resource)
- if obj and len(obj.keys()) > 1:
- 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'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- config['port_priority'] = utils.parse_conf_arg(conf, 'lacp port-priority')
- config['rate'] = utils.parse_conf_arg(conf, 'lacp rate')
- config['mode'] = utils.parse_conf_arg(conf, 'mode')
- suspend_individual = re.search(r'no lacp suspend-individual', conf)
- if suspend_individual:
- config['suspend_individual'] = False
- max_links = utils.parse_conf_arg(conf, 'lacp max-bundle')
- if max_links:
- config['links']['max'] = max_links
- min_links = utils.parse_conf_arg(conf, 'lacp min-links')
- if min_links:
- config['links']['min'] = min_links
- graceful = re.search(r'no lacp graceful-convergence', conf)
- if graceful:
- config['convergence']['gracefule'] = False
- vpc = re.search(r'lacp vpc-convergence', conf)
- if vpc:
- config['convergence']['vpc'] = True
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index 983212409d..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)#!/usr/bin/python
-"""
-The nxos 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.nxos.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type, normalize_interface
-
-
-class Lag_interfacesFacts(object):
- """ The nxos 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 data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- if not data:
- data = connection.get('show running-config | include channel-group')
- config = re.split('(\n |)channel-group ', data)
- config = list(dict.fromkeys(config))
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf, connection)
- if obj and len(obj.keys()) > 1:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('lag_interfaces', None)
- facts = {}
- if objs:
- facts['lag_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['lag_interfaces'].append(utils.remove_empties(cfg))
-
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def get_members(self, id, connection):
- """
- Returns members associated with a channel-group
-
- :param name: The channel group
- :rtype: list
- :returns: Members
- """
- members = []
- data = connection.get('show port-channel summary')
- match = re.search(r'{0} (.+)(|\n)'.format(id), data)
- if match:
- interfaces = re.search(r'Eth\d(.+)$', match.group())
- if interfaces:
- for i in interfaces.group().split():
- if get_interface_type(i[:-3]) != 'unknown':
- members.append(normalize_interface(i[:-3]))
-
- return members
-
- def render_config(self, spec, conf, connection):
- """
- 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'(\d+)( |)(force )?(mode \S+)?', conf, re.M)
- if match:
- matches = match.groups()
- config['name'] = 'port-channel' + str(matches[0])
- config['members'] = []
- members = self.get_members(config['name'].strip('port-channel'), connection)
- if members:
- for m in members:
- m_dict = {}
- if matches[2]:
- m_dict['force'] = matches[2]
- if matches[3]:
- m_dict['mode'] = matches[3][5:]
- m_dict['member'] = m
- config['members'].append(m_dict)
- else:
- config = {}
-
- lag_intf_cfg = utils.remove_empties(config)
- # if lag interfaces config is not present return empty dict
- if len(lag_intf_cfg) == 1:
- return {}
- else:
- return lag_intf_cfg
diff --git a/lib/ansible/module_utils/network/nxos/facts/legacy/base.py b/lib/ansible/module_utils/network/nxos/facts/legacy/base.py
deleted file mode 100644
index 28be70b6b6..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/legacy/base.py
+++ /dev/null
@@ -1,756 +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)
-
-import platform
-import re
-
-from ansible.module_utils.network.nxos.nxos import run_commands, get_config, get_capabilities
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.six import iteritems
-
-
-g_config = None
-
-
-class FactsBase(object):
-
- def __init__(self, module):
- self.module = module
- self.warnings = list()
- self.facts = dict()
- self.capabilities = get_capabilities(self.module)
-
- def populate(self):
- pass
-
- def run(self, command, output='text'):
- command_string = command
- command = {
- 'command': command,
- 'output': output
- }
- resp = run_commands(self.module, [command], check_rc='retry_json')
- try:
- return resp[0]
- except IndexError:
- self.warnings.append('command %s failed, facts for this command will not be populated' % command_string)
- return None
-
- def get_config(self):
- global g_config
- if not g_config:
- g_config = get_config(self.module)
- return g_config
-
- def transform_dict(self, data, keymap):
- transform = dict()
- for key, fact in keymap:
- if key in data:
- transform[fact] = data[key]
- return transform
-
- def transform_iterable(self, iterable, keymap):
- for item in iterable:
- yield self.transform_dict(item, keymap)
-
-
-class Default(FactsBase):
-
- def populate(self):
- data = None
- data = self.run('show version')
-
- if data:
- self.facts['serialnum'] = self.parse_serialnum(data)
-
- data = self.run('show license host-id')
- if data:
- self.facts['license_hostid'] = self.parse_license_hostid(data)
-
- self.facts.update(self.platform_facts())
-
- def parse_serialnum(self, data):
- match = re.search(r'Processor Board ID\s*(\S+)', data, re.M)
- if match:
- return match.group(1)
-
- def platform_facts(self):
- platform_facts = {}
-
- resp = self.capabilities
- 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
-
- def parse_license_hostid(self, data):
- match = re.search(r'License hostid: VDH=(.+)$', data, re.M)
- if match:
- return match.group(1)
-
-
-class Config(FactsBase):
-
- def populate(self):
- super(Config, self).populate()
- self.facts['config'] = self.get_config()
-
-
-class Features(FactsBase):
-
- def populate(self):
- super(Features, self).populate()
- data = self.get_config()
-
- if data:
- features = []
- for line in data.splitlines():
- if line.startswith('feature'):
- features.append(line.replace('feature', '').strip())
-
- self.facts['features_enabled'] = features
-
-
-class Hardware(FactsBase):
-
- def populate(self):
- data = self.run('dir')
- if data:
- self.facts['filesystems'] = self.parse_filesystems(data)
-
- data = None
- data = self.run('show system resources', output='json')
-
- if data:
- if isinstance(data, dict):
- self.facts['memtotal_mb'] = int(data['memory_usage_total']) / 1024
- self.facts['memfree_mb'] = int(data['memory_usage_free']) / 1024
- else:
- self.facts['memtotal_mb'] = self.parse_memtotal_mb(data)
- self.facts['memfree_mb'] = self.parse_memfree_mb(data)
-
- def parse_filesystems(self, data):
- return re.findall(r'^Usage for (\S+)//', data, re.M)
-
- def parse_memtotal_mb(self, data):
- match = re.search(r'(\S+)K(\s+|)total', data, re.M)
- if match:
- memtotal = match.group(1)
- return int(memtotal) / 1024
-
- def parse_memfree_mb(self, data):
- match = re.search(r'(\S+)K(\s+|)free', data, re.M)
- if match:
- memfree = match.group(1)
- return int(memfree) / 1024
-
-
-class Interfaces(FactsBase):
-
- INTERFACE_MAP = frozenset([
- ('state', 'state'),
- ('desc', 'description'),
- ('eth_bw', 'bandwidth'),
- ('eth_duplex', 'duplex'),
- ('eth_speed', 'speed'),
- ('eth_mode', 'mode'),
- ('eth_hw_addr', 'macaddress'),
- ('eth_mtu', 'mtu'),
- ('eth_hw_desc', 'type')
- ])
-
- INTERFACE_SVI_MAP = frozenset([
- ('svi_line_proto', 'state'),
- ('svi_bw', 'bandwidth'),
- ('svi_mac', 'macaddress'),
- ('svi_mtu', 'mtu'),
- ('type', 'type')
- ])
-
- INTERFACE_IPV4_MAP = frozenset([
- ('eth_ip_addr', 'address'),
- ('eth_ip_mask', 'masklen')
- ])
-
- INTERFACE_SVI_IPV4_MAP = frozenset([
- ('svi_ip_addr', 'address'),
- ('svi_ip_mask', 'masklen')
- ])
-
- INTERFACE_IPV6_MAP = frozenset([
- ('addr', 'address'),
- ('prefix', 'subnet')
- ])
-
- def ipv6_structure_op_supported(self):
- data = self.capabilities
- if data:
- nxos_os_version = data['device_info']['network_os_version']
- unsupported_versions = ['I2', 'F1', 'A8']
- for ver in unsupported_versions:
- if ver in nxos_os_version:
- return False
- return True
-
- def populate(self):
- self.facts['all_ipv4_addresses'] = list()
- self.facts['all_ipv6_addresses'] = list()
- self.facts['neighbors'] = {}
- data = None
-
- data = self.run('show interface', output='json')
-
- if data:
- if isinstance(data, dict):
- self.facts['interfaces'] = self.populate_structured_interfaces(data)
- else:
- interfaces = self.parse_interfaces(data)
- self.facts['interfaces'] = self.populate_interfaces(interfaces)
-
- if self.ipv6_structure_op_supported():
- data = self.run('show ipv6 interface', output='json')
- else:
- data = None
- if data:
- if isinstance(data, dict):
- self.populate_structured_ipv6_interfaces(data)
- else:
- interfaces = self.parse_interfaces(data)
- self.populate_ipv6_interfaces(interfaces)
-
- data = self.run('show lldp neighbors', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['neighbors'].update(self.populate_structured_neighbors_lldp(data))
- else:
- self.facts['neighbors'].update(self.populate_neighbors(data))
-
- data = self.run('show cdp neighbors detail', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['neighbors'].update(self.populate_structured_neighbors_cdp(data))
- else:
- self.facts['neighbors'].update(self.populate_neighbors_cdp(data))
-
- self.facts['neighbors'].pop(None, None) # Remove null key
-
- def populate_structured_interfaces(self, data):
- interfaces = dict()
- for item in data['TABLE_interface']['ROW_interface']:
- name = item['interface']
-
- intf = dict()
- if 'type' in item:
- intf.update(self.transform_dict(item, self.INTERFACE_SVI_MAP))
- else:
- intf.update(self.transform_dict(item, self.INTERFACE_MAP))
-
- if 'eth_ip_addr' in item:
- intf['ipv4'] = self.transform_dict(item, self.INTERFACE_IPV4_MAP)
- self.facts['all_ipv4_addresses'].append(item['eth_ip_addr'])
-
- if 'svi_ip_addr' in item:
- intf['ipv4'] = self.transform_dict(item, self.INTERFACE_SVI_IPV4_MAP)
- self.facts['all_ipv4_addresses'].append(item['svi_ip_addr'])
-
- interfaces[name] = intf
-
- return interfaces
-
- def populate_structured_ipv6_interfaces(self, data):
- try:
- data = data['TABLE_intf']
- if data:
- if isinstance(data, dict):
- data = [data]
- for item in data:
- name = item['ROW_intf']['intf-name']
- intf = self.facts['interfaces'][name]
- intf['ipv6'] = self.transform_dict(item, self.INTERFACE_IPV6_MAP)
- try:
- addr = item['ROW_intf']['addr']
- except KeyError:
- addr = item['ROW_intf']['TABLE_addr']['ROW_addr']['addr']
- self.facts['all_ipv6_addresses'].append(addr)
- else:
- return ""
- except TypeError:
- return ""
-
- def populate_structured_neighbors_lldp(self, data):
- objects = dict()
- data = data['TABLE_nbor']['ROW_nbor']
-
- if isinstance(data, dict):
- data = [data]
-
- for item in data:
- local_intf = normalize_interface(item['l_port_id'])
- objects[local_intf] = list()
- nbor = dict()
- nbor['port'] = item['port_id']
- nbor['host'] = nbor['sysname'] = item['chassis_id']
- objects[local_intf].append(nbor)
-
- return objects
-
- def populate_structured_neighbors_cdp(self, data):
- objects = dict()
- data = data['TABLE_cdp_neighbor_detail_info']['ROW_cdp_neighbor_detail_info']
-
- if isinstance(data, dict):
- data = [data]
-
- for item in data:
- local_intf = item['intf_id']
- objects[local_intf] = list()
- nbor = dict()
- nbor['port'] = item['port_id']
- nbor['host'] = nbor['sysname'] = item['device_id']
- objects[local_intf].append(nbor)
-
- return objects
-
- def parse_interfaces(self, data):
- parsed = dict()
- key = ''
- for line in data.split('\n'):
- if len(line) == 0:
- continue
- elif line.startswith('admin') or line[0] == ' ':
- parsed[key] += '\n%s' % line
- else:
- match = re.match(r'^(\S+)', line)
- if match:
- key = match.group(1)
- if not key.startswith('admin') or not key.startswith('IPv6 Interface'):
- parsed[key] = line
- return parsed
-
- def populate_interfaces(self, interfaces):
- facts = dict()
- for key, value in iteritems(interfaces):
- intf = dict()
- if get_interface_type(key) == 'svi':
- intf['state'] = self.parse_state(key, value, intf_type='svi')
- intf['macaddress'] = self.parse_macaddress(value, intf_type='svi')
- intf['mtu'] = self.parse_mtu(value, intf_type='svi')
- intf['bandwidth'] = self.parse_bandwidth(value, intf_type='svi')
- intf['type'] = self.parse_type(value, intf_type='svi')
- if 'Internet Address' in value:
- intf['ipv4'] = self.parse_ipv4_address(value, intf_type='svi')
- facts[key] = intf
- else:
- intf['state'] = self.parse_state(key, value)
- intf['description'] = self.parse_description(value)
- intf['macaddress'] = self.parse_macaddress(value)
- intf['mode'] = self.parse_mode(value)
- intf['mtu'] = self.parse_mtu(value)
- intf['bandwidth'] = self.parse_bandwidth(value)
- intf['duplex'] = self.parse_duplex(value)
- intf['speed'] = self.parse_speed(value)
- intf['type'] = self.parse_type(value)
- if 'Internet Address' in value:
- intf['ipv4'] = self.parse_ipv4_address(value)
- facts[key] = intf
-
- return facts
-
- def parse_state(self, key, value, intf_type='ethernet'):
- match = None
- if intf_type == 'svi':
- match = re.search(r'line protocol is\s*(\S+)', value, re.M)
- else:
- match = re.search(r'%s is\s*(\S+)' % key, value, re.M)
-
- if match:
- return match.group(1)
-
- def parse_macaddress(self, value, intf_type='ethernet'):
- match = None
- if intf_type == 'svi':
- match = re.search(r'address is\s*(\S+)', value, re.M)
- else:
- match = re.search(r'address:\s*(\S+)', value, re.M)
-
- if match:
- return match.group(1)
-
- def parse_mtu(self, value, intf_type='ethernet'):
- match = re.search(r'MTU\s*(\S+)', value, re.M)
- if match:
- return match.group(1)
-
- def parse_bandwidth(self, value, intf_type='ethernet'):
- match = re.search(r'BW\s*(\S+)', value, re.M)
- if match:
- return match.group(1)
-
- def parse_type(self, value, intf_type='ethernet'):
- match = None
- if intf_type == 'svi':
- match = re.search(r'Hardware is\s*(\S+)', value, re.M)
- else:
- match = re.search(r'Hardware:\s*(.+),', value, re.M)
-
- if match:
- return match.group(1)
-
- def parse_description(self, value, intf_type='ethernet'):
- match = re.search(r'Description: (.+)$', value, re.M)
- if match:
- return match.group(1)
-
- def parse_mode(self, value, intf_type='ethernet'):
- match = re.search(r'Port mode is (\S+)', value, re.M)
- if match:
- return match.group(1)
-
- def parse_duplex(self, value, intf_type='ethernet'):
- match = re.search(r'(\S+)-duplex', value, re.M)
- if match:
- return match.group(1)
-
- def parse_speed(self, value, intf_type='ethernet'):
- match = re.search(r'duplex, (.+)$', value, re.M)
- if match:
- return match.group(1)
-
- def parse_ipv4_address(self, value, intf_type='ethernet'):
- ipv4 = {}
- match = re.search(r'Internet Address is (.+)$', value, re.M)
- if match:
- address = match.group(1)
- addr = address.split('/')[0]
- ipv4['address'] = address.split('/')[0]
- ipv4['masklen'] = address.split('/')[1]
- self.facts['all_ipv4_addresses'].append(addr)
- return ipv4
-
- def populate_neighbors(self, data):
- objects = dict()
- # if there are no neighbors the show command returns
- # ERROR: No neighbour information
- if data.startswith('ERROR'):
- return dict()
-
- regex = re.compile(r'(\S+)\s+(\S+)\s+\d+\s+\w+\s+(\S+)')
-
- for item in data.split('\n')[4:-1]:
- match = regex.match(item)
- if match:
- nbor = dict()
- nbor['host'] = nbor['sysname'] = match.group(1)
- nbor['port'] = match.group(3)
- local_intf = normalize_interface(match.group(2))
- if local_intf not in objects:
- objects[local_intf] = []
- objects[local_intf].append(nbor)
-
- return objects
-
- def populate_neighbors_cdp(self, data):
- facts = dict()
-
- for item in data.split('----------------------------------------'):
- if item == '':
- continue
- local_intf = self.parse_lldp_intf(item)
- if local_intf not in facts:
- facts[local_intf] = list()
-
- fact = dict()
- fact['port'] = self.parse_lldp_port(item)
- fact['sysname'] = self.parse_lldp_sysname(item)
- facts[local_intf].append(fact)
-
- return facts
-
- def parse_lldp_intf(self, data):
- match = re.search(r'Interface:\s*(\S+)', data, re.M)
- if match:
- return match.group(1).strip(',')
-
- def parse_lldp_port(self, data):
- match = re.search(r'Port ID \(outgoing port\):\s*(\S+)', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lldp_sysname(self, data):
- match = re.search(r'Device ID:(.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def populate_ipv6_interfaces(self, interfaces):
- facts = dict()
- for key, value in iteritems(interfaces):
- intf = dict()
- intf['ipv6'] = self.parse_ipv6_address(value)
- facts[key] = intf
-
- def parse_ipv6_address(self, value):
- ipv6 = {}
- match_addr = re.search(r'IPv6 address:\s*(\S+)', value, re.M)
- if match_addr:
- addr = match_addr.group(1)
- ipv6['address'] = addr
- self.facts['all_ipv6_addresses'].append(addr)
- match_subnet = re.search(r'IPv6 subnet:\s*(\S+)', value, re.M)
- if match_subnet:
- ipv6['subnet'] = match_subnet.group(1)
-
- return ipv6
-
-
-class Legacy(FactsBase):
- # facts from nxos_facts 2.1
-
- VERSION_MAP = frozenset([
- ('host_name', '_hostname'),
- ('kickstart_ver_str', '_os'),
- ('chassis_id', '_platform')
- ])
-
- MODULE_MAP = frozenset([
- ('model', 'model'),
- ('modtype', 'type'),
- ('ports', 'ports'),
- ('status', 'status')
- ])
-
- FAN_MAP = frozenset([
- ('fanname', 'name'),
- ('fanmodel', 'model'),
- ('fanhwver', 'hw_ver'),
- ('fandir', 'direction'),
- ('fanstatus', 'status')
- ])
-
- POWERSUP_MAP = frozenset([
- ('psmodel', 'model'),
- ('psnum', 'number'),
- ('ps_status', 'status'),
- ('ps_status_3k', 'status'),
- ('actual_out', 'actual_output'),
- ('actual_in', 'actual_in'),
- ('total_capa', 'total_capacity'),
- ('input_type', 'input_type'),
- ('watts', 'watts'),
- ('amps', 'amps')
- ])
-
- def populate(self):
- data = None
-
- data = self.run('show version', output='json')
- if data:
- if isinstance(data, dict):
- self.facts.update(self.transform_dict(data, self.VERSION_MAP))
- else:
- self.facts['hostname'] = self.parse_hostname(data)
- self.facts['os'] = self.parse_os(data)
- self.facts['platform'] = self.parse_platform(data)
-
- data = self.run('show interface', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['interfaces_list'] = self.parse_structured_interfaces(data)
- else:
- self.facts['interfaces_list'] = self.parse_interfaces(data)
-
- data = self.run('show vlan brief', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['vlan_list'] = self.parse_structured_vlans(data)
- else:
- self.facts['vlan_list'] = self.parse_vlans(data)
-
- data = self.run('show module', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['module'] = self.parse_structured_module(data)
- else:
- self.facts['module'] = self.parse_module(data)
-
- data = self.run('show environment fan', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['fan_info'] = self.parse_structured_fan_info(data)
- else:
- self.facts['fan_info'] = self.parse_fan_info(data)
-
- data = self.run('show environment power', output='json')
- if data:
- if isinstance(data, dict):
- self.facts['power_supply_info'] = self.parse_structured_power_supply_info(data)
- else:
- self.facts['power_supply_info'] = self.parse_power_supply_info(data)
-
- def parse_structured_interfaces(self, data):
- objects = list()
- for item in data['TABLE_interface']['ROW_interface']:
- objects.append(item['interface'])
- return objects
-
- def parse_structured_vlans(self, data):
- objects = list()
- data = data['TABLE_vlanbriefxbrief']['ROW_vlanbriefxbrief']
- if isinstance(data, dict):
- objects.append(data['vlanshowbr-vlanid-utf'])
- elif isinstance(data, list):
- for item in data:
- objects.append(item['vlanshowbr-vlanid-utf'])
- return objects
-
- def parse_structured_module(self, data):
- data = data['TABLE_modinfo']['ROW_modinfo']
- if isinstance(data, dict):
- data = [data]
- objects = list(self.transform_iterable(data, self.MODULE_MAP))
- return objects
-
- def parse_structured_fan_info(self, data):
- objects = list()
-
- for key in ("fandetails", "fandetails_3k"):
- if data.get(key):
- try:
- data = data[key]['TABLE_faninfo']['ROW_faninfo']
- except KeyError:
- # Some virtual images don't actually report faninfo. In this case, move on and
- # just return an empty list.
- pass
- else:
- objects = list(self.transform_iterable(data, self.FAN_MAP))
- break
-
- return objects
-
- def parse_structured_power_supply_info(self, data):
- if data.get('powersup').get('TABLE_psinfo_n3k'):
- fact = data['powersup']['TABLE_psinfo_n3k']['ROW_psinfo_n3k']
- else:
- if isinstance(data['powersup']['TABLE_psinfo'], list):
- fact = []
- for i in data['powersup']['TABLE_psinfo']:
- fact.append(i['ROW_psinfo'])
- else:
- fact = data['powersup']['TABLE_psinfo']['ROW_psinfo']
-
- objects = list(self.transform_iterable(fact, self.POWERSUP_MAP))
- return objects
-
- def parse_hostname(self, data):
- match = re.search(r'\s+Device name:\s+(\S+)', data, re.M)
- if match:
- return match.group(1)
-
- def parse_os(self, data):
- match = re.search(r'\s+system:\s+version\s*(\S+)', data, re.M)
- if match:
- return match.group(1)
- else:
- match = re.search(r'\s+kickstart:\s+version\s*(\S+)', data, re.M)
- if match:
- return match.group(1)
-
- def parse_platform(self, data):
- match = re.search(r'Hardware\n\s+cisco\s+(\S+\s+\S+)', data, re.M)
- if match:
- return match.group(1)
-
- def parse_interfaces(self, data):
- objects = list()
- for line in data.split('\n'):
- if len(line) == 0:
- continue
- elif line.startswith('admin') or line[0] == ' ':
- continue
- else:
- match = re.match(r'^(\S+)', line)
- if match:
- intf = match.group(1)
- if get_interface_type(intf) != 'unknown':
- objects.append(intf)
- return objects
-
- def parse_vlans(self, data):
- objects = list()
- for line in data.splitlines():
- if line == '':
- continue
- if line[0].isdigit():
- vlan = line.split()[0]
- objects.append(vlan)
- return objects
-
- def parse_module(self, data):
- objects = list()
- for line in data.splitlines():
- if line == '':
- break
- if line[0].isdigit():
- obj = {}
- match_port = re.search(r'\d\s*(\d*)', line, re.M)
- if match_port:
- obj['ports'] = match_port.group(1)
-
- match = re.search(r'\d\s*\d*\s*(.+)$', line, re.M)
- if match:
- l = match.group(1).split(' ')
- items = list()
- for item in l:
- if item == '':
- continue
- items.append(item.strip())
-
- if items:
- obj['type'] = items[0]
- obj['model'] = items[1]
- obj['status'] = items[2]
-
- objects.append(obj)
- return objects
-
- def parse_fan_info(self, data):
- objects = list()
-
- for l in data.splitlines():
- if '-----------------' in l or 'Status' in l:
- continue
- line = l.split()
- if len(line) > 1:
- obj = {}
- obj['name'] = line[0]
- obj['model'] = line[1]
- obj['hw_ver'] = line[-2]
- obj['status'] = line[-1]
- objects.append(obj)
- return objects
-
- def parse_power_supply_info(self, data):
- objects = list()
-
- for l in data.splitlines():
- if l == '':
- break
- if l[0].isdigit():
- obj = {}
- line = l.split()
- obj['model'] = line[1]
- obj['number'] = line[0]
- obj['status'] = line[-1]
-
- objects.append(obj)
- return objects
diff --git a/lib/ansible/module_utils/network/nxos/facts/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/nxos/facts/lldp_global/lldp_global.py
deleted file mode 100644
index c780c2030c..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,105 +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 nxos lldp_global fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.nxos.argspec.lldp_global.lldp_global import Lldp_globalArgs
-
-
-class Lldp_globalFacts(object):
- """ The nxos lldp_global fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Lldp_globalArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lldp_global
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
-
- if not data:
- data = connection.get('show running-config | include lldp')
-
- objs = {}
- objs = self.render_config(self.generated_spec, data)
- ansible_facts['ansible_network_resources'].pop('lldp_global', None)
- facts = {}
- if objs:
- params = utils.validate_config(
- self.argument_spec, {'config': objs})
- facts['lldp_global'] = params['config']
- facts = utils.remove_empties(facts)
- 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)
- conf = re.split('\n', conf)
- for command in conf:
- param = re.search(
- r'(.*)lldp (\w+(-?)\w+)',
- command) # get the word after 'lldp'
- if param:
- # get the nested-dict/value for that param
- key2 = re.search(r'%s(.*)' % param.group(2), command)
- key2 = key2.group(1).strip()
- key1 = param.group(2).replace('-', '_')
-
- if key1 == 'portid_subtype':
- key1 = 'port_id'
- config[key1] = key2
- elif key1 == 'tlv_select':
- key2 = key2.split()
- key2[0] = key2[0].replace('-', '_')
- if len(key2) == 1:
- if 'port' in key2[0] or 'system' in key2[0]: # nested dicts
- key2 = key2[0].split('_')
- # config[tlv_select][system][name]=False
- config[key1][key2[0]][key2[1]] = False
- else:
- # config[tlv_select][dcbxp]=False
- config[key1][key2[0]] = False
- else:
- # config[tlv_select][management_address][v6]=False
- config[key1][key2[0]][key2[1]] = False
- else:
- config[key1] = key2 # config[reinit]=4
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/nxos/facts/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 63ee03e7f6..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/lldp_interfaces/lldp_interfaces.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)
-"""
-The nxos 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.nxos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
-from ansible.module_utils.network.nxos.utils.utils import get_interface_type
-
-
-class Lldp_interfacesFacts(object):
- """ The nxos 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 get_device_data(self, connection):
- return connection.get('show running-config | section ^interface')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for 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 = self.get_device_data(connection)
-
- objs = []
-
- data = data.split('interface')
- resources = []
-
- for i in range(len(data)):
- intf = data[i].split('\n')
- for l in range(1, len(intf)):
- if not re.search('lldp', intf[l]):
- intf[l] = ''
- intf = list(filter(None, intf))
- intf = ''.join(i for i in intf)
- resources.append(intf)
-
- for resource in resources:
- if resource: # and re.search(r'lldp', resource):
- obj = self.render_config(self.generated_spec, resource)
- if obj and len(obj.keys()) >= 1:
- 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'^ (\S+)', conf)
- if match is None:
- return {}
- intf = match.group(1)
- if get_interface_type(intf) not in ['management', 'ethernet']:
- return {}
- config['name'] = intf
- if 'lldp receive' in conf: # for parsed state only
- config['receive'] = True
- if 'no lldp receive' in conf:
- config['receive'] = False
-
- if 'lldp transmit' in conf: # for parsed state only
- config['transmit'] = True
- if 'no lldp transmit' in conf:
- config['transmit'] = False
- if 'management-address' in conf:
- config['tlv_set']['management_address'] = re.search(
- r'management-address (\S*)', conf).group(1)
- if 'vlan' in conf:
- config['tlv_set']['vlan'] = re.search(
- r'vlan (\S*)', conf).group(1)
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/telemetry/telemetry.py b/lib/ansible/module_utils/network/nxos/facts/telemetry/telemetry.py
deleted file mode 100644
index 825d1bc8df..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/telemetry/telemetry.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos telemetry 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.nxos.argspec.telemetry.telemetry import TelemetryArgs
-from ansible.module_utils.network.nxos.cmdref.telemetry.telemetry import TMS_GLOBAL, TMS_DESTGROUP, TMS_SENSORGROUP, TMS_SUBSCRIPTION
-from ansible.module_utils.network.nxos.utils.telemetry.telemetry import get_instance_data, cr_key_lookup
-from ansible.module_utils.network.nxos.utils.telemetry.telemetry import normalize_data
-from ansible.module_utils.network.nxos.nxos import NxosCmdRef
-
-
-class TelemetryFacts(object):
- """ The nxos telemetry fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = TelemetryArgs.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 telemetry
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if connection: # just for linting purposes, remove
- pass
-
- cmd_ref = {}
- cmd_ref['TMS_GLOBAL'] = {}
- cmd_ref['TMS_DESTGROUP'] = {}
- cmd_ref['TMS_SENSORGROUP'] = {}
- cmd_ref['TMS_SUBSCRIPTION'] = {}
-
- # For fact gathering, module state should be 'present' when using
- # NxosCmdRef to query state
- if self._module.params.get('state'):
- saved_module_state = self._module.params['state']
- self._module.params['state'] = 'present'
-
- # Get Telemetry Global Data
- cmd_ref['TMS_GLOBAL']['ref'] = []
- cmd_ref['TMS_GLOBAL']['ref'].append(NxosCmdRef(self._module, TMS_GLOBAL))
- ref = cmd_ref['TMS_GLOBAL']['ref'][0]
- ref.set_context()
- ref.get_existing()
- device_cache = ref.cache_existing
-
- if device_cache is None:
- device_cache_lines = []
- else:
- device_cache_lines = device_cache.split("\n")
-
- # Get Telemetry Destination Group Data
- cmd_ref['TMS_DESTGROUP']['ref'] = []
- for line in device_cache_lines:
- if re.search(r'destination-group', line):
- resource_key = line.strip()
- cmd_ref['TMS_DESTGROUP']['ref'].append(NxosCmdRef(self._module, TMS_DESTGROUP))
- ref = cmd_ref['TMS_DESTGROUP']['ref'][-1]
- ref.set_context([resource_key])
- ref.get_existing(device_cache)
- normalize_data(ref)
-
- # Get Telemetry Sensorgroup Group Data
- cmd_ref['TMS_SENSORGROUP']['ref'] = []
- for line in device_cache_lines:
- if re.search(r'sensor-group', line):
- resource_key = line.strip()
- cmd_ref['TMS_SENSORGROUP']['ref'].append(NxosCmdRef(self._module, TMS_SENSORGROUP))
- ref = cmd_ref['TMS_SENSORGROUP']['ref'][-1]
- ref.set_context([resource_key])
- ref.get_existing(device_cache)
-
- # Get Telemetry Subscription Data
- cmd_ref['TMS_SUBSCRIPTION']['ref'] = []
- for line in device_cache_lines:
- if re.search(r'subscription', line):
- resource_key = line.strip()
- cmd_ref['TMS_SUBSCRIPTION']['ref'].append(NxosCmdRef(self._module, TMS_SUBSCRIPTION))
- ref = cmd_ref['TMS_SUBSCRIPTION']['ref'][-1]
- ref.set_context([resource_key])
- ref.get_existing(device_cache)
-
- objs = []
- objs = self.render_config(self.generated_spec, cmd_ref)
- facts = {'telemetry': {}}
- if objs:
- # params = utils.validate_config(self.argument_spec, {'config': objs})
- facts['telemetry'] = objs
-
- ansible_facts['ansible_network_resources'].update(facts)
- if self._module.params.get('state'):
- self._module.params['state'] = saved_module_state
- return ansible_facts
-
- def render_config(self, spec, cmd_ref):
- """
- 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['destination_groups'] = []
- config['sensor_groups'] = []
- config['subscriptions'] = []
- managed_objects = ['TMS_GLOBAL', 'TMS_DESTGROUP', 'TMS_SENSORGROUP', 'TMS_SUBSCRIPTION']
-
- # Walk the argspec and cmd_ref objects and build out config dict.
- for key in config.keys():
- for mo in managed_objects:
- for cr in cmd_ref[mo]['ref']:
- cr_keys = cr_key_lookup(key, mo)
- for cr_key in cr_keys:
- if cr._ref.get(cr_key) and cr._ref[cr_key].get('existing'):
- if isinstance(config[key], dict):
- for k in config[key].keys():
- for existing_key in cr._ref[cr_key]['existing'].keys():
- config[key][k] = cr._ref[cr_key]['existing'][existing_key][k]
- continue
- if isinstance(config[key], list):
- for existing_key in cr._ref[cr_key]['existing'].keys():
- data = get_instance_data(key, cr_key, cr, existing_key)
- config[key].append(data)
- continue
- for existing_key in cr._ref[cr_key]['existing'].keys():
- config[key] = cr._ref[cr_key]['existing'][existing_key]
- elif cr._ref.get(cr_key):
- data = get_instance_data(key, cr_key, cr, None)
- if isinstance(config[key], list) and data not in config[key]:
- config[key].append(data)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/nxos/facts/vlans/vlans.py b/lib/ansible/module_utils/network/nxos/facts/vlans/vlans.py
deleted file mode 100644
index 260fae1a23..0000000000
--- a/lib/ansible/module_utils/network/nxos/facts/vlans/vlans.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)#!/usr/bin/python
-"""
-The nxos vlans fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-import ast
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.common.utils import parse_conf_arg, parse_conf_cmd_arg
-from ansible.module_utils.network.nxos.argspec.vlans.vlans import VlansArgs
-
-
-class VlansFacts(object):
- """ The nxos vlans fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = VlansArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_device_data(self, connection, show_cmd):
- """Wrapper method for `connection.get()`
- This exists solely to allow the unit test framework to mock device connection calls.
- """
- return connection.get(show_cmd)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for vlans
- :param connection: the device connection
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
- # **TBD**
- # N7K EOL/legacy image 6.2 does not support show vlan | json output.
- # If support is still required for this image then:
- # - Wrapp the json calls below in a try/except
- # - When excepted, use a helper method to parse the run_cfg_output,
- # using the run_cfg_output data to generate compatible json data that
- # can be read by normalize_table_data.
- if not data:
- # Use structured for most of the vlan parameter states.
- # This data is consistent across the supported nxos platforms.
- structured = self.get_device_data(connection, 'show vlan | json')
-
- # Raw cli config is needed for mapped_vni, which is not included in structured.
- run_cfg_output = self.get_device_data(connection, 'show running-config | section ^vlan')
-
- # Create a single dictionary from all data sources
- data = self.normalize_table_data(structured, run_cfg_output)
-
- for vlan in data:
- obj = self.render_config(self.generated_spec, vlan)
- if obj:
- objs.append(obj)
-
- ansible_facts['ansible_network_resources'].pop('vlans', None)
- facts = {}
- if objs:
- facts['vlans'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['vlans'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
- return ansible_facts
-
- def render_config(self, spec, vlan):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param vlan: structured data vlan settings (dict) and raw cfg from device
- :rtype: dictionary
- :returns: The generated config
- Sample inputs: test/units/modules/network/nxos/fixtures/nxos_vlans/show_vlan
- """
- obj = deepcopy(spec)
-
- obj['vlan_id'] = vlan['vlan_id']
-
- # name: 'VLAN000x' (default name) or custom name
- name = vlan['vlanshowbr-vlanname']
- if name and re.match("VLAN%04d" % int(vlan['vlan_id']), name):
- name = None
- obj['name'] = name
-
- # mode: 'ce-vlan' or 'fabricpath-vlan'
- obj['mode'] = vlan['vlanshowinfo-vlanmode'].replace('-vlan', '')
-
- # enabled: shutdown, noshutdown
- obj['enabled'] = True if 'noshutdown' in vlan['vlanshowbr-shutstate'] else False
-
- # state: active, suspend
- obj['state'] = vlan['vlanshowbr-vlanstate']
-
- # non-structured data
- obj['mapped_vni'] = parse_conf_arg(vlan['run_cfg'], 'vn-segment')
-
- return utils.remove_empties(obj)
-
- def normalize_table_data(self, structured, run_cfg_output):
- """Normalize structured output and raw running-config output into
- a single dict to simplify render_config usage.
- This is needed because:
- - The NXOS devices report most of the vlan settings within two
- structured data keys: 'vlanbrief' and 'mtuinfo', but the output is
- incomplete and therefore raw running-config data is also needed.
- - running-config by itself is insufficient because of major differences
- in the cli config syntax across platforms.
- - Thus a helper method combines settings from the separate top-level keys,
- and adds a 'run_cfg' key containing raw cli from the device.
- """
- # device output may be string, convert to list
- structured = ast.literal_eval(str(structured))
-
- vlanbrief = []
- mtuinfo = []
- if 'TABLE_vlanbrief' in structured:
- # SAMPLE: {"TABLE_vlanbriefid": {"ROW_vlanbriefid": {
- # "vlanshowbr-vlanid": "4", "vlanshowbr-vlanid-utf": "4",
- # "vlanshowbr-vlanname": "VLAN0004", "vlanshowbr-vlanstate": "active",
- # "vlanshowbr-shutstate": "noshutdown"}},
- vlanbrief = structured['TABLE_vlanbrief']['ROW_vlanbrief']
-
- # SAMPLE: "TABLE_mtuinfoid": {"ROW_mtuinfoid": {
- # "vlanshowinfo-vlanid": "4", "vlanshowinfo-media-type": "enet",
- # "vlanshowinfo-vlanmode": "ce-vlan"}}
- mtuinfo = structured['TABLE_mtuinfo']['ROW_mtuinfo']
-
- if type(vlanbrief) is not list:
- # vlanbrief is not a list when only one vlan is found.
- vlanbrief = [vlanbrief]
- mtuinfo = [mtuinfo]
-
- # split out any per-vlan cli config
- run_cfg_list = re.split(r'[\n^]vlan ', run_cfg_output)
-
- # Create a list of vlan dicts where each dict contains vlanbrief,
- # mtuinfo, and non-structured running-config data for one vlan.
- vlans = []
- for index, v in enumerate(vlanbrief):
- v['vlan_id'] = v.get('vlanshowbr-vlanid-utf')
- vlan = {}
- vlan.update(v)
- vlan.update(mtuinfo[index])
-
- run_cfg = [i for i in run_cfg_list if "%s\n" % v['vlan_id'] in i] or ['']
- vlan['run_cfg'] = run_cfg.pop()
- vlans.append(vlan)
- return vlans
diff --git a/lib/ansible/module_utils/network/nxos/nxos.py b/lib/ansible/module_utils/network/nxos/nxos.py
deleted file mode 100644
index 431691c47c..0000000000
--- a/lib/ansible/module_utils/network/nxos/nxos.py
+++ /dev/null
@@ -1,1310 +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) 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 collections
-import json
-import re
-import sys
-from copy import deepcopy
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.network.common.utils import to_list, ComplexList
-from ansible.module_utils.connection import Connection, ConnectionError
-from ansible.module_utils.common._collections_compat import Mapping
-from ansible.module_utils.network.common.config import NetworkConfig, dumps
-from ansible.module_utils.network.common.config import CustomNetworkConfig
-from ansible.module_utils.six import iteritems, PY2, PY3
-from ansible.module_utils.urls import fetch_url
-
-try:
- import yaml
- HAS_YAML = True
-except ImportError:
- HAS_YAML = False
-
-try:
- if sys.version_info[:2] < (2, 7):
- from ordereddict import OrderedDict
- else:
- from collections import OrderedDict
- HAS_ORDEREDDICT = True
-except ImportError:
- HAS_ORDEREDDICT = False
-
-_DEVICE_CONNECTION = None
-
-nxos_provider_spec = {
- 'host': dict(type='str'),
- 'port': dict(type='int'),
-
- 'username': dict(type='str', fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
- 'password': dict(type='str', no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
- 'ssh_keyfile': dict(type='str', fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE'])),
-
- 'authorize': dict(type='bool', fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE'])),
- 'auth_pass': dict(type='str', no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])),
-
- 'use_ssl': dict(type='bool'),
- 'use_proxy': dict(type='bool', default=True),
- 'validate_certs': dict(type='bool'),
-
- 'timeout': dict(type='int'),
-
- 'transport': dict(type='str', default='cli', choices=['cli', 'nxapi'])
-}
-nxos_argument_spec = {
- 'provider': dict(type='dict', options=nxos_provider_spec, removed_in_version=2.14),
-}
-
-
-def get_provider_argspec():
- return nxos_provider_spec
-
-
-def get_connection(module):
- global _DEVICE_CONNECTION
- if not _DEVICE_CONNECTION:
- if is_local_nxapi(module):
- conn = LocalNxapi(module)
- else:
- connection_proxy = Connection(module._socket_path)
- cap = json.loads(connection_proxy.get_capabilities())
- if cap['network_api'] == 'cliconf':
- conn = Cli(module)
- elif cap['network_api'] == 'nxapi':
- conn = HttpApi(module)
- _DEVICE_CONNECTION = conn
- return _DEVICE_CONNECTION
-
-
-class Cli:
-
- def __init__(self, module):
- self._module = module
- self._device_configs = {}
- self._connection = None
-
- def _get_connection(self):
- if self._connection:
- return self._connection
- self._connection = Connection(self._module._socket_path)
-
- return self._connection
-
- def get_config(self, flags=None):
- """Retrieves the current config from the device or cache
- """
- flags = [] if flags is None else flags
-
- cmd = 'show running-config '
- cmd += ' '.join(flags)
- cmd = cmd.strip()
-
- try:
- return self._device_configs[cmd]
- except KeyError:
- connection = self._get_connection()
- try:
- out = connection.get_config(flags=flags)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- cfg = to_text(out, errors='surrogate_then_replace').strip() + '\n'
- self._device_configs[cmd] = cfg
- return cfg
-
- def run_commands(self, commands, check_rc=True):
- """Run list of commands on remote device and return results
- """
- connection = self._get_connection()
-
- try:
- out = connection.run_commands(commands, check_rc)
- if check_rc == 'retry_json':
- capabilities = self.get_capabilities()
- network_api = capabilities.get('network_api')
-
- if network_api == 'cliconf' and out:
- for index, resp in enumerate(out):
- if ('Invalid command at' in resp or 'Ambiguous command at' in resp) and 'json' in resp:
- if commands[index]['output'] == 'json':
- commands[index]['output'] = 'text'
- out = connection.run_commands(commands, check_rc)
- return out
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc))
-
- def load_config(self, config, return_error=False, opts=None, replace=None):
- """Sends configuration commands to the remote device
- """
- if opts is None:
- opts = {}
-
- connection = self._get_connection()
- responses = []
- try:
- resp = connection.edit_config(config, replace=replace)
- if isinstance(resp, Mapping):
- resp = resp['response']
- except ConnectionError as e:
- code = getattr(e, 'code', 1)
- message = getattr(e, 'err', e)
- err = to_text(message, errors='surrogate_then_replace')
- if opts.get('ignore_timeout') and code:
- responses.append(err)
- return responses
- elif code and 'no graceful-restart' in err:
- if 'ISSU/HA will be affected if Graceful Restart is disabled' in err:
- msg = ['']
- responses.extend(msg)
- return responses
- else:
- self._module.fail_json(msg=err)
- elif code:
- self._module.fail_json(msg=err)
-
- responses.extend(resp)
- return responses
-
- def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- conn = self._get_connection()
- try:
- response = conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path,
- diff_replace=diff_replace)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- return response
-
- def get_capabilities(self):
- """Returns platform info of the remove device
- """
- if hasattr(self._module, '_capabilities'):
- return self._module._capabilities
-
- connection = self._get_connection()
- try:
- capabilities = connection.get_capabilities()
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- self._module._capabilities = json.loads(capabilities)
- return self._module._capabilities
-
- def read_module_context(self, module_key):
- connection = self._get_connection()
- try:
- module_context = connection.read_module_context(module_key)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return module_context
-
- def save_module_context(self, module_key, module_context):
- connection = self._get_connection()
- try:
- connection.save_module_context(module_key, module_context)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return None
-
-
-class LocalNxapi:
-
- OUTPUT_TO_COMMAND_TYPE = {
- 'text': 'cli_show_ascii',
- 'json': 'cli_show',
- 'bash': 'bash',
- 'config': 'cli_conf'
- }
-
- def __init__(self, module):
- self._module = module
- self._nxapi_auth = None
- self._device_configs = {}
- self._module_context = {}
-
- provider = self._module.params.get("provider") or {}
- self._module.params['url_username'] = provider.get('username')
- self._module.params['url_password'] = provider.get('password')
-
- host = provider.get('host')
- port = provider.get('port')
-
- if provider.get('use_ssl'):
- proto = 'https'
- port = port or 443
- else:
- proto = 'http'
- port = port or 80
-
- self._url = '%s://%s:%s/ins' % (proto, host, port)
-
- def _error(self, msg, **kwargs):
- self._nxapi_auth = None
- if 'url' not in kwargs:
- kwargs['url'] = self._url
- self._module.fail_json(msg=msg, **kwargs)
-
- def _request_builder(self, commands, output, version='1.0', chunk='0', sid=None):
- """Encodes a NXAPI JSON request message
- """
- try:
- command_type = self.OUTPUT_TO_COMMAND_TYPE[output]
- except KeyError:
- msg = 'invalid format, received %s, expected one of %s' % \
- (output, ','.join(self.OUTPUT_TO_COMMAND_TYPE.keys()))
- self._error(msg=msg)
-
- if isinstance(commands, (list, set, tuple)):
- commands = ' ;'.join(commands)
-
- # Order should not matter but some versions of NX-OS software fail
- # to process the payload properly if 'input' gets serialized before
- # 'type' and the payload of 'input' contains the word 'type'.
- msg = collections.OrderedDict()
- msg['version'] = version
- msg['type'] = command_type
- msg['chunk'] = chunk
- msg['sid'] = sid
- msg['input'] = commands
- msg['output_format'] = 'json'
-
- return dict(ins_api=msg)
-
- def send_request(self, commands, output='text', check_status=True,
- return_error=False, opts=None):
- # only 10 show commands can be encoded in each request
- # messages sent to the remote device
- if opts is None:
- opts = {}
- if output != 'config':
- commands = collections.deque(to_list(commands))
- stack = list()
- requests = list()
-
- while commands:
- stack.append(commands.popleft())
- if len(stack) == 10:
- body = self._request_builder(stack, output)
- data = self._module.jsonify(body)
- requests.append(data)
- stack = list()
-
- if stack:
- body = self._request_builder(stack, output)
- data = self._module.jsonify(body)
- requests.append(data)
-
- else:
- body = self._request_builder(commands, 'config')
- requests = [self._module.jsonify(body)]
-
- headers = {'Content-Type': 'application/json'}
- result = list()
- timeout = self._module.params['provider']['timeout']
- use_proxy = self._module.params['provider']['use_proxy']
-
- for req in requests:
- if self._nxapi_auth:
- headers['Cookie'] = self._nxapi_auth
-
- response, headers = fetch_url(
- self._module, self._url, data=req, headers=headers,
- timeout=timeout, method='POST', use_proxy=use_proxy
- )
- self._nxapi_auth = headers.get('set-cookie')
-
- if opts.get('ignore_timeout') and re.search(r'(-1|5\d\d)', str(headers['status'])):
- result.append(headers['status'])
- return result
- elif headers['status'] != 200:
- self._error(**headers)
-
- try:
- response = self._module.from_json(response.read())
- except ValueError:
- self._module.fail_json(msg='unable to parse response')
-
- if response['ins_api'].get('outputs'):
- output = response['ins_api']['outputs']['output']
- for item in to_list(output):
- if check_status is True and item['code'] != '200':
- if return_error:
- result.append(item)
- else:
- self._error(output=output, **item)
- elif 'body' in item:
- result.append(item['body'])
- # else:
- # error in command but since check_status is disabled
- # silently drop it.
- # result.append(item['msg'])
-
- return result
-
- def get_config(self, flags=None):
- """Retrieves the current config from the device or cache
- """
- flags = [] if flags is None else flags
-
- cmd = 'show running-config '
- cmd += ' '.join(flags)
- cmd = cmd.strip()
-
- try:
- return self._device_configs[cmd]
- except KeyError:
- out = self.send_request(cmd)
- cfg = str(out[0]).strip()
- self._device_configs[cmd] = cfg
- return cfg
-
- def run_commands(self, commands, check_rc=True):
- """Run list of commands on remote device and return results
- """
- output = None
- queue = list()
- responses = list()
-
- def _send(commands, output):
- return self.send_request(commands, output, check_status=check_rc)
-
- for item in to_list(commands):
- if is_json(item['command']):
- item['command'] = str(item['command']).rsplit('|', 1)[0]
- item['output'] = 'json'
-
- if all((output == 'json', item['output'] == 'text')) or all((output == 'text', item['output'] == 'json')):
- responses.extend(_send(queue, output))
- queue = list()
-
- output = item['output'] or 'json'
- queue.append(item['command'])
-
- if queue:
- responses.extend(_send(queue, output))
-
- return responses
-
- def load_config(self, commands, return_error=False, opts=None, replace=None):
- """Sends the ordered set of commands to the device
- """
-
- if opts is None:
- opts = {}
-
- responses = []
-
- if replace:
- device_info = self.get_device_info()
- if '9K' not in device_info.get('network_os_platform', ''):
- self._module.fail_json(msg='replace is supported only on Nexus 9K devices')
- commands = 'config replace {0}'.format(replace)
-
- commands = to_list(commands)
- try:
- resp = self.send_request(commands, output='config', check_status=True,
- return_error=return_error, opts=opts)
- except ValueError as exc:
- code = getattr(exc, 'code', 1)
- message = getattr(exc, 'err', exc)
- err = to_text(message, errors='surrogate_then_replace')
- if opts.get('ignore_timeout') and code:
- responses.append(code)
- return responses
- elif code and 'no graceful-restart' in err:
- if 'ISSU/HA will be affected if Graceful Restart is disabled' in err:
- msg = ['']
- responses.extend(msg)
- return responses
- else:
- self._module.fail_json(msg=err)
- elif code:
- self._module.fail_json(msg=err)
-
- if return_error:
- return resp
- else:
- return responses.extend(resp)
-
- def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- diff = {}
-
- # prepare candidate configuration
- candidate_obj = NetworkConfig(indent=2)
- candidate_obj.load(candidate)
-
- if running and diff_match != 'none' and diff_replace != 'config':
- # running configuration
- running_obj = NetworkConfig(indent=2, contents=running, ignore_lines=diff_ignore_lines)
- configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace)
-
- else:
- configdiffobjs = candidate_obj.items
-
- diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
- return diff
-
- def get_device_info(self):
- device_info = {}
-
- device_info['network_os'] = 'nxos'
- reply = self.run_commands({'command': 'show version', 'output': 'json'})
- data = reply[0]
-
- platform_reply = self.run_commands({'command': 'show inventory', 'output': 'json'})
- platform_info = platform_reply[0]
-
- device_info['network_os_version'] = data.get('sys_ver_str') or data.get('kickstart_ver_str')
- device_info['network_os_model'] = data['chassis_id']
- device_info['network_os_hostname'] = data['host_name']
- device_info['network_os_image'] = data.get('isan_file_name') or data.get('kick_file_name')
-
- if platform_info:
- inventory_table = platform_info['TABLE_inv']['ROW_inv']
- for info in inventory_table:
- if 'Chassis' in info['name']:
- device_info['network_os_platform'] = info['productid']
-
- return device_info
-
- def get_capabilities(self):
- result = {}
- result['device_info'] = self.get_device_info()
- result['network_api'] = 'nxapi'
- return result
-
- def read_module_context(self, module_key):
- if self._module_context.get(module_key):
- return self._module_context[module_key]
-
- return None
-
- def save_module_context(self, module_key, module_context):
- self._module_context[module_key] = module_context
-
- return None
-
-
-class HttpApi:
- def __init__(self, module):
- self._module = module
- self._device_configs = {}
- self._module_context = {}
- self._connection_obj = None
-
- @property
- def _connection(self):
- if not self._connection_obj:
- self._connection_obj = Connection(self._module._socket_path)
-
- return self._connection_obj
-
- def run_commands(self, commands, check_rc=True):
- """Runs list of commands on remote device and returns results
- """
- try:
- out = self._connection.send_request(commands)
- except ConnectionError as exc:
- if check_rc is True:
- raise
- out = to_text(exc)
-
- out = to_list(out)
- if not out[0]:
- return out
-
- for index, response in enumerate(out):
- if response[0] == '{':
- out[index] = json.loads(response)
-
- return out
-
- def get_config(self, flags=None):
- """Retrieves the current config from the device or cache
- """
- flags = [] if flags is None else flags
-
- cmd = 'show running-config '
- cmd += ' '.join(flags)
- cmd = cmd.strip()
-
- try:
- return self._device_configs[cmd]
- except KeyError:
- try:
- out = self._connection.send_request(cmd)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- cfg = to_text(out).strip()
- self._device_configs[cmd] = cfg
- return cfg
-
- def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- diff = {}
-
- # prepare candidate configuration
- candidate_obj = NetworkConfig(indent=2)
- candidate_obj.load(candidate)
-
- if running and diff_match != 'none' and diff_replace != 'config':
- # running configuration
- running_obj = NetworkConfig(indent=2, contents=running, ignore_lines=diff_ignore_lines)
- configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace)
-
- else:
- configdiffobjs = candidate_obj.items
-
- diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
- return diff
-
- def load_config(self, commands, return_error=False, opts=None, replace=None):
- """Sends the ordered set of commands to the device
- """
- if opts is None:
- opts = {}
-
- responses = []
- try:
- resp = self.edit_config(commands, replace=replace)
- except ConnectionError as exc:
- code = getattr(exc, 'code', 1)
- message = getattr(exc, 'err', exc)
- err = to_text(message, errors='surrogate_then_replace')
- if opts.get('ignore_timeout') and code:
- responses.append(code)
- return responses
- elif opts.get('catch_clierror') and '400' in code:
- return [code, err]
- elif code and 'no graceful-restart' in err:
- if 'ISSU/HA will be affected if Graceful Restart is disabled' in err:
- msg = ['']
- responses.extend(msg)
- return responses
- else:
- self._module.fail_json(msg=err)
- elif code:
- self._module.fail_json(msg=err)
-
- responses.extend(resp)
- return responses
-
- def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
- resp = list()
-
- self.check_edit_config_capability(candidate, commit, replace, comment)
-
- if replace:
- candidate = 'config replace {0}'.format(replace)
-
- responses = self._connection.send_request(candidate, output='config')
- for response in to_list(responses):
- if response != '{}':
- resp.append(response)
- if not resp:
- resp = ['']
-
- return resp
-
- def get_capabilities(self):
- """Returns platform info of the remove device
- """
- try:
- capabilities = self._connection.get_capabilities()
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return json.loads(capabilities)
-
- def check_edit_config_capability(self, candidate=None, commit=True, replace=None, comment=None):
- operations = self._connection.get_device_operations()
-
- if not candidate and not replace:
- raise ValueError("must provide a candidate or replace to load configuration")
-
- if commit not in (True, False):
- raise ValueError("'commit' must be a bool, got %s" % commit)
-
- if replace and not operations.get('supports_replace'):
- raise ValueError("configuration replace is not supported")
-
- if comment and not operations.get('supports_commit_comment', False):
- raise ValueError("commit comment is not supported")
-
- def read_module_context(self, module_key):
- try:
- module_context = self._connection.read_module_context(module_key)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return module_context
-
- def save_module_context(self, module_key, module_context):
- try:
- self._connection.save_module_context(module_key, module_context)
- except ConnectionError as exc:
- self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- return None
-
-
-class NxosCmdRef:
- """NXOS Command Reference utilities.
- The NxosCmdRef class takes a yaml-formatted string of nxos module commands
- and converts it into dict-formatted database of getters/setters/defaults
- and associated common and platform-specific values. The utility methods
- add additional data such as existing states, playbook states, and proposed cli.
- The utilities also abstract away platform differences such as different
- defaults and different command syntax.
-
- Callers must provide a yaml formatted string that defines each command and
- its properties; e.g. BFD global:
- ---
- _template: # _template holds common settings for all commands
- # Enable feature bfd if disabled
- feature: bfd
- # Common getter syntax for BFD commands
- get_command: show run bfd all | incl '^(no )*bfd'
-
- interval:
- kind: dict
- getval: bfd interval (?P<tx>\\d+) min_rx (?P<min_rx>\\d+) multiplier (?P<multiplier>\\d+)
- setval: bfd interval {tx} min_rx {min_rx} multiplier {multiplier}
- default:
- tx: 50
- min_rx: 50
- multiplier: 3
- N3K:
- # Platform overrides
- default:
- tx: 250
- min_rx: 250
- multiplier: 3
- """
-
- def __init__(self, module, cmd_ref_str, ref_only=False):
- """Initialize cmd_ref from yaml data."""
-
- self._module = module
- self._check_imports()
- self._yaml_load(cmd_ref_str)
- self.cache_existing = None
- self.present_states = ['present', 'merged', 'replaced']
- self.absent_states = ['absent', 'deleted']
- ref = self._ref
-
- # Create a list of supported commands based on ref keys
- ref['commands'] = sorted([k for k in ref if not k.startswith('_')])
- ref['_proposed'] = []
- ref['_context'] = []
- ref['_resource_key'] = None
-
- if not ref_only:
- ref['_state'] = module.params.get('state', 'present')
- self.feature_enable()
- self.get_platform_defaults()
- self.normalize_defaults()
-
- def __getitem__(self, key=None):
- if key is None:
- return self._ref
- return self._ref[key]
-
- def _check_imports(self):
- module = self._module
- msg = nxosCmdRef_import_check()
- if msg:
- module.fail_json(msg=msg)
-
- def _yaml_load(self, cmd_ref_str):
- if PY2:
- self._ref = yaml.load(cmd_ref_str)
- elif PY3:
- self._ref = yaml.load(cmd_ref_str, Loader=yaml.FullLoader)
-
- def feature_enable(self):
- """Add 'feature <foo>' to _proposed if ref includes a 'feature' key. """
- ref = self._ref
- feature = ref['_template'].get('feature')
- if feature:
- show_cmd = "show run | incl 'feature {0}'".format(feature)
- output = self.execute_show_command(show_cmd, 'text')
- if not output or 'CLI command error' in output:
- msg = "** 'feature {0}' is not enabled. Module will auto-enable feature {0} ** ".format(feature)
- self._module.warn(msg)
- ref['_proposed'].append('feature {0}'.format(feature))
- ref['_cli_is_feature_disabled'] = ref['_proposed']
-
- def get_platform_shortname(self):
- """Query device for platform type, normalize to a shortname/nickname.
- Returns platform shortname (e.g. 'N3K-3058P' returns 'N3K') or None.
- """
- # TBD: add this method logic to get_capabilities() after those methods
- # are made consistent across transports
- platform_info = self.execute_show_command('show inventory', 'json')
- if not platform_info or not isinstance(platform_info, dict):
- return None
- inventory_table = platform_info['TABLE_inv']['ROW_inv']
- for info in inventory_table:
- if 'Chassis' in info['name']:
- network_os_platform = info['productid']
- break
- else:
- return None
-
- # Supported Platforms: N3K,N5K,N6K,N7K,N9K,N3K-F,N9K-F
- m = re.match('(?P<short>N[35679][K57])-(?P<N35>C35)*', network_os_platform)
- if not m:
- return None
- shortname = m.group('short')
-
- # Normalize
- if m.groupdict().get('N35'):
- shortname = 'N35'
- elif re.match('N77', shortname):
- shortname = 'N7K'
- elif re.match(r'N3K|N9K', shortname):
- for info in inventory_table:
- if '-R' in info['productid']:
- # Fretta Platform
- shortname += '-F'
- break
- return shortname
-
- def get_platform_defaults(self):
- """Update ref with platform specific defaults"""
- plat = self.get_platform_shortname()
- if not plat:
- return
-
- ref = self._ref
- ref['_platform_shortname'] = plat
- # Remove excluded commands (no platform support for command)
- for k in ref['commands']:
- if plat in ref[k].get('_exclude', ''):
- ref['commands'].remove(k)
-
- # Update platform-specific settings for each item in ref
- plat_spec_cmds = [k for k in ref['commands'] if plat in ref[k]]
- for k in plat_spec_cmds:
- for plat_key in ref[k][plat]:
- ref[k][plat_key] = ref[k][plat][plat_key]
-
- def normalize_defaults(self):
- """Update ref defaults with normalized data"""
- ref = self._ref
- for k in ref['commands']:
- if 'default' in ref[k] and ref[k]['default']:
- kind = ref[k]['kind']
- if 'int' == kind:
- ref[k]['default'] = int(ref[k]['default'])
- elif 'list' == kind:
- ref[k]['default'] = [str(i) for i in ref[k]['default']]
- elif 'dict' == kind:
- for key, v in ref[k]['default'].items():
- if v:
- v = str(v)
- ref[k]['default'][key] = v
-
- def execute_show_command(self, command, format):
- """Generic show command helper.
- Warning: 'CLI command error' exceptions are caught, must be handled by caller.
- Return device output as a newline-separated string or None.
- """
- cmds = [{
- 'command': command,
- 'output': format,
- }]
- output = None
- try:
- output = run_commands(self._module, cmds)
- if output:
- output = output[0]
- except ConnectionError as exc:
- if 'CLI command error' in repr(exc):
- # CLI may be feature disabled
- output = repr(exc)
- else:
- raise
- return output
-
- def pattern_match_existing(self, output, k):
- """Pattern matching helper for `get_existing`.
- `k` is the command name string. Use the pattern from cmd_ref to
- find a matching string in the output.
- Return regex match object or None.
- """
- ref = self._ref
- pattern = re.compile(ref[k]['getval'])
- multiple = 'multiple' in ref[k].keys()
- match_lines = [re.search(pattern, line) for line in output]
- if 'dict' == ref[k]['kind']:
- match = [m for m in match_lines if m]
- if not match:
- return None
- if len(match) > 1 and not multiple:
- raise ValueError("get_existing: multiple matches found for property {0}".format(k))
- else:
- match = [m.groups() for m in match_lines if m]
- if not match:
- return None
- if len(match) > 1 and not multiple:
- raise ValueError("get_existing: multiple matches found for property {0}".format(k))
- for item in match:
- index = match.index(item)
- match[index] = list(item) # tuple to list
-
- # Handle config strings that nvgen with the 'no' prefix.
- # Example match behavior:
- # When pattern is: '(no )*foo *(\S+)*$' AND
- # When output is: 'no foo' -> match: ['no ', None]
- # When output is: 'foo 50' -> match: [None, '50']
- if None is match[index][0]:
- match[index].pop(0)
- elif 'no' in match[index][0]:
- match[index].pop(0)
- if not match:
- return None
-
- return match
-
- def set_context(self, context=None):
- """Update ref with command context.
- """
- if context is None:
- context = []
- ref = self._ref
- # Process any additional context that this propoerty might require.
- # 1) Global context from NxosCmdRef _template.
- # 2) Context passed in using context arg.
- ref['_context'] = ref['_template'].get('context', [])
- for cmd in context:
- ref['_context'].append(cmd)
- # Last key in context is the resource key
- ref['_resource_key'] = context[-1] if context else ref['_resource_key']
-
- def get_existing(self, cache_output=None):
- """Update ref with existing command states from the device.
- Store these states in each command's 'existing' key.
- """
- ref = self._ref
- if ref.get('_cli_is_feature_disabled'):
- # Add context to proposed if state is present
- if ref['_state'] in self.present_states:
- [ref['_proposed'].append(ctx) for ctx in ref['_context']]
- return
-
- show_cmd = ref['_template']['get_command']
- if cache_output:
- output = cache_output
- else:
- output = self.execute_show_command(show_cmd, 'text') or []
- self.cache_existing = output
-
- # Add additional command context if needed.
- if ref['_context']:
- output = CustomNetworkConfig(indent=2, contents=output)
- output = output.get_section(ref['_context'])
-
- if not output:
- # Add context to proposed if state is present
- if ref['_state'] in self.present_states:
- [ref['_proposed'].append(ctx) for ctx in ref['_context']]
- return
-
- # We need to remove the last item in context for state absent case.
- if ref['_state'] in self.absent_states and ref['_context']:
- if ref['_resource_key'] and ref['_resource_key'] == ref['_context'][-1]:
- if ref['_context'][-1] in output:
- ref['_context'][-1] = 'no ' + ref['_context'][-1]
- else:
- del ref['_context'][-1]
- return
-
- # Walk each cmd in ref, use cmd pattern to discover existing cmds
- output = output.split('\n')
- for k in ref['commands']:
- match = self.pattern_match_existing(output, k)
- if not match:
- continue
- ref[k]['existing'] = {}
- for item in match:
- index = match.index(item)
- kind = ref[k]['kind']
- if 'int' == kind:
- ref[k]['existing'][index] = int(item[0])
- elif 'list' == kind:
- ref[k]['existing'][index] = [str(i) for i in item[0]]
- elif 'dict' == kind:
- # The getval pattern should contain regex named group keys that
- # match up with the setval named placeholder keys; e.g.
- # getval: my-cmd (?P<foo>\d+) bar (?P<baz>\d+)
- # setval: my-cmd {foo} bar {baz}
- ref[k]['existing'][index] = {}
- for key in item.groupdict().keys():
- ref[k]['existing'][index][key] = str(item.group(key))
- elif 'str' == kind:
- ref[k]['existing'][index] = item[0]
- else:
- raise ValueError("get_existing: unknown 'kind' value specified for key '{0}'".format(k))
-
- def get_playvals(self):
- """Update ref with values from the playbook.
- Store these values in each command's 'playval' key.
- """
- ref = self._ref
- module = self._module
- params = {}
- if module.params.get('config'):
- # Resource module builder packs playvals under 'config' key
- param_data = module.params.get('config')
- params['global'] = param_data
- for key in param_data.keys():
- if isinstance(param_data[key], list):
- params[key] = param_data[key]
- else:
- params['global'] = module.params
- for k in ref.keys():
- for level in params.keys():
- if isinstance(params[level], dict):
- params[level] = [params[level]]
- for item in params[level]:
- if k in item and item[k] is not None:
- if not ref[k].get('playval'):
- ref[k]['playval'] = {}
- playval = item[k]
- index = params[level].index(item)
- # Normalize each value
- if 'int' == ref[k]['kind']:
- playval = int(playval)
- elif 'list' == ref[k]['kind']:
- playval = [str(i) for i in playval]
- elif 'dict' == ref[k]['kind']:
- for key, v in playval.items():
- playval[key] = str(v)
- ref[k]['playval'][index] = playval
-
- def build_cmd_set(self, playval, existing, k):
- """Helper function to create list of commands to configure device
- Return a list of commands
- """
- ref = self._ref
- proposed = ref['_proposed']
- cmd = None
- kind = ref[k]['kind']
- if 'int' == kind:
- cmd = ref[k]['setval'].format(playval)
- elif 'list' == kind:
- cmd = ref[k]['setval'].format(*(playval))
- elif 'dict' == kind:
- # The setval pattern should contain placeholder keys that
- # match up with the getval regex named group keys; e.g.
- # getval: my-cmd (?P<foo>\d+) bar (?P<baz>\d+)
- # setval: my-cmd {foo} bar {baz}
- cmd = ref[k]['setval'].format(**playval)
- elif 'str' == kind:
- if 'deleted' in playval:
- if existing:
- cmd = 'no ' + ref[k]['setval'].format(existing)
- else:
- cmd = ref[k]['setval'].format(playval)
- else:
- raise ValueError("get_proposed: unknown 'kind' value specified for key '{0}'".format(k))
- if cmd:
- if ref['_state'] in self.absent_states and not re.search(r'^no', cmd):
- cmd = 'no ' + cmd
- # Commands may require parent commands for proper context.
- # Global _template context is replaced by parameter context
- [proposed.append(ctx) for ctx in ref['_context']]
- [proposed.append(ctx) for ctx in ref[k].get('context', [])]
- proposed.append(cmd)
-
- def get_proposed(self):
- """Compare playbook values against existing states and create a list
- of proposed commands.
- Return a list of raw cli command strings.
- """
- ref = self._ref
- # '_proposed' may be empty list or contain initializations; e.g. ['feature foo']
- proposed = ref['_proposed']
-
- if ref['_context'] and ref['_context'][-1].startswith('no'):
- [proposed.append(ctx) for ctx in ref['_context']]
- return proposed
-
- # Create a list of commands that have playbook values
- play_keys = [k for k in ref['commands'] if 'playval' in ref[k]]
-
- def compare(playval, existing):
- if ref['_state'] in self.present_states:
- if existing is None:
- return False
- elif playval == existing:
- return True
- elif isinstance(existing, dict) and playval in existing.values():
- return True
-
- if ref['_state'] in self.absent_states:
- if isinstance(existing, dict) and all(x is None for x in existing.values()):
- existing = None
- if existing is None or playval not in existing.values():
- return True
- return False
-
- # Compare against current state
- for k in play_keys:
- playval = ref[k]['playval']
- # Create playval copy to avoid RuntimeError
- # dictionary changed size during iteration error
- playval_copy = deepcopy(playval)
- existing = ref[k].get('existing', ref[k]['default'])
- multiple = 'multiple' in ref[k].keys()
-
- # Multiple Instances:
- if isinstance(existing, dict) and multiple:
- for ekey, evalue in existing.items():
- if isinstance(evalue, dict):
- # Remove values set to string 'None' from dvalue
- evalue = dict((k, v) for k, v in evalue.items() if v != 'None')
- for pkey, pvalue in playval.items():
- if compare(pvalue, evalue):
- if playval_copy.get(pkey):
- del playval_copy[pkey]
- if not playval_copy:
- continue
- # Single Instance:
- else:
- for pkey, pval in playval.items():
- if compare(pval, existing):
- if playval_copy.get(pkey):
- del playval_copy[pkey]
- if not playval_copy:
- continue
-
- playval = playval_copy
- # Multiple Instances:
- if isinstance(existing, dict):
- for dkey, dvalue in existing.items():
- for pval in playval.values():
- self.build_cmd_set(pval, dvalue, k)
- # Single Instance:
- else:
- for pval in playval.values():
- self.build_cmd_set(pval, existing, k)
-
- # Remove any duplicate commands before returning.
- # pylint: disable=unnecessary-lambda
- cmds = sorted(set(proposed), key=lambda x: proposed.index(x))
- return cmds
-
-
-def nxosCmdRef_import_check():
- """Return import error messages or empty string"""
- msg = ''
- if PY2:
- if not HAS_ORDEREDDICT and sys.version_info[:2] < (2, 7):
- msg += "Mandatory python library 'ordereddict' is not present, try 'pip install ordereddict'\n"
- if not HAS_YAML:
- msg += "Mandatory python library 'yaml' is not present, try 'pip install yaml'\n"
- elif PY3:
- if not HAS_YAML:
- msg += "Mandatory python library 'PyYAML' is not present, try 'pip install PyYAML'\n"
- return msg
-
-
-def is_json(cmd):
- return to_text(cmd).endswith('| json')
-
-
-def is_text(cmd):
- return not is_json(cmd)
-
-
-def is_local_nxapi(module):
- provider = module.params.get('provider')
- if provider:
- return provider.get("transport") == 'nxapi'
- return False
-
-
-def to_command(module, commands):
- if is_local_nxapi(module):
- default_output = 'json'
- else:
- default_output = 'text'
-
- transform = ComplexList(dict(
- command=dict(key=True),
- output=dict(default=default_output),
- prompt=dict(type='list'),
- answer=dict(type='list'),
- newline=dict(type='bool', default=True),
- sendonly=dict(type='bool', default=False),
- check_all=dict(type='bool', default=False),
- ), module)
-
- commands = transform(to_list(commands))
-
- for item in commands:
- if is_json(item['command']):
- item['output'] = 'json'
-
- return commands
-
-
-def get_config(module, flags=None):
- flags = [] if flags is None else flags
-
- conn = get_connection(module)
- return conn.get_config(flags=flags)
-
-
-def run_commands(module, commands, check_rc=True):
- conn = get_connection(module)
- return conn.run_commands(to_command(module, commands), check_rc)
-
-
-def load_config(module, config, return_error=False, opts=None, replace=None):
- conn = get_connection(module)
- return conn.load_config(config, return_error, opts, replace=replace)
-
-
-def get_capabilities(module):
- conn = get_connection(module)
- return conn.get_capabilities()
-
-
-def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- conn = self.get_connection()
- return conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path, diff_replace=diff_replace)
-
-
-def 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('et'):
- if_type = 'Ethernet'
- elif name.lower().startswith('vl'):
- if_type = 'Vlan'
- elif name.lower().startswith('lo'):
- if_type = 'loopback'
- elif name.lower().startswith('po'):
- if_type = 'port-channel'
- elif name.lower().startswith('nv'):
- if_type = 'nve'
- 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('ET'):
- return 'ethernet'
- elif interface.upper().startswith('VL'):
- return 'svi'
- elif interface.upper().startswith('LO'):
- return 'loopback'
- elif interface.upper().startswith('MG'):
- return 'management'
- elif interface.upper().startswith('MA'):
- return 'management'
- elif interface.upper().startswith('PO'):
- return 'portchannel'
- elif interface.upper().startswith('NV'):
- return 'nve'
- else:
- return 'unknown'
-
-
-def default_intf_enabled(name='', sysdefs=None, mode=None):
- """Get device/version/interface-specific default 'enabled' state.
- L3:
- - Most L3 intfs default to 'shutdown'. Loopbacks default to 'no shutdown'.
- - Some legacy platforms default L3 intfs to 'no shutdown'.
- L2:
- - User-System-Default 'system default switchport shutdown' defines the
- enabled state for L2 intf's. USD defaults may be different on some platforms.
- - An intf may be explicitly defined as L2 with 'switchport' or it may be
- implicitly defined as L2 when USD 'system default switchport' is defined.
- """
- if not name:
- return None
- if sysdefs is None:
- sysdefs = {}
- default = False
-
- if re.search('port-channel|loopback', name):
- default = True
- else:
- if mode is None:
- # intf 'switchport' cli is not present so use the user-system-default
- mode = sysdefs.get('mode')
-
- if mode == 'layer3':
- default = sysdefs.get('L3_enabled')
- elif mode == 'layer2':
- default = sysdefs.get('L2_enabled')
- return default
-
-
-def read_module_context(module):
- conn = get_connection(module)
- return conn.read_module_context(module._name)
-
-
-def save_module_context(module, module_context):
- conn = get_connection(module)
- return conn.save_module_context(module._name, module_context)
diff --git a/lib/ansible/module_utils/network/nxos/utils/telemetry/telemetry.py b/lib/ansible/module_utils/network/nxos/utils/telemetry/telemetry.py
deleted file mode 100644
index 597adb5674..0000000000
--- a/lib/ansible/module_utils/network/nxos/utils/telemetry/telemetry.py
+++ /dev/null
@@ -1,250 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Cisco and/or its affiliates.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The nxos telemetry utility library
-"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import re
-from copy import deepcopy
-
-
-def get_module_params_subsection(module_params, tms_config, resource_key=None):
- """
- Helper method to get a specific module_params subsection
- """
- mp = {}
- if tms_config == 'TMS_GLOBAL':
- relevant_keys = ['certificate',
- 'compression',
- 'source_interface',
- 'vrf']
- for key in relevant_keys:
- mp[key] = module_params[key]
-
- if tms_config == 'TMS_DESTGROUP':
- mp['destination_groups'] = []
- for destgrp in module_params['destination_groups']:
- if destgrp['id'] == resource_key:
- mp['destination_groups'].append(destgrp)
-
- if tms_config == 'TMS_SENSORGROUP':
- mp['sensor_groups'] = []
- for sensor in module_params['sensor_groups']:
- if sensor['id'] == resource_key:
- mp['sensor_groups'].append(sensor)
-
- if tms_config == 'TMS_SUBSCRIPTION':
- mp['subscriptions'] = []
- for sensor in module_params['subscriptions']:
- if sensor['id'] == resource_key:
- mp['subscriptions'].append(sensor)
-
- return mp
-
-
-def valiate_input(playvals, type, module):
- """
- Helper method to validate playbook values for destination groups
- """
- if type == 'destination_groups':
- if not playvals.get('id'):
- msg = "Invalid playbook value: {0}.".format(playvals)
- msg += " Parameter <id> under <destination_groups> is required"
- module.fail_json(msg=msg)
- if playvals.get('destination') and not isinstance(playvals['destination'], dict):
- msg = "Invalid playbook value: {0}.".format(playvals)
- msg += " Parameter <destination> under <destination_groups> must be a dict"
- module.fail_json(msg=msg)
- if not playvals.get('destination') and len(playvals) > 1:
- msg = "Invalid playbook value: {0}.".format(playvals)
- msg += " Playbook entry contains unrecongnized parameters."
- msg += " Make sure <destination> keys under <destination_groups> are specified as follows:"
- msg += " destination: {ip: <ip>, port: <port>, protocol: <prot>, encoding: <enc>}}"
- module.fail_json(msg=msg)
-
- if type == 'sensor_groups':
- if not playvals.get('id'):
- msg = "Invalid playbook value: {0}.".format(playvals)
- msg += " Parameter <id> under <sensor_groups> is required"
- module.fail_json(msg=msg)
- if playvals.get('path') and 'name' not in playvals['path'].keys():
- msg = "Invalid playbook value: {0}.".format(playvals)
- msg += " Parameter <path> under <sensor_groups> requires <name> key"
- module.fail_json(msg=msg)
-
-
-def get_instance_data(key, cr_key, cr, existing_key):
- """
- Helper method to get instance data used to populate list structure in config
- fact dictionary
- """
- data = {}
- if existing_key is None:
- instance = None
- else:
- instance = cr._ref[cr_key]['existing'][existing_key]
-
- patterns = {
- 'destination_groups': r"destination-group (\d+)",
- 'sensor_groups': r"sensor-group (\d+)",
- 'subscriptions': r"subscription (\d+)",
- }
- if key in patterns.keys():
- m = re.search(patterns[key], cr._ref['_resource_key'])
- instance_key = m.group(1)
- data = {'id': instance_key, cr_key: instance}
-
- # Remove None values
- data = dict((k, v) for k, v in data.items() if v is not None)
- return data
-
-
-def cr_key_lookup(key, mo):
- """
- Helper method to get instance key value for Managed Object (mo)
- """
- cr_keys = [key]
- if key == 'destination_groups' and mo == 'TMS_DESTGROUP':
- cr_keys = ['destination']
- elif key == 'sensor_groups' and mo == 'TMS_SENSORGROUP':
- cr_keys = ['data_source', 'path']
- elif key == 'subscriptions' and mo == 'TMS_SUBSCRIPTION':
- cr_keys = ['destination_group', 'sensor_group']
-
- return cr_keys
-
-
-def normalize_data(cmd_ref):
- ''' Normalize playbook values and get_exisiting data '''
-
- playval = cmd_ref._ref.get('destination').get('playval')
- existing = cmd_ref._ref.get('destination').get('existing')
-
- dest_props = ['protocol', 'encoding']
- if playval:
- for prop in dest_props:
- for key in playval.keys():
- playval[key][prop] = playval[key][prop].lower()
- if existing:
- for key in existing.keys():
- for prop in dest_props:
- existing[key][prop] = existing[key][prop].lower()
-
-
-def remove_duplicate_context(cmds):
- ''' Helper method to remove duplicate telemetry context commands '''
- if not cmds:
- return cmds
- feature_indices = [i for i, x in enumerate(cmds) if x == "feature telemetry"]
- telemetry_indices = [i for i, x in enumerate(cmds) if x == "telemetry"]
- if len(feature_indices) == 1 and len(telemetry_indices) == 1:
- return cmds
- if len(feature_indices) == 1 and not telemetry_indices:
- return cmds
- if len(telemetry_indices) == 1 and not feature_indices:
- return cmds
- if feature_indices and feature_indices[-1] > 1:
- cmds.pop(feature_indices[-1])
- return remove_duplicate_context(cmds)
- if telemetry_indices and telemetry_indices[-1] > 1:
- cmds.pop(telemetry_indices[-1])
- return remove_duplicate_context(cmds)
-
-
-def get_setval_path(module_or_path_data):
- ''' Build setval for path parameter based on playbook inputs
- Full Command:
- - path {name} depth {depth} query-condition {query_condition} filter-condition {filter_condition}
- Required:
- - path {name}
- Optional:
- - depth {depth}
- - query-condition {query_condition},
- - filter-condition {filter_condition}
- '''
- if isinstance(module_or_path_data, dict):
- path = module_or_path_data
- else:
- path = module_or_path_data.params['config']['sensor_groups'][0].get('path')
- if path is None:
- return path
-
- setval = 'path {name}'
- if 'depth' in path.keys():
- if path.get('depth') != 'None':
- setval = setval + ' depth {depth}'
- if 'query_condition' in path.keys():
- if path.get('query_condition') != 'None':
- setval = setval + ' query-condition {query_condition}'
- if 'filter_condition' in path.keys():
- if path.get('filter_condition') != 'None':
- setval = setval + ' filter-condition {filter_condition}'
-
- return setval
-
-
-def remove_duplicate_commands(commands_list):
- # Remove any duplicate commands.
- # pylint: disable=unnecessary-lambda
- return sorted(set(commands_list), key=lambda x: commands_list.index(x))
-
-
-def massage_data(have_or_want):
- # Massage non global into a data structure that is indexed by id and
- # normalized for destination_groups, sensor_groups and subscriptions.
- data = deepcopy(have_or_want)
- massaged = {}
- massaged['destination_groups'] = {}
- massaged['sensor_groups'] = {}
- massaged['subscriptions'] = {}
- from pprint import pprint
- for subgroup in ['destination_groups', 'sensor_groups', 'subscriptions']:
- for item in data.get(subgroup, []):
- id = str(item.get('id'))
- if id not in massaged[subgroup].keys():
- massaged[subgroup][id] = []
- item.pop('id')
- if not item:
- item = None
- else:
- if item.get('destination'):
- if item.get('destination').get('port'):
- item['destination']['port'] = str(item['destination']['port'])
- if item.get('destination').get('protocol'):
- item['destination']['protocol'] = item['destination']['protocol'].lower()
- if item.get('destination').get('encoding'):
- item['destination']['encoding'] = item['destination']['encoding'].lower()
- if item.get('path'):
- for key in ['filter_condition', 'query_condition', 'depth']:
- if item.get('path').get(key) == 'None':
- del item['path'][key]
- if item.get('path').get('depth') is not None:
- item['path']['depth'] = str(item['path']['depth'])
- if item.get('destination_group'):
- item['destination_group'] = str(item['destination_group'])
- if item.get('sensor_group'):
- if item.get('sensor_group').get('id'):
- item['sensor_group']['id'] = str(item['sensor_group']['id'])
- if item.get('sensor_group').get('sample_interval'):
- item['sensor_group']['sample_interval'] = str(item['sensor_group']['sample_interval'])
- if item.get('destination_group') and item.get('sensor_group'):
- item_copy = deepcopy(item)
- del item_copy['sensor_group']
- del item['destination_group']
- massaged[subgroup][id].append(item_copy)
- massaged[subgroup][id].append(item)
- continue
- if item.get('path') and item.get('data_source'):
- item_copy = deepcopy(item)
- del item_copy['data_source']
- del item['path']
- massaged[subgroup][id].append(item_copy)
- massaged[subgroup][id].append(item)
- continue
- massaged[subgroup][id].append(item)
- return massaged
diff --git a/lib/ansible/module_utils/network/nxos/utils/utils.py b/lib/ansible/module_utils/network/nxos/utils/utils.py
deleted file mode 100644
index 9564758cb7..0000000000
--- a/lib/ansible/module_utils/network/nxos/utils/utils.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import socket
-
-from ansible.module_utils.six import iteritems
-
-
-def search_obj_in_list(name, lst, identifier):
- for o in lst:
- if o[identifier] == name:
- return o
- return None
-
-
-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 validate_ipv4_addr(address):
- address = address.split('/')[0]
- try:
- socket.inet_aton(address)
- except socket.error:
- return False
- return address.count('.') == 3
-
-
-def validate_ipv6_addr(address):
- address = address.split('/')[0]
- try:
- socket.inet_pton(socket.AF_INET6, address)
- except socket.error:
- return False
- return True
-
-
-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('et'):
- if_type = 'Ethernet'
- elif name.lower().startswith('vl'):
- if_type = 'Vlan'
- elif name.lower().startswith('lo'):
- if_type = 'loopback'
- elif name.lower().startswith('po'):
- if_type = 'port-channel'
- elif name.lower().startswith('nv'):
- if_type = 'nve'
- 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('ET'):
- return 'ethernet'
- elif interface.upper().startswith('VL'):
- return 'svi'
- elif interface.upper().startswith('LO'):
- return 'loopback'
- elif interface.upper().startswith('MG'):
- return 'management'
- elif interface.upper().startswith('MA'):
- return 'management'
- elif interface.upper().startswith('PO'):
- return 'portchannel'
- elif interface.upper().startswith('NV'):
- return 'nve'
- else:
- return 'unknown'
-
-
-def remove_rsvd_interfaces(interfaces):
- """Exclude reserved interfaces from user management
- """
- return [i for i in interfaces if get_interface_type(i['name']) != 'management']
-
-
-def vlan_range_to_list(vlans):
- result = []
- if vlans:
- for part in vlans.split(','):
- if part == 'none':
- break
- if '-' in part:
- a, b = part.split('-')
- a, b = int(a), int(b)
- result.extend(range(a, b + 1))
- else:
- a = int(part)
- result.append(a)
- return numerical_sort(result)
- return result
-
-
-def numerical_sort(string_int_list):
- """Sorts list of integers that are digits in numerical order.
- """
-
- as_int_list = []
-
- for vlan in string_int_list:
- as_int_list.append(int(vlan))
- as_int_list.sort()
- return as_int_list