summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py66
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/acls/acls.py593
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/facts/facts.py24
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py47
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py57
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py53
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py47
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py48
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py52
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py58
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py52
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py85
-rw-r--r--lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py50
-rw-r--r--lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py405
-rw-r--r--lib/ansible/module_utils/network/ios/config/acls/acls.py717
-rw-r--r--lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py295
-rw-r--r--lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py336
-rw-r--r--lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py328
-rw-r--r--lib/ansible/module_utils/network/ios/config/lacp/lacp.py189
-rw-r--r--lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py260
-rw-r--r--lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py296
-rw-r--r--lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py238
-rw-r--r--lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py270
-rw-r--r--lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py532
-rw-r--r--lib/ansible/module_utils/network/ios/config/vlans/vlans.py292
-rw-r--r--lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py122
-rw-r--r--lib/ansible/module_utils/network/ios/facts/acls/acls.py498
-rw-r--r--lib/ansible/module_utils/network/ios/facts/facts.py79
-rw-r--r--lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py97
-rw-r--r--lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py114
-rw-r--r--lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py124
-rw-r--r--lib/ansible/module_utils/network/ios/facts/lacp/lacp.py83
-rw-r--r--lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py102
-rw-r--r--lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py118
-rw-r--r--lib/ansible/module_utils/network/ios/facts/legacy/base.py380
-rw-r--r--lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py90
-rw-r--r--lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py108
-rw-r--r--lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py225
-rw-r--r--lib/ansible/module_utils/network/ios/facts/vlans/vlans.py144
-rw-r--r--lib/ansible/module_utils/network/ios/ios.py183
-rw-r--r--lib/ansible/module_utils/network/ios/providers/cli/config/base.py77
-rw-r--r--lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py140
-rw-r--r--lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py196
-rw-r--r--lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py140
-rw-r--r--lib/ansible/module_utils/network/ios/providers/module.py62
-rw-r--r--lib/ansible/module_utils/network/ios/providers/providers.py120
-rw-r--r--lib/ansible/module_utils/network/ios/utils/utils.py328
-rw-r--r--lib/ansible/modules/network/ios/_ios_interface.py495
-rw-r--r--lib/ansible/modules/network/ios/_ios_l2_interface.py499
-rw-r--r--lib/ansible/modules/network/ios/_ios_l3_interface.py327
-rw-r--r--lib/ansible/modules/network/ios/_ios_vlan.py350
-rw-r--r--lib/ansible/modules/network/ios/ios_acl_interfaces.py633
-rw-r--r--lib/ansible/modules/network/ios/ios_acls.py1417
-rw-r--r--lib/ansible/modules/network/ios/ios_banner.py186
-rw-r--r--lib/ansible/modules/network/ios/ios_bgp.py438
-rw-r--r--lib/ansible/modules/network/ios/ios_command.py230
-rw-r--r--lib/ansible/modules/network/ios/ios_config.py567
-rw-r--r--lib/ansible/modules/network/ios/ios_facts.py239
-rw-r--r--lib/ansible/modules/network/ios/ios_interfaces.py405
-rw-r--r--lib/ansible/modules/network/ios/ios_l2_interfaces.py390
-rw-r--r--lib/ansible/modules/network/ios/ios_l3_interfaces.py442
-rw-r--r--lib/ansible/modules/network/ios/ios_lacp.py185
-rw-r--r--lib/ansible/modules/network/ios/ios_lacp_interfaces.py363
-rw-r--r--lib/ansible/modules/network/ios/ios_lag_interfaces.py390
-rw-r--r--lib/ansible/modules/network/ios/ios_linkagg.py318
-rw-r--r--lib/ansible/modules/network/ios/ios_lldp.py112
-rw-r--r--lib/ansible/modules/network/ios/ios_lldp_global.py256
-rw-r--r--lib/ansible/modules/network/ios/ios_lldp_interfaces.py501
-rw-r--r--lib/ansible/modules/network/ios/ios_logging.py429
-rw-r--r--lib/ansible/modules/network/ios/ios_ntp.py308
-rw-r--r--lib/ansible/modules/network/ios/ios_ping.py210
-rw-r--r--lib/ansible/modules/network/ios/ios_static_route.py313
-rw-r--r--lib/ansible/modules/network/ios/ios_static_routes.py710
-rw-r--r--lib/ansible/modules/network/ios/ios_system.py380
-rw-r--r--lib/ansible/modules/network/ios/ios_user.py533
-rw-r--r--lib/ansible/modules/network/ios/ios_vlans.py464
-rw-r--r--lib/ansible/modules/network/ios/ios_vrf.py719
-rw-r--r--lib/ansible/plugins/action/ios.py95
-rw-r--r--lib/ansible/plugins/cliconf/ios.py387
-rw-r--r--lib/ansible/plugins/doc_fragments/ios.py81
-rw-r--r--lib/ansible/plugins/terminal/ios.py102
81 files changed, 0 insertions, 22394 deletions
diff --git a/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index 608cf6e728..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_acl_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Acl_InterfacesArgs(object):
- """The arg spec for the ios_acl_interfaces module
- """
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'name': {'required': True, 'type': 'str'},
- 'access_groups': {
- 'type': 'list',
- 'elements': 'dict',
- 'options': {
- 'afi': {'required': True, 'choices': ['ipv4', 'ipv6'], 'type': 'str'},
- 'acls': {
- 'type': 'list',
- 'elements': 'dict',
- 'options': {
- 'name': {'required': True, 'type': 'str'},
- 'direction': {'required': True, 'choices': ['in', 'out'], 'type': 'str'}
- }
- }
- }
- }
- },
- 'type': 'list'
- },
- 'running_config': {'type': 'str'},
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted', 'gathered', 'rendered', 'parsed'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/ios/argspec/acls/acls.py b/lib/ansible/module_utils/network/ios/argspec/acls/acls.py
deleted file mode 100644
index ca8982e557..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/acls/acls.py
+++ /dev/null
@@ -1,593 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the ios_acls module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class AclsArgs(object):
- """The arg spec for the ios_acls module
- """
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'afi': {
- 'required': True,
- 'choices': ['ipv4', 'ipv6'],
- 'type': 'str'
- },
- 'acls': {
- 'elements': 'dict',
- 'type': 'list',
- 'options': {
- 'name': {
- 'required': True,
- 'type': 'str'
- },
- 'acl_type': {
- 'choices': ['extended', 'standard'],
- 'type': 'str'
- },
- 'aces': {
- 'elements': 'dict',
- 'type': 'list',
- 'options': {
- 'grant': {
- 'choices': ['permit', 'deny'],
- 'type': 'str'
- },
- 'sequence': {
- 'type': 'int'
- },
- 'source': {
- 'type':
- 'dict',
- 'mutually_exclusive':
- [['address', 'any', 'host'],
- ['wildcard_bits', 'any', 'host']],
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'wildcard_bits': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'host': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'type': 'dict',
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'type': 'dict',
- 'options': {
- 'start': {
- 'type': 'int'
- },
- 'end': {
- 'type': 'int'
- }
- }
- }
- }
- }
- },
- },
- 'destination': {
- 'type':
- 'dict',
- 'mutually_exclusive':
- [['address', 'any', 'host'],
- ['wildcard_bits', 'any', 'host']],
- 'options': {
- 'address': {
- 'type': 'str'
- },
- 'wildcard_bits': {
- 'type': 'str'
- },
- 'any': {
- 'type': 'bool'
- },
- 'host': {
- 'type': 'str'
- },
- 'port_protocol': {
- 'type': 'dict',
- 'options': {
- 'eq': {
- 'type': 'str'
- },
- 'gt': {
- 'type': 'str'
- },
- 'lt': {
- 'type': 'str'
- },
- 'neq': {
- 'type': 'str'
- },
- 'range': {
- 'type': 'dict',
- 'options': {
- 'start': {
- 'type': 'int'
- },
- 'end': {
- 'type': 'int'
- }
- }
- }
- }
- }
- }
- },
- 'protocol': {
- 'type': 'str'
- },
- 'protocol_options': {
- 'type': 'dict',
- 'options': {
- 'protocol_number': {
- 'type': 'int'
- },
- 'ahp': {
- 'type': 'bool'
- },
- 'eigrp': {
- 'type': 'bool'
- },
- 'esp': {
- 'type': 'bool'
- },
- 'gre': {
- 'type': 'bool'
- },
- 'hbh': {
- 'type': 'bool'
- },
- 'icmp': {
- 'type': 'dict',
- 'options': {
- 'administratively_prohibited':
- {
- 'type': 'bool'
- },
- 'alternate_address': {
- 'type': 'bool'
- },
- 'conversion_error': {
- 'type': 'bool'
- },
- 'dod_host_prohibited': {
- 'type': 'bool'
- },
- 'dod_net_prohibited': {
- 'type': 'bool'
- },
- 'echo': {
- 'type': 'bool'
- },
- 'echo_reply': {
- 'type': 'bool'
- },
- 'general_parameter_problem': {
- 'type': 'bool'
- },
- 'host_isolated': {
- 'type': 'bool'
- },
- 'host_precedence_unreachable':
- {
- 'type': 'bool'
- },
- 'host_redirect': {
- 'type': 'bool'
- },
- 'host_tos_redirect': {
- 'type': 'bool'
- },
- 'host_tos_unreachable': {
- 'type': 'bool'
- },
- 'host_unknown': {
- 'type': 'bool'
- },
- 'host_unreachable': {
- 'type': 'bool'
- },
- 'information_reply': {
- 'type': 'bool'
- },
- 'information_request': {
- 'type': 'bool'
- },
- 'mask_reply': {
- 'type': 'bool'
- },
- 'mask_request': {
- 'type': 'bool'
- },
- 'mobile_redirect': {
- 'type': 'bool'
- },
- 'net_redirect': {
- 'type': 'bool'
- },
- 'net_tos_redirect': {
- 'type': 'bool'
- },
- 'net_tos_unreachable': {
- 'type': 'bool'
- },
- 'net_unreachable': {
- 'type': 'bool'
- },
- 'network_unknown': {
- 'type': 'bool'
- },
- 'no_room_for_option': {
- 'type': 'bool'
- },
- 'option_missing': {
- 'type': 'bool'
- },
- 'packet_too_big': {
- 'type': 'bool'
- },
- 'parameter_problem': {
- 'type': 'bool'
- },
- 'port_unreachable': {
- 'type': 'bool'
- },
- 'precedence_unreachable': {
- 'type': 'bool'
- },
- 'protocol_unreachable': {
- 'type': 'bool'
- },
- 'reassembly_timeout': {
- 'type': 'bool'
- },
- 'redirect': {
- 'type': 'bool'
- },
- 'router_advertisement': {
- 'type': 'bool'
- },
- 'router_solicitation': {
- 'type': 'bool'
- },
- 'source_quench': {
- 'type': 'bool'
- },
- 'source_route_failed': {
- 'type': 'bool'
- },
- 'time_exceeded': {
- 'type': 'bool'
- },
- 'timestamp_reply': {
- 'type': 'bool'
- },
- 'timestamp_request': {
- 'type': 'bool'
- },
- 'traceroute': {
- 'type': 'bool'
- },
- 'ttl_exceeded': {
- 'type': 'bool'
- },
- 'unreachable': {
- 'type': 'bool'
- },
- }
- },
- 'igmp': {
- 'type': 'dict',
- 'options': {
- 'dvmrp': {
- 'type': 'bool'
- },
- 'host_query': {
- 'type': 'bool'
- },
- 'mtrace_resp': {
- 'type': 'bool'
- },
- 'mtrace_route': {
- 'type': 'bool'
- },
- 'pim': {
- 'type': 'bool'
- },
- 'trace': {
- 'type': 'bool'
- },
- 'v1host_report': {
- 'type': 'bool'
- },
- 'v2host_report': {
- 'type': 'bool'
- },
- 'v2leave_group': {
- 'type': 'bool'
- },
- 'v3host_report': {
- 'type': 'bool'
- }
- }
- },
- 'ip': {
- 'type': 'bool'
- },
- 'ipv6': {
- 'type': 'bool'
- },
- 'ipinip': {
- 'type': 'bool'
- },
- 'nos': {
- 'type': 'bool'
- },
- 'ospf': {
- 'type': 'bool'
- },
- 'pcp': {
- 'type': 'bool'
- },
- 'pim': {
- 'type': 'bool'
- },
- 'sctp': {
- 'type': 'bool'
- },
- 'tcp': {
- 'options': {
- 'ack': {
- 'type': 'bool'
- },
- 'established': {
- 'type': 'bool'
- },
- 'fin': {
- 'type': 'bool'
- },
- 'psh': {
- 'type': 'bool'
- },
- 'rst': {
- 'type': 'bool'
- },
- 'syn': {
- 'type': 'bool'
- },
- 'urg': {
- 'type': 'bool'
- }
- },
- 'type': 'dict'
- },
- 'udp': {
- 'type': 'bool'
- }
- }
- },
- 'dscp': {
- 'type': 'str'
- },
- 'fragments': {
- 'type': 'str'
- },
- 'log': {
- 'type': 'str'
- },
- 'log_input': {
- 'type': 'str'
- },
- 'option': {
- 'type': 'dict',
- 'options': {
- 'add_ext': {
- 'type': 'bool'
- },
- 'any_options': {
- 'type': 'bool'
- },
- 'com_security': {
- 'type': 'bool'
- },
- 'dps': {
- 'type': 'bool'
- },
- 'encode': {
- 'type': 'bool'
- },
- 'eool': {
- 'type': 'bool'
- },
- 'ext_ip': {
- 'type': 'bool'
- },
- 'ext_security': {
- 'type': 'bool'
- },
- 'finn': {
- 'type': 'bool'
- },
- 'imitd': {
- 'type': 'bool'
- },
- 'lsr': {
- 'type': 'bool'
- },
- 'mtup': {
- 'type': 'bool'
- },
- 'mtur': {
- 'type': 'bool'
- },
- 'no_op': {
- 'type': 'bool'
- },
- 'nsapa': {
- 'type': 'bool'
- },
- 'record_route': {
- 'type': 'bool'
- },
- 'router_alert': {
- 'type': 'bool'
- },
- 'sdb': {
- 'type': 'bool'
- },
- 'security': {
- 'type': 'bool'
- },
- 'ssr': {
- 'type': 'bool'
- },
- 'stream_id': {
- 'type': 'bool'
- },
- 'timestamp': {
- 'type': 'bool'
- },
- 'traceroute': {
- 'type': 'bool'
- },
- 'ump': {
- 'type': 'bool'
- },
- 'visa': {
- 'type': 'bool'
- },
- 'zsu': {
- 'type': 'bool'
- }
- }
- },
- 'precedence': {
- 'type': 'int'
- },
- 'time_range': {
- 'type': 'str'
- },
- 'tos': {
- 'type': 'dict',
- 'options': {
- 'service_value': {
- 'type': 'int'
- },
- 'max_reliability': {
- 'type': 'bool'
- },
- 'max_throughput': {
- 'type': 'bool'
- },
- 'min_delay': {
- 'type': 'bool'
- },
- 'min_monetary_cost': {
- 'type': 'bool'
- },
- 'normal': {
- 'type': 'bool'
- }
- }
- },
- 'ttl': {
- 'type': 'dict',
- 'options': {
- 'eq': {
- 'type': 'int'
- },
- 'gt': {
- 'type': 'int'
- },
- 'lt': {
- 'type': 'int'
- },
- 'neq': {
- 'type': 'int'
- },
- 'range': {
- 'type': 'dict',
- 'options': {
- 'start': {
- 'type': 'int'
- },
- 'end': {
- 'type': 'int'
- }
- }
- }
- }
- },
- }
- }
- }
- },
- },
- 'type': 'list'
- },
- 'running_config': {
- 'type': 'str'
- },
- 'state': {
- 'choices': [
- 'merged', 'replaced', 'overridden', 'deleted', 'gathered',
- 'rendered', 'parsed'
- ],
- 'default':
- 'merged',
- 'type':
- 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/ios/argspec/facts/facts.py b/lib/ansible/module_utils/network/ios/argspec/facts/facts.py
deleted file mode 100644
index 8cac9e9827..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/facts/facts.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The arg spec for the ios facts module.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class FactsArgs(object):
- """ The arg spec for the ios facts module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'gather_subset': dict(default=['!config'], type='list'),
- 'gather_network_resources': dict(type='list'),
- }
diff --git a/lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py
deleted file mode 100644
index ae097f5307..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/interfaces/interfaces.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the ios_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class InterfacesArgs(object):
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'type': 'str', 'required': True},
- 'description': {'type': 'str'},
- 'enabled': {'default': True, 'type': 'bool'},
- 'speed': {'type': 'str'},
- 'mtu': {'type': 'int'},
- 'duplex': {'type': 'str', 'choices': ['full', 'half', 'auto']}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index 5ef51fa23d..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the ios_l2_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class L2_InterfacesArgs(object):
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'type': 'str', 'required': True},
- 'mode': {'type': 'str', 'choices': ['access', 'trunk']},
- 'access': {'type': 'dict',
- 'options': {'vlan': {'type': 'int'}}
- },
- 'voice': {'type': 'dict',
- 'options': {'vlan': {'type': 'int'}}
- },
- 'trunk': {'type': 'dict',
- 'options': {'allowed_vlans': {'type': 'list'},
- 'encapsulation': {'type': 'str',
- 'choices':
- ['dot1q', 'isl', 'negotiate']},
- 'native_vlan': {'type': 'int'},
- 'pruning_vlans': {'type': 'list'}}
- }},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index cdf209a27a..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the ios_l3_interfaces module
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class L3_InterfacesArgs(object):
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'type': 'str', 'required': True},
- 'ipv4': {'element': 'dict',
- 'type': 'list',
- 'options': {'address': {'type': 'str'},
- 'secondary': {'type': 'bool'},
- 'dhcp_client': {'type': 'int'},
- 'dhcp_hostname': {'type': 'str'}}},
- 'ipv6': {'element': 'dict',
- 'type': 'list',
- 'options': {'address': {'type': 'str'}}}
- },
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py b/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py
deleted file mode 100644
index 1e7294bc5c..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/lacp/lacp.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_lacp module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class LacpArgs(object):
- """The arg spec for the ios_lacp module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {'options': {'system': {'options': {'priority': {'required': True, 'type': 'int'}},
- 'type': 'dict'}
- }, 'type': 'dict'
- },
- 'state': {'choices': ['merged', 'replaced', 'deleted'], 'default': 'merged',
- 'type': 'str'}
- }
diff --git a/lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 10b17e5635..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_lacp_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lacp_InterfacesArgs(object):
- """The arg spec for the ios_lacp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'required': True, 'type': 'str'},
- 'port_priority': {'type': 'int'},
- 'fast_switchover': {'type': 'bool'},
- 'max_bundle': {'type': 'int'}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index 0f9b7e2535..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_lag_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lag_interfacesArgs(object):
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'required': True, 'type': 'str'},
- 'members': {'elements': 'dict',
- 'options': {
- 'member': {'type': 'str'},
- 'mode': {'choices': ['auto', 'on', 'desirable',
- 'active', 'passive'],
- 'type': 'str', 'required': True},
- 'link': {'type': 'int'}
- },
- 'type': 'list'}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py
deleted file mode 100644
index 62630036c2..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-"""
-The arg spec for the ios_lldp_global module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lldp_globalArgs(object):
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'options': {'holdtime': {'type': 'int'},
- 'reinit': {'type': 'int'},
- 'enabled': {'type': 'bool'},
- 'timer': {'type': 'int'},
- 'tlv_select': {
- 'options': {
- 'four_wire_power_management': {'type': 'bool'},
- 'mac_phy_cfg': {'type': 'bool'},
- 'management_address': {'type': 'bool'},
- 'port_description': {'type': 'bool'},
- 'port_vlan': {'type': 'bool'},
- 'power_management': {'type': 'bool'},
- 'system_capabilities': {'type': 'bool'},
- 'system_description': {'type': 'bool'},
- 'system_name': {'type': 'bool'}
- },
- 'type': 'dict'},
- },
- 'type': 'dict'},
- 'state': {'choices': ['merged', 'replaced', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 45af268d4d..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_lldp_interfaces module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Lldp_InterfacesArgs(object):
- """The arg spec for the ios_lldp_interfaces module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'required': True, 'type': 'str'},
- 'transmit': {'type': 'bool'},
- 'receive': {'type': 'bool'},
- 'med_tlv_select': {'options': {'inventory_management': {'type': 'bool'}},
- 'type': 'dict'},
- 'tlv_select': {'options': {'power_management': {'type': 'bool'}},
- 'type': 'dict'}
- },
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py
deleted file mode 100644
index 3362187987..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/static_routes/static_routes.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_static_routes module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class Static_RoutesArgs(object):
- """The arg spec for the ios_static_routes module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {
- 'config': {
- 'elements': 'dict',
- 'options': {
- 'vrf': {'type': 'str'},
- 'address_families': {
- 'elements': 'dict',
- 'type': 'list',
- 'options': {
- 'afi': {'required': True, 'choices': ['ipv4', 'ipv6'], 'type': 'str'},
- 'routes': {
- 'elements': 'dict',
- 'type': 'list',
- 'options': {
- 'dest': {'required': True, 'type': 'str'},
- 'topology': {'type': 'str'},
- 'next_hops': {
- 'elements': 'dict',
- 'type': 'list',
- 'options': {
- 'forward_router_address': {'type': 'str'},
- 'interface': {'type': 'str'},
- 'dhcp': {'type': 'bool'},
- 'distance_metric': {'type': 'int'},
- 'global': {'type': 'bool'},
- 'name': {'type': 'str'},
- 'multicast': {'type': 'bool'},
- 'permanent': {'type': 'bool'},
- 'tag': {'type': 'int'},
- 'track': {'type': 'int'}
- }
- }
- }
- }
- }
- }
- },
- 'type': 'list'
- },
- 'running_config': {'type': 'str'},
- 'state': {
- 'choices': ['merged', 'replaced', 'overridden', 'deleted', 'gathered', 'rendered', 'parsed'],
- 'default': 'merged',
- 'type': 'str'
- }
- }
diff --git a/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py b/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py
deleted file mode 100644
index 893904cfe7..0000000000
--- a/lib/ansible/module_utils/network/ios/argspec/vlans/vlans.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The arg spec for the ios_vlans module
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-class VlansArgs(object):
- """The arg spec for the ios_vlans module
- """
-
- def __init__(self, **kwargs):
- pass
-
- argument_spec = {'config': {'elements': 'dict',
- 'options': {'name': {'type': 'str'},
- 'vlan_id': {'required': True, 'type': 'int'},
- 'mtu': {'type': 'int'},
- 'remote_span': {'type': 'bool'},
- 'state': {'type': 'str', 'choices': ['active', 'suspend']},
- 'shutdown': {'type': 'str', 'choices': ['enabled', 'disabled']}},
- 'type': 'list'},
- 'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
- 'default': 'merged',
- 'type': 'str'}}
diff --git a/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index fa3352389c..0000000000
--- a/lib/ansible/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,405 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_acl_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.ios.utils.utils import remove_duplicate_interface, normalize_interface
-
-
-class Acl_Interfaces(ConfigBase):
- """
- The ios_acl_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'acl_interfaces',
- ]
-
- def __init__(self, module):
- super(Acl_Interfaces, self).__init__(module)
-
- def get_acl_interfaces_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data)
- acl_interfaces_facts = facts['ansible_network_resources'].get('acl_interfaces')
- if not acl_interfaces_facts:
- return []
-
- return acl_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
- :rtype: A dictionary
- :returns: The result from moduel execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- if self.state in self.ACTION_STATES:
- existing_acl_interfaces_facts = self.get_acl_interfaces_facts()
- else:
- existing_acl_interfaces_facts = []
-
- if self.state in self.ACTION_STATES or self.state == 'rendered':
- commands.extend(self.set_config(existing_acl_interfaces_facts))
-
- if commands and self.state in self.ACTION_STATES:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
-
- if self.state in self.ACTION_STATES:
- result['commands'] = commands
-
- if self.state in self.ACTION_STATES or self.state == 'gathered':
- changed_acl_interfaces_facts = self.get_acl_interfaces_facts()
- elif self.state == 'rendered':
- result['rendered'] = commands
- elif self.state == 'parsed':
- running_config = self._module.params['running_config']
- if not running_config:
- self._module.fail_json(
- msg="value of running_config parameter must not be empty for state parsed"
- )
- result['parsed'] = self.get_acl_interfaces_facts(data=running_config)
- else:
- changed_acl_interfaces_facts = []
-
- if self.state in self.ACTION_STATES:
- result['before'] = existing_acl_interfaces_facts
- if result['changed']:
- result['after'] = changed_acl_interfaces_facts
- elif self.state == 'gathered':
- result['gathered'] = changed_acl_interfaces_facts
-
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_acl_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- want = self._module.params['config']
- if want:
- for item in want:
- item['name'] = normalize_interface(item['name'])
-
- have = existing_acl_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced', 'rendered') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged' or state == 'rendered':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- commands.extend(self._clear_config(interface, each, 'replaced'))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- if each['name'] == interface['name']:
- break
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we recieved an empty desired state.
- interface = dict(name=each['name'])
- commands.extend(self._clear_config(interface, each))
- continue
- commands.extend(self._clear_config(interface, each, 'overridden'))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
- :param want: the additive configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- # configuring non-existing interface
- commands.extend(self._set_config(interface, dict()))
- continue
- commands.extend(self._set_config(interface, each))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
- :param want: the objects from which the configuration should be removed
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- commands.extend(self._clear_config(dict(), each))
-
- return commands
-
- def dict_to_set(self, input_dict, test_set, final_set, count=0):
- # recursive function to convert input dict to set for comparision
- test_dict = dict()
- if isinstance(input_dict, dict):
- input_dict_len = len(input_dict)
- for k, v in sorted(iteritems(input_dict)):
- count += 1
- if isinstance(v, list):
- for each in v:
- if isinstance(each, dict):
- input_dict_len = len(each)
- if [True for i in each.values() if type(i) == list]:
- self.dict_to_set(each, set(), final_set, count)
- else:
- self.dict_to_set(each, test_set, final_set, 0)
- else:
- if v is not None:
- test_dict.update({k: v})
- if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len:
- test_set.add(tuple(iteritems(test_dict)))
- count = 0
- if count == input_dict_len + 1:
- test_set.update(tuple(iteritems(test_dict)))
- final_set.add(tuple(test_set))
-
- def _set_config(self, want, have):
- """ Function that sets the acls config based on the want and have config
- :param want: want config
- :param have: have config
- :param acl_want: want acl config
- :param afi: acl afi type
- :rtype: A list
- :returns: the commands generated based on input want/have params
- """
- commands = []
-
- want_set = set()
- have_set = set()
- self.dict_to_set(want, set(), want_set)
- self.dict_to_set(have, set(), have_set)
-
- for w in want_set:
- want_afi = dict(w).get('afi')
- if have_set:
- def common_diff_config_code(diff_list, cmd, commands):
- for each in diff_list:
- try:
- temp = dict(each)
- temp_cmd = cmd + ' {0} {1}'.format(temp['name'], temp['direction'])
- if temp_cmd not in commands:
- commands.append(temp_cmd)
- except ValueError:
- continue
- for h in have_set:
- have_afi = dict(h).get('afi')
- if have_afi == want_afi:
- if want_afi == 'ipv4':
- diff = set(w) - set(h)
- if diff:
- cmd = 'ip access-group'
- common_diff_config_code(diff, cmd, commands)
- if want_afi == 'ipv6':
- diff = set(w) - set(h)
- if diff:
- cmd = 'ipv6 traffic-filter'
- common_diff_config_code(diff, cmd, commands)
- break
- else:
- if want_afi == 'ipv4':
- diff = set(w) - set(h)
- if diff:
- cmd = 'ip access-group'
- common_diff_config_code(diff, cmd, commands)
- if want_afi == 'ipv6':
- diff = set(w) - set(h)
- if diff:
- cmd = 'ipv6 traffic-filter'
- common_diff_config_code(diff, cmd, commands)
- else:
- def common_want_config_code(want, cmd, commands):
- for each in want:
- if each[0] == 'afi':
- continue
- temp = dict(each)
- temp_cmd = cmd + ' {0} {1}'.format(temp['name'], temp['direction'])
- commands.append(temp_cmd)
- if want_afi == 'ipv4':
- cmd = 'ip access-group'
- common_want_config_code(w, cmd, commands)
- if want_afi == 'ipv6':
- cmd = 'ipv6 traffic-filter'
- common_want_config_code(w, cmd, commands)
- commands.sort()
- if commands:
- interface = want.get('name')
- commands.insert(0, 'interface {0}'.format(interface))
-
- return commands
-
- def _clear_config(self, want, have, state=''):
- """ Function that deletes the acl config based on the want and have config
- :param acl: acl config
- :param config: config
- :rtype: A list
- :returns: the commands generated based on input acl/config params
- """
- commands = []
-
- if want.get('name'):
- interface = 'interface ' + want['name']
- else:
- interface = 'interface ' + have['name']
-
- w_access_group = want.get('access_groups')
- temp_want_afi = []
- temp_want_acl_name = []
- if w_access_group:
- # get the user input afi and acls
- for each in w_access_group:
- want_afi = each.get('afi')
- want_acls = each.get('acls')
- if want_afi:
- temp_want_afi.append(want_afi)
- if want_acls:
- for each in want_acls:
- temp_want_acl_name.append(each.get('name'))
-
- h_access_group = have.get('access_groups')
- if h_access_group:
- for access_grp in h_access_group:
- for acl in access_grp.get('acls'):
- have_afi = access_grp.get('afi')
- acl_name = acl.get('name')
- acl_direction = acl.get('direction')
- if temp_want_afi and state not in ['replaced', 'overridden']:
- # if user want to delete acls based on afi
- if 'ipv4' in temp_want_afi and have_afi == 'ipv4':
- if acl_name in temp_want_acl_name:
- continue
- cmd = 'no ip access-group'
- cmd += ' {0} {1}'.format(acl_name, acl_direction)
- commands.append(cmd)
- if 'ipv6' in temp_want_afi and have_afi == 'ipv6':
- if acl_name in temp_want_acl_name:
- continue
- cmd = 'no ipv6 traffic-filter'
- cmd += ' {0} {1}'.format(acl_name, acl_direction)
- commands.append(cmd)
- else:
- # if user want to delete acls based on interface
- if access_grp.get('afi') == 'ipv4':
- if acl_name in temp_want_acl_name:
- continue
- cmd = 'no ip access-group'
- cmd += ' {0} {1}'.format(acl_name, acl_direction)
- commands.append(cmd)
- elif access_grp.get('afi') == 'ipv6':
- if acl_name in temp_want_acl_name:
- continue
- cmd = 'no ipv6 traffic-filter'
- cmd += ' {0} {1}'.format(acl_name, acl_direction)
- commands.append(cmd)
- if commands:
- # inserting the interface at first
- commands.insert(0, interface)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/acls/acls.py b/lib/ansible/module_utils/network/ios/config/acls/acls.py
deleted file mode 100644
index 2a3f3f244b..0000000000
--- a/lib/ansible/module_utils/network/ios/config/acls/acls.py
+++ /dev/null
@@ -1,717 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_acls class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import copy
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import remove_empties
-from ansible.module_utils.network.ios.utils.utils import new_dict_to_set
-
-
-class Acls(ConfigBase):
- """
- The ios_acls class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'acls',
- ]
-
- def __init__(self, module):
- super(Acls, self).__init__(module)
-
- def get_acl_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data)
- acl_facts = facts['ansible_network_resources'].get('acls')
- if not acl_facts:
- return []
-
- return acl_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from moduel execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- if self.state in self.ACTION_STATES:
- existing_acl_facts = self.get_acl_facts()
- else:
- existing_acl_facts = []
-
- if self.state in self.ACTION_STATES or self.state == 'rendered':
- commands.extend(self.set_config(existing_acl_facts))
-
- if commands and self.state in self.ACTION_STATES:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
-
- if self.state in self.ACTION_STATES:
- result['commands'] = commands
-
- if self.state in self.ACTION_STATES or self.state == 'gathered':
- changed_acl_facts = self.get_acl_facts()
- elif self.state == 'rendered':
- result['rendered'] = commands
- elif self.state == 'parsed':
- running_config = self._module.params['running_config']
- if not running_config:
- self._module.fail_json(msg="value of running_config parameter must not be empty for state parsed")
- result['parsed'] = self.get_acl_facts(data=running_config)
- else:
- changed_acl_facts = []
-
- if self.state in self.ACTION_STATES:
- result['before'] = existing_acl_facts
- if result['changed']:
- result['after'] = changed_acl_facts
- elif self.state == 'gathered':
- result['gathered'] = changed_acl_facts
-
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_acl_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- want = self._module.params['config']
- have = existing_acl_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced', 'rendered') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged' or state == 'rendered':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- for config_want in want:
- for acls_want in config_want.get('acls'):
- for ace_want in acls_want.get('aces'):
- check = False
- for config_have in have:
- for acls_have in config_have.get('acls'):
- for ace_have in acls_have.get('aces'):
- if acls_want.get('name') == acls_have.get('name'):
- ace_want = remove_empties(ace_want)
- acls_want = remove_empties(acls_want)
- cmd, change = self._set_config(ace_want,
- ace_have,
- acls_want,
- config_want['afi'])
- if cmd:
- for temp_acls_have in config_have.get('acls'):
- for temp_ace_have in temp_acls_have.get('aces'):
- if acls_want.get('name') == temp_acls_have.get('name'):
- commands.extend(
- self._clear_config(temp_acls_have,
- config_have,
- temp_ace_have.get('sequence')))
- commands.extend(cmd)
- check = True
- if check:
- break
- if check:
- break
- if not check:
- # For configuring any non-existing want config
- ace_want = remove_empties(ace_want)
- cmd, change = self._set_config(ace_want,
- {},
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- # Split and arrange the config commands
- commands = self.split_set_cmd(commands)
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
- # Creating a copy of want, so that want dict is intact even after delete operation
- # performed during override want n have comparison
- temp_want = copy.deepcopy(want)
-
- for config_have in have:
- for acls_have in config_have.get('acls'):
- for ace_have in acls_have.get('aces'):
- check = False
- for config_want in temp_want:
- count = 0
- for acls_want in config_want.get('acls'):
- for ace_want in acls_want.get('aces'):
- if acls_want.get('name') == acls_have.get('name'):
- ace_want = remove_empties(ace_want)
- acls_want = remove_empties(acls_want)
- cmd, change = self._set_config(ace_want, ace_have, acls_want, config_want['afi'])
- if cmd:
- for temp_acls_have in config_have.get('acls'):
- for temp_ace_have in temp_acls_have.get('aces'):
- if acls_want.get('name') == temp_acls_have.get('name'):
- commands.extend(
- self._clear_config(temp_acls_have,
- config_have,
- temp_ace_have.get('sequence')))
- commands.extend(cmd)
- check = True
- if check:
- del config_want.get('acls')[count]
- else:
- count += 1
- if check:
- break
- if check:
- break
- if not check:
- # Delete the config not present in want config
- commands.extend(self._clear_config(acls_have, config_have))
-
- # For configuring any non-existing want config
- for config_want in temp_want:
- for acls_want in config_want.get('acls'):
- for ace_want in acls_want.get('aces'):
- ace_want = remove_empties(ace_want)
- cmd, change = self._set_config(ace_want,
- {},
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
-
- # Split and arrange the config commands
- commands = self.split_set_cmd(commands)
- # Arranging the cmds suct that all delete cmds are fired before all set cmds
- negate_commands = [each for each in commands if 'no' in each and 'access-list' in each]
- negate_commands.extend([each for each in commands if each not in negate_commands])
- commands = negate_commands
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :param want: the additive configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for config_want in want:
- for acls_want in config_want.get('acls'):
- for ace_want in acls_want.get('aces'):
- check = False
- for config_have in have:
- for acls_have in config_have.get('acls'):
- for ace_have in acls_have.get('aces'):
- if acls_want.get('name') == acls_have.get('name') and \
- ace_want.get('sequence') == ace_have.get('sequence'):
- ace_want = remove_empties(ace_want)
- cmd, change = self._set_config(ace_want,
- ace_have,
- acls_want,
- config_want['afi'])
- # clear config will be fired only when there's command wrt to config
- if config_want.get('afi') == 'ipv4' and change:
- # for ipv4 only inplace update cannot be done, so deleting the sequence ace
- # and then updating the want ace changes
- commands.extend(self._clear_config(acls_want,
- config_want,
- ace_want.get('sequence')))
- commands.extend(cmd)
- check = True
- elif acls_want.get('name') == acls_have.get('name'):
- ace_want = remove_empties(ace_want)
- cmd, check = self.common_condition_check(ace_want,
- ace_have,
- acls_want,
- config_want,
- check,
- acls_have)
- if acls_have.get('acl_type') == 'standard':
- check = True
- commands.extend(cmd)
- if check:
- break
- if check:
- break
- if not check:
- # For configuring any non-existing want config
- ace_want = remove_empties(ace_want)
- cmd, change = self._set_config(ace_want,
- {},
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- # Split and arrange the config commands
- commands = self.split_set_cmd(commands)
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :param want: the objects from which the configuration should be removed
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
- if want:
- for config_want in want:
- if config_want.get('acls'):
- for acls_want in config_want.get('acls'):
- if acls_want.get('aces'):
- for ace_want in acls_want.get('aces'):
- for config_have in have:
- for acls_have in config_have.get('acls'):
- if acls_want.get('name') == acls_have.get('name'):
- if ace_want.get('sequence'):
- commands.extend(self._clear_config(acls_want,
- config_want,
- ace_want.get('sequence')))
- else:
- commands.extend(self._clear_config(acls_want,
- config_want))
- else:
- for config_have in have:
- for acls_have in config_have.get('acls'):
- if acls_want.get('name') == acls_have.get('name'):
- commands.extend(self._clear_config(acls_want,
- config_want))
- else:
- afi_want = config_want.get('afi')
- for config_have in have:
- if config_have.get('afi') == afi_want:
- for acls_have in config_have.get('acls'):
- commands.extend(self._clear_config(acls_have, config_want))
- # Split and arrange the config commands
- commands = self.split_set_cmd(commands)
- else:
- for config_have in have:
- for acls_have in config_have.get('acls'):
- commands.extend(self._clear_config(acls_have, config_have))
-
- return commands
-
- def common_condition_check(self, want, have, acls_want, config_want, check, state='', acls_have=None):
- """ The command formatter from the generated command
- :param want: want config
- :param have: have config
- :param acls_want: acls want config
- :param config_want: want config list
- :param check: for same acls in want and have config, check=True
- :param state: operation state
- :rtype: A list
- :returns: commands generated from want n have config diff
- """
- commands = []
-
- if want.get('source') and want.get('destination') and have.get('source') and have.get('destination'):
- if want.get('destination') and have.get('destination') or \
- want.get('source').get('address') and have.get('source'):
- if want.get('destination').get('address') == \
- have.get('destination').get('address') and \
- want.get('source').get('address') == \
- have.get('source').get('address'):
- cmd, change = self._set_config(want,
- have,
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- check = True
- if commands:
- if state == 'replaced' or state == 'overridden':
- commands.extend(self._clear_config(acls_want, config_want))
- elif want.get('destination').get('any') == \
- have.get('destination').get('any') and \
- want.get('source').get('address') == \
- have.get('source').get('address') and \
- want.get('destination').get('any'):
- cmd, change = self._set_config(want,
- have,
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- check = True
- if commands:
- if state == 'replaced' or state == 'overridden':
- commands.extend(self._clear_config(acls_want, config_want))
- elif want.get('destination').get('address') == \
- have.get('destination').get('address') and \
- want.get('source').get('any') == have.get('source').get('any') and \
- want.get('source').get('any'):
- cmd, change = self._set_config(want,
- have,
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- check = True
- if commands:
- if state == 'replaced' or state == 'overridden':
- commands.extend(self._clear_config(acls_want, config_want))
- elif want.get('destination').get('any') == \
- have.get('destination').get('any') and \
- want.get('source').get('any') == have.get('source').get('any') and \
- want.get('destination').get('any'):
- cmd, change = self._set_config(want,
- have,
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
- check = True
- if commands:
- if state == 'replaced' or state == 'overridden':
- commands.extend(self._clear_config(acls_want, config_want))
- elif acls_have and acls_have.get('acl_type') == 'standard':
- check = True
- if want.get('source') == have.get('source'):
- cmd, change = self._set_config(want,
- have,
- acls_want,
- config_want['afi'])
- commands.extend(cmd)
-
- return commands, check
-
- def split_set_cmd(self, cmds):
- """ The command formatter from the generated command
- :param cmds: generated command
- :rtype: A list
- :returns: the formatted commands which is compliant and
- actually fired on the device
- """
- command = []
-
- def common_code(access_grant, cmd, command):
- cmd = cmd.split(access_grant)
- access_list = cmd[0].strip(' ')
- if access_list not in command:
- command.append(access_list)
- command_items = len(command)
- # get the last index of the list and push the trimmed cmd at the end of list
- index = command.index(access_list) + (command_items - command.index(access_list))
- cmd = access_grant + cmd[1]
- command.insert(index + 1, cmd)
-
- def sequence_common_code(sequence_index, each_list, command):
- # Command to split
- def join_list_to_str(temp_list, cmd=''):
- for item in temp_list:
- cmd += item
- cmd += ' '
- return cmd
-
- temp_list = each_list[:sequence_index]
- cmd = join_list_to_str(temp_list).rstrip(' ')
- if cmd not in command:
- command.append(cmd)
- temp_list = each_list[sequence_index:]
- cmd = join_list_to_str(temp_list).rstrip(' ')
- command.append(cmd)
-
- def grant_common_code(cmd_list, grant_type, command):
- index = cmd_list.index(grant_type)
- if 'extended' in each_list:
- if cmd_list.index('extended') == (index - 2):
- common_code(grant_type, each, command)
- else:
- sequence_common_code((index - 1), each_list, command)
- elif 'standard' in each_list:
- if cmd_list.index('standard') == (index - 2):
- common_code(grant_type, each, command)
- else:
- sequence_common_code((index - 1), each_list, command)
- elif 'ipv6' in each_list:
- if 'sequence' in each_list:
- sequence_index = each_list.index('sequence')
- sequence_common_code(sequence_index, each_list, command)
- else:
- common_code(grant_type, each, command)
- return command
-
- for each in cmds:
- each_list = each.split(' ')
- if 'no' in each:
- if each_list.index('no') == 0:
- command.append(each)
- else:
- common_code('no', each, command)
- if 'deny' in each:
- grant_common_code(each_list, 'deny', command)
- if 'permit' in each:
- grant_common_code(each_list, 'permit', command)
-
- return command
-
- def source_dest_config(self, config, cmd, protocol_option):
- """ Function to populate source/destination address and port protocol options
- :param config: want and have diff config
- :param cmd: source/destination command
- :param protocol_option: source/destination protocol option
- :rtype: A list
- :returns: the commands generated based on input source/destination params
- """
- if 'ipv6' in cmd:
- address = config.get('address')
- host = config.get('host')
- if (address and '::' not in address) or (host and '::' not in host):
- self._module.fail_json(msg='Incorrect IPV6 address!')
- else:
- address = config.get('address')
- wildcard = config.get('wildcard_bits')
- host = config.get('host')
- any = config.get('any')
- if 'standard' in cmd and address and not wildcard:
- cmd = cmd + ' {0}'.format(address)
- elif address and wildcard:
- cmd = cmd + ' {0} {1}'.format(address, wildcard)
- elif host:
- cmd = cmd + ' host {0}'.format(host)
- if any:
- cmd = cmd + ' {0}'.format('any')
- port_protocol = config.get('port_protocol')
- if port_protocol and (protocol_option.get('tcp') or protocol_option.get('udp')):
- cmd = cmd + ' {0} {1}'.format(list(port_protocol)[0], list(port_protocol.values())[0])
- elif port_protocol and not (protocol_option.get('tcp') or protocol_option.get('udp')):
- self._module.fail_json(msg='Port Protocol option is valid only with TCP/UDP Protocol option!')
-
- return cmd
-
- def _set_config(self, want, have, acl_want, afi):
- """ Function that sets the acls config based on the want and have config
- :param want: want config
- :param have: have config
- :param acl_want: want acls config
- :param afi: acls afi type
- :rtype: A list
- :returns: the commands generated based on input want/have params
- """
- commands = []
- change = False
- want_set = set()
- have_set = set()
- # Convert the want and have dict to its respective set for taking the set diff
- new_dict_to_set(want, [], want_set)
- new_dict_to_set(have, [], have_set)
- diff = want_set - have_set
-
- # Populate the config only when there's a diff b/w want and have config
- if diff:
- name = acl_want.get('name')
- if afi == 'ipv4':
- try:
- name = int(name)
- # If name is numbered acls
- if name <= 99:
- cmd = 'ip access-list standard {0}'.format(name)
- elif name >= 100:
- cmd = 'ip access-list extended {0}'.format(name)
- except ValueError:
- # If name is named acls
- acl_type = acl_want.get('acl_type')
- if acl_type:
- cmd = 'ip access-list {0} {1}'.format(acl_type, name)
- else:
- self._module.fail_json(msg='ACL type value is required for Named ACL!')
-
- elif afi == 'ipv6':
- cmd = 'ipv6 access-list {0}'.format(name)
-
- # Get all of aces option values from diff dict
- sequence = want.get('sequence')
- grant = want.get('grant')
- source = want.get('source')
- destination = want.get('destination')
- po = want.get('protocol_options')
- protocol = want.get('protocol')
- dscp = want.get('dscp')
- fragments = want.get('fragments')
- log = want.get('log')
- log_input = want.get('log_input')
- option = want.get('option')
- precedence = want.get('precedence')
- time_range = want.get('time_range')
- tos = want.get('tos')
- ttl = want.get('ttl')
-
- if sequence:
- if afi == 'ipv6':
- cmd = cmd + ' sequence {0}'.format(sequence)
- else:
- cmd = cmd + ' {0}'.format(sequence)
- if grant:
- cmd = cmd + ' {0}'.format(grant)
- if po and isinstance(po, dict):
- po_key = list(po)[0]
- if protocol and protocol != po_key:
- self._module.fail_json(msg='Protocol value cannot be different from Protocol option protocol value!')
- cmd = cmd + ' {0}'.format(po_key)
- if po.get('icmp'):
- po_val = po.get('icmp')
- elif po.get('igmp'):
- po_val = po.get('igmp')
- elif po.get('tcp'):
- po_val = po.get('tcp')
- elif protocol:
- cmd = cmd + ' {0}'.format(protocol)
- if source:
- cmd = self.source_dest_config(source, cmd, po)
- if destination:
- cmd = self.source_dest_config(destination, cmd, po)
- if po:
- cmd = cmd + ' {0}'.format(list(po_val)[0])
- if dscp:
- cmd = cmd + ' dscp {0}'.format(dscp)
- if fragments:
- cmd = cmd + ' fragments {0}'.format(fragments)
- if log:
- cmd = cmd + ' log {0}'.format(log)
- if log_input:
- cmd = cmd + ' log-input {0}'.format(log_input)
- if option:
- cmd = cmd + ' option {0}'.format(list(option)[0])
- if precedence:
- cmd = cmd + ' precedence {0}'.format(precedence)
- if time_range:
- cmd = cmd + ' time-range {0}'.format(time_range)
- if tos:
- for k, v in iteritems(tos):
- if k == 'service_value':
- cmd = cmd + ' tos {0}'.format(v)
- else:
- cmd = cmd + ' tos {0}'.format(v)
- if ttl:
- for k, v in iteritems(ttl):
- if k == 'range' and v:
- start = v.get('start')
- end = v.get('start')
- cmd = cmd + ' ttl {0} {1}'.format(start, end)
- elif v:
- cmd = cmd + ' ttl {0} {1}'.format(k, v)
-
- commands.append(cmd)
- if commands:
- change = True
-
- return commands, change
-
- def _clear_config(self, acls, config, sequence=''):
- """ Function that deletes the acls config based on the want and have config
- :param acls: acls config
- :param config: config
- :rtype: A list
- :returns: the commands generated based on input acls/config params
- """
- commands = []
- afi = config.get('afi')
- name = acls.get('name')
- if afi == 'ipv4' and name:
- try:
- name = int(name)
- if name <= 99 and not sequence:
- cmd = 'no ip access-list standard {0}'.format(name)
- elif name >= 100 and not sequence:
- cmd = 'no ip access-list extended {0}'.format(name)
- elif sequence:
- if name <= 99:
- cmd = 'ip access-list standard {0} '.format(name)
- elif name >= 100:
- cmd = 'ip access-list extended {0} '.format(name)
- cmd += 'no {0}'.format(sequence)
- except ValueError:
- acl_type = acls.get('acl_type')
- if acl_type == 'extended' and not sequence:
- cmd = 'no ip access-list extended {0}'.format(name)
- elif acl_type == 'standard' and not sequence:
- cmd = 'no ip access-list standard {0}'.format(name)
- elif sequence:
- if acl_type == 'extended':
- cmd = 'ip access-list extended {0} '.format(name)
- elif acl_type == 'standard':
- cmd = 'ip access-list standard {0}'.format(name)
- cmd += 'no {0}'.format(sequence)
- else:
- self._module.fail_json(msg="ACL type value is required for Named ACL!")
- elif afi == 'ipv6' and name:
- if sequence:
- cmd = 'no sequence {0}'.format(sequence)
- else:
- cmd = 'no ipv6 access-list {0}'.format(name)
- commands.append(cmd)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py
deleted file mode 100644
index bcf817f4d8..0000000000
--- a/lib/ansible/module_utils/network/ios/config/interfaces/interfaces.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, dict_to_set
-from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class Interfaces(ConfigBase):
- """
- The ios_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'interfaces',
- ]
-
- params = ('description', 'mtu', 'speed', 'duplex')
-
- def __init__(self, module):
- super(Interfaces, self).__init__(module)
-
- def get_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- interfaces_facts = facts['ansible_network_resources'].get('interfaces')
- if not interfaces_facts:
- return []
-
- return interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from moduel execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_interfaces_facts = self.get_interfaces_facts()
- commands.extend(self.set_config(existing_interfaces_facts))
-
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_interfaces_facts = self.get_interfaces_facts()
-
- result['before'] = existing_interfaces_facts
- if result['changed']:
- result['after'] = changed_interfaces_facts
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- want = self._module.params['config']
- have = existing_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- elif interface['name'] in each['name']:
- break
- else:
- # configuring non-existing interface
- commands.extend(self._set_config(interface, dict()))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
-
- :param want: the desired configuration as a dictionary
- :param obj_in_have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- count = 0
- if each['name'] == interface['name']:
- break
- elif interface['name'] in each['name']:
- break
- count += 1
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- interface = dict(name=each['name'])
- commands.extend(self._clear_config(interface, each))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # as the pre-existing interface are now configured by
- # above set_config call, deleting the respective
- # interface entry from the want list
- del want[count]
-
- # Iterating through want list which now only have new interfaces to be
- # configured
- for each in want:
- commands.extend(self._set_config(each, dict()))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :param want: the additive configuration as a dictionary
- :param obj_in_have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- # configuring non-existing interface
- commands.extend(self._set_config(interface, dict()))
- continue
- commands.extend(self._set_config(interface, each))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :param want: the objects from which the configuration should be removed
- :param obj_in_have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- interface = dict(name=interface['name'])
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- want = dict()
- commands.extend(self._clear_config(want, each))
-
- return commands
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
- interface = 'interface ' + want['name']
-
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- diff = dict(diff)
- for item in self.params:
- if diff.get(item):
- cmd = item + ' ' + str(want.get(item))
- add_command_to_config_list(interface, cmd, commands)
- if diff.get('enabled'):
- add_command_to_config_list(interface, 'no shutdown', commands)
- elif diff.get('enabled') is False:
- add_command_to_config_list(interface, 'shutdown', commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- commands = []
-
- if want.get('name'):
- interface_type = get_interface_type(want['name'])
- interface = 'interface ' + want['name']
- else:
- interface_type = get_interface_type(have['name'])
- interface = 'interface ' + have['name']
-
- if have.get('description') and want.get('description') != have.get('description'):
- remove_command_from_config_list(interface, 'description', commands)
- if not have.get('enabled') and want.get('enabled') != have.get('enabled'):
- # if enable is False set enable as True which is the default behavior
- remove_command_from_config_list(interface, 'shutdown', commands)
-
- if interface_type.lower() == 'gigabitethernet':
- if have.get('speed') and have.get('speed') != 'auto' and want.get('speed') != have.get('speed'):
- remove_command_from_config_list(interface, 'speed', commands)
- if have.get('duplex') and have.get('duplex') != 'auto' and want.get('duplex') != have.get('duplex'):
- remove_command_from_config_list(interface, 'duplex', commands)
- if have.get('mtu') and want.get('mtu') != have.get('mtu'):
- remove_command_from_config_list(interface, 'mtu', commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index 1ebfcbda58..0000000000
--- a/lib/ansible/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,336 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_l2_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class L2_Interfaces(ConfigBase):
- """
- The ios_l2_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'l2_interfaces',
- ]
-
- access_cmds = {'access_vlan': 'switchport access vlan'}
- voice_cmds = {'voice_vlan': 'switchport voice vlan'}
- trunk_cmds = {'encapsulation': 'switchport trunk encapsulation', 'pruning_vlans': 'switchport trunk pruning vlan',
- 'native_vlan': 'switchport trunk native vlan', 'allowed_vlans': 'switchport trunk allowed vlan'}
-
- def get_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- interfaces_facts = facts['ansible_network_resources'].get('l2_interfaces')
- if not interfaces_facts:
- return []
-
- return interfaces_facts
-
- def execute_module(self):
- """ Execute the module
- :rtype: A dictionary
- :returns: The result from moduel execution
- """
- result = {'changed': False}
- commands = []
- warnings = []
- existing_facts = self.get_interfaces_facts()
- commands.extend(self.set_config(existing_facts))
- result['before'] = existing_facts
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- interfaces_facts = self.get_interfaces_facts()
-
- if result['changed']:
- result['after'] = interfaces_facts
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
-
- want = self._module.params['config']
- have = existing_facts
- resp = self.set_state(want, have)
-
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have, self._module)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have, self._module)
- elif state == 'replaced':
- commands = self._state_replaced(want, have, self._module)
-
- return commands
-
- def _state_replaced(self, want, have, module):
- """ The command generator when state is replaced
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have, module):
- """ The command generator when state is overridden
- :param want: the desired configuration as a dictionary
- :param obj_in_have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- if each['name'] == interface['name']:
- break
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- interface = dict(name=each['name'])
- kwargs = {'want': interface, 'have': each}
- commands.extend(self._clear_config(**kwargs))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have, module):
- """ The command generator when state is merged
- :param want: the additive configuration as a dictionary
- :param obj_in_have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- commands.extend(self._set_config(interface, each, module))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
- :param want: the objects from which the configuration should be removed
- :param obj_in_have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- interface = dict(name=interface['name'])
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- want = dict()
- commands.extend(self._clear_config(want, each))
-
- return commands
-
- def _check_for_correct_vlan_range(self, vlan, module):
- # Function to check if the VLAN range passed is Valid
- for each in vlan:
- vlan_range = each.split('-')
- if len(vlan_range) > 1:
- if vlan_range[0] < vlan_range[1]:
- return True
- else:
- module.fail_json(msg='Command rejected: Bad VLAN list - end of range not larger than the'
- ' start of range!')
- else:
- return True
-
- def _set_config(self, want, have, module):
- # Set the interface config based on the want and have config
- commands = []
- interface = 'interface ' + want['name']
-
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- want_trunk = dict(want_dict).get('trunk')
- have_trunk = dict(have_dict).get('trunk')
- if want_trunk and have_trunk:
- diff = set(tuple(dict(want_dict).get('trunk'))) - set(tuple(dict(have_dict).get('trunk')))
- else:
- diff = want_dict - have_dict
-
- if diff:
- diff = dict(diff)
- mode = diff.get('mode')
- access = diff.get('access')
- trunk = diff.get('trunk')
-
- if access:
- cmd = 'switchport access vlan {0}'.format(access[0][1])
- add_command_to_config_list(interface, cmd, commands)
-
- if diff.get('voice'):
- cmd = 'switchport voice vlan {0}'.format(diff.get('voice')[0][1])
- add_command_to_config_list(interface, cmd, commands)
-
- if want_trunk:
- if trunk:
- diff = dict(trunk)
- if diff.get('encapsulation'):
- cmd = self.trunk_cmds['encapsulation'] + ' {0}'.format(diff.get('encapsulation'))
- add_command_to_config_list(interface, cmd, commands)
- if diff.get('native_vlan'):
- cmd = self.trunk_cmds['native_vlan'] + ' {0}'.format(diff.get('native_vlan'))
- add_command_to_config_list(interface, cmd, commands)
- allowed_vlans = diff.get('allowed_vlans')
- pruning_vlans = diff.get('pruning_vlans')
-
- if allowed_vlans and self._check_for_correct_vlan_range(allowed_vlans, module):
- allowed_vlans = ','.join(allowed_vlans)
- cmd = self.trunk_cmds['allowed_vlans'] + ' {0}'.format(allowed_vlans)
- add_command_to_config_list(interface, cmd, commands)
- if pruning_vlans and self._check_for_correct_vlan_range(pruning_vlans, module):
- pruning_vlans = ','.join(pruning_vlans)
- cmd = self.trunk_cmds['pruning_vlans'] + ' {0}'.format(pruning_vlans)
- add_command_to_config_list(interface, cmd, commands)
-
- if mode:
- cmd = 'switchport mode {0}'.format(mode)
- add_command_to_config_list(interface, cmd, commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- commands = []
- if want.get('name'):
- interface = 'interface ' + want['name']
- else:
- interface = 'interface ' + have['name']
-
- if have.get('mode') or want.get('mode'):
- remove_command_from_config_list(interface, 'switchport mode', commands)
-
- if have.get('access') and want.get('access') is None:
- remove_command_from_config_list(interface, L2_Interfaces.access_cmds['access_vlan'], commands)
- elif have.get('access') and want.get('access'):
- if have.get('access').get('vlan') != want.get('access').get('vlan'):
- remove_command_from_config_list(interface, L2_Interfaces.access_cmds['access_vlan'], commands)
-
- if have.get('voice') and want.get('voice') is None:
- remove_command_from_config_list(interface, L2_Interfaces.voice_cmds['voice_vlan'], commands)
- elif have.get('voice') and want.get('voice'):
- if have.get('voice').get('vlan') != want.get('voice').get('vlan'):
- remove_command_from_config_list(interface, L2_Interfaces.voice_cmds['voice_vlan'], commands)
-
- if have.get('trunk') and want.get('trunk') is None:
- # Check when no config is passed
- if have.get('trunk').get('encapsulation'):
- remove_command_from_config_list(interface, self.trunk_cmds['encapsulation'], commands)
- if have.get('trunk').get('native_vlan'):
- remove_command_from_config_list(interface, self.trunk_cmds['native_vlan'], commands)
- if have.get('trunk').get('allowed_vlans'):
- remove_command_from_config_list(interface, self.trunk_cmds['allowed_vlans'], commands)
- if have.get('trunk').get('pruning_vlans'):
- remove_command_from_config_list(interface, self.trunk_cmds['pruning_vlans'], commands)
- elif have.get('trunk') and want.get('trunk'):
- # Check when config is passed, also used in replaced and override state
- if have.get('trunk').get('encapsulation')\
- and have.get('trunk').get('encapsulation') != want.get('trunk').get('encapsulation'):
- remove_command_from_config_list(interface, self.trunk_cmds['encapsulation'], commands)
- if have.get('trunk').get('native_vlan') \
- and have.get('trunk').get('native_vlan') != want.get('trunk').get('native_vlan'):
- remove_command_from_config_list(interface, self.trunk_cmds['native_vlan'], commands)
- if have.get('trunk').get('allowed_vlans') \
- and have.get('trunk').get('allowed_vlans') != want.get('trunk').get('allowed_vlans'):
- remove_command_from_config_list(interface, self.trunk_cmds['allowed_vlans'], commands)
- if have.get('trunk').get('pruning_vlans') \
- and have.get('trunk').get('pruning_vlans') != want.get('trunk').get('pruning_vlans'):
- remove_command_from_config_list(interface, self.trunk_cmds['pruning_vlans'], commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 221f276ab2..0000000000
--- a/lib/ansible/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,328 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_l3_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-from ansible.module_utils.network.ios.utils.utils import validate_n_expand_ipv4, validate_ipv6
-
-
-class L3_Interfaces(ConfigBase):
- """
- The ios_l3_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'l3_interfaces'
- ]
-
- def get_l3_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- l3_interfaces_facts = facts['ansible_network_resources'].get('l3_interfaces')
- if not l3_interfaces_facts:
- return []
-
- return l3_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_l3_interfaces_facts = self.get_l3_interfaces_facts()
- commands.extend(self.set_config(existing_l3_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_l3_interfaces_facts = self.get_l3_interfaces_facts()
-
- result['before'] = existing_l3_interfaces_facts
- if result['changed']:
- result['after'] = changed_l3_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_l3_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_l3_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have, self._module)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have, self._module)
- elif state == 'replaced':
- commands = self._state_replaced(want, have, self._module)
-
- return commands
-
- def _state_replaced(self, want, have, module):
- """ The command generator when state is replaced
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- if '.' in interface['name']:
- commands.extend(self._set_config(interface, dict(), module))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have, module):
- """ The command generator when state is overridden
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- if each['name'] == interface['name']:
- break
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- interface = dict(name=each['name'])
- kwargs = {'want': interface, 'have': each}
- commands.extend(self._clear_config(**kwargs))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have, module):
- """ The command generator when state is merged
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- if '.' in interface['name']:
- commands.extend(self._set_config(interface, dict(), module))
- continue
- commands.extend(self._set_config(interface, each, module))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- elif interface['name'] in each['name']:
- break
- else:
- continue
- interface = dict(name=interface['name'])
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- want = dict()
- commands.extend(self._clear_config(want, each))
-
- return commands
-
- def verify_diff_again(self, want, have):
- """
- Verify the IPV4 difference again as sometimes due to
- change in order of set, set difference may result into change,
- when there's actually no difference between want and have
- :param want: want_dict IPV4
- :param have: have_dict IPV4
- :return: diff
- """
- diff = False
- for each in want:
- each_want = dict(each)
- for every in have:
- every_have = dict(every)
- if each_want.get('address') != every_have.get('address') and \
- each_want.get('secondary') != every_have.get('secondary') and \
- len(each_want.keys()) == len(every_have.keys()):
- diff = True
- break
- elif each_want.get('dhcp_client') != every_have.get('dhcp_client') and each_want.get(
- 'dhcp_client') is not None:
- diff = True
- break
- elif each_want.get('dhcp_hostname') != every_have.get('dhcp_hostname') and each_want.get(
- 'dhcp_hostname') is not None:
- diff = True
- break
- elif each_want.get('address') != every_have.get('address') and len(each_want.keys()) == len(
- every_have.keys()):
- diff = True
- break
- if diff:
- break
-
- return diff
-
- def _set_config(self, want, have, module):
- # Set the interface config based on the want and have config
- commands = []
- interface = 'interface ' + want['name']
-
- # To handle L3 IPV4 configuration
- if want.get("ipv4"):
- for each in want.get("ipv4"):
- if each.get('address') != 'dhcp':
- ip_addr_want = validate_n_expand_ipv4(module, each)
- each['address'] = ip_addr_want
-
- # Convert the want and have dict to set
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
-
- # To handle L3 IPV4 configuration
- if want.get('ipv4'):
- # Get the diff b/w want and have IPV4
- if have.get('ipv4'):
- ipv4 = tuple(set(dict(want_dict).get('ipv4')) - set(dict(have_dict).get('ipv4')))
- if ipv4:
- ipv4 = ipv4 if self.verify_diff_again(dict(want_dict).get('ipv4'), dict(have_dict).get('ipv4')) else ()
- else:
- diff = want_dict - have_dict
- ipv4 = dict(diff).get('ipv4')
- if ipv4:
- for each in ipv4:
- ipv4_dict = dict(each)
- if ipv4_dict.get('address') != 'dhcp':
- cmd = "ip address {0}".format(ipv4_dict['address'])
- if ipv4_dict.get("secondary"):
- cmd += " secondary"
- elif ipv4_dict.get('address') == 'dhcp':
- cmd = "ip address dhcp"
- if ipv4_dict.get('dhcp_client') is not None and ipv4_dict.get('dhcp_hostname'):
- cmd = "ip address dhcp client-id GigabitEthernet 0/{0} hostname {1}"\
- .format(ipv4_dict.get('dhcp_client'), ipv4_dict.get('dhcp_hostname'))
- elif ipv4_dict.get('dhcp_client') and not ipv4_dict.get('dhcp_hostname'):
- cmd = "ip address dhcp client-id GigabitEthernet 0/{0}"\
- .format(ipv4_dict.get('dhcp_client'))
- elif not ipv4_dict.get('dhcp_client') and ipv4_dict.get('dhcp_hostname'):
- cmd = "ip address dhcp hostname {0}".format(ipv4_dict.get('dhcp_client'))
-
- add_command_to_config_list(interface, cmd, commands)
-
- # To handle L3 IPV6 configuration
- if want.get('ipv6'):
- # Get the diff b/w want and have IPV6
- if have.get('ipv6'):
- ipv6 = tuple(set(dict(want_dict).get('ipv6')) - set(dict(have_dict).get('ipv6')))
- else:
- diff = want_dict - have_dict
- ipv6 = dict(diff).get('ipv6')
- if ipv6:
- for each in ipv6:
- ipv6_dict = dict(each)
- validate_ipv6(ipv6_dict.get('address'), module)
- cmd = "ipv6 address {0}".format(ipv6_dict.get('address'))
- add_command_to_config_list(interface, cmd, commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- count = 0
- commands = []
- if want.get('name'):
- interface = 'interface ' + want['name']
- else:
- interface = 'interface ' + have['name']
-
- if have.get('ipv4') and want.get('ipv4'):
- for each in have.get('ipv4'):
- if each.get('secondary') and not (want.get('ipv4')[count].get('secondary')):
- cmd = 'ipv4 address {0} secondary'.format(each.get('address'))
- remove_command_from_config_list(interface, cmd, commands)
- count += 1
- if have.get('ipv4') and not want.get('ipv4'):
- remove_command_from_config_list(interface, 'ip address', commands)
- if have.get('ipv6') and not want.get('ipv6'):
- remove_command_from_config_list(interface, 'ipv6 address', commands)
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/lacp/lacp.py b/lib/ansible/module_utils/network/ios/config/lacp/lacp.py
deleted file mode 100644
index 3f6bc0c0eb..0000000000
--- a/lib/ansible/module_utils/network/ios/config/lacp/lacp.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lacp class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-
-
-class Lacp(ConfigBase):
- """
- The ios_lacp class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lacp',
- ]
-
- def __init__(self, module):
- super(Lacp, self).__init__(module)
-
- def get_lacp_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lacp_facts = facts['ansible_network_resources'].get('lacp')
- if not lacp_facts:
- return []
-
- return lacp_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lacp_facts = self.get_lacp_facts()
- commands.extend(self.set_config(existing_lacp_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lacp_facts = self.get_lacp_facts()
-
- result['before'] = existing_lacp_facts
- if result['changed']:
- result['after'] = changed_lacp_facts
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_lacp_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_lacp_facts
- resp = self.set_state(want, have)
-
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- commands.extend(self._set_config(want, have))
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- commands.extend(self._set_config(want, have))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- commands.extend(self._clear_config(have))
- else:
- commands.extend(self._clear_config(have))
-
- return commands
-
- def _remove_command_from_config_list(self, cmd, commands):
- commands.append('no %s' % cmd)
- return commands
-
- def _add_command_to_config_list(self, cmd, commands):
- if cmd not in commands:
- commands.append(cmd)
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
-
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- cmd = 'lacp system-priority {0}'.format(want.get('system').get('priority'))
- self._add_command_to_config_list(cmd, commands)
-
- return commands
-
- def _clear_config(self, have):
- # Delete the interface config based on the want and have config
- commands = []
-
- if have.get('system').get('priority') and have.get('system').get('priority') != 32768:
- cmd = 'lacp system-priority'
- self._remove_command_from_config_list(cmd, commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 71ac96d0c3..0000000000
--- a/lib/ansible/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,260 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lacp_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class Lacp_Interfaces(ConfigBase):
- """
- The ios_lacp_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lacp_interfaces',
- ]
-
- def __init__(self, module):
- super(Lacp_Interfaces, self).__init__(module)
-
- def get_lacp_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lacp_interfaces_facts = facts['ansible_network_resources'].get('lacp_interfaces')
-
- if not lacp_interfaces_facts:
- return []
- return lacp_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
- commands.extend(self.set_config(existing_lacp_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
-
- result['before'] = existing_lacp_interfaces_facts
- if result['changed']:
- result['after'] = changed_lacp_interfaces_facts
-
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_lacp_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_lacp_interfaces_facts
- resp = self.set_state(want, have)
-
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- if each['name'] == interface['name']:
- break
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- interface = dict(name=each['name'])
- commands.extend(self._clear_config(interface, each))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if interface['name'] == each['name']:
- break
- else:
- continue
- commands.extend(self._set_config(interface, each))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- interface = dict(name=interface['name'])
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- commands.extend(self._clear_config(dict(), each))
-
- return commands
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
- interface = 'interface ' + have['name']
-
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- port_priotity = dict(diff).get('port_priority')
- max_bundle = dict(diff).get('max_bundle')
- fast_switchover = dict(diff).get('fast_switchover')
- if port_priotity:
- cmd = 'lacp port-priority {0}'.format(port_priotity)
- add_command_to_config_list(interface, cmd, commands)
- if max_bundle:
- cmd = 'lacp max-bundle {0}'.format(max_bundle)
- add_command_to_config_list(interface, cmd, commands)
- if fast_switchover:
- cmd = 'lacp fast-switchover'
- add_command_to_config_list(interface, cmd, commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- commands = []
- if want.get('name'):
- interface = 'interface ' + want['name']
- else:
- interface = 'interface ' + have['name']
-
- if have.get('port_priority') and have.get('port_priority') != want.get('port_priority'):
- cmd = 'lacp port-priority'
- remove_command_from_config_list(interface, cmd, commands)
- if have.get('max_bundle') and have.get('max_bundle') != want.get('max_bundle'):
- cmd = 'lacp max-bundle'
- remove_command_from_config_list(interface, cmd, commands)
- if have.get('fast_switchover'):
- cmd = 'lacp fast-switchover'
- remove_command_from_config_list(interface, cmd, commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index c4760c1061..0000000000
--- a/lib/ansible/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,296 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lag_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class Lag_interfaces(ConfigBase):
- """
- The ios_lag_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lag_interfaces',
- ]
-
- def __init__(self, module):
- super(Lag_interfaces, self).__init__(module)
-
- def get_lag_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lag_interfaces_facts = facts['ansible_network_resources'].get('lag_interfaces')
- if not lag_interfaces_facts:
- return []
- return lag_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
- commands.extend(self.set_config(existing_lag_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lag_interfaces_facts = self.get_lag_interfaces_facts()
-
- result['before'] = existing_lag_interfaces_facts
- if result['changed']:
- result['after'] = changed_lag_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_lag_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_lag_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
-
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- module = self._module
- if state == 'overridden':
- commands = self._state_overridden(want, have, module)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have, module)
- elif state == 'replaced':
- commands = self._state_replaced(want, have, module)
- return commands
-
- def _state_replaced(self, want, have, module):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for interface in want:
- for each_interface in interface.get('members'):
- for each in have:
- if each.get('members'):
- for every in each.get('members'):
- match = False
- if every['member'] == each_interface['member']:
- match = True
- break
- else:
- continue
- if match:
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- elif each.get('name') == each_interface['member']:
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- break
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have, module):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for interface in want:
- for each_interface in interface.get('members'):
- for each in have:
- if each.get('members'):
- for every in each.get('members'):
- match = False
- if every['member'] == each_interface['member']:
- match = True
- break
- else:
- commands.extend(self._clear_config(interface, each))
- continue
- if match:
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- elif each.get('name') == each_interface['member']:
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each, module))
- break
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have, module):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each_interface in interface.get('members'):
- for each in have:
- if each.get('members'):
- for every in each.get('members'):
- if every['member'] == each_interface['member']:
- break
- elif each.get('name') == each_interface['member']:
- break
- else:
- continue
- commands.extend(self._set_config(interface, each, module))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each.get('name') == interface['name']:
- break
- else:
- continue
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- commands.extend(self._clear_config(dict(), each))
-
- return commands
-
- def remove_command_from_config_list(self, interface, cmd, commands):
- # To delete the passed config
- if interface not in commands:
- commands.append(interface)
- commands.append('no %s' % cmd)
- return commands
-
- def add_command_to_config_list(self, interface, cmd, commands):
- # To set the passed config
- if interface not in commands:
- commands.append(interface)
- commands.append(cmd)
- return commands
-
- def _set_config(self, want, have, module):
- # Set the interface config based on the want and have config
- commands = []
-
- # To remove keys with None values from want dict
- want = utils.remove_empties(want)
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- # To get the channel-id from lag port-channel name
- lag_config = dict(diff).get('members')
- channel_name = re.search(r'(\d+)', want.get('name'))
- if channel_name:
- channel_id = channel_name.group()
- else:
- module.fail_json(msg="Lag Interface Name is not correct!")
- if lag_config:
- for each in lag_config:
- each = dict(each)
- each_interface = 'interface {0}'.format(each.get('member'))
- if have.get('name') == want['members'][0]['member'] or have.get('name').lower().startswith('po'):
- if each.get('mode'):
- cmd = 'channel-group {0} mode {1}'.format(channel_id, each.get('mode'))
- self.add_command_to_config_list(each_interface, cmd, commands)
- elif each.get('link'):
- cmd = 'channel-group {0} link {1}'.format(channel_id, each.get('link'))
- self.add_command_to_config_list(each_interface, cmd, commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- commands = []
-
- if have.get('members'):
- for each in have['members']:
- interface = 'interface ' + each['member']
- if want.get('members'):
- if each.get('member') and each.get('member') != want['members'][0]['member']:
- self.remove_command_from_config_list(interface, 'channel-group', commands)
- elif each.get('member'):
- self.remove_command_from_config_list(interface, 'channel-group', commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py
deleted file mode 100644
index a3f6dd6091..0000000000
--- a/lib/ansible/module_utils/network/ios/config/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lldp_global class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to its desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value
-
-
-class Lldp_global(ConfigBase):
- """
- The ios_lldp_global class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lldp_global',
- ]
-
- tlv_select_params = {'four_wire_power_management': '4-wire-power-management', 'mac_phy_cfg': 'mac-phy-cfg',
- 'management_address': 'management-address', 'port_description': 'port-description',
- 'port_vlan': 'port-vlan', 'power_management': 'power-management',
- 'system_capabilities': 'system-capabilities', 'system_description': 'system-description',
- 'system_name': 'system-name'}
-
- def __init__(self, module):
- super(Lldp_global, self).__init__(module)
-
- def get_lldp_global_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lldp_global_facts = facts['ansible_network_resources'].get('lldp_global')
- if not lldp_global_facts:
- return {}
-
- return lldp_global_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from moduel execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lldp_global_facts = self.get_lldp_global_facts()
- commands.extend(self.set_config(existing_lldp_global_facts))
-
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lldp_global_facts = self.get_lldp_global_facts()
-
- result['before'] = existing_lldp_global_facts
- if result['changed']:
- result['after'] = changed_lldp_global_facts
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_lldp_global_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- want = self._module.params['config']
- have = existing_lldp_global_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
- state = self._module.params['state']
- if state in ('merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the deisred configuration
- """
- commands = []
-
- have_dict = filter_dict_having_none_value(want, have)
- commands.extend(self._clear_config(have_dict))
- commands.extend(self._set_config(want, have))
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :param want: the additive configuration as a dictionary
- :param obj_in_have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- commands.extend(self._set_config(want, have))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :param want: the objects from which the configuration should be removed
- :param obj_in_have: the current configuration as a dictionary
- :param interface_type: interface type
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- commands.extend(self._clear_config(have))
-
- return commands
-
- def _remove_command_from_config_list(self, cmd, commands):
- if cmd not in commands:
- commands.append('no %s' % cmd)
-
- def add_command_to_config_list(self, cmd, commands):
- if cmd not in commands:
- commands.append(cmd)
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
-
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- diff = dict(diff)
- holdtime = diff.get('holdtime')
- enabled = diff.get('enabled')
- timer = diff.get('timer')
- reinit = diff.get('reinit')
- tlv_select = diff.get('tlv_select')
-
- if holdtime:
- cmd = 'lldp holdtime {0}'.format(holdtime)
- self.add_command_to_config_list(cmd, commands)
- if enabled:
- cmd = 'lldp run'
- self.add_command_to_config_list(cmd, commands)
- if timer:
- cmd = 'lldp timer {0}'.format(timer)
- self.add_command_to_config_list(cmd, commands)
- if reinit:
- cmd = 'lldp reinit {0}'.format(reinit)
- self.add_command_to_config_list(cmd, commands)
- if tlv_select:
- tlv_selec_dict = dict(tlv_select)
- for k, v in iteritems(self.tlv_select_params):
- if k in tlv_selec_dict and tlv_selec_dict[k]:
- cmd = 'lldp tlv-select {0}'.format(v)
- self.add_command_to_config_list(cmd, commands)
-
- return commands
-
- def _clear_config(self, have):
- # Delete the interface config based on the want and have config
- commands = []
-
- if have.get('holdtime'):
- cmd = 'lldp holdtime'
- self._remove_command_from_config_list(cmd, commands)
- if have.get('enabled'):
- cmd = 'lldp run'
- self._remove_command_from_config_list(cmd, commands)
- if have.get('timer'):
- cmd = 'lldp timer'
- self._remove_command_from_config_list(cmd, commands)
- if have.get('reinit'):
- cmd = 'lldp reinit'
- self._remove_command_from_config_list(cmd, commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index 57a6a3cd4c..0000000000
--- a/lib/ansible/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lldp_interfaces class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to its desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-from ansible.module_utils.network.ios.utils.utils import remove_command_from_config_list, add_command_to_config_list
-from ansible.module_utils.network.ios.utils.utils import filter_dict_having_none_value, remove_duplicate_interface
-
-
-class Lldp_Interfaces(ConfigBase):
- """
- The ios_lldp_interfaces class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'lldp_interfaces',
- ]
-
- def __init__(self, module):
- super(Lldp_Interfaces, self).__init__(module)
-
- def get_lldp_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- lldp_interfaces_facts = facts['ansible_network_resources'].get('lldp_interfaces')
-
- if not lldp_interfaces_facts:
- return []
- return lldp_interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
- commands.extend(self.set_config(existing_lldp_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
-
- result['before'] = existing_lldp_interfaces_facts
- if result['changed']:
- result['after'] = changed_lldp_interfaces_facts
-
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_lldp_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_lldp_interfaces_facts
- resp = self.set_state(want, have)
-
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
-
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- for each in have:
- for interface in want:
- if each['name'] == interface['name']:
- break
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- interface = dict(name=each['name'])
- commands.extend(self._clear_config(interface, each))
- continue
- have_dict = filter_dict_having_none_value(interface, each)
- commands.extend(self._clear_config(dict(), have_dict))
- commands.extend(self._set_config(interface, each))
- # Remove the duplicate interface call
- commands = remove_duplicate_interface(commands)
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- for interface in want:
- for each in have:
- if interface['name'] == each['name']:
- break
- else:
- continue
- commands.extend(self._set_config(interface, each))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- for interface in want:
- for each in have:
- if each['name'] == interface['name']:
- break
- else:
- continue
- interface = dict(name=interface['name'])
- commands.extend(self._clear_config(interface, each))
- else:
- for each in have:
- commands.extend(self._clear_config(dict(), each))
-
- return commands
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
-
- interface = 'interface ' + have['name']
- # Get the diff b/w want and have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- diff = dict(diff)
- receive = diff.get('receive')
- transmit = diff.get('transmit')
- med_tlv_select = diff.get('med_tlv_select')
- tlv_select = diff.get('tlv_select')
- if receive:
- cmd = 'lldp receive'
- add_command_to_config_list(interface, cmd, commands)
- elif receive is False:
- cmd = 'no lldp receive'
- add_command_to_config_list(interface, cmd, commands)
- if transmit:
- cmd = 'lldp transmit'
- add_command_to_config_list(interface, cmd, commands)
- elif transmit is False:
- cmd = 'no lldp transmit'
- add_command_to_config_list(interface, cmd, commands)
-
- if med_tlv_select:
- med_tlv_select = dict(med_tlv_select)
- if med_tlv_select.get('inventory_management'):
- add_command_to_config_list(interface, 'lldp med-tlv-select inventory-management', commands)
- if tlv_select:
- tlv_select = dict(tlv_select)
- if tlv_select.get('power_management'):
- add_command_to_config_list(interface, 'lldp tlv-select power-management', commands)
-
- return commands
-
- def _clear_config(self, want, have):
- # Delete the interface config based on the want and have config
- commands = []
- if want.get('name'):
- interface = 'interface ' + want['name']
- else:
- interface = 'interface ' + have['name']
-
- if have.get('receive') and have.get('receive') != want.get('receive'):
- cmd = 'lldp receive'
- remove_command_from_config_list(interface, cmd, commands)
- if have.get('transmit') and have.get('transmit') != want.get('transmit'):
- cmd = 'lldp transmit'
- remove_command_from_config_list(interface, cmd, commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py
deleted file mode 100644
index 0e3eb4a66b..0000000000
--- a/lib/ansible/module_utils/network/ios/config/static_routes/static_routes.py
+++ /dev/null
@@ -1,532 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_static_routes class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import copy
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import new_dict_to_set, validate_n_expand_ipv4, filter_dict_having_none_value
-
-
-class Static_Routes(ConfigBase):
- """
- The ios_static_routes class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'static_routes',
- ]
-
- def __init__(self, module):
- super(Static_Routes, self).__init__(module)
-
- def get_static_routes_facts(self, data=None):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data)
- static_routes_facts = facts['ansible_network_resources'].get('static_routes')
- if not static_routes_facts:
- return []
- return static_routes_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- if self.state in self.ACTION_STATES:
- existing_static_routes_facts = self.get_static_routes_facts()
- else:
- existing_static_routes_facts = []
-
- if self.state in self.ACTION_STATES or self.state == 'rendered':
- commands.extend(self.set_config(existing_static_routes_facts))
-
- if commands and self.state in self.ACTION_STATES:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
-
- if self.state in self.ACTION_STATES:
- result['commands'] = commands
-
- if self.state in self.ACTION_STATES or self.state == 'gathered':
- changed_static_routes_facts = self.get_static_routes_facts()
- elif self.state == 'rendered':
- result['rendered'] = commands
- elif self.state == 'parsed':
- running_config = self._module.params['running_config']
- if not running_config:
- self._module.fail_json(
- msg="value of running_config parameter must not be empty for state parsed"
- )
- result['parsed'] = self.get_static_routes_facts(data=running_config)
- else:
- changed_static_routes_facts = []
-
- if self.state in self.ACTION_STATES:
- result['before'] = existing_static_routes_facts
- if result['changed']:
- result['after'] = changed_static_routes_facts
- elif self.state == 'gathered':
- result['gathered'] = changed_static_routes_facts
-
- result['warnings'] = warnings
-
- return result
-
- def set_config(self, existing_static_routes_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_static_routes_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced', 'rendered') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
- commands = []
- if state == 'overridden':
- commands = self._state_overridden(want, have)
- elif state == 'deleted':
- commands = self._state_deleted(want, have)
- elif state == 'merged' or state == 'rendered':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
-
- commands = []
-
- # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call
- for w in want:
- for addr_want in w.get('address_families'):
- for route_want in addr_want.get('routes'):
- check = False
- for h in have:
- if h.get('address_families'):
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- if route_want.get('dest') == route_have.get('dest')\
- and addr_want['afi'] == addr_have['afi']:
- check = True
- have_set = set()
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- new_dict_to_set(addr_have, [], have_set, 0)
- # Check if the have dict next_hops value is diff from want dict next_hops
- have_dict = filter_dict_having_none_value(route_want.get('next_hops')[0],
- route_have.get('next_hops')[0])
- # update the have_dict with forward_router_address
- have_dict.update({'forward_router_address': route_have.get('next_hops')[0].
- get('forward_router_address')})
- # updating the have_dict with next_hops val that's not None
- new_have_dict = {}
- for k, v in have_dict.items():
- if v is not None:
- new_have_dict.update({k: v})
-
- # Set the new config from the user provided want config
- cmd = self._set_config(w, h, addr_want, route_want, route_have, new_hops, have_set)
-
- if cmd:
- # since inplace update isn't allowed for static routes, preconfigured
- # static routes needs to be deleted before the new want static routes changes
- # are applied
- clear_route_have = copy.deepcopy(route_have)
- # inplace update is allowed in case of ipv6 static routes, so not deleting it
- # before applying the want changes
- if ':' not in route_want.get('dest'):
- commands.extend(self._clear_config({}, h, {}, addr_have,
- {}, clear_route_have))
- commands.extend(cmd)
- if check:
- break
- if check:
- break
- if not check:
- # For configuring any non-existing want config
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set()))
- commands = [each for each in commands if 'no' in each] + \
- [each for each in commands if 'no' not in each]
-
- return commands
-
- def _state_overridden(self, want, have):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
-
- commands = []
- # Creating a copy of want, so that want dict is intact even after delete operation
- # performed during override want n have comparison
- temp_want = copy.deepcopy(want)
-
- # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call
- for h in have:
- if h.get('address_families'):
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- check = False
- for w in temp_want:
- for addr_want in w.get('address_families'):
- count = 0
- for route_want in addr_want.get('routes'):
- if route_want.get('dest') == route_have.get('dest') \
- and addr_want['afi'] == addr_have['afi']:
- check = True
- have_set = set()
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- new_dict_to_set(addr_have, [], have_set, 0)
- commands.extend(self._clear_config(w, h, addr_want, addr_have,
- route_want, route_have))
- commands.extend(self._set_config(w, h, addr_want,
- route_want, route_have, new_hops, have_set))
- del addr_want.get('routes')[count]
- count += 1
- if check:
- break
- if check:
- break
- if not check:
- commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have))
- # For configuring any non-existing want config
- for w in temp_want:
- for addr_want in w.get('address_families'):
- for route_want in addr_want.get('routes'):
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set()))
- # Arranging the cmds suct that all delete cmds are fired before all set cmds
- commands = [each for each in sorted(commands) if 'no' in each] + \
- [each for each in sorted(commands) if 'no' not in each]
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- # Drill each iteration of want n have and then based on dest and afi tyoe comparison take config call
- for w in want:
- for addr_want in w.get('address_families'):
- for route_want in addr_want.get('routes'):
- check = False
- for h in have:
- if h.get('address_families'):
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- if route_want.get('dest') == route_have.get('dest')\
- and addr_want['afi'] == addr_have['afi']:
- check = True
- have_set = set()
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- new_dict_to_set(addr_have, [], have_set, 0)
- commands.extend(self._set_config(w, h, addr_want,
- route_want, route_have, new_hops, have_set))
- if check:
- break
- if check:
- break
- if not check:
- # For configuring any non-existing want config
- new_hops = []
- for each in route_want.get('next_hops'):
- want_set = set()
- new_dict_to_set(each, [], want_set, 0)
- new_hops.append(want_set)
- commands.extend(self._set_config(w, {}, addr_want, route_want, {}, new_hops, set()))
-
- return commands
-
- def _state_deleted(self, want, have):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- # Drill each iteration of want n have and then based on dest and afi type comparison fire delete config call
- for w in want:
- if w.get('address_families'):
- for addr_want in w.get('address_families'):
- for route_want in addr_want.get('routes'):
- check = False
- for h in have:
- if h.get('address_families'):
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- if route_want.get('dest') == route_have.get('dest') \
- and addr_want['afi'] == addr_have['afi']:
- check = True
- if route_want.get('next_hops'):
- commands.extend(self._clear_config({}, w, {}, addr_want, {}, route_want))
- else:
- commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have))
- if check:
- break
- if check:
- break
- else:
- for h in have:
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- if w.get('vrf') == h.get('vrf'):
- commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have))
- else:
- # Drill each iteration of have and then based on dest and afi type comparison fire delete config call
- for h in have:
- for addr_have in h.get('address_families'):
- for route_have in addr_have.get('routes'):
- commands.extend(self._clear_config({}, h, {}, addr_have, {}, route_have))
-
- return commands
-
- def prepare_config_commands(self, config_dict, cmd):
- """
- function to parse the input dict and form the prepare the config commands
- :rtype: A str
- :returns: The command necessary to configure the static routes
- """
-
- dhcp = config_dict.get('dhcp')
- distance_metric = config_dict.get('distance_metric')
- forward_router_address = config_dict.get('forward_router_address')
- global_route_config = config_dict.get('global')
- interface = config_dict.get('interface')
- multicast = config_dict.get('multicast')
- name = config_dict.get('name')
- permanent = config_dict.get('permanent')
- tag = config_dict.get('tag')
- track = config_dict.get('track')
- dest = config_dict.get('dest')
- temp_dest = dest.split('/')
- if temp_dest and ':' not in dest:
- dest = validate_n_expand_ipv4(self._module, {'address': dest})
-
- cmd = cmd + dest
- if interface:
- cmd = cmd + ' {0}'.format(interface)
- if forward_router_address:
- cmd = cmd + ' {0}'.format(forward_router_address)
- if dhcp:
- cmd = cmd + ' DHCP'
- if distance_metric:
- cmd = cmd + ' {0}'.format(distance_metric)
- if global_route_config:
- cmd = cmd + ' global'
- if multicast:
- cmd = cmd + ' multicast'
- if name:
- cmd = cmd + ' name {0}'.format(name)
- if permanent:
- cmd = cmd + ' permanent'
- elif track:
- cmd = cmd + ' track {0}'.format(track)
- if tag:
- cmd = cmd + ' tag {0}'.format(tag)
-
- return cmd
-
- def _set_config(self, want, have, addr_want, route_want, route_have, hops, have_set):
- """
- Set the interface config based on the want and have config
- :rtype: A list
- :returns: The commands necessary to configure the static routes
- """
-
- commands = []
- cmd = None
-
- vrf_diff = False
- topology_diff = False
- want_vrf = want.get('vrf')
- have_vrf = have.get('vrf')
- if want_vrf != have_vrf:
- vrf_diff = True
- want_topology = want.get('topology')
- have_topology = have.get('topology')
- if want_topology != have_topology:
- topology_diff = True
-
- have_dest = route_have.get('dest')
- if have_dest:
- have_set.add(tuple(iteritems({'dest': have_dest})))
-
- # configure set cmd for each hops under the same destination
- for each in hops:
- diff = each - have_set
- if vrf_diff:
- each.add(tuple(iteritems({'vrf': want_vrf})))
- if topology_diff:
- each.add(tuple(iteritems({'topology': want_topology})))
- if diff or vrf_diff or topology_diff:
- if want_vrf and not vrf_diff:
- each.add(tuple(iteritems({'vrf': want_vrf})))
- if want_topology and not vrf_diff:
- each.add(tuple(iteritems({'topology': want_topology})))
- each.add(tuple(iteritems({'afi': addr_want.get('afi')})))
- each.add(tuple(iteritems({'dest': route_want.get('dest')})))
- temp_want = {}
- for each_want in each:
- temp_want.update(dict(each_want))
-
- if temp_want.get('afi') == 'ipv4':
- cmd = 'ip route '
- vrf = temp_want.get('vrf')
- if vrf:
- cmd = cmd + 'vrf {0} '.format(vrf)
- cmd = self.prepare_config_commands(temp_want, cmd)
- elif temp_want.get('afi') == 'ipv6':
- cmd = 'ipv6 route '
- cmd = self.prepare_config_commands(temp_want, cmd)
- commands.append(cmd)
-
- return commands
-
- def _clear_config(self, want, have, addr_want, addr_have, route_want, route_have):
- """
- Delete the interface config based on the want and have config
- :rtype: A list
- :returns: The commands necessary to configure the static routes
- """
-
- commands = []
- cmd = None
-
- vrf_diff = False
- topology_diff = False
- want_vrf = want.get('vrf')
- have_vrf = have.get('vrf')
- if want_vrf != have_vrf:
- vrf_diff = True
- want_topology = want.get('topology')
- have_topology = have.get('topology')
- if want_topology != have_topology:
- topology_diff = True
-
- want_set = set()
- new_dict_to_set(addr_want, [], want_set, 0)
-
- have_hops = []
- for each in route_have.get('next_hops'):
- temp_have_set = set()
- new_dict_to_set(each, [], temp_have_set, 0)
- have_hops.append(temp_have_set)
-
- # configure delete cmd for each hops under the same destination
- for each in have_hops:
- diff = each - want_set
- if vrf_diff:
- each.add(tuple(iteritems({'vrf': have_vrf})))
- if topology_diff:
- each.add(tuple(iteritems({'topology': want_topology})))
- if diff or vrf_diff or topology_diff:
- if want_vrf and not vrf_diff:
- each.add(tuple(iteritems({'vrf': want_vrf})))
- if want_topology and not vrf_diff:
- each.add(tuple(iteritems({'topology': want_topology})))
- if addr_want:
- each.add(tuple(iteritems({'afi': addr_want.get('afi')})))
- else:
- each.add(tuple(iteritems({'afi': addr_have.get('afi')})))
- if route_want:
- each.add(tuple(iteritems({'dest': route_want.get('dest')})))
- else:
- each.add(tuple(iteritems({'dest': route_have.get('dest')})))
- temp_want = {}
- for each_want in each:
- temp_want.update(dict(each_want))
-
- if temp_want.get('afi') == 'ipv4':
- cmd = 'no ip route '
- vrf = temp_want.get('vrf')
- if vrf:
- cmd = cmd + 'vrf {0} '.format(vrf)
- cmd = self.prepare_config_commands(temp_want, cmd)
- elif temp_want.get('afi') == 'ipv6':
- cmd = 'no ipv6 route '
- cmd = self.prepare_config_commands(temp_want, cmd)
- commands.append(cmd)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/config/vlans/vlans.py b/lib/ansible/module_utils/network/ios/config/vlans/vlans.py
deleted file mode 100644
index d77e298770..0000000000
--- a/lib/ansible/module_utils/network/ios/config/vlans/vlans.py
+++ /dev/null
@@ -1,292 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_vlans class
-It is in this file where the current configuration (as dict)
-is compared to the provided configuration (as dict) and the command set
-necessary to bring the current configuration to it's desired end-state is
-created
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.cfg.base import ConfigBase
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.utils.utils import dict_to_set
-
-
-class Vlans(ConfigBase):
- """
- The ios_vlans class
- """
-
- gather_subset = [
- '!all',
- '!min',
- ]
-
- gather_network_resources = [
- 'vlans',
- ]
-
- def __init__(self, module):
- super(Vlans, self).__init__(module)
-
- def get_interfaces_facts(self):
- """ Get the 'facts' (the current configuration)
-
- :rtype: A dictionary
- :returns: The current configuration as a dictionary
- """
- facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
- interfaces_facts = facts['ansible_network_resources'].get('vlans')
- if not interfaces_facts:
- return []
- return interfaces_facts
-
- def execute_module(self):
- """ Execute the module
-
- :rtype: A dictionary
- :returns: The result from module execution
- """
- result = {'changed': False}
- commands = list()
- warnings = list()
-
- existing_interfaces_facts = self.get_interfaces_facts()
- commands.extend(self.set_config(existing_interfaces_facts))
- if commands:
- if not self._module.check_mode:
- self._connection.edit_config(commands)
- result['changed'] = True
- result['commands'] = commands
-
- changed_interfaces_facts = self.get_interfaces_facts()
-
- result['before'] = existing_interfaces_facts
- if result['changed']:
- result['after'] = changed_interfaces_facts
-
- result['warnings'] = warnings
- return result
-
- def set_config(self, existing_interfaces_facts):
- """ Collect the configuration from the args passed to the module,
- collect the current configuration (as a dict from facts)
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- want = self._module.params['config']
- have = existing_interfaces_facts
- resp = self.set_state(want, have)
- return to_list(resp)
-
- def set_state(self, want, have):
- """ Select the appropriate function based on the state provided
-
- :param want: the desired configuration as a dictionary
- :param have: the current configuration as a dictionary
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- state = self._module.params['state']
- if state in ('overridden', 'merged', 'replaced') and not want:
- self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(state))
-
- if state == 'overridden':
- commands = self._state_overridden(want, have, state)
- elif state == 'deleted':
- commands = self._state_deleted(want, have, state)
- elif state == 'merged':
- commands = self._state_merged(want, have)
- elif state == 'replaced':
- commands = self._state_replaced(want, have)
- return commands
-
- def _state_replaced(self, want, have):
- """ The command generator when state is replaced
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- check = False
- for each in want:
- for every in have:
- if every['vlan_id'] == each['vlan_id']:
- check = True
- break
- else:
- continue
- if check:
- commands.extend(self._set_config(each, every))
- else:
- commands.extend(self._set_config(each, dict()))
-
- return commands
-
- def _state_overridden(self, want, have, state):
- """ The command generator when state is overridden
-
- :rtype: A list
- :returns: the commands necessary to migrate the current configuration
- to the desired configuration
- """
- commands = []
-
- want_local = want
- for each in have:
- count = 0
- for every in want_local:
- if each['vlan_id'] == every['vlan_id']:
- break
- count += 1
- else:
- # We didn't find a matching desired state, which means we can
- # pretend we received an empty desired state.
- commands.extend(self._clear_config(every, each, state))
- continue
- commands.extend(self._set_config(every, each))
- # as the pre-existing VLAN are now configured by
- # above set_config call, deleting the respective
- # VLAN entry from the want_local list
- del want_local[count]
-
- # Iterating through want_local list which now only have new VLANs to be
- # configured
- for each in want_local:
- commands.extend(self._set_config(each, dict()))
-
- return commands
-
- def _state_merged(self, want, have):
- """ The command generator when state is merged
-
- :rtype: A list
- :returns: the commands necessary to merge the provided into
- the current configuration
- """
- commands = []
-
- check = False
- for each in want:
- for every in have:
- if each.get('vlan_id') == every.get('vlan_id'):
- check = True
- break
- else:
- continue
- if check:
- commands.extend(self._set_config(each, every))
- else:
- commands.extend(self._set_config(each, dict()))
-
- return commands
-
- def _state_deleted(self, want, have, state):
- """ The command generator when state is deleted
-
- :rtype: A list
- :returns: the commands necessary to remove the current configuration
- of the provided objects
- """
- commands = []
-
- if want:
- check = False
- for each in want:
- for every in have:
- if each.get('vlan_id') == every.get('vlan_id'):
- check = True
- break
- else:
- check = False
- continue
- if check:
- commands.extend(self._clear_config(each, every, state))
- else:
- for each in have:
- commands.extend(self._clear_config(dict(), each, state))
-
- return commands
-
- def remove_command_from_config_list(self, vlan, cmd, commands):
- if vlan not in commands and cmd != 'vlan':
- commands.insert(0, vlan)
- elif cmd == 'vlan':
- commands.append('no %s' % vlan)
- return commands
- commands.append('no %s' % cmd)
- return commands
-
- def add_command_to_config_list(self, vlan_id, cmd, commands):
- if vlan_id not in commands:
- commands.insert(0, vlan_id)
- if cmd not in commands:
- commands.append(cmd)
-
- def _set_config(self, want, have):
- # Set the interface config based on the want and have config
- commands = []
- vlan = 'vlan {0}'.format(want.get('vlan_id'))
-
- # Get the diff b/w want n have
- want_dict = dict_to_set(want)
- have_dict = dict_to_set(have)
- diff = want_dict - have_dict
-
- if diff:
- name = dict(diff).get('name')
- state = dict(diff).get('state')
- shutdown = dict(diff).get('shutdown')
- mtu = dict(diff).get('mtu')
- remote_span = dict(diff).get('remote_span')
- if name:
- cmd = 'name {0}'.format(name)
- self.add_command_to_config_list(vlan, cmd, commands)
- if state:
- cmd = 'state {0}'.format(state)
- self.add_command_to_config_list(vlan, cmd, commands)
- if mtu:
- cmd = 'mtu {0}'.format(mtu)
- self.add_command_to_config_list(vlan, cmd, commands)
- if remote_span:
- self.add_command_to_config_list(vlan, 'remote-span', commands)
- if shutdown == 'enabled':
- self.add_command_to_config_list(vlan, 'shutdown', commands)
- elif shutdown == 'disabled':
- self.add_command_to_config_list(vlan, 'no shutdown', commands)
-
- return commands
-
- def _clear_config(self, want, have, state):
- # Delete the interface config based on the want and have config
- commands = []
- vlan = 'vlan {0}'.format(have.get('vlan_id'))
-
- if have.get('vlan_id') and 'default' not in have.get('name')\
- and (have.get('vlan_id') != want.get('vlan_id') or state == 'deleted'):
- self.remove_command_from_config_list(vlan, 'vlan', commands)
- elif 'default' not in have.get('name'):
- if have.get('mtu') != want.get('mtu'):
- self.remove_command_from_config_list(vlan, 'mtu', commands)
- if have.get('remote_span') != want.get('remote_span') and want.get('remote_span'):
- self.remove_command_from_config_list(vlan, 'remote-span', commands)
- if have.get('shutdown') != want.get('shutdown') and want.get('shutdown'):
- self.remove_command_from_config_list(vlan, 'shutdown', commands)
- if have.get('state') != want.get('state') and want.get('state'):
- self.remove_command_from_config_list(vlan, 'state', commands)
-
- return commands
diff --git a/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py b/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
deleted file mode 100644
index c80939aeba..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_acl_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type
-from ansible.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import Acl_InterfacesArgs
-
-
-class Acl_InterfacesFacts(object):
- """ The ios_acl_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Acl_InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_acl_interfaces_data(self, connection):
- return connection.get('sh running-config | include interface|ip access-group|ipv6 traffic-filter')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = self.get_acl_interfaces_data(connection)
- # operate on a collection of resource x
- config = data.split('interface ')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
-
- facts = {}
- if objs:
- facts['acl_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
-
- for cfg in params['config']:
- facts['acl_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- config['name'] = intf
- config['access_groups'] = []
- acl_v4_config = {}
- acl_v6_config = {}
-
- def common_iter_code(cmd, conf):
- # Common code for IPV4 and IPV6 config parsing
- acls = []
- re_cmd = cmd + ' (\\S+.*)'
- ip_all = re.findall(re_cmd, conf)
- for each in ip_all:
- acl = {}
- access_grp_config = each.split(' ')
- acl['name'] = access_grp_config[0]
- acl['direction'] = access_grp_config[1]
- acls.append(acl)
- return acls
-
- if 'ip' in conf:
- acls = common_iter_code('ip access-group', conf)
- acl_v4_config['afi'] = 'ipv4'
- acl_v4_config['acls'] = acls
- config['access_groups'].append(acl_v4_config)
- if 'ipv6' in conf:
- acls = common_iter_code('ipv6 traffic-filter', conf)
- acl_v6_config['afi'] = 'ipv6'
- acl_v6_config['acls'] = acls
- config['access_groups'].append(acl_v6_config)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/acls/acls.py b/lib/ansible/module_utils/network/ios/facts/acls/acls.py
deleted file mode 100644
index 3b99a18f5c..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/acls/acls.py
+++ /dev/null
@@ -1,498 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_acls fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import check_n_return_valid_ipv6_addr
-from ansible.module_utils.network.ios.argspec.acls.acls import AclsArgs
-
-
-class AclsFacts(object):
- """ The ios_acls fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
-
- self._module = module
- self.argument_spec = AclsArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_acl_data(self, connection):
- # Get the access-lists from the ios router
- return connection.get('sh access-list')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for acls
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
-
- if not data:
- data = self.get_acl_data(connection)
- # operate on a collection of resource x
- config = data.split('\n')
- spec = {'acls': list(), 'afi': None}
- if config:
- objs = self.render_config(spec, config)
- # check if rendered config list has only empty dict
- if len(objs) == 1 and objs[0] == {}:
- objs = []
- facts = {}
-
- if objs:
- facts['acls'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['acls'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def create_config_dict(self, config):
- """ Function that parse the acls config and convert to module usable config
- :param config: config
- :rtype: A dict
- :returns: the config generated based on have config params
- """
- conf = {}
- temp_list = []
- access_list_name = ''
- count = 0
- if len(config) >= 1 and config[0] != '':
- for each in config:
- if 'access-list' in each:
- temp = each.split('access-list ')[1].split(' ')[0]
- if temp == 'extended' or temp == 'standard':
- temp = each.split('access-list ')[1]
- if not access_list_name:
- access_list_name = temp
- if 'access-list' not in each:
- if 'extended' in temp or 'standard' in temp:
- temp_list.append('ipv4 access-list ' + temp + each)
- else:
- temp_list.append('ipv6 access-list ' + temp + each)
- if temp == access_list_name and 'access-list' in each and \
- not ('extended' in access_list_name or 'standard' in access_list_name):
- temp_list.append(each)
- elif temp != access_list_name:
- conf[access_list_name] = temp_list
- temp_list = list()
- if 'permit' in each or 'deny' in each:
- temp_list.append(each)
- access_list_name = temp
- count += 1
- if len(config) == count:
- conf[access_list_name] = temp_list
- temp_list = []
- return conf
-
- def populate_port_protocol(self, source, destination, each_list):
- """ Function Populates port portocol wrt to source and destination
- :param acls: source config
- :param config: destination config
- :param each_list: config
- :rtype: A list
- :returns: the commands generated based on source and destination params
- """
- operators = ['eq', 'gt', 'lt', 'neq', 'range']
- for item in operators:
- if item in each_list:
- index = each_list.index(item)
- if source.get('address') or source.get('any') or source.get('host') and not source.get('port_protocol'):
- try:
- source_index = each_list.index(source.get('address'))
- except ValueError:
- try:
- source_index = each_list.index('any')
- except ValueError:
- source_index = each_list.index('host')
- if source.get('address'):
- if (source_index + 2) == index and 'ipv6' not in each_list:
- source['port_protocol'] = {item: each_list[index + 1]}
- each_list.remove(item)
- del each_list[index]
- elif (source_index + 1) == index and 'ipv6' in each_list:
- source['port_protocol'] = {item: each_list[index + 1]}
- each_list.remove(item)
- del each_list[source_index]
- del each_list[index - 1]
- elif source.get('any'):
- if (source_index + 1) == index:
- source['port_protocol'] = {item: each_list[index + 1]}
- each_list.remove(item)
- del each_list[index - 1]
- del each_list[source_index]
- elif source.get('host'):
- if (source_index + 1) == index:
- source['port_protocol'] = {item: each_list[index + 1]}
- each_list.remove(item)
- del each_list[index - 1]
- del each_list[source_index]
- if destination.get('address') or destination.get('any') or destination.get('host'):
- try:
- destination_index = each_list.index(destination.get('address'))
- except ValueError:
- try:
- destination_index = each_list.index('any')
- except ValueError:
- destination_index = each_list.index('host') + 1
- index -= 1
- if (destination_index + 1) == index or (destination_index + 2) == index:
- destination['port_protocol'] = {item: each_list[index + 1]}
- each_list.remove(item)
- del each_list[index]
- break
- if 'eq' in each_list or 'gt' in each_list or 'lt' in each_list or 'neq' in each_list or 'range' in each_list:
- self.populate_port_protocol(source, destination, each_list)
-
- def populate_source_destination(self, each, config, source, destination):
- any = []
- if 'any' in each:
- any = re.findall('any', each)
- if len(any) == 2:
- source['any'] = True
- destination['any'] = True
- elif 'host' in each:
- host = re.findall('host', each)
- each = each.split(' ')
- if len(host) == 2:
- host_index = each.index('host')
- source['host'] = each[host_index + 1]
- del each[host_index]
- host_index = each.index('host')
- destination['host'] = each[host_index + 1]
- else:
- ip_n_wildcard_bits = re.findall(r'[0-9]+(?:\.[0-9]+){3}', each)
- ip_index = None
- if ip_n_wildcard_bits:
- ip_index = each.index(ip_n_wildcard_bits[0])
- host_index = each.index('host')
- if ip_index:
- if host_index < ip_index:
- source['host'] = each(host_index + 1)
- destination['address'] = ip_n_wildcard_bits[0]
- destination['wildcard_bits'] = ip_n_wildcard_bits[1]
- elif host_index > ip_index:
- destination['host'] = each(host_index + 1)
- source['address'] = ip_n_wildcard_bits[0]
- source['wildcard_bits'] = ip_n_wildcard_bits[1]
- else:
- if config['afi'] == 'ipv4':
- ip_n_wildcard_bits = re.findall(r'[0-9]+(?:\.[0-9]+){3}', each)
- each = each.split(' ')
- if len(ip_n_wildcard_bits) == 0 and len(any) == 1:
- source['any'] = True
- elif len(ip_n_wildcard_bits) == 1:
- source['address'] = ip_n_wildcard_bits[0]
- elif len(ip_n_wildcard_bits) == 2:
- if 'any' in each:
- if each.index('any') > each.index(ip_n_wildcard_bits[0]):
- source['address'] = ip_n_wildcard_bits[0]
- source['wildcard_bits'] = ip_n_wildcard_bits[1]
- destination['any'] = True
- elif each.index('any') < each.index(ip_n_wildcard_bits[0]):
- source['any'] = True
- destination['address'] = ip_n_wildcard_bits[0]
- destination['wildcard_bits'] = ip_n_wildcard_bits[1]
- else:
- source['address'] = ip_n_wildcard_bits[0]
- source['wildcard_bits'] = ip_n_wildcard_bits[1]
- elif len(ip_n_wildcard_bits) == 4:
- source['address'] = ip_n_wildcard_bits[0]
- source['wildcard_bits'] = ip_n_wildcard_bits[1]
- destination['address'] = ip_n_wildcard_bits[2]
- destination['wildcard_bits'] = ip_n_wildcard_bits[3]
- elif config['afi'] == 'ipv6':
- temp_ipv6 = []
- each = each.split(' ')
- check_n_return_valid_ipv6_addr(self._module, each, temp_ipv6)
- count = 0
- for every in each:
- if len(temp_ipv6) == 2:
- if temp_ipv6[0] in every or temp_ipv6[1] in every:
- temp_ipv6[count] = every
- count += 1
- elif len(temp_ipv6) == 1:
- if temp_ipv6[0] in every:
- temp_ipv6[count] = every
- if 'any' in each:
- if each.index('any') > each.index(temp_ipv6[0]):
- source['address'] = temp_ipv6[0]
- destination['any'] = True
- elif each.index('any') < each.index(temp_ipv6[0]):
- source['any'] = True
- destination['address'] = temp_ipv6[0]
- elif len(temp_ipv6) == 2:
- source['address'] = temp_ipv6[0]
- destination['address'] = temp_ipv6[1]
-
- def parsed_config_facts(self, have_config):
- """
- For parsed config have_config is string of commands which
- need to be splitted before passing it through render_config
- from spec for null values
- :param have_config: The configuration
- :rtype: list of have config
- :returns: The splitted generated config
- """
- split_config = re.split('ip|ipv6 access-list', have_config[0])
- temp_config = []
-
- # common piece of code for populating the temp_config list
- def common_config_code(each, grant, temp_config):
- temp = re.split(grant, each)
- temp_config.append(temp[0])
- temp_config.extend([grant + item for item in temp if 'access-list' not in item])
-
- for each in split_config:
- if 'v6' in each:
- each = 'ipv6 ' + each.split('v6 ')[1]
- if 'permit' in each:
- common_config_code(each, 'permit', temp_config)
- elif 'deny' in each:
- common_config_code(each, 'deny', temp_config)
- else:
- each = 'ip' + each
- if 'permit' in each:
- common_config_code(each, 'permit', temp_config)
- if 'deny' in each:
- common_config_code(each, 'deny', temp_config)
- return temp_config
-
- def render_config(self, spec, have_config):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
-
- # for parsed scnenario where commands are passed to generate the acls facts
- if len(have_config) == 1:
- have_config = self.parsed_config_facts(have_config)
-
- config = deepcopy(spec)
- render_config = list()
- acls = dict()
- aces = list()
- temp_name = ''
- for each in have_config:
- each_list = [val for val in each.split(' ') if val != '']
- if 'IPv6' in each or 'ipv6' in each:
- if aces:
- config['acls'].append(acls)
- ip_config = config
- if ip_config.get('acls'):
- render_config.append(ip_config)
- if not config['afi'] or config['afi'] == 'ipv4':
- config = deepcopy(spec)
- config['afi'] = 'ipv6'
- acls = dict()
- aces = list()
- elif not config['afi'] and ('IP' in each or 'ip' in each):
- config['afi'] = 'ipv4'
- if 'access list' in each or 'access-list' in each:
- try:
- temp_index = each_list.index('list')
- name = (each_list[temp_index + 1])
- except ValueError:
- name = each_list[-1]
- if temp_name != name:
- if aces:
- config['acls'].append(acls)
- acls = dict()
- aces = list()
- temp_name = name
- acls['name'] = name
- if 'Extended' in each:
- acls['acl_type'] = 'extended'
- continue
- elif 'Standard' in each:
- acls['acl_type'] = 'standard'
- continue
- ace_options = {}
- try:
- if config['afi'] == 'ipv4':
- if 'deny' in each_list or 'permit' in each_list:
- ace_options['sequence'] = int(each_list[0])
- elif config['afi'] == 'ipv6':
- if 'sequence' in each_list:
- ace_options['sequence'] = int(each_list[each_list.index('sequence') + 1])
- except ValueError:
- pass
- if utils.parse_conf_arg(each, 'permit'):
- ace_options['grant'] = 'permit'
- each_list.remove('permit')
- elif utils.parse_conf_arg(each, 'deny'):
- ace_options['grant'] = 'deny'
- each_list.remove('deny')
-
- protocol_option = ['ahp', 'eigrp', 'esp', 'gre', 'hbh', 'icmp', 'igmp', 'ip', 'ipv6', 'ipinip', 'nos',
- 'ospf', 'pcp', 'pim', 'sctp', 'tcp', 'udp']
- tcp_flags = ['ack', 'established', 'fin', 'psh', 'rst', 'syn', 'urg']
- icmp_options = ['administratively_prohibited', 'alternate_address', 'conversion_error',
- 'dod_host_prohibited', 'dod_net_prohibited', 'echo', 'echo_reply',
- 'general_parameter_problem', 'host_isolated', 'host_precedence_unreachable',
- 'host_redirect', 'host_tos_redirect', 'host_tos_unreachable', 'host_unknown',
- 'host_unreachable', 'information_reply', 'information_request', 'mask_reply',
- 'mask_request', 'mobile_redirect', 'net_redirect', 'net_tos_redirect',
- 'net_tos_unreachable', 'net_unreachable', 'network_unknown', 'no_room_for_option',
- 'option_missing', 'packet_too_big', 'parameter_problem', 'port_unreachable',
- 'precedence_unreachable', 'protocol_unreachable', 'reassembly_timeout', 'redirect',
- 'router_advertisement', 'router_solicitation', 'source_quench', 'source_route_failed',
- 'time_exceeded', 'timestamp_reply', 'timestamp_request', 'traceroute', 'ttl_exceeded',
- 'unreachable']
- igmp_options = ['dvmrp', 'host_query', 'mtrace_resp', 'mtrace_route', 'pim', 'trace', 'v1host_report',
- 'v2host_report', 'v2leave_group', 'v3host_report']
-
- temp_option = ''
- for option in protocol_option:
- if option in each_list and 'access' not in each_list[each_list.index(option) + 1]:
- temp_option = option
- each_list.remove(temp_option)
- if temp_option == 'tcp':
- temp_flag = [each_flag for each_flag in tcp_flags if each_flag in each]
- if temp_flag:
- flag = temp_flag[0]
- if flag in each_list:
- each_list.remove(flag)
- temp_flag = flag
- if temp_option == 'icmp':
- temp_flag = [each_option for each_option in icmp_options if each_option in each]
- if temp_flag:
- flag = temp_flag[0]
- if flag in each_list:
- each_list.remove(flag)
- temp_flag = flag
- if temp_option == 'igmp':
- temp_flag = [each_option for each_option in igmp_options if each_option in each]
- if temp_flag:
- flag = temp_flag[0]
- if flag in each_list:
- each_list.remove(flag)
- temp_flag = flag
- break
-
- dscp = utils.parse_conf_arg(each, 'dscp')
- if dscp:
- ace_options['dscp'] = dscp.split(' ')[0]
- fragments = utils.parse_conf_arg(each, 'fragments')
- if fragments:
- ace_options['fragments'] = fragments.split(' ')[0]
- log = utils.parse_conf_arg(each, 'log')
- if log:
- ace_options['log'] = log.split(' ')[0]
- log_input = utils.parse_conf_arg(each, 'log_input')
- if log_input:
- ace_options['log_input'] = log_input.split(' ')[0]
- option = utils.parse_conf_arg(each, 'option')
- if option:
- option = option.split(' ')[0]
- option_dict = {}
- option_dict[option] = True
- ace_options['option'] = option_dict
- precedence = utils.parse_conf_arg(each, 'precedence')
- if precedence:
- ace_options['precedence'] = precedence.split(' ')[0]
- time_range = utils.parse_conf_arg(each, 'time_range')
- if time_range:
- ace_options['time_range'] = time_range.split(' ')[0]
- tos = utils.parse_conf_arg(each, 'tos')
- if tos:
- tos_val = dict()
- try:
- tos_val['service_value'] = int(tos)
- except ValueError:
- tos = tos.replace('-', '_')
- tos_val[tos] = True
- ace_options['tos'] = tos_val
- ttl = utils.parse_conf_arg(each, 'ttl')
- if ttl:
- temp_ttl = ttl.split(' ')
- ttl = {}
- ttl[temp_ttl[0]] = temp_ttl[1]
- each_list = [item for item in each_list[:each_list.index('ttl')]]
- ace_options['ttl'] = ttl
-
- source = {}
- destination = {}
- self.populate_source_destination(each, config, source, destination)
-
- if source.get('address') and source.get('address') == destination.get('address'):
- self._module.fail_json(msg='Source and Destination address cannot be same!')
- else:
- self.populate_port_protocol(source, destination, each_list)
-
- if source:
- ace_options['source'] = source
- if destination:
- ace_options['destination'] = destination
- if temp_option:
- protocol_options = {}
- ace_options['protocol'] = temp_option
- if temp_option == 'tcp':
- tcp = {}
- if temp_flag:
- tcp[temp_flag] = True
- else:
- tcp['set'] = True
- protocol_options[temp_option] = tcp
- elif temp_option == 'icmp':
- icmp = dict()
- if temp_flag:
- icmp[temp_flag] = True
- else:
- icmp['set'] = True
- protocol_options[temp_option] = icmp
- elif temp_option == 'igmp':
- igmp = dict()
- if temp_flag:
- igmp[temp_flag] = True
- else:
- igmp['set'] = True
- protocol_options[temp_option] = igmp
- else:
- protocol_options[temp_option] = True
- ace_options['protocol_options'] = protocol_options
- if ace_options:
- aces.append(ace_options)
- acls['aces'] = aces
- if acls:
- if not config.get('acls'):
- config['acls'] = list()
- config['acls'].append(acls)
-
- if config not in render_config:
- render_config.append(utils.remove_empties(config))
- # delete the populated config
- del config
-
- return render_config
diff --git a/lib/ansible/module_utils/network/ios/facts/facts.py b/lib/ansible/module_utils/network/ios/facts/facts.py
deleted file mode 100644
index 8d66e87963..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/facts.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The facts class for ios
-this file validates each subset of facts and selectively
-calls the appropriate facts gathering function
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible.module_utils.network.common.facts.facts import FactsBase
-from ansible.module_utils.network.ios.facts.interfaces.interfaces import InterfacesFacts
-from ansible.module_utils.network.ios.facts.l2_interfaces.l2_interfaces import L2_InterfacesFacts
-from ansible.module_utils.network.ios.facts.vlans.vlans import VlansFacts
-from ansible.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
-from ansible.module_utils.network.ios.facts.lacp.lacp import LacpFacts
-from ansible.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import Lacp_InterfacesFacts
-from ansible.module_utils.network.ios.facts.lldp_global.lldp_global import Lldp_globalFacts
-from ansible.module_utils.network.ios.facts.lldp_interfaces.lldp_interfaces import Lldp_InterfacesFacts
-from ansible.module_utils.network.ios.facts.l3_interfaces.l3_interfaces import L3_InterfacesFacts
-from ansible.module_utils.network.ios.facts.acl_interfaces.acl_interfaces import Acl_InterfacesFacts
-from ansible.module_utils.network.ios.facts.static_routes.static_routes import Static_RoutesFacts
-from ansible.module_utils.network.ios.facts.acls.acls import AclsFacts
-from ansible.module_utils.network.ios.facts.legacy.base import Default, Hardware, Interfaces, Config
-
-
-FACT_LEGACY_SUBSETS = dict(
- default=Default,
- hardware=Hardware,
- interfaces=Interfaces,
- config=Config
-)
-
-FACT_RESOURCE_SUBSETS = dict(
- interfaces=InterfacesFacts,
- l2_interfaces=L2_InterfacesFacts,
- vlans=VlansFacts,
- lag_interfaces=Lag_interfacesFacts,
- lacp=LacpFacts,
- lacp_interfaces=Lacp_InterfacesFacts,
- lldp_global=Lldp_globalFacts,
- lldp_interfaces=Lldp_InterfacesFacts,
- l3_interfaces=L3_InterfacesFacts,
- acl_interfaces=Acl_InterfacesFacts,
- static_routes=Static_RoutesFacts,
- acls=AclsFacts,
-)
-
-
-class Facts(FactsBase):
- """ The fact class for ios
- """
-
- VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys())
- VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys())
-
- def __init__(self, module):
- super(Facts, self).__init__(module)
-
- def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None):
- """ Collect the facts for ios
- :param legacy_facts_type: List of legacy facts types
- :param resource_facts_type: List of resource fact types
- :param data: previously collected conf
- :rtype: dict
- :return: the facts gathered
- """
- if self.VALID_RESOURCE_SUBSETS:
- self.get_network_resources_facts(FACT_RESOURCE_SUBSETS, resource_facts_type, data)
-
- if self.VALID_LEGACY_GATHER_SUBSETS:
- self.get_network_legacy_facts(FACT_LEGACY_SUBSETS, legacy_facts_type)
-
- return self.ansible_facts, self._warnings
diff --git a/lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py b/lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py
deleted file mode 100644
index a6802bd2e8..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/interfaces/interfaces.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.interfaces.interfaces import InterfacesArgs
-
-
-class InterfacesFacts(object):
- """ The ios interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
- # operate on a collection of resource x
- config = data.split('interface ')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
- facts = {}
-
- if objs:
- facts['interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- # populate the facts from the configuration
- config['name'] = normalize_interface(intf)
- config['description'] = utils.parse_conf_arg(conf, 'description')
- config['speed'] = utils.parse_conf_arg(conf, 'speed')
- if utils.parse_conf_arg(conf, 'mtu'):
- config['mtu'] = int(utils.parse_conf_arg(conf, 'mtu'))
- config['duplex'] = utils.parse_conf_arg(conf, 'duplex')
- enabled = utils.parse_conf_cmd_arg(conf, 'shutdown', False)
- config['enabled'] = enabled if enabled is not None else True
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py b/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
deleted file mode 100644
index 8f6ddf2698..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from copy import deepcopy
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import L2_InterfacesArgs
-
-
-class L2_InterfacesFacts(object):
- """ The ios l2 interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = L2_InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
- # operate on a collection of resource x
- config = data.split('interface ')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
-
- facts = {}
- if objs:
- facts['l2_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['l2_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
-
- if intf.upper()[:2] in ('HU', 'FO', 'TW', 'TE', 'GI', 'FA', 'ET', 'PO'):
- # populate the facts from the configuration
- config['name'] = normalize_interface(intf)
- has_mode = utils.parse_conf_arg(conf, 'switchport mode')
- if has_mode:
- config['mode'] = has_mode
- has_access = utils.parse_conf_arg(conf, 'switchport access vlan')
- if has_access:
- config["access"] = {"vlan": int(has_access)}
-
- has_voice = utils.parse_conf_arg(conf, 'switchport voice vlan')
- if has_voice:
- config["voice"] = {"vlan": int(has_voice)}
-
- trunk = dict()
- trunk["encapsulation"] = utils.parse_conf_arg(conf, 'encapsulation')
- native_vlan = utils.parse_conf_arg(conf, 'native vlan')
- if native_vlan:
- trunk["native_vlan"] = int(native_vlan)
- allowed_vlan = utils.parse_conf_arg(conf, 'allowed vlan')
- if allowed_vlan:
- trunk["allowed_vlans"] = allowed_vlan.split(',')
- pruning_vlan = utils.parse_conf_arg(conf, 'pruning vlan')
- if pruning_vlan:
- trunk['pruning_vlans'] = pruning_vlan.split(',')
-
- config['trunk'] = trunk
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py b/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
deleted file mode 100644
index 5afab57b37..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_l3_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-import re
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import L3_InterfacesArgs
-
-
-class L3_InterfacesFacts(object):
- """ The ios l3 interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = L3_InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for l3 interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
- # operate on a collection of resource x
- config = data.split('interface ')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
- facts = {}
-
- if objs:
- facts['l3_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['l3_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys from spec for null values
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- # populate the facts from the configuration
- config['name'] = normalize_interface(intf)
-
- ipv4 = []
- ipv4_all = re.findall(r"ip address (\S+.*)", conf)
- for each in ipv4_all:
- each_ipv4 = dict()
- if 'secondary' not in each and 'dhcp' not in each:
- each_ipv4['address'] = each
- elif 'secondary' in each:
- each_ipv4['address'] = each.split(' secondary')[0]
- each_ipv4['secondary'] = True
- elif 'dhcp' in each:
- each_ipv4['address'] = 'dhcp'
- if 'client-id' in each:
- each_ipv4['dhcp_client'] = int(each.split(' hostname ')[0].split('/')[-1])
- if 'hostname' in each:
- each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1]
- if 'client-id' in each and each_ipv4['dhcp_client'] is None:
- each_ipv4['dhcp_client'] = int(each.split('/')[-1])
- if 'hostname' in each and not each_ipv4["dhcp_hostname"]:
- each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1]
- ipv4.append(each_ipv4)
- config['ipv4'] = ipv4
-
- # Get the configured IPV6 details
- ipv6 = []
- ipv6_all = re.findall(r"ipv6 address (\S+)", conf)
- for each in ipv6_all:
- each_ipv6 = dict()
- if 'autoconfig' in each:
- each_ipv6['autoconfig'] = True
- if 'dhcp' in each:
- each_ipv6['dhcp'] = True
- each_ipv6['address'] = each.lower()
- ipv6.append(each_ipv6)
- config['ipv6'] = ipv6
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py b/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py
deleted file mode 100644
index 455460fc94..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/lacp/lacp.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios lacp fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.argspec.lacp.lacp import LacpArgs
-
-
-class LacpFacts(object):
- """ The ios lacp fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = LacpArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lacp
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if connection:
- pass
-
- if not data:
- data = connection.get('show lacp sys-id')
-
- obj = {}
- if data:
- lacp_obj = self.render_config(self.generated_spec, data)
- if lacp_obj:
- obj = lacp_obj
-
- ansible_facts['ansible_network_resources'].pop('lacp', None)
- facts = {}
-
- params = utils.validate_config(self.argument_spec, {'config': obj})
- facts['lacp'] = utils.remove_empties(params['config'])
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- config['system']['priority'] = int(conf.split(',')[0])
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
deleted file mode 100644
index 722557e269..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lacp_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import re
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import Lacp_InterfacesArgs
-
-
-class Lacp_InterfacesFacts(object):
- """ The ios_lacp_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
-
- self._module = module
- self.argument_spec = Lacp_InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lacp_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if connection:
- pass
-
- objs = []
- if not data:
- data = connection.get('show running-config | section ^interface')
- # operate on a collection of resource x
- config = data.split('interface ')
-
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
- facts = {}
-
- if objs:
- facts['lacp_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['lacp_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
- if get_interface_type(intf) == 'unknown':
- return {}
-
- config['name'] = normalize_interface(intf)
- port_priority = utils.parse_conf_arg(conf, 'lacp port-priority')
- max_bundle = utils.parse_conf_arg(conf, 'lacp max-bundle')
- if port_priority:
- config['port_priority'] = int(port_priority)
- if 'lacp fast-switchover' in conf:
- config['fast_switchover'] = True
- if max_bundle:
- config['max_bundle'] = int(max_bundle)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
deleted file mode 100644
index e396bb0b51..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios lag_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
-
-
-class Lag_interfacesFacts(object):
- """ The ios_lag_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Lag_interfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = []
-
- if not data:
- data = connection.get('show running-config | section ^interface')
- # operate on a collection of resource x
- config = data.split('interface ')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- if not obj.get('members'):
- obj.update({'members': []})
- objs.append(obj)
-
- # for appending members configured with same channel-group
- for each in range(len(objs)):
- if each < (len(objs) - 1):
- if objs[each]['name'] == objs[each + 1]['name']:
- objs[each]['members'].append(objs[each + 1]['members'][0])
- del objs[each + 1]
- facts = {}
-
- if objs:
- facts['lag_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
-
- for cfg in params['config']:
- facts['lag_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)', conf)
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- member_config = {}
- channel_group = utils.parse_conf_arg(conf, 'channel-group')
- if intf.startswith('Gi'):
- config['name'] = intf
- config['members'] = []
- if channel_group:
- channel_group = channel_group.split(' ')
- id = channel_group[0]
- config['name'] = 'Port-channel{0}'.format(str(id))
- if 'mode' in channel_group:
- mode = channel_group[2]
- member_config.update({'mode': mode})
- if 'link' in channel_group:
- link = channel_group[2]
- member_config.update({'link': link})
- if member_config.get('mode') or member_config.get('link'):
- member_config['member'] = normalize_interface(intf)
- config['members'].append(member_config)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/legacy/base.py b/lib/ansible/module_utils/network/ios/facts/legacy/base.py
deleted file mode 100644
index 75a7e9974d..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/legacy/base.py
+++ /dev/null
@@ -1,380 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-"""
-The ios legacy fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import platform
-import re
-
-from ansible.module_utils.network.ios.ios import run_commands, get_capabilities
-from ansible.module_utils.network.ios.ios import normalize_interface
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six.moves import zip
-
-
-class FactsBase(object):
-
- COMMANDS = list()
-
- def __init__(self, module):
- self.module = module
- self.facts = dict()
- self.warnings = list()
- self.responses = None
-
- def populate(self):
- self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False)
-
- def run(self, cmd):
- return run_commands(self.module, commands=cmd, check_rc=False)
-
-
-class Default(FactsBase):
-
- COMMANDS = ['show version']
-
- def populate(self):
- super(Default, self).populate()
- self.facts.update(self.platform_facts())
- data = self.responses[0]
- if data:
- self.facts['iostype'] = self.parse_iostype(data)
- self.facts['serialnum'] = self.parse_serialnum(data)
- self.parse_stacks(data)
-
- def parse_iostype(self, data):
- match = re.search(r'\S+(X86_64_LINUX_IOSD-UNIVERSALK9-M)(\S+)', data)
- if match:
- return "IOS-XE"
- else:
- return "IOS"
-
- def parse_serialnum(self, data):
- match = re.search(r'board ID (\S+)', data)
- if match:
- return match.group(1)
-
- def parse_stacks(self, data):
- match = re.findall(r'^Model [Nn]umber\s+: (\S+)', data, re.M)
- if match:
- self.facts['stacked_models'] = match
-
- match = re.findall(r'^System [Ss]erial [Nn]umber\s+: (\S+)', data, re.M)
- if match:
- self.facts['stacked_serialnums'] = match
-
- def platform_facts(self):
- platform_facts = {}
-
- resp = get_capabilities(self.module)
- device_info = resp['device_info']
-
- platform_facts['system'] = device_info['network_os']
-
- for item in ('model', 'image', 'version', 'platform', 'hostname'):
- val = device_info.get('network_os_%s' % item)
- if val:
- platform_facts[item] = val
-
- platform_facts['api'] = resp['network_api']
- platform_facts['python_version'] = platform.python_version()
-
- return platform_facts
-
-
-class Hardware(FactsBase):
-
- COMMANDS = [
- 'dir',
- 'show memory statistics'
- ]
-
- def populate(self):
- warnings = list()
- super(Hardware, self).populate()
- data = self.responses[0]
- if data:
- self.facts['filesystems'] = self.parse_filesystems(data)
- self.facts['filesystems_info'] = self.parse_filesystems_info(data)
-
- data = self.responses[1]
- if data:
- if 'Invalid input detected' in data:
- warnings.append('Unable to gather memory statistics')
- else:
- processor_line = [l for l in data.splitlines()
- if 'Processor' in l].pop()
- match = re.findall(r'\s(\d+)\s', processor_line)
- if match:
- self.facts['memtotal_mb'] = int(match[0]) / 1024
- self.facts['memfree_mb'] = int(match[3]) / 1024
-
- def parse_filesystems(self, data):
- return re.findall(r'^Directory of (\S+)/', data, re.M)
-
- def parse_filesystems_info(self, data):
- facts = dict()
- fs = ''
- for line in data.split('\n'):
- match = re.match(r'^Directory of (\S+)/', line)
- if match:
- fs = match.group(1)
- facts[fs] = dict()
- continue
- match = re.match(r'^(\d+) bytes total \((\d+) bytes free\)', line)
- if match:
- facts[fs]['spacetotal_kb'] = int(match.group(1)) / 1024
- facts[fs]['spacefree_kb'] = int(match.group(2)) / 1024
- return facts
-
-
-class Config(FactsBase):
-
- COMMANDS = ['show running-config']
-
- def populate(self):
- super(Config, self).populate()
- data = self.responses[0]
- if data:
- data = re.sub(
- r'^Building configuration...\s+Current configuration : \d+ bytes\n',
- '', data, flags=re.MULTILINE)
- self.facts['config'] = data
-
-
-class Interfaces(FactsBase):
-
- COMMANDS = [
- 'show interfaces',
- 'show ip interface',
- 'show ipv6 interface',
- 'show lldp',
- 'show cdp'
- ]
-
- def populate(self):
- super(Interfaces, self).populate()
-
- self.facts['all_ipv4_addresses'] = list()
- self.facts['all_ipv6_addresses'] = list()
- self.facts['neighbors'] = {}
-
- data = self.responses[0]
- if data:
- interfaces = self.parse_interfaces(data)
- self.facts['interfaces'] = self.populate_interfaces(interfaces)
-
- data = self.responses[1]
- if data:
- data = self.parse_interfaces(data)
- self.populate_ipv4_interfaces(data)
-
- data = self.responses[2]
- if data:
- data = self.parse_interfaces(data)
- self.populate_ipv6_interfaces(data)
-
- data = self.responses[3]
- lldp_errs = ['Invalid input', 'LLDP is not enabled']
-
- if data and not any(err in data for err in lldp_errs):
- neighbors = self.run(['show lldp neighbors detail'])
- if neighbors:
- self.facts['neighbors'].update(self.parse_neighbors(neighbors[0]))
-
- data = self.responses[4]
- cdp_errs = ['CDP is not enabled']
-
- if data and not any(err in data for err in cdp_errs):
- cdp_neighbors = self.run(['show cdp neighbors detail'])
- if cdp_neighbors:
- self.facts['neighbors'].update(self.parse_cdp_neighbors(cdp_neighbors[0]))
-
- def populate_interfaces(self, interfaces):
- facts = dict()
- for key, value in iteritems(interfaces):
- intf = dict()
- intf['description'] = self.parse_description(value)
- intf['macaddress'] = self.parse_macaddress(value)
-
- intf['mtu'] = self.parse_mtu(value)
- intf['bandwidth'] = self.parse_bandwidth(value)
- intf['mediatype'] = self.parse_mediatype(value)
- intf['duplex'] = self.parse_duplex(value)
- intf['lineprotocol'] = self.parse_lineprotocol(value)
- intf['operstatus'] = self.parse_operstatus(value)
- intf['type'] = self.parse_type(value)
-
- facts[key] = intf
- return facts
-
- def populate_ipv4_interfaces(self, data):
- for key, value in data.items():
- self.facts['interfaces'][key]['ipv4'] = list()
- primary_address = addresses = []
- primary_address = re.findall(r'Internet address is (.+)$', value, re.M)
- addresses = re.findall(r'Secondary address (.+)$', value, re.M)
- if len(primary_address) == 0:
- continue
- addresses.append(primary_address[0])
- for address in addresses:
- addr, subnet = address.split("/")
- ipv4 = dict(address=addr.strip(), subnet=subnet.strip())
- self.add_ip_address(addr.strip(), 'ipv4')
- self.facts['interfaces'][key]['ipv4'].append(ipv4)
-
- def populate_ipv6_interfaces(self, data):
- for key, value in iteritems(data):
- try:
- self.facts['interfaces'][key]['ipv6'] = list()
- except KeyError:
- self.facts['interfaces'][key] = dict()
- self.facts['interfaces'][key]['ipv6'] = list()
- addresses = re.findall(r'\s+(.+), subnet', value, re.M)
- subnets = re.findall(r', subnet is (.+)$', value, re.M)
- for addr, subnet in zip(addresses, subnets):
- ipv6 = dict(address=addr.strip(), subnet=subnet.strip())
- self.add_ip_address(addr.strip(), 'ipv6')
- self.facts['interfaces'][key]['ipv6'].append(ipv6)
-
- def add_ip_address(self, address, family):
- if family == 'ipv4':
- self.facts['all_ipv4_addresses'].append(address)
- else:
- self.facts['all_ipv6_addresses'].append(address)
-
- def parse_neighbors(self, neighbors):
- facts = dict()
- for entry in neighbors.split('------------------------------------------------'):
- if entry == '':
- continue
- intf = self.parse_lldp_intf(entry)
- if intf is None:
- return facts
- intf = normalize_interface(intf)
- if intf not in facts:
- facts[intf] = list()
- fact = dict()
- fact['host'] = self.parse_lldp_host(entry)
- fact['port'] = self.parse_lldp_port(entry)
- facts[intf].append(fact)
- return facts
-
- def parse_cdp_neighbors(self, neighbors):
- facts = dict()
- for entry in neighbors.split('-------------------------'):
- if entry == '':
- continue
- intf_port = self.parse_cdp_intf_port(entry)
- if intf_port is None:
- return facts
- intf, port = intf_port
- if intf not in facts:
- facts[intf] = list()
- fact = dict()
- fact['host'] = self.parse_cdp_host(entry)
- fact['port'] = port
- facts[intf].append(fact)
- return facts
-
- def parse_interfaces(self, data):
- parsed = dict()
- key = ''
- for line in data.split('\n'):
- if len(line) == 0:
- continue
- elif line[0] == ' ':
- parsed[key] += '\n%s' % line
- else:
- match = re.match(r'^(\S+)', line)
- if match:
- key = match.group(1)
- parsed[key] = line
- return parsed
-
- def parse_description(self, data):
- match = re.search(r'Description: (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_macaddress(self, data):
- match = re.search(r'Hardware is (?:.*), address is (\S+)', data)
- if match:
- return match.group(1)
-
- def parse_ipv4(self, data):
- match = re.search(r'Internet address is (\S+)', data)
- if match:
- addr, masklen = match.group(1).split('/')
- return dict(address=addr, masklen=int(masklen))
-
- def parse_mtu(self, data):
- match = re.search(r'MTU (\d+)', data)
- if match:
- return int(match.group(1))
-
- def parse_bandwidth(self, data):
- match = re.search(r'BW (\d+)', data)
- if match:
- return int(match.group(1))
-
- def parse_duplex(self, data):
- match = re.search(r'(\w+) Duplex', data, re.M)
- if match:
- return match.group(1)
-
- def parse_mediatype(self, data):
- match = re.search(r'media type is (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_type(self, data):
- match = re.search(r'Hardware is (.+),', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lineprotocol(self, data):
- match = re.search(r'line protocol is (\S+)\s*$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_operstatus(self, data):
- match = re.search(r'^(?:.+) is (.+),', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lldp_intf(self, data):
- match = re.search(r'^Local Intf: (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lldp_host(self, data):
- match = re.search(r'System Name: (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_lldp_port(self, data):
- match = re.search(r'Port id: (.+)$', data, re.M)
- if match:
- return match.group(1)
-
- def parse_cdp_intf_port(self, data):
- match = re.search(r'^Interface: (.+), Port ID \(outgoing port\): (.+)$', data, re.M)
- if match:
- return match.group(1), match.group(2)
-
- def parse_cdp_host(self, data):
- match = re.search(r'^Device ID: (.+)$', data, re.M)
- if match:
- return match.group(1)
diff --git a/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py b/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py
deleted file mode 100644
index 1643d52476..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/lldp_global/lldp_global.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios lldp_global fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.argspec.lldp_global.lldp_global import Lldp_globalArgs
-
-
-class Lldp_globalFacts(object):
- """ The ios lldp_global fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = Lldp_globalArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lldp_global
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- objs = dict()
- if not data:
- data = connection.get('show running-config | section ^lldp')
- # operate on a collection of resource x
- config = data.split('\n')
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.update(obj)
- facts = {}
-
- if objs:
- params = utils.validate_config(self.argument_spec, {'config': utils.remove_empties(objs)})
- facts['lldp_global'] = utils.remove_empties(params['config'])
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- holdtime = utils.parse_conf_arg(conf, 'lldp holdtime')
- timer = utils.parse_conf_arg(conf, 'lldp timer')
- reinit = utils.parse_conf_arg(conf, 'lldp reinit')
- if holdtime:
- config['holdtime'] = int(holdtime)
- if 'lldp run' in conf:
- config['enabled'] = True
- if timer:
- config['timer'] = int(timer)
- if reinit:
- config['reinit'] = int(reinit)
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
deleted file mode 100644
index f97f87fbc4..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_lldp_interfaces fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-import re
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import get_interface_type, normalize_interface
-from ansible.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import Lldp_InterfacesArgs
-
-
-class Lldp_InterfacesFacts(object):
- """ The ios_lldp_interfaces fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
-
- self._module = module
- self.argument_spec = Lldp_InterfacesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for lldp_interfaces
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if connection:
- pass
-
- objs = []
- if not data:
- data = connection.get('show lldp interface')
- # operate on a collection of resource x
- config = data.split('\n\n')
-
- for conf in config:
- if conf:
- obj = self.render_config(self.generated_spec, conf)
- if obj:
- objs.append(obj)
- facts = {}
-
- if objs:
- facts['lldp_interfaces'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['lldp_interfaces'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- match = re.search(r'^(\S+)(:)', conf)
- intf = ''
- if match:
- intf = match.group(1)
-
- if get_interface_type(intf) == 'unknown':
- return {}
- if intf.lower().startswith('gi'):
- config['name'] = normalize_interface(intf)
- receive = utils.parse_conf_arg(conf, 'Rx:')
- transmit = utils.parse_conf_arg(conf, 'Tx:')
-
- if receive == 'enabled':
- config['receive'] = True
- elif receive == 'disabled':
- config['receive'] = False
- if transmit == 'enabled':
- config['transmit'] = True
- elif transmit == 'disabled':
- config['transmit'] = False
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py b/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py
deleted file mode 100644
index f7ada0b3f5..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/static_routes/static_routes.py
+++ /dev/null
@@ -1,225 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios_static_routes fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.utils.utils import netmask_to_cidr
-from ansible.module_utils.network.ios.argspec.static_routes.static_routes import Static_RoutesArgs
-
-
-class Static_RoutesFacts(object):
- """ The ios_static_routes fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
-
- self._module = module
- self.argument_spec = Static_RoutesArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def get_static_routes_data(self, connection):
- return connection.get('sh running-config | include ip route|ipv6 route')
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for static_routes
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
-
- objs = []
- if not data:
- data = self.get_static_routes_data(connection)
- # operate on a collection of resource x
- config = data.split('\n')
-
- same_dest = self.populate_destination(config)
- for key in same_dest.keys():
- if key:
- obj = self.render_config(self.generated_spec, key, same_dest[key])
- if obj:
- objs.append(obj)
- facts = {}
-
- # append all static routes address_family with NO VRF together
- no_vrf_address_family = {
- 'address_families': [each.get('address_families')[0] for each in objs if each.get('vrf') is None]
- }
-
- temp_objs = [each for each in objs if each.get('vrf') is not None]
- temp_objs.append(no_vrf_address_family)
- objs = temp_objs
-
- if objs:
- facts['static_routes'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
- for cfg in params['config']:
- facts['static_routes'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def update_netmask_to_cidr(self, filter, pos, del_pos):
- netmask = filter.split(' ')
- dest = netmask[pos] + '/' + netmask_to_cidr(netmask[del_pos])
- netmask[pos] = dest
- del netmask[del_pos]
- filter_vrf = ' '
- return filter_vrf.join(netmask), dest
-
- def populate_destination(self, config):
- same_dest = {}
- ip_str = ''
- for i in sorted(config):
- if i:
- if '::' in i and 'vrf' in i:
- ip_str = 'ipv6 route vrf'
- elif '::' in i and 'vrf' not in i:
- ip_str = 'ipv6 route'
- elif '.' in i and 'vrf' in i:
- ip_str = 'ip route vrf'
- elif '.' in i and 'vrf' not in i:
- ip_str = 'ip route'
-
- if 'vrf' in i:
- filter_vrf = utils.parse_conf_arg(i, ip_str)
- if '/' not in filter_vrf and '::' not in filter_vrf:
- filter_vrf, dest_vrf = self.update_netmask_to_cidr(filter_vrf, 1, 2)
- dest_vrf = dest_vrf + '_vrf'
- else:
- dest_vrf = filter_vrf.split(' ')[1]
- if dest_vrf not in same_dest.keys():
- same_dest[dest_vrf] = []
- same_dest[dest_vrf].append('vrf ' + filter_vrf)
- elif 'vrf' not in same_dest[dest_vrf][0]:
- same_dest[dest_vrf] = []
- same_dest[dest_vrf].append('vrf ' + filter_vrf)
- else:
- same_dest[dest_vrf].append(('vrf ' + filter_vrf))
- else:
- filter = utils.parse_conf_arg(i, ip_str)
- if '/' not in filter and '::' not in filter:
- filter, dest = self.update_netmask_to_cidr(filter, 0, 1)
- else:
- dest = filter.split(' ')[0]
- if dest not in same_dest.keys():
- same_dest[dest] = []
- same_dest[dest].append(filter)
- elif 'vrf' in same_dest[dest][0]:
- same_dest[dest] = []
- same_dest[dest].append(filter)
- else:
- same_dest[dest].append(filter)
- return same_dest
-
- def render_config(self, spec, conf, conf_val):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
- config['address_families'] = []
- route_dict = dict()
- final_route = dict()
- afi = dict()
- final_route['routes'] = []
- next_hops = []
- hops = {}
- vrf = ''
- address_family = dict()
- for each in conf_val:
- route = each.split(' ')
- if 'vrf' in conf_val[0]:
- vrf = route[route.index('vrf') + 1]
- route_dict['dest'] = conf.split('_')[0]
- else:
- route_dict['dest'] = conf
- if 'vrf' in conf_val[0]:
- hops = {}
- if '::' in conf:
- hops['forward_router_address'] = route[3]
- afi['afi'] = 'ipv6'
- elif '.' in conf:
- hops['forward_router_address'] = route[3]
- afi['afi'] = "ipv4"
- else:
- hops['interface'] = conf
- else:
-
- if '::' in conf:
- hops['forward_router_address'] = route[1]
- afi['afi'] = 'ipv6'
- elif '.' in conf:
- hops['forward_router_address'] = route[1]
- afi['afi'] = "ipv4"
- else:
- hops['interface'] = route[1]
- try:
- temp_list = each.split(' ')
- if 'tag' in temp_list:
- del temp_list[temp_list.index('tag') + 1]
- if 'track' in temp_list:
- del temp_list[temp_list.index('track') + 1]
- # find distance metric
- dist_metrics = int(
- [i for i in temp_list if '.' not in i and ':' not in i and ord(i[0]) > 48 and ord(i[0]) < 57][0]
- )
- except IndexError:
- dist_metrics = None
- if dist_metrics:
- hops['distance_metric'] = dist_metrics
- if 'name' in route:
- hops['name'] = route[route.index('name') + 1]
- if 'multicast' in route:
- hops['multicast'] = True
- if 'dhcp' in route:
- hops['dhcp'] = True
- if 'global' in route:
- hops['global'] = True
- if 'permanent' in route:
- hops['permanent'] = True
- if 'tag' in route:
- hops['tag'] = route[route.index('tag') + 1]
- if 'track' in route:
- hops['track'] = route[route.index('track') + 1]
- next_hops.append(hops)
- hops = {}
- route_dict['next_hops'] = next_hops
- if route_dict:
- final_route['routes'].append(route_dict)
- address_family.update(afi)
- address_family.update(final_route)
- config['address_families'].append(address_family)
- if vrf:
- config['vrf'] = vrf
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py b/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py
deleted file mode 100644
index b499be5ce9..0000000000
--- a/lib/ansible/module_utils/network/ios/facts/vlans/vlans.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-The ios vlans fact class
-It is in this file the configuration is collected from the device
-for a given resource, parsed, and the facts tree is populated
-based on the configuration.
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from copy import deepcopy
-from ansible.module_utils.network.common import utils
-from ansible.module_utils.network.ios.argspec.vlans.vlans import VlansArgs
-
-
-class VlansFacts(object):
- """ The ios vlans fact class
- """
-
- def __init__(self, module, subspec='config', options='options'):
- self._module = module
- self.argument_spec = VlansArgs.argument_spec
- spec = deepcopy(self.argument_spec)
- if subspec:
- if options:
- facts_argument_spec = spec[subspec][options]
- else:
- facts_argument_spec = spec[subspec]
- else:
- facts_argument_spec = spec
-
- self.generated_spec = utils.generate_dict(facts_argument_spec)
-
- def populate_facts(self, connection, ansible_facts, data=None):
- """ Populate the facts for vlans
- :param connection: the device connection
- :param ansible_facts: Facts dictionary
- :param data: previously collected conf
- :rtype: dictionary
- :returns: facts
- """
- if connection:
- pass
-
- objs = []
- mtu_objs = []
- remote_objs = []
- final_objs = []
- if not data:
- data = connection.get('show vlan')
- # operate on a collection of resource x
- config = data.split('\n')
- # Get individual vlan configs separately
- vlan_info = ''
- for conf in config:
- if 'Name' in conf:
- vlan_info = 'Name'
- elif 'Type' in conf:
- vlan_info = 'Type'
- elif 'Remote' in conf:
- vlan_info = 'Remote'
- if conf and ' ' not in filter(None, conf.split('-')):
- obj = self.render_config(self.generated_spec, conf, vlan_info)
- if 'mtu' in obj:
- mtu_objs.append(obj)
- elif 'remote_span' in obj:
- remote_objs = obj
- elif obj:
- objs.append(obj)
- # Appending MTU value to the retrieved dictionary
- for o, m in zip(objs, mtu_objs):
- o.update(m)
- final_objs.append(o)
-
- # Appending Remote Span value to related VLAN:
- if remote_objs:
- if remote_objs.get('remote_span'):
- for each in remote_objs.get('remote_span'):
- for every in final_objs:
- if each == every.get('vlan_id'):
- every.update({'remote_span': True})
- break
-
- facts = {}
- if final_objs:
- facts['vlans'] = []
- params = utils.validate_config(self.argument_spec, {'config': objs})
-
- for cfg in params['config']:
- facts['vlans'].append(utils.remove_empties(cfg))
- ansible_facts['ansible_network_resources'].update(facts)
-
- return ansible_facts
-
- def render_config(self, spec, conf, vlan_info):
- """
- Render config as dictionary structure and delete keys
- from spec for null values
-
- :param spec: The facts tree, generated from the argspec
- :param conf: The configuration
- :rtype: dictionary
- :returns: The generated config
- """
- config = deepcopy(spec)
-
- if vlan_info == 'Name' and 'Name' not in conf:
- conf = list(filter(None, conf.split(' ')))
- config['vlan_id'] = int(conf[0])
- config['name'] = conf[1]
- if len(conf[2].split('/')) > 1:
- if conf[2].split('/')[0] == 'sus':
- config['state'] = 'suspend'
- elif conf[2].split('/')[0] == 'act':
- config['state'] = 'active'
- config['shutdown'] = 'enabled'
- else:
- if conf[2] == 'suspended':
- config['state'] = 'suspend'
- elif conf[2] == 'active':
- config['state'] = 'active'
- config['shutdown'] = 'disabled'
- elif vlan_info == 'Type' and 'Type' not in conf:
- conf = list(filter(None, conf.split(' ')))
- config['mtu'] = int(conf[3])
- elif vlan_info == 'Remote':
- if len(conf.split(',')) > 1 or conf.isdigit():
- remote_span_vlan = []
- if len(conf.split(',')) > 1:
- remote_span_vlan = conf.split(',')
- else:
- remote_span_vlan.append(conf)
- remote_span = []
- for each in remote_span_vlan:
- remote_span.append(int(each))
- config['remote_span'] = remote_span
-
- return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/ios/ios.py b/lib/ansible/module_utils/network/ios/ios.py
deleted file mode 100644
index 3e1c680aa3..0000000000
--- a/lib/ansible/module_utils/network/ios/ios.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# (c) 2016 Red Hat Inc.
-#
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-import json
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.connection import Connection, ConnectionError
-
-_DEVICE_CONFIGS = {}
-
-ios_provider_spec = {
- 'host': dict(),
- 'port': dict(type='int'),
- 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
- 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
- 'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
- 'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
- 'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True),
- 'timeout': dict(type='int')
-}
-ios_argument_spec = {
- 'provider': dict(type='dict', options=ios_provider_spec, removed_in_version=2.14),
-}
-
-
-def get_provider_argspec():
- return ios_provider_spec
-
-
-def get_connection(module):
- if hasattr(module, '_ios_connection'):
- return module._ios_connection
-
- capabilities = get_capabilities(module)
- network_api = capabilities.get('network_api')
- if network_api == 'cliconf':
- module._ios_connection = Connection(module._socket_path)
- else:
- module.fail_json(msg='Invalid connection type %s' % network_api)
-
- return module._ios_connection
-
-
-def get_capabilities(module):
- if hasattr(module, '_ios_capabilities'):
- return module._ios_capabilities
- try:
- capabilities = Connection(module._socket_path).get_capabilities()
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- module._ios_capabilities = json.loads(capabilities)
- return module._ios_capabilities
-
-
-def get_defaults_flag(module):
- connection = get_connection(module)
- try:
- out = connection.get_defaults_flag()
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- return to_text(out, errors='surrogate_then_replace').strip()
-
-
-def get_config(module, flags=None):
- flags = to_list(flags)
-
- section_filter = False
- if flags and 'section' in flags[-1]:
- section_filter = True
-
- flag_str = ' '.join(flags)
-
- try:
- return _DEVICE_CONFIGS[flag_str]
- except KeyError:
- connection = get_connection(module)
- try:
- out = connection.get_config(flags=flags)
- except ConnectionError as exc:
- if section_filter:
- # Some ios devices don't understand `| section foo`
- out = get_config(module, flags=flags[:-1])
- else:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
- cfg = to_text(out, errors='surrogate_then_replace').strip()
- _DEVICE_CONFIGS[flag_str] = cfg
- return cfg
-
-
-def run_commands(module, commands, check_rc=True):
- connection = get_connection(module)
- try:
- return connection.run_commands(commands=commands, check_rc=check_rc)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc))
-
-
-def load_config(module, commands):
- connection = get_connection(module)
-
- try:
- resp = connection.edit_config(commands)
- return resp.get('response')
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc))
-
-
-def normalize_interface(name):
- """Return the normalized interface name
- """
- if not name:
- return
-
- def _get_number(name):
- digits = ''
- for char in name:
- if char.isdigit() or char in '/.':
- digits += char
- return digits
-
- if name.lower().startswith('gi'):
- if_type = 'GigabitEthernet'
- elif name.lower().startswith('te'):
- if_type = 'TenGigabitEthernet'
- elif name.lower().startswith('fa'):
- if_type = 'FastEthernet'
- elif name.lower().startswith('fo'):
- if_type = 'FortyGigabitEthernet'
- elif name.lower().startswith('et'):
- if_type = 'Ethernet'
- elif name.lower().startswith('vl'):
- if_type = 'Vlan'
- elif name.lower().startswith('lo'):
- if_type = 'loopback'
- elif name.lower().startswith('po'):
- if_type = 'port-channel'
- elif name.lower().startswith('nv'):
- if_type = 'nve'
- elif name.lower().startswith('twe'):
- if_type = 'TwentyFiveGigE'
- elif name.lower().startswith('hu'):
- if_type = 'HundredGigE'
- else:
- if_type = None
-
- number_list = name.split(' ')
- if len(number_list) == 2:
- if_number = number_list[-1].strip()
- else:
- if_number = _get_number(name)
-
- if if_type:
- proper_interface = if_type + if_number
- else:
- proper_interface = name
-
- return proper_interface
diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/base.py b/lib/ansible/module_utils/network/ios/providers/cli/config/base.py
deleted file mode 100644
index eade249a09..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/cli/config/base.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.common.config import NetworkConfig
-
-
-class ConfigBase(object):
-
- argument_spec = {}
-
- mutually_exclusive = []
-
- identifier = ()
-
- def __init__(self, **kwargs):
- self.values = {}
- self._rendered_configuration = {}
- self.active_configuration = None
-
- for item in self.identifier:
- self.values[item] = kwargs.pop(item)
-
- for key, value in iteritems(kwargs):
- if key in self.argument_spec:
- setattr(self, key, value)
-
- for key, value in iteritems(self.argument_spec):
- if value.get('default'):
- if not getattr(self, key, None):
- setattr(self, key, value.get('default'))
-
- def __getattr__(self, key):
- if key in self.argument_spec:
- return self.values.get(key)
-
- def __setattr__(self, key, value):
- if key in self.argument_spec:
- if key in self.identifier:
- raise TypeError('cannot set value')
- elif value is not None:
- self.values[key] = value
- else:
- super(ConfigBase, self).__setattr__(key, value)
-
- def context_config(self, cmd):
- if 'context' not in self._rendered_configuration:
- self._rendered_configuration['context'] = list()
- self._rendered_configuration['context'].extend(to_list(cmd))
-
- def global_config(self, cmd):
- if 'global' not in self._rendered_configuration:
- self._rendered_configuration['global'] = list()
- self._rendered_configuration['global'].extend(to_list(cmd))
-
- def get_rendered_configuration(self):
- config = list()
- for section in ('context', 'global'):
- config.extend(self._rendered_configuration.get(section, []))
- return config
-
- def set_active_configuration(self, config):
- self.active_configuration = config
-
- def render(self, config=None):
- raise NotImplementedError
-
- def get_section(self, config, section):
- if config is not None:
- netcfg = NetworkConfig(indent=1, contents=config)
- try:
- config = netcfg.get_block_config(to_list(section))
- except ValueError:
- config = None
- return config
diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py
deleted file mode 100644
index 366f6413c1..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/address_family.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-import re
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.providers.providers import CliProvider
-from ansible.module_utils.network.ios.providers.cli.config.bgp.neighbors import AFNeighbors
-from ansible.module_utils.common.network import to_netmask
-
-
-class AddressFamily(CliProvider):
-
- def render(self, config=None):
- commands = list()
- safe_list = list()
-
- router_context = 'router bgp %s' % self.get_value('config.bgp_as')
- context_config = None
-
- for item in self.get_value('config.address_family'):
- context = 'address-family %s' % item['afi']
- if item['safi'] != 'unicast':
- context += ' %s' % item['safi']
- context_commands = list()
-
- if config:
- context_path = [router_context, context]
- context_config = self.get_config_context(config, context_path, indent=1)
-
- for key, value in iteritems(item):
- if value is not None:
- meth = getattr(self, '_render_%s' % key, None)
- if meth:
- resp = meth(item, context_config)
- if resp:
- context_commands.extend(to_list(resp))
-
- if context_commands:
- commands.append(context)
- commands.extend(context_commands)
- commands.append('exit-address-family')
-
- safe_list.append(context)
-
- if self.params['operation'] == 'replace':
- if config:
- resp = self._negate_config(config, safe_list)
- commands.extend(resp)
-
- return commands
-
- def _negate_config(self, config, safe_list=None):
- commands = list()
- matches = re.findall(r'(address-family .+)$', config, re.M)
- for item in set(matches).difference(safe_list):
- commands.append('no %s' % item)
- return commands
-
- def _render_auto_summary(self, item, config=None):
- cmd = 'auto-summary'
- if item['auto_summary'] is False:
- cmd = 'no %s' % cmd
- if not config or cmd not in config:
- return cmd
-
- def _render_synchronization(self, item, config=None):
- cmd = 'synchronization'
- if item['synchronization'] is False:
- cmd = 'no %s' % cmd
- if not config or cmd not in config:
- return cmd
-
- def _render_networks(self, item, config=None):
- commands = list()
- safe_list = list()
-
- for entry in item['networks']:
- network = entry['prefix']
- cmd = 'network %s' % network
- if entry['masklen']:
- cmd += ' mask %s' % to_netmask(entry['masklen'])
- network += ' mask %s' % to_netmask(entry['masklen'])
- if entry['route_map']:
- cmd += ' route-map %s' % entry['route_map']
- network += ' route-map %s' % entry['route_map']
-
- safe_list.append(network)
-
- if not config or cmd not in config:
- commands.append(cmd)
-
- if self.params['operation'] == 'replace':
- if config:
- matches = re.findall(r'network (.*)', config, re.M)
- for entry in set(matches).difference(safe_list):
- commands.append('no network %s' % entry)
-
- return commands
-
- def _render_redistribute(self, item, config=None):
- commands = list()
- safe_list = list()
-
- for entry in item['redistribute']:
- option = entry['protocol']
-
- cmd = 'redistribute %s' % entry['protocol']
-
- if entry['id'] and entry['protocol'] in ('ospf', 'ospfv3', 'eigrp'):
- cmd += ' %s' % entry['id']
- option += ' %s' % entry['id']
-
- if entry['metric']:
- cmd += ' metric %s' % entry['metric']
-
- if entry['route_map']:
- cmd += ' route-map %s' % entry['route_map']
-
- if not config or cmd not in config:
- commands.append(cmd)
-
- safe_list.append(option)
-
- if self.params['operation'] == 'replace':
- if config:
- matches = re.findall(r'redistribute (\S+)(?:\s*)(\d*)', config, re.M)
- for i in range(0, len(matches)):
- matches[i] = ' '.join(matches[i]).strip()
- for entry in set(matches).difference(safe_list):
- commands.append('no redistribute %s' % entry)
-
- return commands
-
- def _render_neighbors(self, item, config):
- """ generate bgp neighbor configuration
- """
- return AFNeighbors(self.params).render(config, nbr_list=item['neighbors'])
diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
deleted file mode 100644
index 2cee73382a..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-import re
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.providers.providers import CliProvider
-
-
-class Neighbors(CliProvider):
-
- def render(self, config=None, nbr_list=None):
- commands = list()
- safe_list = list()
- if not nbr_list:
- nbr_list = self.get_value('config.neighbors')
-
- for item in nbr_list:
- neighbor_commands = list()
- context = 'neighbor %s' % item['neighbor']
- cmd = '%s remote-as %s' % (context, item['remote_as'])
-
- if not config or cmd not in config:
- neighbor_commands.append(cmd)
-
- for key, value in iteritems(item):
- if value is not None:
- meth = getattr(self, '_render_%s' % key, None)
- if meth:
- resp = meth(item, config)
- if resp:
- neighbor_commands.extend(to_list(resp))
-
- commands.extend(neighbor_commands)
- safe_list.append(context)
-
- if self.params['operation'] == 'replace':
- if config and safe_list:
- commands.extend(self._negate_config(config, safe_list))
-
- return commands
-
- def _negate_config(self, config, safe_list=None):
- commands = list()
- matches = re.findall(r'(neighbor \S+)', config, re.M)
- for item in set(matches).difference(safe_list):
- commands.append('no %s' % item)
- return commands
-
- def _render_local_as(self, item, config=None):
- cmd = 'neighbor %s local-as %s' % (item['neighbor'], item['local_as'])
- if not config or cmd not in config:
- return cmd
-
- def _render_port(self, item, config=None):
- cmd = 'neighbor %s port %s' % (item['neighbor'], item['port'])
- if not config or cmd not in config:
- return cmd
-
- def _render_description(self, item, config=None):
- cmd = 'neighbor %s description %s' % (item['neighbor'], item['description'])
- if not config or cmd not in config:
- return cmd
-
- def _render_enabled(self, item, config=None):
- cmd = 'neighbor %s shutdown' % item['neighbor']
- if item['enabled'] is True:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_update_source(self, item, config=None):
- cmd = 'neighbor %s update-source %s' % (item['neighbor'], item['update_source'])
- if not config or cmd not in config:
- return cmd
-
- def _render_password(self, item, config=None):
- cmd = 'neighbor %s password %s' % (item['neighbor'], item['password'])
- if not config or cmd not in config:
- return cmd
-
- def _render_ebgp_multihop(self, item, config=None):
- cmd = 'neighbor %s ebgp-multihop %s' % (item['neighbor'], item['ebgp_multihop'])
- if not config or cmd not in config:
- return cmd
-
- def _render_peer_group(self, item, config=None):
- cmd = 'neighbor %s peer-group %s' % (item['neighbor'], item['peer_group'])
- if not config or cmd not in config:
- return cmd
-
- def _render_timers(self, item, config):
- """generate bgp timer related configuration
- """
- keepalive = item['timers']['keepalive']
- holdtime = item['timers']['holdtime']
- min_neighbor_holdtime = item['timers']['min_neighbor_holdtime']
- neighbor = item['neighbor']
-
- if keepalive and holdtime:
- cmd = 'neighbor %s timers %s %s' % (neighbor, keepalive, holdtime)
- if min_neighbor_holdtime:
- cmd += ' %s' % min_neighbor_holdtime
- if not config or cmd not in config:
- return cmd
-
-
-class AFNeighbors(CliProvider):
-
- def render(self, config=None, nbr_list=None):
- commands = list()
- if not nbr_list:
- return
-
- for item in nbr_list:
- neighbor_commands = list()
- for key, value in iteritems(item):
- if value is not None:
- meth = getattr(self, '_render_%s' % key, None)
- if meth:
- resp = meth(item, config)
- if resp:
- neighbor_commands.extend(to_list(resp))
-
- commands.extend(neighbor_commands)
-
- return commands
-
- def _render_advertisement_interval(self, item, config=None):
- cmd = 'neighbor %s advertisement-interval %s' % (item['neighbor'], item['advertisement_interval'])
- if not config or cmd not in config:
- return cmd
-
- def _render_route_reflector_client(self, item, config=None):
- cmd = 'neighbor %s route-reflector-client' % item['neighbor']
- if item['route_reflector_client'] is False:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_route_server_client(self, item, config=None):
- cmd = 'neighbor %s route-server-client' % item['neighbor']
- if item['route_server_client'] is False:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_remove_private_as(self, item, config=None):
- cmd = 'neighbor %s remove-private-as' % item['neighbor']
- if item['remove_private_as'] is False:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_next_hop_self(self, item, config=None):
- cmd = 'neighbor %s next-hop-self' % item['neighbor']
- if item['next_hop_self'] is False:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_activate(self, item, config=None):
- cmd = 'neighbor %s activate' % item['neighbor']
- if item['activate'] is False:
- if not config or cmd in config:
- cmd = 'no %s' % cmd
- return cmd
- elif not config or cmd not in config:
- return cmd
-
- def _render_maximum_prefix(self, item, config=None):
- cmd = 'neighbor %s maximum-prefix %s' % (item['neighbor'], item['maximum_prefix'])
- if not config or cmd not in config:
- return cmd
-
- def _render_prefix_list_in(self, item, config=None):
- cmd = 'neighbor %s prefix-list %s in' % (item['neighbor'], item['prefix_list_in'])
- if not config or cmd not in config:
- return cmd
-
- def _render_prefix_list_out(self, item, config=None):
- cmd = 'neighbor %s prefix-list %s out' % (item['neighbor'], item['prefix_list_out'])
- if not config or cmd not in config:
- return cmd
diff --git a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py b/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py
deleted file mode 100644
index d74cf92773..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/cli/config/bgp/process.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-import re
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.ios.providers.providers import register_provider
-from ansible.module_utils.network.ios.providers.providers import CliProvider
-from ansible.module_utils.network.ios.providers.cli.config.bgp.neighbors import Neighbors
-from ansible.module_utils.network.ios.providers.cli.config.bgp.address_family import AddressFamily
-from ansible.module_utils.common.network import to_netmask
-
-REDISTRIBUTE_PROTOCOLS = frozenset(['ospf', 'ospfv3', 'eigrp', 'isis', 'static', 'connected',
- 'odr', 'lisp', 'mobile', 'rip'])
-
-
-@register_provider('ios', 'ios_bgp')
-class Provider(CliProvider):
-
- def render(self, config=None):
- commands = list()
-
- existing_as = None
- if config:
- match = re.search(r'router bgp (\d+)', config, re.M)
- if match:
- existing_as = match.group(1)
-
- operation = self.params['operation']
-
- context = None
- if self.params['config']:
- context = 'router bgp %s' % self.get_value('config.bgp_as')
-
- if operation == 'delete':
- if existing_as:
- commands.append('no router bgp %s' % existing_as)
- elif context:
- commands.append('no %s' % context)
-
- else:
- self._validate_input(config)
- if operation == 'replace':
- if existing_as and int(existing_as) != self.get_value('config.bgp_as'):
- commands.append('no router bgp %s' % existing_as)
- config = None
-
- elif operation == 'override':
- if existing_as:
- commands.append('no router bgp %s' % existing_as)
- config = None
-
- context_commands = list()
-
- for key, value in iteritems(self.get_value('config')):
- if value is not None:
- meth = getattr(self, '_render_%s' % key, None)
- if meth:
- resp = meth(config)
- if resp:
- context_commands.extend(to_list(resp))
-
- if context and context_commands:
- commands.append(context)
- commands.extend(context_commands)
- commands.append('exit')
- return commands
-
- def _render_router_id(self, config=None):
- cmd = 'bgp router-id %s' % self.get_value('config.router_id')
- if not config or cmd not in config:
- return cmd
-
- def _render_log_neighbor_changes(self, config=None):
- cmd = 'bgp log-neighbor-changes'
- log_neighbor_changes = self.get_value('config.log_neighbor_changes')
- if log_neighbor_changes is True:
- if not config or cmd not in config:
- return cmd
- elif log_neighbor_changes is False:
- if config and cmd in config:
- return 'no %s' % cmd
-
- def _render_networks(self, config=None):
- commands = list()
- safe_list = list()
-
- for entry in self.get_value('config.networks'):
- network = entry['prefix']
- cmd = 'network %s' % network
- if entry['masklen'] and entry['masklen'] not in (24, 16, 8):
- cmd += ' mask %s' % to_netmask(entry['masklen'])
- network += ' mask %s' % to_netmask(entry['masklen'])
-
- if entry['route_map']:
- cmd += ' route-map %s' % entry['route_map']
- network += ' route-map %s' % entry['route_map']
-
- safe_list.append(network)
-
- if not config or cmd not in config:
- commands.append(cmd)
-
- if self.params['operation'] == 'replace':
- if config:
- matches = re.findall(r'network (.*)', config, re.M)
- for entry in set(matches).difference(safe_list):
- commands.append('no network %s' % entry)
-
- return commands
-
- def _render_neighbors(self, config):
- """ generate bgp neighbor configuration
- """
- return Neighbors(self.params).render(config)
-
- def _render_address_family(self, config):
- """ generate address-family configuration
- """
- return AddressFamily(self.params).render(config)
-
- def _validate_input(self, config=None):
- def device_has_AF(config):
- return re.search(r'address-family (?:.*)', config)
-
- address_family = self.get_value('config.address_family')
- root_networks = self.get_value('config.networks')
- operation = self.params['operation']
-
- if operation == 'replace':
- if address_family and root_networks:
- for item in address_family:
- if item['networks']:
- raise ValueError('operation is replace but provided both root level network(s) and network(s) under %s %s address family'
- % (item['afi'], item['safi']))
-
- if root_networks and config and device_has_AF(config):
- raise ValueError('operation is replace and device has one or more address family activated but root level network(s) provided')
diff --git a/lib/ansible/module_utils/network/ios/providers/module.py b/lib/ansible/module_utils/network/ios/providers/module.py
deleted file mode 100644
index 69c6dd9659..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/module.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible.module_utils.network.ios.providers import providers
-from ansible.module_utils._text import to_text
-
-
-class NetworkModule(AnsibleModule):
-
- fail_on_missing_provider = True
-
- def __init__(self, connection=None, *args, **kwargs):
- super(NetworkModule, self).__init__(*args, **kwargs)
-
- if connection is None:
- connection = Connection(self._socket_path)
-
- self.connection = connection
-
- @property
- def provider(self):
- if not hasattr(self, '_provider'):
- capabilities = self.from_json(self.connection.get_capabilities())
-
- network_os = capabilities['device_info']['network_os']
- network_api = capabilities['network_api']
-
- if network_api == 'cliconf':
- connection_type = 'network_cli'
-
- cls = providers.get(network_os, self._name.split('.')[-1], connection_type)
-
- if not cls:
- msg = 'unable to find suitable provider for network os %s' % network_os
- if self.fail_on_missing_provider:
- self.fail_json(msg=msg)
- else:
- self.warn(msg)
-
- obj = cls(self.params, self.connection, self.check_mode)
-
- setattr(self, '_provider', obj)
-
- return getattr(self, '_provider')
-
- def get_facts(self, subset=None):
- try:
- self.provider.get_facts(subset)
- except Exception as exc:
- self.fail_json(msg=to_text(exc))
-
- def edit_config(self, config_filter=None):
- current_config = self.connection.get_config(flags=config_filter)
- try:
- commands = self.provider.edit_config(current_config)
- changed = bool(commands)
- return {'commands': commands, 'changed': changed}
- except Exception as exc:
- self.fail_json(msg=to_text(exc))
diff --git a/lib/ansible/module_utils/network/ios/providers/providers.py b/lib/ansible/module_utils/network/ios/providers/providers.py
deleted file mode 100644
index a466b033d9..0000000000
--- a/lib/ansible/module_utils/network/ios/providers/providers.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-import json
-
-from threading import RLock
-
-from ansible.module_utils.six import itervalues
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.common.config import NetworkConfig
-
-
-_registered_providers = {}
-_provider_lock = RLock()
-
-
-def register_provider(network_os, module_name):
- def wrapper(cls):
- _provider_lock.acquire()
- try:
- if network_os not in _registered_providers:
- _registered_providers[network_os] = {}
- for ct in cls.supported_connections:
- if ct not in _registered_providers[network_os]:
- _registered_providers[network_os][ct] = {}
- for item in to_list(module_name):
- for entry in itervalues(_registered_providers[network_os]):
- entry[item] = cls
- finally:
- _provider_lock.release()
- return cls
- return wrapper
-
-
-def get(network_os, module_name, connection_type):
- network_os_providers = _registered_providers.get(network_os)
- if network_os_providers is None:
- raise ValueError('unable to find a suitable provider for this module')
- if connection_type not in network_os_providers:
- raise ValueError('provider does not support this connection type')
- elif module_name not in network_os_providers[connection_type]:
- raise ValueError('could not find a suitable provider for this module')
- return network_os_providers[connection_type][module_name]
-
-
-class ProviderBase(object):
-
- supported_connections = ()
-
- def __init__(self, params, connection=None, check_mode=False):
- self.params = params
- self.connection = connection
- self.check_mode = check_mode
-
- @property
- def capabilities(self):
- if not hasattr(self, '_capabilities'):
- resp = self.from_json(self.connection.get_capabilities())
- setattr(self, '_capabilities', resp)
- return getattr(self, '_capabilities')
-
- def get_value(self, path):
- params = self.params.copy()
- for key in path.split('.'):
- params = params[key]
- return params
-
- def get_facts(self, subset=None):
- raise NotImplementedError(self.__class__.__name__)
-
- def edit_config(self):
- raise NotImplementedError(self.__class__.__name__)
-
-
-class CliProvider(ProviderBase):
-
- supported_connections = ('network_cli',)
-
- @property
- def capabilities(self):
- if not hasattr(self, '_capabilities'):
- resp = self.from_json(self.connection.get_capabilities())
- setattr(self, '_capabilities', resp)
- return getattr(self, '_capabilities')
-
- def get_config_context(self, config, path, indent=1):
- if config is not None:
- netcfg = NetworkConfig(indent=indent, contents=config)
- try:
- config = netcfg.get_block_config(to_list(path))
- except ValueError:
- config = None
- return config
-
- def render(self, config=None):
- raise NotImplementedError(self.__class__.__name__)
-
- def cli(self, command):
- try:
- if not hasattr(self, '_command_output'):
- setattr(self, '_command_output', {})
- return self._command_output[command]
- except KeyError:
- out = self.connection.get(command)
- try:
- out = json.loads(out)
- except ValueError:
- pass
- self._command_output[command] = out
- return out
-
- def get_facts(self, subset=None):
- return self.populate()
-
- def edit_config(self, config=None):
- commands = self.render(config)
- if commands and self.check_mode is False:
- self.connection.edit_config(commands)
- return commands
diff --git a/lib/ansible/module_utils/network/ios/utils/utils.py b/lib/ansible/module_utils/network/ios/utils/utils.py
deleted file mode 100644
index cfcfe82dbc..0000000000
--- a/lib/ansible/module_utils/network/ios/utils/utils.py
+++ /dev/null
@@ -1,328 +0,0 @@
-#
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-# utils
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import socket
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import is_masklen, to_netmask
-
-
-def remove_command_from_config_list(interface, cmd, commands):
- # To delete the passed config
- if interface not in commands:
- commands.insert(0, interface)
- commands.append('no %s' % cmd)
- return commands
-
-
-def add_command_to_config_list(interface, cmd, commands):
- # To set the passed config
- if interface not in commands:
- commands.insert(0, interface)
- commands.append(cmd)
-
-
-def check_n_return_valid_ipv6_addr(module, input_list, filtered_ipv6_list):
- # To verify the valid ipv6 address
- try:
- for each in input_list:
- if '::' in each:
- if '/' in each:
- each = each.split('/')[0]
- if socket.inet_pton(socket.AF_INET6, each):
- filtered_ipv6_list.append(each)
- return filtered_ipv6_list
- except socket.error:
- module.fail_json(msg='Incorrect IPV6 address!')
-
-
-def new_dict_to_set(input_dict, temp_list, test_set, count=0):
- # recursive function to convert input dict to set for comparision
- test_dict = dict()
- if isinstance(input_dict, dict):
- input_dict_len = len(input_dict)
- for k, v in sorted(iteritems(input_dict)):
- count += 1
- if isinstance(v, list):
- temp_list.append(k)
- for each in v:
- if isinstance(each, dict):
- if [True for i in each.values() if type(i) == list]:
- new_dict_to_set(each, temp_list, test_set, count)
- else:
- new_dict_to_set(each, temp_list, test_set, 0)
- else:
- if v is not None:
- test_dict.update({k: v})
- try:
- if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len:
- test_set.add(tuple(iteritems(test_dict)))
- count = 0
- except TypeError:
- temp_dict = {}
-
- def expand_dict(dict_to_expand):
- temp = dict()
- for k, v in iteritems(dict_to_expand):
- if isinstance(v, dict):
- expand_dict(v)
- else:
- if v is not None:
- temp.update({k: v})
- temp_dict.update(tuple(iteritems(temp)))
- new_dict = {k: v}
- expand_dict(new_dict)
- if tuple(iteritems(temp_dict)) not in test_set:
- test_set.add(tuple(iteritems(temp_dict)))
-
-
-def dict_to_set(sample_dict):
- # Generate a set with passed dictionary for comparison
- test_dict = dict()
- if isinstance(sample_dict, dict):
- for k, v in iteritems(sample_dict):
- if v is not None:
- if isinstance(v, list):
- if isinstance(v[0], dict):
- li = []
- for each in v:
- for key, value in iteritems(each):
- if isinstance(value, list):
- each[key] = tuple(value)
- li.append(tuple(iteritems(each)))
- v = tuple(li)
- else:
- v = tuple(v)
- elif isinstance(v, dict):
- li = []
- for key, value in iteritems(v):
- if isinstance(value, list):
- v[key] = tuple(value)
- li.extend(tuple(iteritems(v)))
- v = tuple(li)
- test_dict.update({k: v})
- return_set = set(tuple(iteritems(test_dict)))
- else:
- return_set = set(sample_dict)
- return return_set
-
-
-def filter_dict_having_none_value(want, have):
- # Generate dict with have dict value which is None in want dict
- test_dict = dict()
- name = want.get('name')
- if name:
- test_dict['name'] = name
- diff_ip = False
- for k, v in iteritems(want):
- if isinstance(v, dict):
- for key, value in iteritems(v):
- test_key_dict = dict()
- if value is None:
- dict_val = have.get(k).get(key)
- test_key_dict.update({key: dict_val})
- elif k == 'ipv6' and value.lower() != have.get(k)[0].get(key).lower():
- # as multiple IPV6 address can be configured on same
- # interface, for replace state in place update will
- # actually create new entry, which isn't as expected
- # for replace state, so in case of IPV6 address
- # every time 1st delete the existing IPV6 config and
- # then apply the new change
- dict_val = have.get(k)[0].get(key)
- test_key_dict.update({key: dict_val})
- if test_key_dict:
- test_dict.update({k: test_key_dict})
- if isinstance(v, list):
- for key, value in iteritems(v[0]):
- test_key_dict = dict()
- if value is None:
- dict_val = have.get(k).get(key)
- test_key_dict.update({key: dict_val})
- elif k == 'ipv6' and value.lower() != have.get(k)[0].get(key).lower():
- dict_val = have.get(k)[0].get(key)
- test_key_dict.update({key: dict_val})
- if test_key_dict:
- test_dict.update({k: test_key_dict})
- # below conditions checks are added to check if
- # secondary IP is configured, if yes then delete
- # the already configured IP if want and have IP
- # is different else if it's same no need to delete
- for each in v:
- if each.get('secondary'):
- want_ip = each.get('address').split('/')
- have_ip = have.get('ipv4')
- if len(want_ip) > 1 and have_ip and have_ip[0].get('secondary'):
- have_ip = have_ip[0]['address'].split(' ')[0]
- if have_ip != want_ip[0]:
- diff_ip = True
- if each.get('secondary') and diff_ip is True:
- test_key_dict.update({'secondary': True})
- test_dict.update({'ipv4': test_key_dict})
- if v is None:
- val = have.get(k)
- test_dict.update({k: val})
- return test_dict
-
-
-def remove_duplicate_interface(commands):
- # Remove duplicate interface from commands
- set_cmd = []
- for each in commands:
- if 'interface' in each:
- if each not in set_cmd:
- set_cmd.append(each)
- else:
- set_cmd.append(each)
-
- return set_cmd
-
-
-def validate_ipv4(value, module):
- if value:
- address = value.split('/')
- if len(address) != 2:
- module.fail_json(msg='address format is <ipv4 address>/<mask>, got invalid format {0}'.format(value))
-
- if not is_masklen(address[1]):
- module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-32'.format(address[1]))
-
-
-def validate_ipv6(value, module):
- if value:
- address = value.split('/')
- if len(address) != 2:
- module.fail_json(msg='address format is <ipv6 address>/<mask>, got invalid format {0}'.format(value))
- else:
- if not 0 <= int(address[1]) <= 128:
- module.fail_json(msg='invalid value for mask: {0}, mask should be in range 0-128'.format(address[1]))
-
-
-def validate_n_expand_ipv4(module, want):
- # Check if input IPV4 is valid IP and expand IPV4 with its subnet mask
- ip_addr_want = want.get('address')
- if len(ip_addr_want.split(' ')) > 1:
- return ip_addr_want
- validate_ipv4(ip_addr_want, module)
- ip = ip_addr_want.split('/')
- if len(ip) == 2:
- ip_addr_want = '{0} {1}'.format(ip[0], to_netmask(ip[1]))
-
- return ip_addr_want
-
-
-def netmask_to_cidr(netmask):
- bit_range = [128, 64, 32, 16, 8, 4, 2, 1]
- count = 0
- cidr = 0
- netmask_list = netmask.split('.')
- netmask_calc = [i for i in netmask_list if int(i) != 255 and int(i) != 0]
- if netmask_calc:
- netmask_calc_index = netmask_list.index(netmask_calc[0])
- elif sum(list(map(int, netmask_list))) == 0:
- return '32'
- else:
- return '24'
- for each in bit_range:
- if cidr == int(netmask.split('.')[2]):
- if netmask_calc_index == 1:
- return str(8 + count)
- elif netmask_calc_index == 2:
- return str(8 * 2 + count)
- elif netmask_calc_index == 3:
- return str(8 * 3 + count)
- break
- cidr += each
- count += 1
-
-
-def normalize_interface(name):
- """Return the normalized interface name
- """
- if not name:
- return
-
- def _get_number(name):
- digits = ''
- for char in name:
- if char.isdigit() or char in '/.':
- digits += char
- return digits
-
- if name.lower().startswith('gi'):
- if_type = 'GigabitEthernet'
- elif name.lower().startswith('te'):
- if_type = 'TenGigabitEthernet'
- elif name.lower().startswith('fa'):
- if_type = 'FastEthernet'
- elif name.lower().startswith('fo'):
- if_type = 'FortyGigabitEthernet'
- elif name.lower().startswith('long'):
- if_type = 'LongReachEthernet'
- elif name.lower().startswith('et'):
- if_type = 'Ethernet'
- elif name.lower().startswith('vl'):
- if_type = 'Vlan'
- elif name.lower().startswith('lo'):
- if_type = 'loopback'
- elif name.lower().startswith('po'):
- if_type = 'Port-channel'
- elif name.lower().startswith('nv'):
- if_type = 'nve'
- elif name.lower().startswith('twe'):
- if_type = 'TwentyFiveGigE'
- elif name.lower().startswith('hu'):
- if_type = 'HundredGigE'
- else:
- if_type = None
-
- number_list = name.split(' ')
- if len(number_list) == 2:
- number = number_list[-1].strip()
- else:
- number = _get_number(name)
-
- if if_type:
- proper_interface = if_type + number
- else:
- proper_interface = name
-
- return proper_interface
-
-
-def get_interface_type(interface):
- """Gets the type of interface
- """
-
- if interface.upper().startswith('GI'):
- return 'GigabitEthernet'
- elif interface.upper().startswith('TE'):
- return 'TenGigabitEthernet'
- elif interface.upper().startswith('FA'):
- return 'FastEthernet'
- elif interface.upper().startswith('FO'):
- return 'FortyGigabitEthernet'
- elif interface.upper().startswith('LON'):
- return 'LongReachEthernet'
- elif interface.upper().startswith('ET'):
- return 'Ethernet'
- elif interface.upper().startswith('VL'):
- return 'Vlan'
- elif interface.upper().startswith('LO'):
- return 'loopback'
- elif interface.upper().startswith('PO'):
- return 'Port-channel'
- elif interface.upper().startswith('NV'):
- return 'nve'
- elif interface.upper().startswith('TWE'):
- return 'TwentyFiveGigE'
- elif interface.upper().startswith('HU'):
- return 'HundredGigE'
- else:
- return 'unknown'
diff --git a/lib/ansible/modules/network/ios/_ios_interface.py b/lib/ansible/modules/network/ios/_ios_interface.py
deleted file mode 100644
index d6241acb16..0000000000
--- a/lib/ansible/modules/network/ios/_ios_interface.py
+++ /dev/null
@@ -1,495 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_interface
-version_added: "2.4"
-author: "Ganesh Nalawade (@ganeshrn)"
-short_description: Manage Interface on Cisco IOS network devices
-description:
- - This module provides declarative management of Interfaces
- on Cisco IOS network devices.
-deprecated:
- removed_in: '2.13'
- alternative: ios_interfaces
- why: Newer and updated modules released with more functionality in Ansible 2.9
-notes:
- - Tested against IOS 15.6
-options:
- name:
- description:
- - Name of the Interface.
- required: true
- description:
- description:
- - Description of Interface.
- enabled:
- description:
- - Interface link status.
- type: bool
- speed:
- description:
- - Interface link speed.
- mtu:
- description:
- - Maximum size of transmit packet.
- duplex:
- description:
- - Interface link status
- default: auto
- choices: ['full', 'half', 'auto']
- tx_rate:
- description:
- - Transmit rate in bits per second (bps).
- - This is state check parameter only.
- - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html)
- rx_rate:
- description:
- - Receiver rate in bits per second (bps).
- - This is state check parameter only.
- - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html)
- neighbors:
- description:
- - Check the operational state of given interface C(name) for CDP/LLDP neighbor.
- - The following suboptions are available.
- suboptions:
- host:
- description:
- - "CDP/LLDP neighbor host for given interface C(name)."
- port:
- description:
- - "CDP/LLDP neighbor port to which given interface C(name) is connected."
- aggregate:
- description: List of Interfaces definitions.
- delay:
- description:
- - Time in seconds to wait before checking for the operational state on remote
- device. This wait is applicable for operational state argument which are
- I(state) with values C(up)/C(down), I(tx_rate) and I(rx_rate).
- default: 10
- state:
- description:
- - State of the Interface configuration, C(up) means present and
- operationally up and C(down) means present and operationally C(down)
- default: present
- choices: ['present', 'absent', 'up', 'down']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: configure interface
- ios_interface:
- name: GigabitEthernet0/2
- description: test-interface
- speed: 100
- duplex: half
- mtu: 512
-
-- name: remove interface
- ios_interface:
- name: Loopback9
- state: absent
-
-- name: make interface up
- ios_interface:
- name: GigabitEthernet0/2
- enabled: True
-
-- name: make interface down
- ios_interface:
- name: GigabitEthernet0/2
- enabled: False
-
-- name: Check intent arguments
- ios_interface:
- name: GigabitEthernet0/2
- state: up
- tx_rate: ge(0)
- rx_rate: le(0)
-
-- name: Check neighbors intent arguments
- ios_interface:
- name: Gi0/0
- neighbors:
- - port: eth0
- host: netdev
-
-- name: Config + intent
- ios_interface:
- name: GigabitEthernet0/2
- enabled: False
- state: down
-
-- name: Add interface using aggregate
- ios_interface:
- aggregate:
- - { name: GigabitEthernet0/1, mtu: 256, description: test-interface-1 }
- - { name: GigabitEthernet0/2, mtu: 516, description: test-interface-2 }
- duplex: full
- speed: 100
- state: present
-
-- name: Delete interface using aggregate
- ios_interface:
- aggregate:
- - name: Loopback9
- - name: Loopback10
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device.
- returned: always, except for the platforms that use Netconf transport to manage the device.
- type: list
- sample:
- - interface GigabitEthernet0/2
- - description test-interface
- - duplex half
- - mtu 512
-"""
-import re
-
-from copy import deepcopy
-from time import sleep
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import exec_command
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.network.common.config import NetworkConfig
-from ansible.module_utils.network.common.utils import conditional, remove_default_spec
-
-
-def validate_mtu(value, module):
- if value and not 64 <= int(value) <= 9600:
- module.fail_json(msg='mtu must be between 64 and 9600')
-
-
-def validate_param_values(module, obj, param=None):
- if param is None:
- param = module.params
- for key in obj:
- # validate the param value (if validator func exists)
- validator = globals().get('validate_%s' % key)
- if callable(validator):
- validator(param.get(key), module)
-
-
-def parse_shutdown(configobj, name):
- cfg = configobj['interface %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'^shutdown', cfg, re.M)
- if match:
- return True
- else:
- return False
-
-
-def parse_config_argument(configobj, name, arg=None):
- cfg = configobj['interface %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'%s (.+)$' % arg, cfg, re.M)
- if match:
- return match.group(1)
-
-
-def search_obj_in_list(name, lst):
- for o in lst:
- if o['name'] == name:
- return o
-
- return None
-
-
-def add_command_to_interface(interface, cmd, commands):
- if interface not in commands:
- commands.append(interface)
- commands.append(cmd)
-
-
-def map_config_to_obj(module):
- config = get_config(module)
- configobj = NetworkConfig(indent=1, contents=config)
-
- match = re.findall(r'^interface (\S+)', config, re.M)
- if not match:
- return list()
-
- instances = list()
-
- for item in set(match):
- obj = {
- 'name': item,
- 'description': parse_config_argument(configobj, item, 'description'),
- 'speed': parse_config_argument(configobj, item, 'speed'),
- 'duplex': parse_config_argument(configobj, item, 'duplex'),
- 'mtu': parse_config_argument(configobj, item, 'mtu'),
- 'disable': True if parse_shutdown(configobj, item) else False,
- 'state': 'present'
- }
- instances.append(obj)
- return instances
-
-
-def map_params_to_obj(module):
- obj = []
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- validate_param_values(module, item, item)
- d = item.copy()
-
- if d['enabled']:
- d['disable'] = False
- else:
- d['disable'] = True
-
- obj.append(d)
-
- else:
- params = {
- 'name': module.params['name'],
- 'description': module.params['description'],
- 'speed': module.params['speed'],
- 'mtu': module.params['mtu'],
- 'duplex': module.params['duplex'],
- 'state': module.params['state'],
- 'delay': module.params['delay'],
- 'tx_rate': module.params['tx_rate'],
- 'rx_rate': module.params['rx_rate'],
- 'neighbors': module.params['neighbors']
- }
-
- validate_param_values(module, params)
- if module.params['enabled']:
- params.update({'disable': False})
- else:
- params.update({'disable': True})
-
- obj.append(params)
- return obj
-
-
-def map_obj_to_commands(updates):
- commands = list()
- want, have = updates
-
- args = ('speed', 'description', 'duplex', 'mtu')
- for w in want:
- name = w['name']
- disable = w['disable']
- state = w['state']
-
- obj_in_have = search_obj_in_list(name, have)
- interface = 'interface ' + name
-
- if state == 'absent' and obj_in_have:
- commands.append('no ' + interface)
-
- elif state in ('present', 'up', 'down'):
- if obj_in_have:
- for item in args:
- candidate = w.get(item)
- running = obj_in_have.get(item)
- if candidate != running:
- if candidate:
- cmd = item + ' ' + str(candidate)
- add_command_to_interface(interface, cmd, commands)
-
- if disable and not obj_in_have.get('disable', False):
- add_command_to_interface(interface, 'shutdown', commands)
- elif not disable and obj_in_have.get('disable', False):
- add_command_to_interface(interface, 'no shutdown', commands)
- else:
- commands.append(interface)
- for item in args:
- value = w.get(item)
- if value:
- commands.append(item + ' ' + str(value))
-
- if disable:
- commands.append('no shutdown')
- return commands
-
-
-def check_declarative_intent_params(module, want, result):
- failed_conditions = []
- have_neighbors_lldp = None
- have_neighbors_cdp = None
- for w in want:
- want_state = w.get('state')
- want_tx_rate = w.get('tx_rate')
- want_rx_rate = w.get('rx_rate')
- want_neighbors = w.get('neighbors')
-
- if want_state not in ('up', 'down') and not want_tx_rate and not want_rx_rate and not want_neighbors:
- continue
-
- if result['changed']:
- sleep(w['delay'])
-
- command = 'show interfaces %s' % w['name']
- rc, out, err = exec_command(module, command)
- if rc != 0:
- module.fail_json(msg=to_text(err, errors='surrogate_then_replace'), command=command, rc=rc)
-
- if want_state in ('up', 'down'):
- match = re.search(r'%s (\w+)' % 'line protocol is', out, re.M)
- have_state = None
- if match:
- have_state = match.group(1)
- if have_state is None or not conditional(want_state, have_state.strip()):
- failed_conditions.append('state ' + 'eq(%s)' % want_state)
-
- if want_tx_rate:
- match = re.search(r'%s (\d+)' % 'output rate', out, re.M)
- have_tx_rate = None
- if match:
- have_tx_rate = match.group(1)
-
- if have_tx_rate is None or not conditional(want_tx_rate, have_tx_rate.strip(), cast=int):
- failed_conditions.append('tx_rate ' + want_tx_rate)
-
- if want_rx_rate:
- match = re.search(r'%s (\d+)' % 'input rate', out, re.M)
- have_rx_rate = None
- if match:
- have_rx_rate = match.group(1)
-
- if have_rx_rate is None or not conditional(want_rx_rate, have_rx_rate.strip(), cast=int):
- failed_conditions.append('rx_rate ' + want_rx_rate)
-
- if want_neighbors:
- have_host = []
- have_port = []
-
- # Process LLDP neighbors
- if have_neighbors_lldp is None:
- rc, have_neighbors_lldp, err = exec_command(module, 'show lldp neighbors detail')
- if rc != 0:
- module.fail_json(msg=to_text(err, errors='surrogate_then_replace'), command=command, rc=rc)
-
- if have_neighbors_lldp:
- lines = have_neighbors_lldp.strip().split('Local Intf: ')
- for line in lines:
- field = line.split('\n')
- if field[0].strip() == w['name']:
- for item in field:
- if item.startswith('System Name:'):
- have_host.append(item.split(':')[1].strip())
- if item.startswith('Port Description:'):
- have_port.append(item.split(':')[1].strip())
-
- # Process CDP neighbors
- if have_neighbors_cdp is None:
- rc, have_neighbors_cdp, err = exec_command(module, 'show cdp neighbors detail')
- if rc != 0:
- module.fail_json(msg=to_text(err, errors='surrogate_then_replace'), command=command, rc=rc)
-
- if have_neighbors_cdp:
- neighbors_cdp = re.findall('Device ID: (.*?)\n.*?Interface: (.*?), Port ID .outgoing port.: (.*?)\n', have_neighbors_cdp, re.S)
- for host, localif, remoteif in neighbors_cdp:
- if localif == w['name']:
- have_host.append(host)
- have_port.append(remoteif)
-
- for item in want_neighbors:
- host = item.get('host')
- port = item.get('port')
- if host and host not in have_host:
- failed_conditions.append('host ' + host)
- if port and port not in have_port:
- failed_conditions.append('port ' + port)
- return failed_conditions
-
-
-def main():
- """ main entry point for module execution
- """
- neighbors_spec = dict(
- host=dict(),
- port=dict()
- )
-
- element_spec = dict(
- name=dict(),
- description=dict(),
- speed=dict(),
- mtu=dict(),
- duplex=dict(choices=['full', 'half', 'auto']),
- enabled=dict(default=True, type='bool'),
- tx_rate=dict(),
- rx_rate=dict(),
- neighbors=dict(type='list', elements='dict', options=neighbors_spec),
- delay=dict(default=10, type='int'),
- state=dict(default='present',
- choices=['present', 'absent', 'up', 'down'])
- )
-
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['name'] = dict(required=True)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- required_one_of = [['name', 'aggregate']]
- mutually_exclusive = [['name', 'aggregate']]
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_one_of=required_one_of,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
- warnings = list()
-
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands((want, have))
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- failed_conditions = check_declarative_intent_params(module, want, result)
-
- if failed_conditions:
- msg = 'One or more conditional statements have not been satisfied'
- module.fail_json(msg=msg, failed_conditions=failed_conditions)
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/_ios_l2_interface.py b/lib/ansible/modules/network/ios/_ios_l2_interface.py
deleted file mode 100644
index 710c435c4e..0000000000
--- a/lib/ansible/modules/network/ios/_ios_l2_interface.py
+++ /dev/null
@@ -1,499 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_l2_interface
-extends_documentation_fragment: ios
-version_added: "2.5"
-short_description: Manage Layer-2 interface on Cisco IOS devices.
-description:
- - This module provides declarative management of Layer-2 interfaces on
- Cisco IOS devices.
-deprecated:
- removed_in: '2.13'
- alternative: ios_l2_interfaces
- why: Newer and updated modules released with more functionality in Ansible 2.9
-author:
- - Nathaniel Case (@Qalthos)
-options:
- name:
- description:
- - Full name of the interface excluding any logical
- unit number, i.e. GigabitEthernet0/1.
- required: true
- aliases: ['interface']
- mode:
- description:
- - Mode in which interface needs to be configured.
- default: access
- choices: ['access', 'trunk']
- access_vlan:
- description:
- - Configure given VLAN in access port.
- If C(mode=access), used as the access VLAN ID.
- trunk_vlans:
- description:
- - List of VLANs to be configured in trunk port.
- If C(mode=trunk), used as the VLAN range to ADD or REMOVE
- from the trunk.
- native_vlan:
- description:
- - Native VLAN to be configured in trunk port.
- If C(mode=trunk), used as the trunk native VLAN ID.
- trunk_allowed_vlans:
- description:
- - List of allowed VLANs in a given trunk port.
- If C(mode=trunk), these are the only VLANs that will be
- configured on the trunk, i.e. "2-10,15".
- aggregate:
- description:
- - List of Layer-2 interface definitions.
- state:
- description:
- - Manage the state of the Layer-2 Interface configuration.
- default: present
- choices: ['present','absent', 'unconfigured']
-"""
-
-EXAMPLES = """
-- name: Ensure GigabitEthernet0/5 is in its default l2 interface state
- ios_l2_interface:
- name: GigabitEthernet0/5
- state: unconfigured
-- name: Ensure GigabitEthernet0/5 is configured for access vlan 20
- ios_l2_interface:
- name: GigabitEthernet0/5
- mode: access
- access_vlan: 20
-- name: Ensure GigabitEthernet0/5 only has vlans 5-10 as trunk vlans
- ios_l2_interface:
- name: GigabitEthernet0/5
- mode: trunk
- native_vlan: 10
- trunk_allowed_vlans: 5-10
-- name: Ensure GigabitEthernet0/5 is a trunk port and ensure 2-50 are being tagged (doesn't mean others aren't also being tagged)
- ios_l2_interface:
- name: GigabitEthernet0/5
- mode: trunk
- native_vlan: 10
- trunk_vlans: 2-50
-- name: Ensure these VLANs are not being tagged on the trunk
- ios_l2_interface:
- name: GigabitEthernet0/5
- mode: trunk
- trunk_vlans: 51-4094
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always, except for the platforms that use Netconf transport to manage the device.
- type: list
- sample:
- - interface GigabitEthernet0/5
- - switchport access vlan 20
-"""
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import remove_default_spec
-from ansible.module_utils.network.ios.ios import load_config, run_commands
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def get_interface_type(interface):
- intf_type = 'unknown'
- if interface.upper()[:2] in ('ET', 'GI', 'FA', 'TE', 'FO', 'HU', 'TWE', 'TW'):
- intf_type = 'ethernet'
- elif interface.upper().startswith('VL'):
- intf_type = 'svi'
- elif interface.upper().startswith('LO'):
- intf_type = 'loopback'
- elif interface.upper()[:2] in ('MG', 'MA'):
- intf_type = 'management'
- elif interface.upper().startswith('PO'):
- intf_type = 'portchannel'
- elif interface.upper().startswith('NV'):
- intf_type = 'nve'
-
- return intf_type
-
-
-def is_switchport(name, module):
- intf_type = get_interface_type(name)
-
- if intf_type in ('ethernet', 'portchannel'):
- config = run_commands(module, ['show interface {0} switchport'.format(name)])[0]
- match = re.search(r'Switchport: Enabled', config)
- return bool(match)
- return False
-
-
-def interface_is_portchannel(name, module):
- if get_interface_type(name) == 'ethernet':
- config = run_commands(module, ['show run interface {0}'.format(name)])[0]
- if any(c in config for c in ['channel group', 'channel-group']):
- return True
- return False
-
-
-def get_switchport(name, module):
- config = run_commands(module, ['show interface {0} switchport'.format(name)])[0]
- mode = re.search(r'Administrative Mode: (?:.* )?(\w+)$', config, re.M)
- access = re.search(r'Access Mode VLAN: (\d+)', config)
- native = re.search(r'Trunking Native Mode VLAN: (\d+)', config)
- trunk = re.search(r'Trunking VLANs Enabled: (.+)$', config, re.M)
- if mode:
- mode = mode.group(1)
- if access:
- access = access.group(1)
- if native:
- native = native.group(1)
- if trunk:
- trunk = trunk.group(1)
- if trunk == 'ALL':
- trunk = '1-4094'
-
- switchport_config = {
- "interface": name,
- "mode": mode,
- "access_vlan": access,
- "native_vlan": native,
- "trunk_vlans": trunk,
- }
-
- return switchport_config
-
-
-def remove_switchport_config_commands(name, existing, proposed, module):
- mode = proposed.get('mode')
- commands = []
- command = None
-
- if mode == 'access':
- av_check = existing.get('access_vlan') == proposed.get('access_vlan')
- if av_check:
- command = 'no switchport access vlan {0}'.format(existing.get('access_vlan'))
- commands.append(command)
-
- elif mode == 'trunk':
- # Supported Remove Scenarios for trunk_vlans_list
- # 1) Existing: 1,2,3 Proposed: 1,2,3 - Remove all
- # 2) Existing: 1,2,3 Proposed: 1,2 - Remove 1,2 Leave 3
- # 3) Existing: 1,2,3 Proposed: 2,3 - Remove 2,3 Leave 1
- # 4) Existing: 1,2,3 Proposed: 4,5,6 - None removed.
- # 5) Existing: None Proposed: 1,2,3 - None removed.
- existing_vlans = existing.get('trunk_vlans_list')
- proposed_vlans = proposed.get('trunk_vlans_list')
- vlans_to_remove = set(proposed_vlans).intersection(existing_vlans)
-
- if vlans_to_remove:
- proposed_allowed_vlans = proposed.get('trunk_allowed_vlans')
- remove_trunk_allowed_vlans = proposed.get('trunk_vlans', proposed_allowed_vlans)
- command = 'switchport trunk allowed vlan remove {0}'.format(remove_trunk_allowed_vlans)
- commands.append(command)
-
- native_check = existing.get('native_vlan') == proposed.get('native_vlan')
- if native_check and proposed.get('native_vlan'):
- command = 'no switchport trunk native vlan {0}'.format(existing.get('native_vlan'))
- commands.append(command)
-
- if commands:
- commands.insert(0, 'interface ' + name)
- return commands
-
-
-def get_switchport_config_commands(name, existing, proposed, module):
- """Gets commands required to config a given switchport interface
- """
-
- proposed_mode = proposed.get('mode')
- existing_mode = existing.get('mode')
- commands = []
- command = None
-
- if proposed_mode != existing_mode:
- if proposed_mode == 'trunk':
- command = 'switchport mode trunk'
- elif proposed_mode == 'access':
- command = 'switchport mode access'
-
- if command:
- commands.append(command)
-
- if proposed_mode == 'access':
- av_check = str(existing.get('access_vlan')) == str(proposed.get('access_vlan'))
- if not av_check:
- command = 'switchport access vlan {0}'.format(proposed.get('access_vlan'))
- commands.append(command)
-
- elif proposed_mode == 'trunk':
- tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list')
-
- if not tv_check:
- if proposed.get('allowed'):
- command = 'switchport trunk allowed vlan {0}'.format(proposed.get('trunk_allowed_vlans'))
- commands.append(command)
-
- else:
- existing_vlans = existing.get('trunk_vlans_list')
- proposed_vlans = proposed.get('trunk_vlans_list')
- vlans_to_add = set(proposed_vlans).difference(existing_vlans)
- if vlans_to_add:
- command = 'switchport trunk allowed vlan add {0}'.format(proposed.get('trunk_vlans'))
- commands.append(command)
-
- native_check = str(existing.get('native_vlan')) == str(proposed.get('native_vlan'))
- if not native_check and proposed.get('native_vlan'):
- command = 'switchport trunk native vlan {0}'.format(proposed.get('native_vlan'))
- commands.append(command)
-
- if commands:
- commands.insert(0, 'interface ' + name)
- return commands
-
-
-def is_switchport_default(existing):
- """Determines if switchport has a default config based on mode
- Args:
- existing (dict): existing switchport configuration from Ansible mod
- Returns:
- boolean: True if switchport has OOB Layer 2 config, i.e.
- vlan 1 and trunk all and mode is access
- """
-
- c1 = str(existing['access_vlan']) == '1'
- c2 = str(existing['native_vlan']) == '1'
- c3 = existing['trunk_vlans'] == '1-4094'
- c4 = existing['mode'] == 'access'
-
- default = c1 and c2 and c3 and c4
-
- return default
-
-
-def default_switchport_config(name):
- commands = []
- commands.append('interface ' + name)
- commands.append('switchport mode access')
- commands.append('switch access vlan 1')
- commands.append('switchport trunk native vlan 1')
- commands.append('switchport trunk allowed vlan all')
- return commands
-
-
-def vlan_range_to_list(vlans):
- result = []
- if vlans:
- for part in vlans.split(','):
- if part.lower() == 'none':
- break
- if part:
- if '-' in part:
- start, stop = (int(i) for i in part.split('-'))
- result.extend(range(start, stop + 1))
- else:
- result.append(int(part))
- return sorted(result)
-
-
-def get_list_of_vlans(module):
- config = run_commands(module, ['show vlan'])[0]
- vlans = set()
-
- lines = config.strip().splitlines()
- for line in lines:
- line_parts = line.split()
- if line_parts:
- try:
- int(line_parts[0])
- except ValueError:
- continue
- vlans.add(line_parts[0])
-
- return list(vlans)
-
-
-def flatten_list(commands):
- flat_list = []
- for command in commands:
- if isinstance(command, list):
- flat_list.extend(command)
- else:
- flat_list.append(command)
- return flat_list
-
-
-def map_params_to_obj(module):
- obj = []
-
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- obj.append(item.copy())
- else:
- obj.append({
- 'name': module.params['name'],
- 'mode': module.params['mode'],
- 'access_vlan': module.params['access_vlan'],
- 'native_vlan': module.params['native_vlan'],
- 'trunk_vlans': module.params['trunk_vlans'],
- 'trunk_allowed_vlans': module.params['trunk_allowed_vlans'],
- 'state': module.params['state']
- })
-
- return obj
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- name=dict(type='str', aliases=['interface']),
- mode=dict(choices=['access', 'trunk']),
- access_vlan=dict(type='str'),
- native_vlan=dict(type='str'),
- trunk_vlans=dict(type='str'),
- trunk_allowed_vlans=dict(type='str'),
- state=dict(choices=['absent', 'present', 'unconfigured'], default='present')
- )
-
- aggregate_spec = deepcopy(element_spec)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- mutually_exclusive=[['access_vlan', 'trunk_vlans'],
- ['access_vlan', 'native_vlan'],
- ['access_vlan', 'trunk_allowed_vlans']],
- supports_check_mode=True)
-
- warnings = list()
- commands = []
- result = {'changed': False, 'warnings': warnings}
-
- want = map_params_to_obj(module)
- for w in want:
- name = w['name']
- mode = w['mode']
- access_vlan = w['access_vlan']
- state = w['state']
- trunk_vlans = w['trunk_vlans']
- native_vlan = w['native_vlan']
- trunk_allowed_vlans = w['trunk_allowed_vlans']
-
- args = dict(name=name, mode=mode, access_vlan=access_vlan,
- native_vlan=native_vlan, trunk_vlans=trunk_vlans,
- trunk_allowed_vlans=trunk_allowed_vlans)
-
- proposed = dict((k, v) for k, v in args.items() if v is not None)
-
- name = name.lower()
-
- if mode == 'access' and state == 'present' and not access_vlan:
- module.fail_json(msg='access_vlan param is required when mode=access && state=present')
-
- if mode == 'trunk' and access_vlan:
- module.fail_json(msg='access_vlan param not supported when using mode=trunk')
-
- if not is_switchport(name, module):
- module.fail_json(msg='Ensure interface is configured to be a L2'
- '\nport first before using this module. You can use'
- '\nthe ios_interface module for this.')
-
- if interface_is_portchannel(name, module):
- module.fail_json(msg='Cannot change L2 config on physical '
- '\nport because it is in a portchannel. '
- '\nYou should update the portchannel config.')
-
- # existing will never be null for Eth intfs as there is always a default
- existing = get_switchport(name, module)
-
- # Safeguard check
- # If there isn't an existing, something is wrong per previous comment
- if not existing:
- module.fail_json(msg='Make sure you are using the FULL interface name')
-
- if trunk_vlans or trunk_allowed_vlans:
- if trunk_vlans:
- trunk_vlans_list = vlan_range_to_list(trunk_vlans)
- elif trunk_allowed_vlans:
- trunk_vlans_list = vlan_range_to_list(trunk_allowed_vlans)
- proposed['allowed'] = True
-
- existing_trunks_list = vlan_range_to_list((existing['trunk_vlans']))
-
- existing['trunk_vlans_list'] = existing_trunks_list
- proposed['trunk_vlans_list'] = trunk_vlans_list
-
- current_vlans = get_list_of_vlans(module)
-
- if state == 'present':
- if access_vlan and access_vlan not in current_vlans:
- module.fail_json(msg='You are trying to configure a VLAN'
- ' on an interface that\ndoes not exist on the '
- ' switch yet!', vlan=access_vlan)
- elif native_vlan and native_vlan not in current_vlans:
- module.fail_json(msg='You are trying to configure a VLAN'
- ' on an interface that\ndoes not exist on the '
- ' switch yet!', vlan=native_vlan)
- else:
- command = get_switchport_config_commands(name, existing, proposed, module)
- commands.append(command)
- elif state == 'unconfigured':
- is_default = is_switchport_default(existing)
- if not is_default:
- command = default_switchport_config(name)
- commands.append(command)
- elif state == 'absent':
- command = remove_switchport_config_commands(name, existing, proposed, module)
- commands.append(command)
-
- if trunk_vlans or trunk_allowed_vlans:
- existing.pop('trunk_vlans_list')
- proposed.pop('trunk_vlans_list')
-
- cmds = flatten_list(commands)
- if cmds:
- if module.check_mode:
- module.exit_json(changed=True, commands=cmds)
- else:
- result['changed'] = True
- load_config(module, cmds)
- if 'configure' in cmds:
- cmds.pop(0)
-
- result['commands'] = cmds
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/_ios_l3_interface.py b/lib/ansible/modules/network/ios/_ios_l3_interface.py
deleted file mode 100644
index 8435720240..0000000000
--- a/lib/ansible/modules/network/ios/_ios_l3_interface.py
+++ /dev/null
@@ -1,327 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_l3_interface
-version_added: "2.5"
-author: "Ganesh Nalawade (@ganeshrn)"
-short_description: Manage Layer-3 interfaces on Cisco IOS network devices.
-description:
- - This module provides declarative management of Layer-3 interfaces
- on IOS network devices.
-deprecated:
- removed_in: '2.13'
- alternative: ios_l3_interfaces
- why: Newer and updated modules released with more functionality in Ansible 2.9
-notes:
- - Tested against IOS 15.2
-options:
- name:
- description:
- - Name of the Layer-3 interface to be configured eg. GigabitEthernet0/2
- ipv4:
- description:
- - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option.
- The address format is <ipv4 address>/<mask>, the mask is number
- in range 0-32 eg. 192.168.0.1/24
- ipv6:
- description:
- - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option.
- The address format is <ipv6 address>/<mask>, the mask is number
- in range 0-128 eg. fd5d:12c9:2201:1::1/64
- aggregate:
- description:
- - List of Layer-3 interfaces definitions. Each of the entry in aggregate list should
- define name of interface C(name) and a optional C(ipv4) or C(ipv6) address.
- state:
- description:
- - State of the Layer-3 interface configuration. It indicates if the configuration should
- be present or absent on remote device.
- default: present
- choices: ['present', 'absent']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: Remove GigabitEthernet0/3 IPv4 and IPv6 address
- ios_l3_interface:
- name: GigabitEthernet0/3
- state: absent
-- name: Set GigabitEthernet0/3 IPv4 address
- ios_l3_interface:
- name: GigabitEthernet0/3
- ipv4: 192.168.0.1/24
-- name: Set GigabitEthernet0/3 IPv6 address
- ios_l3_interface:
- name: GigabitEthernet0/3
- ipv6: "fd5d:12c9:2201:1::1/64"
-- name: Set GigabitEthernet0/3 in dhcp
- ios_l3_interface:
- name: GigabitEthernet0/3
- ipv4: dhcp
- ipv6: dhcp
-- name: Set interface Vlan1 (SVI) IPv4 address
- ios_l3_interface:
- name: Vlan1
- ipv4: 192.168.0.5/24
-- name: Set IP addresses on aggregate
- ios_l3_interface:
- aggregate:
- - { name: GigabitEthernet0/3, ipv4: 192.168.2.10/24 }
- - { name: GigabitEthernet0/3, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
-- name: Remove IP addresses on aggregate
- ios_l3_interface:
- aggregate:
- - { name: GigabitEthernet0/3, ipv4: 192.168.2.10/24 }
- - { name: GigabitEthernet0/3, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always, except for the platforms that use Netconf transport to manage the device.
- type: list
- sample:
- - interface GigabitEthernet0/2
- - ip address 192.168.0.1 255.255.255.0
- - ipv6 address fd5d:12c9:2201:1::1/64
-"""
-import re
-
-from copy import deepcopy
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.network.common.config import NetworkConfig
-from ansible.module_utils.network.common.utils import remove_default_spec
-from ansible.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
-
-
-def validate_ipv4(value, module):
- if value:
- address = value.split('/')
- if len(address) != 2:
- module.fail_json(msg='address format is <ipv4 address>/<mask>, got invalid format %s' % value)
-
- if not is_masklen(address[1]):
- module.fail_json(msg='invalid value for mask: %s, mask should be in range 0-32' % address[1])
-
-
-def validate_ipv6(value, module):
- if value:
- address = value.split('/')
- if len(address) != 2:
- module.fail_json(msg='address format is <ipv6 address>/<mask>, got invalid format %s' % value)
- else:
- if not 0 <= int(address[1]) <= 128:
- module.fail_json(msg='invalid value for mask: %s, mask should be in range 0-128' % address[1])
-
-
-def validate_param_values(module, obj, param=None):
- if param is None:
- param = module.params
- for key in obj:
- # validate the param value (if validator func exists)
- validator = globals().get('validate_%s' % key)
- if callable(validator):
- validator(param.get(key), module)
-
-
-def parse_config_argument(configobj, name, arg=None):
- cfg = configobj['interface %s' % name]
- cfg = '\n'.join(cfg.children)
-
- values = []
- matches = re.finditer(r'%s (.+)$' % arg, cfg, re.M)
- for match in matches:
- match_str = match.group(1).strip()
- if arg == 'ipv6 address':
- values.append(match_str)
- else:
- values = match_str
- break
-
- return values or None
-
-
-def search_obj_in_list(name, lst):
- for o in lst:
- if o['name'] == name:
- return o
-
- return None
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
- want, have = updates
- for w in want:
- name = w['name']
- ipv4 = w['ipv4']
- ipv6 = w['ipv6']
- state = w['state']
-
- interface = 'interface ' + name
- commands.append(interface)
-
- obj_in_have = search_obj_in_list(name, have)
- if state == 'absent' and obj_in_have:
- if obj_in_have['ipv4']:
- if ipv4:
- address = ipv4.split('/')
- if len(address) == 2:
- ipv4 = '{0} {1}'.format(address[0], to_netmask(address[1]))
- commands.append('no ip address {0}'.format(ipv4))
- else:
- commands.append('no ip address')
- if obj_in_have['ipv6']:
- if ipv6:
- commands.append('no ipv6 address {0}'.format(ipv6))
- else:
- commands.append('no ipv6 address')
- if 'dhcp' in obj_in_have['ipv6']:
- commands.append('no ipv6 address dhcp')
-
- elif state == 'present':
- if ipv4:
- if obj_in_have is None or obj_in_have.get('ipv4') is None or ipv4 != obj_in_have['ipv4']:
- address = ipv4.split('/')
- if len(address) == 2:
- ipv4 = '{0} {1}'.format(address[0], to_netmask(address[1]))
- commands.append('ip address {0}'.format(ipv4))
-
- if ipv6:
- if obj_in_have is None or obj_in_have.get('ipv6') is None or ipv6.lower() not in [addr.lower() for addr in obj_in_have['ipv6']]:
- commands.append('ipv6 address {0}'.format(ipv6))
-
- if commands[-1] == interface:
- commands.pop(-1)
-
- return commands
-
-
-def map_config_to_obj(module):
- config = get_config(module)
- configobj = NetworkConfig(indent=1, contents=config)
-
- match = re.findall(r'^interface (\S+)', config, re.M)
- if not match:
- return list()
-
- instances = list()
-
- for item in set(match):
- ipv4 = parse_config_argument(configobj, item, 'ip address')
- if ipv4:
- # eg. 192.168.2.10 255.255.255.0 -> 192.168.2.10/24
- address = ipv4.strip().split(' ')
- if len(address) == 2 and is_netmask(address[1]):
- ipv4 = '{0}/{1}'.format(address[0], to_text(to_masklen(address[1])))
-
- obj = {
- 'name': item,
- 'ipv4': ipv4,
- 'ipv6': parse_config_argument(configobj, item, 'ipv6 address'),
- 'state': 'present'
- }
- instances.append(obj)
-
- return instances
-
-
-def map_params_to_obj(module):
- obj = []
-
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- validate_param_values(module, item, item)
- obj.append(item.copy())
- else:
- obj.append({
- 'name': module.params['name'],
- 'ipv4': module.params['ipv4'],
- 'ipv6': module.params['ipv6'],
- 'state': module.params['state']
- })
-
- validate_param_values(module, obj)
-
- return obj
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- name=dict(),
- ipv4=dict(),
- ipv6=dict(),
- state=dict(default='present',
- choices=['present', 'absent'])
- )
-
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['name'] = dict(required=True)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- required_one_of = [['name', 'aggregate']]
- mutually_exclusive = [['name', 'aggregate']]
- module = AnsibleModule(argument_spec=argument_spec,
- required_one_of=required_one_of,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- warnings = list()
-
- result = {'changed': False}
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands((want, have), module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- resp = load_config(module, commands)
- warnings.extend((out for out in resp if out))
-
- result['changed'] = True
-
- if warnings:
- result['warnings'] = warnings
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/_ios_vlan.py b/lib/ansible/modules/network/ios/_ios_vlan.py
deleted file mode 100644
index d2b3dcf043..0000000000
--- a/lib/ansible/modules/network/ios/_ios_vlan.py
+++ /dev/null
@@ -1,350 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['deprecated'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_vlan
-version_added: "2.5"
-author: "Trishna Guha (@trishnaguha)"
-short_description: Manage VLANs on IOS network devices
-description:
- - This module provides declarative management of VLANs
- on Cisco IOS network devices.
-deprecated:
- removed_in: '2.13'
- alternative: ios_vlans
- why: Newer and updated modules released with more functionality in Ansible 2.9
-notes:
- - Tested against IOS 15.2
-options:
- name:
- description:
- - Name of the VLAN.
- vlan_id:
- description:
- - ID of the VLAN. Range 1-4094.
- required: true
- interfaces:
- description:
- - List of interfaces that should be associated to the VLAN.
- required: true
- associated_interfaces:
- description:
- - This is a intent option and checks the operational state of the for given vlan C(name)
- for associated interfaces. If the value in the C(associated_interfaces) does not match with
- the operational state of vlan interfaces on device it will result in failure.
- version_added: "2.5"
- delay:
- description:
- - Delay the play should wait to check for declarative intent params values.
- default: 10
- aggregate:
- description: List of VLANs definitions.
- purge:
- description:
- - Purge VLANs not defined in the I(aggregate) parameter.
- default: no
- type: bool
- state:
- description:
- - State of the VLAN configuration.
- default: present
- choices: ['present', 'absent', 'active', 'suspend']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: Create vlan
- ios_vlan:
- vlan_id: 100
- name: test-vlan
- state: present
-
-- name: Add interfaces to VLAN
- ios_vlan:
- vlan_id: 100
- interfaces:
- - GigabitEthernet0/0
- - GigabitEthernet0/1
-
-- name: Check if interfaces is assigned to VLAN
- ios_vlan:
- vlan_id: 100
- associated_interfaces:
- - GigabitEthernet0/0
- - GigabitEthernet0/1
-
-- name: Delete vlan
- ios_vlan:
- vlan_id: 100
- state: absent
-
-- name: Add vlan using aggregate
- ios_vlan:
- aggregate:
- - { vlan_id: 100, name: test-vlan, interfaces: [GigabitEthernet0/1, GigabitEthernet0/2], delay: 15, state: suspend }
- - { vlan_id: 101, name: test-vlan, interfaces: GigabitEthernet0/3 }
-
-- name: Move interfaces to a different VLAN
- ios_vlan:
- vlan_id: 102
- interfaces:
- - GigabitEthernet0/0
- - GigabitEthernet0/1
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - vlan 100
- - name test-vlan
-"""
-
-import re
-import time
-
-from copy import deepcopy
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import remove_default_spec
-from ansible.module_utils.network.ios.ios import load_config, run_commands, normalize_interface
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def search_obj_in_list(vlan_id, lst):
- for o in lst:
- if o['vlan_id'] == vlan_id:
- return o
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
- want, have = updates
- purge = module.params['purge']
-
- for w in want:
- vlan_id = w['vlan_id']
- name = w['name']
- interfaces = w['interfaces']
- state = w['state']
-
- obj_in_have = search_obj_in_list(vlan_id, have)
-
- if state == 'absent':
- if obj_in_have:
- commands.append('no vlan {0}'.format(vlan_id))
-
- elif state == 'present':
- if not obj_in_have:
- commands.append('vlan {0}'.format(vlan_id))
- if name:
- commands.append('name {0}'.format(name))
-
- if interfaces:
- for i in interfaces:
- commands.append('interface {0}'.format(i))
- commands.append('switchport mode access')
- commands.append('switchport access vlan {0}'.format(vlan_id))
-
- else:
- if name:
- if name != obj_in_have['name']:
- commands.append('vlan {0}'.format(vlan_id))
- commands.append('name {0}'.format(name))
-
- if interfaces:
- if not obj_in_have['interfaces']:
- for i in interfaces:
- commands.append('vlan {0}'.format(vlan_id))
- commands.append('interface {0}'.format(i))
- commands.append('switchport mode access')
- commands.append('switchport access vlan {0}'.format(vlan_id))
-
- elif set(interfaces) != set(obj_in_have['interfaces']):
- missing_interfaces = list(set(interfaces) - set(obj_in_have['interfaces']))
- for i in missing_interfaces:
- commands.append('vlan {0}'.format(vlan_id))
- commands.append('interface {0}'.format(i))
- commands.append('switchport mode access')
- commands.append('switchport access vlan {0}'.format(vlan_id))
-
- superfluous_interfaces = list(set(obj_in_have['interfaces']) - set(interfaces))
- for i in superfluous_interfaces:
- commands.append('vlan {0}'.format(vlan_id))
- commands.append('interface {0}'.format(i))
- commands.append('switchport mode access')
- commands.append('no switchport access vlan {0}'.format(vlan_id))
- else:
- commands.append('vlan {0}'.format(vlan_id))
- if name:
- commands.append('name {0}'.format(name))
- commands.append('state {0}'.format(state))
-
- if purge:
- for h in have:
- obj_in_want = search_obj_in_list(h['vlan_id'], want)
- if not obj_in_want and h['vlan_id'] != '1':
- commands.append('no vlan {0}'.format(h['vlan_id']))
-
- return commands
-
-
-def map_params_to_obj(module):
- obj = []
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- d = item.copy()
- d['vlan_id'] = str(d['vlan_id'])
-
- obj.append(d)
- else:
- obj.append({
- 'vlan_id': str(module.params['vlan_id']),
- 'name': module.params['name'],
- 'interfaces': module.params['interfaces'],
- 'associated_interfaces': module.params['associated_interfaces'],
- 'state': module.params['state']
- })
-
- return obj
-
-
-def parse_to_logical_rows(out):
- started_yielding = False
- cur_row = []
- for l in out.splitlines()[2:]:
- if not l:
- """Skip empty lines."""
- continue
- if '0' < l[0] <= '9':
- """Line starting with a number."""
- if started_yielding:
- yield cur_row
- cur_row = [] # Reset it to hold a next chunk
- started_yielding = True
- cur_row.append(l)
-
- # Return the rest of it:
- yield cur_row
-
-
-def map_ports_str_to_list(ports_str):
- return list(filter(bool, (normalize_interface(p.strip()) for p in ports_str.split(', '))))
-
-
-def parse_to_obj(logical_rows):
- first_row = logical_rows[0]
- rest_rows = logical_rows[1:]
- obj = re.match(r'(?P<vlan_id>\d+)\s+(?P<name>[^\s]+)\s+(?P<state>[^\s]+)\s*(?P<interfaces>.*)', first_row).groupdict()
- if obj['state'] == 'suspended':
- obj['state'] = 'suspend'
- obj['interfaces'] = map_ports_str_to_list(obj['interfaces'])
- obj['interfaces'].extend(prts_r for prts in rest_rows for prts_r in map_ports_str_to_list(prts))
- return obj
-
-
-def parse_vlan_brief(vlan_out):
- return [parse_to_obj(r) for r in parse_to_logical_rows(vlan_out)]
-
-
-def map_config_to_obj(module):
- return parse_vlan_brief(run_commands(module, ['show vlan brief'])[0])
-
-
-def check_declarative_intent_params(want, module, result):
-
- have = None
- is_delay = False
-
- for w in want:
- if w.get('associated_interfaces') is None:
- continue
-
- if result['changed'] and not is_delay:
- time.sleep(module.params['delay'])
- is_delay = True
-
- if have is None:
- have = map_config_to_obj(module)
-
- for i in w['associated_interfaces']:
- obj_in_have = search_obj_in_list(w['vlan_id'], have)
- if obj_in_have and 'interfaces' in obj_in_have and i not in obj_in_have['interfaces']:
- module.fail_json(msg="Interface %s not configured on vlan %s" % (i, w['vlan_id']))
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- vlan_id=dict(type='int'),
- name=dict(),
- interfaces=dict(type='list'),
- associated_interfaces=dict(type='list'),
- delay=dict(default=10, type='int'),
- state=dict(default='present',
- choices=['present', 'absent', 'active', 'suspend'])
- )
-
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['vlan_id'] = dict(required=True)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- purge=dict(default=False, type='bool')
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- required_one_of = [['vlan_id', 'aggregate']]
- mutually_exclusive = [['vlan_id', 'aggregate']]
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_one_of=required_one_of,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
- warnings = list()
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
- commands = map_obj_to_commands((want, have), module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- check_declarative_intent_params(want, module, result)
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_acl_interfaces.py b/lib/ansible/modules/network/ios/ios_acl_interfaces.py
deleted file mode 100644
index 7286ac45a8..0000000000
--- a/lib/ansible/modules/network/ios/ios_acl_interfaces.py
+++ /dev/null
@@ -1,633 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_acl_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_acl_interfaces
-version_added: '2.10'
-short_description: Configure and manage access-control (ACL) attributes of interfaces on IOS devices.
-description: This module configures and manages the access-control (ACL) attributes of interfaces on IOS platforms.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of ACL interfaces options
- type: list
- elements: dict
- suboptions:
- name:
- description: Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
- type: str
- required: True
- access_groups:
- description: Specify access-group for IP access list (standard or extended).
- type: list
- elements: dict
- suboptions:
- afi:
- description: Specifies the AFI for the ACLs to be configured on this interface.
- type: str
- required: True
- choices:
- - ipv4
- - ipv6
- acls:
- description: Specifies the ACLs for the provided AFI.
- type: list
- elements: dict
- suboptions:
- name:
- description: Specifies the name of the IPv4/IPv4 ACL for the interface.
- type: str
- required: True
- direction:
- description:
- - Specifies the direction of packets that the ACL will be applied on.
- - With one direction already assigned, other acl direction cannot be same.
- type: str
- required: True
- choices:
- - in
- - out
- running_config:
- description:
- - The module, by default, will connect to the remote device and retrieve the current
- running-config to use as a base for comparing against the contents of source.
- There are times when it is not desirable to have the task get the current running-config
- for every task in a playbook. The I(running_config) argument allows the implementer to
- pass in the configuration to use as the base config for comparison. This value of this
- option should be the output received from device by executing command.
- type: str
- state:
- description:
- - The state the configuration should be left in
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- - gathered
- - parsed
- - rendered
- default: merged
-"""
-
-EXAMPLES = """
----
-
-# Using Merged
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# interface GigabitEthernet0/2
-# ip access-group 123 out
-
-- name: "Merge module attributes of given access-groups"
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- access_groups:
- - afi: ipv4
- acls:
- - name: 110
- direction: in
- - name: 123
- direction: out
- - afi: ipv6
- acls:
- - name: test_v6
- direction: out
- - name: temp_v6
- direction: in
- - name: GigabitEthernet0/2
- access_groups:
- - afi: ipv4
- acls:
- - name: 100
- direction: in
- state: merged
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 100 in
-# ip access-group 123 out
-
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-# Using Replaced
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: "Replace module attributes of given access-groups"
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- access_groups:
- - afi: ipv4
- acls:
- - name: 100
- direction: out
- - name: 110
- direction: in
- state: replaced
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# no ip access-group 123 out
-# no ipv6 traffic-filter temp_v6 in
-# no ipv6 traffic-filter test_v6 out
-# ip access-group 100 out
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 100 out
-# ip access-group 110 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-# Using Overridden
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: "Overridden module attributes of given access-groups"
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- access_groups:
- - afi: ipv4
- acls:
- - name: 100
- direction: out
- - name: 110
- direction: in
- state: overridden
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# no ip access-group 123 out
-# no ipv6 traffic-filter test_v6 out
-# no ipv6 traffic-filter temp_v6 in
-# ip access-group 100 out
-# interface GigabitEthernet0/2
-# no ip access-group 110 in
-# no ip access-group 123 out
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 100 out
-# ip access-group 110 in
-# interface GigabitEthernet0/2
-
-# Using Deleted
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: "Delete module attributes of given Interface"
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- state: deleted
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# no ip access-group 110 in
-# no ip access-group 123 out
-# no ipv6 traffic-filter test_v6 out
-# no ipv6 traffic-filter temp_v6 in
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: "Delete module attributes of given Interface based on AFI"
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- access_groups:
- - afi: ipv4
- state: deleted
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# no ip access-group 110 in
-# no ip access-group 123 out
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-# Using DELETED without any config passed
-#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: "Delete module attributes of given access-groups from ALL Interfaces"
- ios_acl_interfaces:
- config:
- state: deleted
-
-# Commands Fired:
-# ---------------
-#
-# interface GigabitEthernet0/1
-# no ip access-group 110 in
-# no ip access-group 123 out
-# no ipv6 traffic-filter test_v6 out
-# no ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# no ip access-group 110 out
-# no ip access-group 123 out
-
-# After state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# interface GigabitEthernet0/2
-
-# Using Gathered
-
-# Before state:
-# -------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-- name: Gather listed acl interfaces with provided configurations
- ios_acl_interfaces:
- config:
- state: gathered
-
-# Module Execution Result:
-# ------------------------
-#
-# "gathered": [
-# {
-# "name": "Loopback888"
-# },
-# {
-# "name": "GigabitEthernet0/0"
-# },
-# {
-# "access_groups": [
-# {
-# "acls": [
-# {
-# "direction": "in",
-# "name": "110"
-# },
-# {
-# "direction": "out",
-# "name": "123"
-# }
-# ],
-# "afi": "ipv4"
-# },
-# {
-# "acls": [
-# {
-# "direction": "in",
-# "name": "temp_v6"
-# },
-# {
-# "direction": "out",
-# "name": "test_v6"
-# }
-# ],
-# "afi": "ipv6"
-# }
-# ],
-# "name": "GigabitEthernet0/1"
-# },
-# {
-# "access_groups": [
-# {
-# "acls": [
-# {
-# "direction": "in",
-# "name": "100"
-# },
-# {
-# "direction": "out",
-# "name": "123"
-# }
-# ],
-# "afi": "ipv4"
-# }
-# ],
-# "name": "GigabitEthernet0/2"
-# }
-# ]
-
-# After state:
-# ------------
-#
-# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
-# interface Loopback888
-# interface GigabitEthernet0/0
-# interface GigabitEthernet0/1
-# ip access-group 110 in
-# ip access-group 123 out
-# ipv6 traffic-filter test_v6 out
-# ipv6 traffic-filter temp_v6 in
-# interface GigabitEthernet0/2
-# ip access-group 110 in
-# ip access-group 123 out
-
-# Using Rendered
-
-- name: Render the commands for provided configuration
- ios_acl_interfaces:
- config:
- - name: GigabitEthernet0/1
- access_groups:
- - afi: ipv4
- acls:
- - name: 110
- direction: in
- - name: 123
- direction: out
- - afi: ipv6
- acls:
- - name: test_v6
- direction: out
- - name: temp_v6
- direction: in
- state: rendered
-
-# Module Execution Result:
-# ------------------------
-#
-# "rendered": [
-# "interface GigabitEthernet0/1",
-# "ip access-group 110 in",
-# "ip access-group 123 out",
-# "ipv6 traffic-filter temp_v6 in",
-# "ipv6 traffic-filter test_v6 out"
-# ]
-
-# Using Parsed
-
-- name: Parse the commands for provided configuration
- ios_acl_interfaces:
- running_config:
- "interface GigabitEthernet0/1
- ip access-group 110 in
- ip access-group 123 out
- ipv6 traffic-filter temp_v6 in
- ipv6 traffic-filter test_v6 out"
- state: parsed
-
-# Module Execution Result:
-# ------------------------
-#
-# "parsed": [
-# {
-# "access_groups": [
-# {
-# "acls": [
-# {
-# "direction": "in",
-# "name": "110"
-# }
-# ],
-# "afi": "ipv4"
-# },
-# {
-# "acls": [
-# {
-# "direction": "in",
-# "name": "temp_v6"
-# }
-# ],
-# "afi": "ipv6"
-# }
-# ],
-# "name": "GigabitEthernet0/1"
-# }
-# ]
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['interface GigabitEthernet0/1', 'ip access-group 110 in', 'ipv6 traffic-filter test_v6 out']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import Acl_InterfacesArgs
-from ansible.module_utils.network.ios.config.acl_interfaces.acl_interfaces import Acl_Interfaces
-
-
-def main():
- """
- Main entry point for module execution
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',)),
- ('state', 'rendered', ('config',)),
- ('state', 'parsed', ('running_config',))]
-
- mutually_exclusive = [('config', 'running_config')]
-
- module = AnsibleModule(argument_spec=Acl_InterfacesArgs.argument_spec,
- required_if=required_if,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- result = Acl_Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_acls.py b/lib/ansible/modules/network/ios/ios_acls.py
deleted file mode 100644
index a05214d8e1..0000000000
--- a/lib/ansible/modules/network/ios/ios_acls.py
+++ /dev/null
@@ -1,1417 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_acls
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_acls
-version_added: '2.10'
-short_description: Manages named or numbered ACLs on IOS devices.
-description: This module configures and manages the named or numbered ACLs on IOS platforms.
-author: Sumit Jaiswal (@justjais)
-notes:
-- Tested against Cisco IOSv Version 15.2 on VIRL
-- This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of ACL options.
- type: list
- elements: dict
- suboptions:
- afi:
- description:
- - The Address Family Indicator (AFI) for the Access Control Lists (ACL).
- required: true
- type: str
- choices:
- - ipv4
- - ipv6
- acls:
- description:
- - A list of Access Control Lists (ACL).
- type: list
- elements: dict
- suboptions:
- name:
- description: The name or the number of the ACL.
- required: true
- type: str
- acl_type:
- description:
- - ACL type
- - Note, it's mandatory and required for Named ACL, but for
- Numbered ACL it's not mandatory.
- type: str
- choices:
- - extended
- - standard
- aces:
- description: The entries within the ACL.
- elements: dict
- type: list
- suboptions:
- grant:
- description: Specify the action.
- type: str
- choices:
- - permit
- - deny
- sequence:
- description:
- - Sequence Number for the Access Control Entry(ACE).
- - Refer to vendor documentation for valid values.
- type: int
- protocol:
- description:
- - Specify the protocol to match.
- - Refer to vendor documentation for valid values.
- type: str
- protocol_options:
- description: protocol type.
- type: dict
- suboptions:
- protocol_number:
- description: An IP protocol number
- type: int
- ahp:
- description: Authentication Header Protocol.
- type: bool
- eigrp:
- description: Cisco's EIGRP routing protocol.
- type: bool
- esp:
- description: Encapsulation Security Payload.
- type: bool
- gre:
- description: Cisco's GRE tunneling.
- type: bool
- hbh:
- description: Hop by Hop options header. Valid for IPV6
- type: bool
- icmp:
- description: Internet Control Message Protocol.
- type: dict
- suboptions:
- administratively_prohibited:
- description: Administratively prohibited
- type: bool
- alternate_address:
- description: Alternate address
- type: bool
- conversion_error:
- description: Datagram conversion
- type: bool
- dod_host_prohibited:
- description: Host prohibited
- type: bool
- dod_net_prohibited:
- description: Net prohibited
- type: bool
- echo:
- description: Echo (ping)
- type: bool
- echo_reply:
- description: Echo reply
- type: bool
- general_parameter_problem:
- description: Parameter problem
- type: bool
- host_isolated:
- description: Host isolated
- type: bool
- host_precedence_unreachable:
- description: Host unreachable for precedence
- type: bool
- host_redirect:
- description: Host redirect
- type: bool
- host_tos_redirect:
- description: Host redirect for TOS
- type: bool
- host_tos_unreachable:
- description: Host unreachable for TOS
- type: bool
- host_unknown:
- description: Host unknown
- type: bool
- host_unreachable:
- description: Host unreachable
- type: bool
- information_reply:
- description: Information replies
- type: bool
- information_request:
- description: Information requests
- type: bool
- mask_reply:
- description: Mask replies
- type: bool
- mask_request:
- description: mask_request
- type: bool
- mobile_redirect:
- description: Mobile host redirect
- type: bool
- net_redirect:
- description: Network redirect
- type: bool
- net_tos_redirect:
- description: Net redirect for TOS
- type: bool
- net_tos_unreachable:
- description: Network unreachable for TOS
- type: bool
- net_unreachable:
- description: Net unreachable
- type: bool
- network_unknown:
- description: Network unknown
- type: bool
- no_room_for_option:
- description: Parameter required but no room
- type: bool
- option_missing:
- description: Parameter required but not present
- type: bool
- packet_too_big:
- description: Fragmentation needed and DF set
- type: bool
- parameter_problem:
- description: All parameter problems
- type: bool
- port_unreachable:
- description: Port unreachable
- type: bool
- precedence_unreachable:
- description: Precedence cutoff
- type: bool
- protocol_unreachable:
- description: Protocol unreachable
- type: bool
- reassembly_timeout:
- description: Reassembly timeout
- type: bool
- redirect:
- description: All redirects
- type: bool
- router_advertisement:
- description: Router discovery advertisements
- type: bool
- router_solicitation:
- description: Router discovery solicitations
- type: bool
- source_quench:
- description: Source quenches
- type: bool
- source_route_failed:
- description: Source route failed
- type: bool
- time_exceeded:
- description: All time exceededs
- type: bool
- timestamp_reply:
- description: Timestamp replies
- type: bool
- timestamp_request:
- description: Timestamp requests
- type: bool
- traceroute:
- description: Traceroute
- type: bool
- ttl_exceeded:
- description: TTL exceeded
- type: bool
- unreachable:
- description: All unreachables
- type: bool
- igmp:
- description: Internet Gateway Message Protocol.
- type: dict
- suboptions:
- dvmrp:
- description: Distance Vector Multicast Routing Protocol(2)
- type: bool
- host_query:
- description: IGMP Membership Query(0)
- type: bool
- mtrace_resp:
- description: Multicast Traceroute Response(7)
- type: bool
- mtrace_route:
- description: Multicast Traceroute(8)
- type: bool
- pim:
- description: Protocol Independent Multicast(3)
- type: bool
- trace:
- description: Multicast trace(4)
- type: bool
- v1host_report:
- description: IGMPv1 Membership Report(1)
- type: bool
- v2host_report:
- description: IGMPv2 Membership Report(5)
- type: bool
- v2leave_group:
- description: IGMPv2 Leave Group(6)
- type: bool
- v3host_report:
- description: IGMPv3 Membership Report(9)
- type: bool
- ip:
- description: Any Internet Protocol.
- type: bool
- ipv6:
- description: Any IPv6.
- type: bool
- ipinip:
- description: IP in IP tunneling.
- type: bool
- nos:
- description: KA9Q NOS compatible IP over IP tunneling.
- type: bool
- ospf:
- description: OSPF routing protocol.
- type: bool
- pcp:
- description: Payload Compression Protocol.
- type: bool
- pim:
- description: Protocol Independent Multicast.
- type: bool
- sctp:
- description: Stream Control Transmission Protocol.
- type: bool
- udp:
- description: User Datagram Protocol.
- type: bool
- tcp:
- description: Match TCP packet flags
- type: dict
- suboptions:
- ack:
- description: Match on the ACK bit
- type: bool
- established:
- description: Match established connections
- type: bool
- fin:
- description: Match on the FIN bit
- type: bool
- psh:
- description: Match on the PSH bit
- type: bool
- rst:
- description: Match on the RST bit
- type: bool
- syn:
- description: Match on the SYN bit
- type: bool
- urg:
- description: Match on the URG bit
- type: bool
- source:
- description: Specify the packet source.
- type: dict
- suboptions:
- address:
- description: Source network address.
- type: str
- wildcard_bits:
- description: Destination wildcard bits, valid with IPV4 address.
- type: str
- any:
- description: Match any source address.
- type: bool
- host:
- description: A single source host
- type: str
- port_protocol:
- description:
- - Specify the destination port along with protocol.
- - Note, Valid with TCP/UDP protocol_options
- type: dict
- suboptions:
- eq:
- description: Match only packets on a given port number.
- type: str
- gt:
- description: Match only packets with a greater port number.
- type: str
- lt:
- description: Match only packets with a lower port number.
- type: str
- neq:
- description: Match only packets not on a given port number.
- type: str
- range:
- description: Port group.
- type: dict
- suboptions:
- start:
- description: Specify the start of the port range.
- type: int
- end:
- description: Specify the end of the port range.
- type: int
- destination:
- description: Specify the packet destination.
- type: dict
- suboptions:
- address:
- description: Host address to match, or any single host address.
- type: str
- wildcard_bits:
- description: Destination wildcard bits, valid with IPV4 address.
- type: str
- any:
- description: Match any source address.
- type: bool
- host:
- description: A single destination host
- type: str
- port_protocol:
- description:
- - Specify the destination port along with protocol.
- - Note, Valid with TCP/UDP protocol_options
- type: dict
- suboptions:
- eq:
- description: Match only packets on a given port number.
- type: str
- gt:
- description: Match only packets with a greater port number.
- type: str
- lt:
- description: Match only packets with a lower port number.
- type: str
- neq:
- description: Match only packets not on a given port number.
- type: str
- range:
- description: Port group.
- type: dict
- suboptions:
- start:
- description: Specify the start of the port range.
- type: int
- end:
- description: Specify the end of the port range.
- type: int
- dscp:
- description: Match packets with given dscp value.
- type: str
- fragments:
- description: Check non-initial fragments.
- type: str
- log:
- description: Log matches against this entry.
- type: str
- log_input:
- description: Log matches against this entry, including input interface.
- type: str
- option:
- description:
- - Match packets with given IP Options value.
- - Valid only for named acls.
- type: dict
- suboptions:
- add_ext:
- description: Match packets with Address Extension Option (147).
- type: bool
- any_options:
- description: Match packets with ANY Option.
- type: bool
- com_security:
- description: Match packets with Commercial Security Option (134).
- type: bool
- dps:
- description: Match packets with Dynamic Packet State Option (151).
- type: bool
- encode:
- description: Match packets with Encode Option (15).
- type: bool
- eool:
- description: Match packets with End of Options (0).
- type: bool
- ext_ip:
- description: Match packets with Extended IP Option (145).
- type: bool
- ext_security:
- description: Match packets with Extended Security Option (133).
- type: bool
- finn:
- description: Match packets with Experimental Flow Control Option (205).
- type: bool
- imitd:
- description: Match packets with IMI Traffic Desriptor Option (144).
- type: bool
- lsr:
- description: Match packets with Loose Source Route Option (131).
- type: bool
- mtup:
- description: Match packets with MTU Probe Option (11).
- type: bool
- mtur:
- description: Match packets with MTU Reply Option (12).
- type: bool
- no_op:
- description: Match packets with No Operation Option (1).
- type: bool
- nsapa:
- description: Match packets with NSAP Addresses Option (150).
- type: bool
- record_route:
- description: Match packets with Record Route Option (7).
- type: bool
- router_alert:
- description: Match packets with Router Alert Option (148).
- type: bool
- sdb:
- description: Match packets with Selective Directed Broadcast Option (149).
- type: bool
- security:
- description: Match packets with Basic Security Option (130).
- type: bool
- ssr:
- description: Match packets with Strict Source Routing Option (137).
- type: bool
- stream_id:
- description: Match packets with Stream ID Option (136).
- type: bool
- timestamp:
- description: Match packets with Time Stamp Option (68).
- type: bool
- traceroute:
- description: Match packets with Trace Route Option (82).
- type: bool
- ump:
- description: Match packets with Upstream Multicast Packet Option (152).
- type: bool
- visa:
- description: Match packets with Experimental Access Control Option (142).
- type: bool
- zsu:
- description: Match packets with Experimental Measurement Option (10).
- type: bool
- precedence:
- description: Match packets with given precedence value.
- type: int
- time_range:
- description: Specify a time-range.
- type: str
- tos:
- description:
- - Match packets with given TOS value.
- - Note, DSCP and TOS are mutually exclusive
- type: dict
- suboptions:
- service_value:
- description: Type of service value
- type: int
- max_reliability:
- description: Match packets with max reliable TOS (2).
- type: bool
- max_throughput:
- description: Match packets with max throughput TOS (4).
- type: bool
- min_delay :
- description: Match packets with min delay TOS (8).
- type: bool
- min_monetary_cost:
- description: Match packets with min monetary cost TOS (1).
- type: bool
- normal:
- description: Match packets with normal TOS (0).
- type: bool
- ttl:
- description: Match packets with given TTL value.
- type: dict
- suboptions:
- eq:
- description: Match only packets on a given TTL number.
- type: int
- gt:
- description: Match only packets with a greater TTL number.
- type: int
- lt:
- description: Match only packets with a lower TTL number.
- type: int
- neq:
- description: Match only packets not on a given TTL number.
- type: int
- range:
- description: Match only packets in the range of TTLs.
- type: dict
- suboptions:
- start:
- description: Specify the start of the port range.
- type: int
- end:
- description: Specify the end of the port range.
- type: int
- running_config:
- description:
- - The module, by default, will connect to the remote device and
- retrieve the current running-config to use as a base for comparing
- against the contents of source. There are times when it is not
- desirable to have the task get the current running-config for
- every task in a playbook. The I(running_config) argument allows the
- implementer to pass in the configuration to use as the base
- config for comparison.
- type: str
- state:
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- - gathered
- - rendered
- - parsed
- default: merged
- description:
- - The state of the configuration after module completion
- type: str
-"""
-
-EXAMPLES = """
----
-
-# Using merged
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10
-
-- name: Merge provided configuration with device configuration
- ios_acl:
- config:
- - afi: ipv4
- acls:
- - name: std_acl
- acl_type: standard
- aces:
- - grant: deny
- source:
- address: 192.168.1.200
- - grant: deny
- source:
- address: 192.168.2.0
- wildcard_bits: 0.0.0.255
- - name: 110
- aces:
- - grant: deny
- sequence: 10
- protocol_options:
- icmp:
- traceroute: true
- source:
- address: 192.0.2.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 192.0.3.0
- wildcard_bits: 0.0.0.255
- dscp: ef
- ttl:
- eq: 10
- - grant: deny
- protocol_options:
- tcp:
- ack: true
- source:
- host: 198.51.100.0
- destination:
- host: 198.51.110.0
- port_protocol:
- eq: telnet
- - name: test
- acl_type: extended
- aces:
- - grant: deny
- protocol_options:
- tcp:
- fin: true
- source:
- address: 192.0.2.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 192.0.3.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: www
- option:
- traceroute: true
- ttl:
- eq: 10
- - name: 123
- aces:
- - grant: deny
- protocol_options:
- tcp:
- ack: true
- source:
- address: 198.51.100.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 198.51.101.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- tos:
- service_value: 12
- - grant: deny
- protocol_options:
- tcp:
- ack: true
- source:
- address: 192.0.3.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 192.0.4.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: www
- dscp: ef
- ttl:
- lt: 20
- - afi: ipv6
- acls:
- - name: R1_TRAFFIC
- aces:
- - grant: deny
- protocol_options:
- tcp:
- ack: true
- source:
- any: true
- port_protocol:
- eq: www
- destination:
- any: true
- port_protocol:
- eq: telnet
- dscp: af11
- state: merged
-
-# Commands fired:
-# ---------------
-#
-# - ip access-list standard std_acl
-# - deny 192.168.1.200
-# - deny 192.168.2.0 0.0.0.255
-# - ip access-list extended 110
-# - no 10
-# - 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# - deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# - ip access-list extended test
-# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# - ip access-list extended 123
-# - deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# - deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# - ipv6 access-list R1_TRAFFIC
-# - deny tcp any eq www any eq telnet ack dscp af11
-
-# After state:
-# ------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-
-# Using replaced
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-
-- name: Replaces device configuration of listed acls with provided configuration
- ios_acl:
- config:
- - afi: ipv4
- acls:
- - name: 110
- aces:
- - grant: deny
- protocol_options:
- tcp:
- syn: true
- source:
- address: 192.0.2.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 192.0.3.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: www
- dscp: ef
- ttl:
- eq: 10
- - name: 150
- aces:
- - grant: deny
- sequence: 20
- protocol_options:
- tcp:
- syn: true
- source:
- address: 198.51.100.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- destination:
- address: 198.51.110.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- dscp: ef
- ttl:
- eq: 10
- state: replaced
-
-# Commands fired:
-# ---------------
-#
-# - no ip access-list extended 110
-# - ip access-list extended 110
-# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
-# - ip access-list extended 150
-# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
-
-# After state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list 150
-# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-# Using overridden
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-- name: Override device configuration of all acls with provided configuration
- ios_acl:
- config:
- - afi: ipv4
- acls:
- - name: 110
- aces:
- - grant: deny
- sequence: 20
- protocol_options:
- tcp:
- ack: true
- source:
- address: 198.51.100.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- destination:
- address: 198.51.110.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: www
- dscp: ef
- ttl:
- eq: 10
- - name: 150
- aces:
- - grant: deny
- sequence: 10
- protocol_options:
- tcp:
- syn: true
- source:
- address: 198.51.100.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- destination:
- address: 198.51.110.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- dscp: ef
- ttl:
- eq: 10
- state: overridden
-
-# Commands fired:
-# ---------------
-#
-# - no ip access-list standard std_acl
-# - no ip access-list extended 110
-# - no ip access-list extended 123
-# - no ip access-list extended 150
-# - no ip access-list extended test
-# - no ipv6 access-list R1_TRAFFIC
-# - ip access-list extended 150
-# - 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
-# - ip access-list extended 110
-# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
-
-# After state:
-# -------------
-#
-# vios#sh access-lists
-# Extended IP access list 110
-# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
-# Extended IP access list 150
-# 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
-
-# Using Deleted
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-- name: "Delete module attributes of given acls (Note: This won't delete the interface itself)"
- ios_acl:
- config:
- - afi: ipv4
- acls:
- - name: test
- acl_type: extended
- - name: 110
- - name: 123
- aces:
- - sequence: 10
- - afi: ipv6
- acls:
- - name: R1_TRAFFIC
- state: deleted
-
-# Commands fired:
-# ---------------
-#
-# - no ip access-list extended test
-# - no ip access-list extended 110
-# - ip access-list extended 123
-# - no 10
-# - no ipv6 access-list R1_TRAFFIC
-
-# After state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 123
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-- name: "Delete module attributes of given ACL based on AFI (Note: This won't delete the interface itself)"
- ios_acl:
- config:
- - afi: ipv4
- state: deleted
-
-# Commands fired:
-# ---------------
-#
-# - no ip access-list standard std_acl
-# - no ip access-list extended test
-# - no ip access-list extended 110
-# - no ip access-list extended 123
-
-# After state:
-# -------------
-#
-# vios#sh access-lists
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-- name: "Delete module attributes of all acls (Note: This won't delete the interface itself)"
- ios_acl:
- state: deleted
-
-# Commands fired:
-# ---------------
-#
-# - no ip access-list extended test
-# - no ip access-list extended 110
-# - no ip access-list extended 123
-# - no ip access-list extended test
-# - no ipv6 access-list R1_TRAFFIC
-
-# After state:
-# -------------
-#
-# vios#sh access-lists
-
-# Using Gathered
-
-# Before state:
-# -------------
-#
-# vios#sh access-lists
-# Standard IP access list std_acl
-# 10 deny 192.168.1.200
-# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
-# Extended IP access list 110
-# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
-# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
-# Extended IP access list 123
-# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
-# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
-# Extended IP access list test
-# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
-# IPv6 access list R1_TRAFFIC
-# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
-
-- name: Gather listed acls interfaces with provided configurations
- ios_acl_interfaces:
- config:
- state: gathered
-
-# Module Execution Result:
-# ------------------------
-#
-# "gathered": [
-# {
-# "acls": [
-# {
-# "aces": [
-# {
-# "destination": {
-# "address": "192.0.3.0",
-# "wildcard_bits": "0.0.0.255"
-# },
-# "dscp": "ef",
-# "grant": "deny",
-# "protocol_options": {
-# "icmp": {
-# "echo": true
-# }
-# },
-# "sequence": 10,
-# "source": {
-# "address": "192.0.2.0",
-# "wildcard_bits": "0.0.0.255"
-# },
-# "ttl": {
-# "eq": 10
-# }
-# }
-# ],
-# "acl_type": "extended",
-# "name": "110"
-# },
-# {
-# "aces": [
-# {
-# "destination": {
-# "address": "198.51.101.0",
-# "port_protocol": {
-# "eq": "telnet"
-# },
-# "wildcard_bits": "0.0.0.255"
-# },
-# "grant": "deny",
-# "protocol_options": {
-# "tcp": {
-# "ack": true
-# }
-# },
-# "sequence": 10,
-# "source": {
-# "address": "198.51.100.0",
-# "wildcard_bits": "0.0.0.255"
-# },
-# "tos": {
-# "service_value": 12
-# }
-# },
-# {
-# "destination": {
-# "address": "192.0.4.0",
-# "port_protocol": {
-# "eq": "www"
-# },
-# "wildcard_bits": "0.0.0.255"
-# },
-# "dscp": "ef",
-# "grant": "deny",
-# "protocol_options": {
-# "tcp": {
-# "ack": true
-# }
-# },
-# "sequence": 20,
-# "source": {
-# "address": "192.0.3.0",
-# "wildcard_bits": "0.0.0.255"
-# },
-# "ttl": {
-# "lt": 20
-# }
-# }
-# ],
-# "acl_type": "extended",
-# "name": "123"
-# },
-# {
-# "aces": [
-# {
-# "destination": {
-# "address": "192.0.3.0",
-# "port_protocol": {
-# "eq": "www"
-# },
-# "wildcard_bits": "0.0.0.255"
-# },
-# "grant": "deny",
-# "option": {
-# "traceroute": true
-# },
-# "protocol_options": {
-# "tcp": {
-# "fin": true
-# }
-# },
-# "sequence": 10,
-# "source": {
-# "address": "192.0.2.0",
-# "wildcard_bits": "0.0.0.255"
-# },
-# "ttl": {
-# "eq": 10
-# }
-# }
-# ],
-# "acl_type": "extended",
-# "name": "test_acl"
-# }
-# ],
-# "afi": "ipv4"
-# },
-# {
-# "acls": [
-# {
-# "aces": [
-# {
-# "destination": {
-# "any": true,
-# "port_protocol": {
-# "eq": "telnet"
-# }
-# },
-# "dscp": "af11",
-# "grant": "deny",
-# "protocol_options": {
-# "tcp": {
-# "ack": true
-# }
-# },
-# "sequence": 10,
-# "source": {
-# "any": true,
-# "port_protocol": {
-# "eq": "www"
-# }
-# }
-# }
-# ],
-# "name": "R1_TRAFFIC"
-# }
-# ],
-# "afi": "ipv6"
-# }
-# ]
-
-# Using Rendered
-
-- name: Rendered the provided configuration with the exisiting running configuration
- ios_acl:
- config:
- - afi: ipv4
- acls:
- - name: 110
- aces:
- - grant: deny
- sequence: 10
- protocol_options:
- tcp:
- syn: true
- source:
- address: 192.0.2.0
- wildcard_bits: 0.0.0.255
- destination:
- address: 192.0.3.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: www
- dscp: ef
- ttl:
- eq: 10
- - name: 150
- aces:
- - grant: deny
- protocol_options:
- tcp:
- syn: true
- source:
- address: 198.51.100.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- destination:
- address: 198.51.110.0
- wildcard_bits: 0.0.0.255
- port_protocol:
- eq: telnet
- dscp: ef
- ttl:
- eq: 10
- state: rendered
-
-# Module Execution Result:
-# ------------------------
-#
-# "rendered": [
-# "ip access-list extended 110",
-# "10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10",
-# "ip access-list extended 150",
-# "deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10"
-# ]
-
-# Using Parsed
-
-- name: Parse the commands for provided configuration
- ios_acl:
- running_config:
- "ipv6 access-list R1_TRAFFIC
- deny tcp any eq www any eq telnet ack dscp af11"
- state: parsed
-
-# Module Execution Result:
-# ------------------------
-#
-# "parsed": [
-# {
-# "acls": [
-# {
-# "aces": [
-# {
-# "destination": {
-# "any": true,
-# "port_protocol": {
-# "eq": "telnet"
-# }
-# },
-# "dscp": "af11",
-# "grant": "deny",
-# "protocol_options": {
-# "tcp": {
-# "ack": true
-# }
-# },
-# "source": {
-# "any": true,
-# "port_protocol": {
-# "eq": "www"
-# }
-# }
-# }
-# ],
-# "name": "R1_TRAFFIC"
-# }
-# ],
-# "afi": "ipv6"
-# }
-# ]
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['ip access-list extended 110', 'deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.acls.acls import AclsArgs
-from ansible.module_utils.network.ios.config.acls.acls import Acls
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',)),
- ('state', 'rendered', ('config',)),
- ('state', 'parsed', ('running_config',))]
-
- mutually_exclusive = [('config', 'running_config')]
-
- module = AnsibleModule(argument_spec=AclsArgs.argument_spec,
- required_if=required_if,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- result = Acls(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_banner.py b/lib/ansible/modules/network/ios/ios_banner.py
deleted file mode 100644
index c28838407c..0000000000
--- a/lib/ansible/modules/network/ios/ios_banner.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_banner
-version_added: "2.3"
-author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
-short_description: Manage multiline banners on Cisco IOS devices
-description:
- - This will configure both login and motd banners on remote devices
- running Cisco IOS. It allows playbooks to add or remote
- banner text from the active running configuration.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- banner:
- description:
- - Specifies which banner should be configured on the remote device.
- In Ansible 2.4 and earlier only I(login) and I(motd) were supported.
- required: true
- choices: ['login', 'motd', 'exec', 'incoming', 'slip-ppp']
- text:
- description:
- - The banner text that should be
- present in the remote device running configuration. This argument
- accepts a multiline string, with no empty lines. Requires I(state=present).
- state:
- description:
- - Specifies whether or not the configuration is
- present in the current devices active running configuration.
- default: present
- choices: ['present', 'absent']
-"""
-
-EXAMPLES = """
-- name: configure the login banner
- ios_banner:
- banner: login
- text: |
- this is my login banner
- that contains a multiline
- string
- state: present
-
-- name: remove the motd banner
- ios_banner:
- banner: motd
- state: absent
-
-- name: Configure banner from file
- ios_banner:
- banner: motd
- text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}"
- state: present
-
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - banner login
- - this is my login banner
- - that contains a multiline
- - string
-"""
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from re import search, M
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
- want, have = updates
- state = module.params['state']
-
- if state == 'absent' and 'text' in have.keys() and have['text']:
- commands.append('no banner %s' % module.params['banner'])
-
- elif state == 'present':
- if want['text'] and (want['text'] != have.get('text')):
- banner_cmd = 'banner %s' % module.params['banner']
- banner_cmd += ' @\n'
- banner_cmd += want['text'].strip('\n')
- banner_cmd += '\n@'
- commands.append(banner_cmd)
-
- return commands
-
-
-def map_config_to_obj(module):
- """
- This function gets the banner config without stripping any whitespaces,
- and then fetches the required banner from it.
- :param module:
- :return: banner config dict object.
- """
- out = get_config(module, flags='| begin banner %s' % module.params['banner'])
- if out:
- regex = 'banner ' + module.params['banner'] + ' ^C\n'
- if search('banner ' + module.params['banner'], out, M):
- output = str((out.split(regex))[1].split("^C\n")[0])
- else:
- output = None
- else:
- output = None
- obj = {'banner': module.params['banner'], 'state': 'absent'}
- if output:
- obj['text'] = output
- obj['state'] = 'present'
- return obj
-
-
-def map_params_to_obj(module):
- text = module.params['text']
- return {
- 'banner': module.params['banner'],
- 'text': text,
- 'state': module.params['state']
- }
-
-
-def main():
- """ main entry point for module execution
- """
- argument_spec = dict(
- banner=dict(required=True, choices=['login', 'motd', 'exec', 'incoming', 'slip-ppp']),
- text=dict(),
- state=dict(default='present', choices=['present', 'absent'])
- )
-
- argument_spec.update(ios_argument_spec)
-
- required_if = [('state', 'present', ('text',))]
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- warnings = list()
-
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands((want, have), module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
-
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_bgp.py b/lib/ansible/modules/network/ios/ios_bgp.py
deleted file mode 100644
index 88fe29a12c..0000000000
--- a/lib/ansible/modules/network/ios/ios_bgp.py
+++ /dev/null
@@ -1,438 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_bgp
-version_added: "2.8"
-author: "Nilashish Chakraborty (@NilashishC)"
-short_description: Configure global BGP protocol settings on Cisco IOS.
-description:
- - This module provides configuration management of global BGP parameters
- on devices running Cisco IOS
-notes:
- - Tested against Cisco IOS Version 15.6(3)M2
-options:
- config:
- description:
- - Specifies the BGP related configuration.
- suboptions:
- bgp_as:
- description:
- - Specifies the BGP Autonomous System (AS) number to configure on the device.
- type: int
- required: true
- router_id:
- description:
- - Configures the BGP routing process router-id value.
- default: null
- log_neighbor_changes:
- description:
- - Enable/disable logging neighbor up/down and reset reason.
- type: bool
- neighbors:
- description:
- - Specifies BGP neighbor related configurations.
- suboptions:
- neighbor:
- description:
- - Neighbor router address.
- required: True
- remote_as:
- description:
- - Remote AS of the BGP neighbor to configure.
- type: int
- required: True
- update_source:
- description:
- - Source of the routing updates.
- password:
- description:
- - Password to authenticate the BGP peer connection.
- enabled:
- description:
- - Administratively shutdown or enable a neighbor.
- type: bool
- description:
- description:
- - Neighbor specific description.
- ebgp_multihop:
- description:
- - Specifies the maximum hop count for EBGP neighbors not on directly connected networks.
- - The range is from 1 to 255.
- type: int
- peer_group:
- description:
- - Name of the peer group that the neighbor is a member of.
- timers:
- description:
- - Specifies BGP neighbor timer related configurations.
- suboptions:
- keepalive:
- description:
- - Frequency (in seconds) with which the device sends keepalive messages to its peer.
- - The range is from 0 to 65535.
- type: int
- required: True
- holdtime:
- description:
- - Interval (in seconds) after not receiving a keepalive message that IOS declares a peer dead.
- - The range is from 0 to 65535.
- type: int
- required: True
- min_neighbor_holdtime:
- description:
- - Interval (in seconds) specifying the minimum acceptable hold-time from a BGP neighbor.
- - The minimum acceptable hold-time must be less than, or equal to, the interval specified in the holdtime argument.
- - The range is from 0 to 65535.
- type: int
- local_as:
- description:
- - The local AS number for the neighbor.
- type: int
- networks:
- description:
- - Specify Networks to announce via BGP.
- - For operation replace, this option is mutually exclusive with networks option under address_family.
- - For operation replace, if the device already has an address family activated, this option is not allowed.
- suboptions:
- prefix:
- description:
- - Network ID to announce via BGP.
- required: True
- masklen:
- description:
- - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
- route_map:
- description:
- - Route map to modify the attributes.
- address_family:
- description:
- - Specifies BGP address family related configurations.
- suboptions:
- afi:
- description:
- - Type of address family to configure.
- choices:
- - ipv4
- - ipv6
- required: True
- safi:
- description:
- - Specifies the type of cast for the address family.
- choices:
- - flowspec
- - unicast
- - multicast
- - labeled-unicast
- default: unicast
- synchronization:
- description:
- - Enable/disable IGP synchronization.
- type: bool
- auto_summary:
- description:
- - Enable/disable automatic network number summarization.
- type: bool
- redistribute:
- description:
- - Specifies the redistribute information from another routing protocol.
- suboptions:
- protocol:
- description:
- - Specifies the protocol for configuring redistribute information.
- choices: ['ospf', 'ospfv3', 'eigrp', 'isis', 'static', 'connected', 'odr', 'lisp', 'mobile', 'rip']
- required: True
- id:
- description:
- - Identifier for the routing protocol for configuring redistribute information.
- - Valid for protocols 'ospf', 'ospfv3' and 'eigrp'.
- metric:
- description:
- - Specifies the metric for redistributed routes.
- route_map:
- description:
- - Specifies the route map reference.
- networks:
- description:
- - Specify Networks to announce via BGP.
- - For operation replace, this option is mutually exclusive with root level networks option.
- suboptions:
- prefix:
- description:
- - Network ID to announce via BGP.
- required: True
- masklen:
- description:
- - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
- route_map:
- description:
- - Route map to modify the attributes.
- neighbors:
- description:
- - Specifies BGP neighbor related configurations in Address Family configuration mode.
- suboptions:
- neighbor:
- description:
- - Neighbor router address.
- required: True
- advertisement_interval:
- description:
- - Minimum interval between sending BGP routing updates for this neighbor.
- type: int
- route_reflector_client:
- description:
- - Specify a neighbor as a route reflector client.
- type: bool
- route_server_client:
- description:
- - Specify a neighbor as a route server client.
- type: bool
- activate:
- description:
- - Enable the Address Family for this Neighbor.
- type: bool
- remove_private_as:
- description:
- - Remove the private AS number from outbound updates.
- type: bool
- next_hop_self:
- description:
- - Enable/disable the next hop calculation for this neighbor.
- type: bool
- next_hop_unchanged:
- description:
- - Propagate next hop unchanged for iBGP paths to this neighbor.
- type: bool
- maximum_prefix:
- description:
- - Maximum number of prefixes to accept from this peer.
- - The range is from 1 to 2147483647.
- type: int
- prefix_list_in:
- description:
- - Name of ip prefix-list to apply to incoming prefixes.
- prefix_list_out:
- description:
- - Name of ip prefix-list to apply to outgoing prefixes.
- operation:
- description:
- - Specifies the operation to be performed on the BGP process configured on the device.
- - In case of merge, the input configuration will be merged with the existing BGP configuration on the device.
- - In case of replace, if there is a diff between the existing configuration and the input configuration, the
- existing configuration will be replaced by the input configuration for every option that has the diff.
- - In case of override, all the existing BGP configuration will be removed from the device and replaced with
- the input configuration.
- - In case of delete the existing BGP configuration will be removed from the device.
- default: merge
- choices: ['merge', 'replace', 'override', 'delete']
-"""
-
-EXAMPLES = """
-- name: configure global bgp as 64496
- ios_bgp:
- config:
- bgp_as: 64496
- router_id: 192.0.2.1
- log_neighbor_changes: True
- neighbors:
- - neighbor: 203.0.113.5
- remote_as: 64511
- timers:
- keepalive: 300
- holdtime: 360
- min_neighbor_holdtime: 360
- - neighbor: 198.51.100.2
- remote_as: 64498
- networks:
- - prefix: 198.51.100.0
- route_map: RMAP_1
- - prefix: 192.0.2.0
- masklen: 23
- address_family:
- - afi: ipv4
- safi: unicast
- redistribute:
- - protocol: ospf
- id: 223
- metric: 10
- operation: merge
-
-- name: Configure BGP neighbors
- ios_bgp:
- config:
- bgp_as: 64496
- neighbors:
- - neighbor: 192.0.2.10
- remote_as: 64496
- password: ansible
- description: IBGP_NBR_1
- ebgp_multihop: 100
- timers:
- keepalive: 300
- holdtime: 360
- min_neighbor_holdtime: 360
- - neighbor: 192.0.2.15
- remote_as: 64496
- description: IBGP_NBR_2
- ebgp_multihop: 150
- operation: merge
-
-- name: Configure root-level networks for BGP
- ios_bgp:
- config:
- bgp_as: 64496
- networks:
- - prefix: 203.0.113.0
- masklen: 27
- route_map: RMAP_1
- - prefix: 203.0.113.32
- masklen: 27
- route_map: RMAP_2
- operation: merge
-
-- name: Configure BGP neighbors under address family mode
- ios_bgp:
- config:
- bgp_as: 64496
- address_family:
- - afi: ipv4
- safi: unicast
- neighbors:
- - neighbor: 203.0.113.10
- activate: yes
- maximum_prefix: 250
- advertisement_interval: 120
- - neighbor: 192.0.2.15
- activate: yes
- route_reflector_client: True
- operation: merge
-
-- name: remove bgp as 64496 from config
- ios_bgp:
- config:
- bgp_as: 64496
- operation: delete
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - router bgp 64496
- - bgp router-id 192.0.2.1
- - bgp log-neighbor-changes
- - neighbor 203.0.113.5 remote-as 64511
- - neighbor 203.0.113.5 timers 300 360 360
- - neighbor 198.51.100.2 remote-as 64498
- - network 198.51.100.0 route-map RMAP_1
- - network 192.0.2.0 mask 255.255.254.0
- - address-family ipv4
- - redistribute ospf 223 metric 70
- - exit-address-family
-"""
-from ansible.module_utils._text import to_text
-from ansible.module_utils.network.ios.providers.module import NetworkModule
-from ansible.module_utils.network.ios.providers.cli.config.bgp.process import REDISTRIBUTE_PROTOCOLS
-
-
-def main():
- """ main entry point for module execution
- """
- network_spec = {
- 'prefix': dict(required=True),
- 'masklen': dict(type='int'),
- 'route_map': dict(),
- }
-
- redistribute_spec = {
- 'protocol': dict(choices=REDISTRIBUTE_PROTOCOLS, required=True),
- 'id': dict(),
- 'metric': dict(type='int'),
- 'route_map': dict(),
- }
-
- timer_spec = {
- 'keepalive': dict(type='int', required=True),
- 'holdtime': dict(type='int', required=True),
- 'min_neighbor_holdtime': dict(type='int'),
- }
-
- neighbor_spec = {
- 'neighbor': dict(required=True),
- 'remote_as': dict(type='int', required=True),
- 'local_as': dict(type='int'),
- 'update_source': dict(),
- 'password': dict(no_log=True),
- 'enabled': dict(type='bool'),
- 'description': dict(),
- 'ebgp_multihop': dict(type='int'),
- 'timers': dict(type='dict', options=timer_spec),
- 'peer_group': dict(),
- }
-
- af_neighbor_spec = {
- 'neighbor': dict(required=True),
- 'activate': dict(type='bool'),
- 'advertisement_interval': dict(type='int'),
- 'remove_private_as': dict(type='bool'),
- 'next_hop_self': dict(type='bool'),
- 'route_reflector_client': dict(type='bool'),
- 'route_server_client': dict(type='bool'),
- 'maximum_prefix': dict(type='int'),
- 'prefix_list_in': dict(),
- 'prefix_list_out': dict()
- }
-
- address_family_spec = {
- 'afi': dict(choices=['ipv4', 'ipv6'], required=True),
- 'safi': dict(choices=['flowspec', 'labeled-unicast', 'multicast', 'unicast'], default='unicast'),
- 'auto_summary': dict(type='bool'),
- 'synchronization': dict(type='bool'),
- 'networks': dict(type='list', elements='dict', options=network_spec),
- 'redistribute': dict(type='list', elements='dict', options=redistribute_spec),
- 'neighbors': dict(type='list', elements='dict', options=af_neighbor_spec),
- }
-
- config_spec = {
- 'bgp_as': dict(type='int', required=True),
- 'router_id': dict(),
- 'log_neighbor_changes': dict(type='bool'),
- 'neighbors': dict(type='list', elements='dict', options=neighbor_spec),
- 'address_family': dict(type='list', elements='dict', options=address_family_spec),
- 'networks': dict(type='list', elements='dict', options=network_spec)
- }
-
- argument_spec = {
- 'config': dict(type='dict', options=config_spec),
- 'operation': dict(default='merge', choices=['merge', 'replace', 'override', 'delete'])
- }
-
- module = NetworkModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- try:
- result = module.edit_config(config_filter='| section ^router bgp')
- except Exception as exc:
- module.fail_json(msg=to_text(exc))
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_command.py b/lib/ansible/modules/network/ios/ios_command.py
deleted file mode 100644
index 59ea254b2d..0000000000
--- a/lib/ansible/modules/network/ios/ios_command.py
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_command
-version_added: "2.1"
-author: "Peter Sprygada (@privateip)"
-short_description: Run commands on remote devices running Cisco IOS
-description:
- - Sends arbitrary commands to an ios node and returns the results
- read from the device. This module includes an
- argument that will cause the module to wait for a specific condition
- before returning or timing out if the condition is not met.
- - This module does not support running commands in configuration mode.
- Please use M(ios_config) to configure IOS devices.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- commands:
- description:
- - List of commands to send to the remote ios device over the
- configured provider. The resulting output from the command
- is returned. If the I(wait_for) argument is provided, the
- module is not returned until the condition is satisfied or
- the number of retries has expired. If a command sent to the
- device requires answering a prompt, it is possible to pass
- a dict containing I(command), I(answer) and I(prompt).
- Common answers are 'y' or "\\r" (carriage return, must be
- double quotes). See examples.
- required: true
- wait_for:
- description:
- - List of conditions to evaluate against the output of the
- command. The task will wait for each condition to be true
- before moving forward. If the conditional is not true
- within the configured number of retries, the task fails.
- See examples.
- aliases: ['waitfor']
- version_added: "2.2"
- match:
- description:
- - The I(match) argument is used in conjunction with the
- I(wait_for) argument to specify the match policy. Valid
- values are C(all) or C(any). If the value is set to C(all)
- then all conditionals in the wait_for must be satisfied. If
- the value is set to C(any) then only one of the values must be
- satisfied.
- default: all
- choices: ['any', 'all']
- version_added: "2.2"
- retries:
- description:
- - Specifies the number of retries a command should by tried
- before it is considered failed. The command is run on the
- target device every retry and evaluated against the
- I(wait_for) conditions.
- default: 10
- interval:
- description:
- - Configures the interval in seconds to wait between retries
- of the command. If the command does not pass the specified
- conditions, the interval indicates how long to wait before
- trying the command again.
- default: 1
-"""
-
-EXAMPLES = r"""
-tasks:
- - name: run show version on remote devices
- ios_command:
- commands: show version
-
- - name: run show version and check to see if output contains IOS
- ios_command:
- commands: show version
- wait_for: result[0] contains IOS
-
- - name: run multiple commands on remote nodes
- ios_command:
- commands:
- - show version
- - show interfaces
-
- - name: run multiple commands and evaluate the output
- ios_command:
- commands:
- - show version
- - show interfaces
- wait_for:
- - result[0] contains IOS
- - result[1] contains Loopback0
-
- - name: run commands that require answering a prompt
- ios_command:
- commands:
- - command: 'clear counters GigabitEthernet0/1'
- prompt: 'Clear "show interface" counters on this interface \[confirm\]'
- answer: 'y'
- - command: 'clear counters GigabitEthernet0/2'
- prompt: '[confirm]'
- answer: "\r"
-"""
-
-RETURN = """
-stdout:
- description: The set of responses from the commands
- returned: always apart from low level errors (such as action plugin)
- type: list
- sample: ['...', '...']
-stdout_lines:
- description: The value of stdout split into a list
- returned: always apart from low level errors (such as action plugin)
- type: list
- sample: [['...', '...'], ['...'], ['...']]
-failed_conditions:
- description: The list of conditionals that have failed
- returned: failed
- type: list
- sample: ['...', '...']
-"""
-import time
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.parsing import Conditional
-from ansible.module_utils.network.common.utils import transform_commands, to_lines
-from ansible.module_utils.network.ios.ios import run_commands
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def parse_commands(module, warnings):
- commands = transform_commands(module)
-
- if module.check_mode:
- for item in list(commands):
- if not item['command'].startswith('show'):
- warnings.append(
- 'Only show commands are supported when using check mode, not '
- 'executing %s' % item['command']
- )
- commands.remove(item)
-
- return commands
-
-
-def main():
- """main entry point for module execution
- """
- argument_spec = dict(
- commands=dict(type='list', required=True),
-
- wait_for=dict(type='list', aliases=['waitfor']),
- match=dict(default='all', choices=['all', 'any']),
-
- retries=dict(default=10, type='int'),
- interval=dict(default=1, type='int')
- )
-
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- warnings = list()
- result = {'changed': False, 'warnings': warnings}
- commands = parse_commands(module, warnings)
- wait_for = module.params['wait_for'] or list()
-
- try:
- conditionals = [Conditional(c) for c in wait_for]
- except AttributeError as exc:
- module.fail_json(msg=to_text(exc))
-
- retries = module.params['retries']
- interval = module.params['interval']
- match = module.params['match']
-
- while retries > 0:
- responses = run_commands(module, commands)
-
- for item in list(conditionals):
- if item(responses):
- if match == 'any':
- conditionals = list()
- break
- conditionals.remove(item)
-
- if not conditionals:
- break
-
- time.sleep(interval)
- retries -= 1
-
- if conditionals:
- failed_conditions = [item.raw for item in conditionals]
- msg = 'One or more conditional statements have not been satisfied'
- module.fail_json(msg=msg, failed_conditions=failed_conditions)
-
- result.update({
- 'stdout': responses,
- 'stdout_lines': list(to_lines(responses)),
- })
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_config.py b/lib/ansible/modules/network/ios/ios_config.py
deleted file mode 100644
index b359c9cc78..0000000000
--- a/lib/ansible/modules/network/ios/ios_config.py
+++ /dev/null
@@ -1,567 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_config
-version_added: "2.1"
-author: "Peter Sprygada (@privateip)"
-short_description: Manage Cisco IOS configuration sections
-description:
- - Cisco IOS configurations use a simple block indent file syntax
- for segmenting configuration into sections. This module provides
- an implementation for working with IOS configuration sections in
- a deterministic way.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
- - Abbreviated commands are NOT idempotent, see
- L(Network FAQ,../network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands).
-options:
- lines:
- description:
- - The ordered set of commands that should be configured in the
- section. The commands must be the exact same commands as found
- in the device running-config. Be sure to note the configuration
- command syntax as some commands are automatically modified by the
- device config parser.
- aliases: ['commands']
- parents:
- description:
- - The ordered set of parents that uniquely identify the section or hierarchy
- the commands should be checked against. If the parents argument
- is omitted, the commands are checked against the set of top
- level or global commands.
- src:
- description:
- - Specifies the source path to the file that contains the configuration
- or configuration template to load. The path to the source file can
- either be the full path on the Ansible control host or a relative
- path from the playbook or role root directory. This argument is mutually
- exclusive with I(lines), I(parents).
- version_added: "2.2"
- before:
- description:
- - The ordered set of commands to push on to the command stack if
- a change needs to be made. This allows the playbook designer
- the opportunity to perform configuration commands prior to pushing
- any changes without affecting how the set of commands are matched
- against the system.
- after:
- description:
- - The ordered set of commands to append to the end of the command
- stack if a change needs to be made. Just like with I(before) this
- allows the playbook designer to append a set of commands to be
- executed after the command set.
- match:
- description:
- - Instructs the module on the way to perform the matching of
- the set of commands against the current device config. If
- match is set to I(line), commands are matched line by line. If
- match is set to I(strict), command lines are matched with respect
- to position. If match is set to I(exact), command lines
- must be an equal match. Finally, if match is set to I(none), the
- module will not attempt to compare the source configuration with
- the running configuration on the remote device.
- choices: ['line', 'strict', 'exact', 'none']
- default: line
- replace:
- description:
- - Instructs the module on the way to perform the configuration
- on the device. If the replace argument is set to I(line) then
- the modified lines are pushed to the device in configuration
- mode. If the replace argument is set to I(block) then the entire
- command block is pushed to the device in configuration mode if any
- line is not correct.
- default: line
- choices: ['line', 'block']
- multiline_delimiter:
- description:
- - This argument is used when pushing a multiline configuration
- element to the IOS device. It specifies the character to use
- as the delimiting character. This only applies to the
- configuration action.
- default: "@"
- version_added: "2.3"
- backup:
- description:
- - This argument will cause the module to create a full backup of
- the current C(running-config) from the remote device before any
- changes are made. If the C(backup_options) value is not given,
- the backup file is written to the C(backup) folder in the playbook
- root directory or role root directory, if playbook is part of an
- ansible role. If the directory does not exist, it is created.
- type: bool
- default: 'no'
- version_added: "2.2"
- running_config:
- description:
- - The module, by default, will connect to the remote device and
- retrieve the current running-config to use as a base for comparing
- against the contents of source. There are times when it is not
- desirable to have the task get the current running-config for
- every task in a playbook. The I(running_config) argument allows the
- implementer to pass in the configuration to use as the base
- config for comparison.
- aliases: ['config']
- version_added: "2.4"
- defaults:
- description:
- - This argument specifies whether or not to collect all defaults
- when getting the remote device running config. When enabled,
- the module will get the current config by issuing the command
- C(show running-config all).
- type: bool
- default: 'no'
- version_added: "2.2"
- save_when:
- description:
- - When changes are made to the device running-configuration, the
- changes are not copied to non-volatile storage by default. Using
- this argument will change that before. If the argument is set to
- I(always), then the running-config will always be copied to the
- startup-config and the I(modified) flag will always be set to
- True. If the argument is set to I(modified), then the running-config
- will only be copied to the startup-config if it has changed since
- the last save to startup-config. If the argument is set to
- I(never), the running-config will never be copied to the
- startup-config. If the argument is set to I(changed), then the running-config
- will only be copied to the startup-config if the task has made a change.
- I(changed) was added in Ansible 2.5.
- default: never
- choices: ['always', 'never', 'modified', 'changed']
- version_added: "2.4"
- diff_against:
- description:
- - When using the C(ansible-playbook --diff) command line argument
- the module can generate diffs against different sources.
- - When this option is configure as I(startup), the module will return
- the diff of the running-config against the startup-config.
- - When this option is configured as I(intended), the module will
- return the diff of the running-config against the configuration
- provided in the C(intended_config) argument.
- - When this option is configured as I(running), the module will
- return the before and after diff of the running-config with respect
- to any changes made to the device configuration.
- choices: ['running', 'startup', 'intended']
- version_added: "2.4"
- diff_ignore_lines:
- description:
- - Use this argument to specify one or more lines that should be
- ignored during the diff. This is used for lines in the configuration
- that are automatically updated by the system. This argument takes
- a list of regular expressions or exact line matches.
- version_added: "2.4"
- intended_config:
- description:
- - The C(intended_config) provides the master configuration that
- the node should conform to and is used to check the final
- running-config against. This argument will not modify any settings
- on the remote device and is strictly used to check the compliance
- of the current device's configuration against. When specifying this
- argument, the task should also modify the C(diff_against) value and
- set it to I(intended).
- version_added: "2.4"
- backup_options:
- description:
- - This is a dict object containing configurable options related to backup file path.
- The value of this option is read only when C(backup) is set to I(yes), if C(backup) is set
- to I(no) this option will be silently ignored.
- suboptions:
- filename:
- description:
- - The filename to be used to store the backup configuration. If the filename
- is not given it will be generated based on the hostname, current time and date
- in format defined by <hostname>_config.<current-date>@<current-time>
- dir_path:
- description:
- - This option provides the path ending with directory name in which the backup
- configuration file will be stored. If the directory does not exist it will be first
- created and the filename is either the value of C(filename) or default filename
- as described in C(filename) options description. If the path value is not given
- in that case a I(backup) directory will be created in the current working directory
- and backup configuration will be copied in C(filename) within I(backup) directory.
- type: path
- type: dict
- version_added: "2.8"
-"""
-
-EXAMPLES = """
-- name: configure top level configuration
- ios_config:
- lines: hostname {{ inventory_hostname }}
-
-- name: configure interface settings
- ios_config:
- lines:
- - description test interface
- - ip address 172.31.1.1 255.255.255.0
- parents: interface Ethernet1
-
-- name: configure ip helpers on multiple interfaces
- ios_config:
- lines:
- - ip helper-address 172.26.1.10
- - ip helper-address 172.26.3.8
- parents: "{{ item }}"
- with_items:
- - interface Ethernet1
- - interface Ethernet2
- - interface GigabitEthernet1
-
-- name: configure policer in Scavenger class
- ios_config:
- lines:
- - conform-action transmit
- - exceed-action drop
- parents:
- - policy-map Foo
- - class Scavenger
- - police cir 64000
-
-- name: load new acl into device
- ios_config:
- lines:
- - 10 permit ip host 192.0.2.1 any log
- - 20 permit ip host 192.0.2.2 any log
- - 30 permit ip host 192.0.2.3 any log
- - 40 permit ip host 192.0.2.4 any log
- - 50 permit ip host 192.0.2.5 any log
- parents: ip access-list extended test
- before: no ip access-list extended test
- match: exact
-
-- name: check the running-config against master config
- ios_config:
- diff_against: intended
- intended_config: "{{ lookup('file', 'master.cfg') }}"
-
-- name: check the startup-config against the running-config
- ios_config:
- diff_against: startup
- diff_ignore_lines:
- - ntp clock .*
-
-- name: save running to startup when modified
- ios_config:
- save_when: modified
-
-- name: for idempotency, use full-form commands
- ios_config:
- lines:
- # - shut
- - shutdown
- # parents: int gig1/0/11
- parents: interface GigabitEthernet1/0/11
-
-# Set boot image based on comparison to a group_var (version) and the version
-# that is returned from the `ios_facts` module
-- name: SETTING BOOT IMAGE
- ios_config:
- lines:
- - no boot system
- - boot system flash bootflash:{{new_image}}
- host: "{{ inventory_hostname }}"
- when: ansible_net_version != version
-
-- name: render a Jinja2 template onto an IOS device
- ios_config:
- backup: yes
- src: ios_template.j2
-
-- name: configurable backup path
- ios_config:
- src: ios_template.j2
- backup: yes
- backup_options:
- filename: backup.cfg
- dir_path: /home/user
-"""
-
-RETURN = """
-updates:
- description: The set of commands that will be pushed to the remote device
- returned: always
- type: list
- sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1']
-commands:
- description: The set of commands that will be pushed to the remote device
- returned: always
- type: list
- sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1']
-backup_path:
- description: The full path to the backup file
- returned: when backup is yes
- type: str
- sample: /playbooks/ansible/backup/ios_config.2016-07-16@22:28:34
-filename:
- description: The name of the backup file
- returned: when backup is yes and filename is not specified in backup options
- type: str
- sample: ios_config.2016-07-16@22:28:34
-shortname:
- description: The full path to the backup file excluding the timestamp
- returned: when backup is yes and filename is not specified in backup options
- type: str
- sample: /playbooks/ansible/backup/ios_config
-date:
- description: The date extracted from the backup file name
- returned: when backup is yes
- type: str
- sample: "2016-07-16"
-time:
- description: The time extracted from the backup file name
- returned: when backup is yes
- type: str
- sample: "22:28:34"
-"""
-import json
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.connection import ConnectionError
-from ansible.module_utils.network.ios.ios import run_commands, get_config
-from ansible.module_utils.network.ios.ios import get_defaults_flag, get_connection
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.config import NetworkConfig, dumps
-
-
-def check_args(module, warnings):
- if module.params['multiline_delimiter']:
- if len(module.params['multiline_delimiter']) != 1:
- module.fail_json(msg='multiline_delimiter value can only be a '
- 'single character')
-
-
-def edit_config_or_macro(connection, commands):
- # only catch the macro configuration command,
- # not negated 'no' variation.
- if commands[0].startswith("macro name"):
- connection.edit_macro(candidate=commands)
- else:
- connection.edit_config(candidate=commands)
-
-
-def get_candidate_config(module):
- candidate = ''
- if module.params['src']:
- candidate = module.params['src']
-
- elif module.params['lines']:
- candidate_obj = NetworkConfig(indent=1)
- parents = module.params['parents'] or list()
- candidate_obj.add(module.params['lines'], parents=parents)
- candidate = dumps(candidate_obj, 'raw')
-
- return candidate
-
-
-def get_running_config(module, current_config=None, flags=None):
- running = module.params['running_config']
- if not running:
- if not module.params['defaults'] and current_config:
- running = current_config
- else:
- running = get_config(module, flags=flags)
-
- return running
-
-
-def save_config(module, result):
- result['changed'] = True
- if not module.check_mode:
- run_commands(module, 'copy running-config startup-config\r')
- else:
- module.warn('Skipping command `copy running-config startup-config` '
- 'due to check_mode. Configuration not copied to '
- 'non-volatile storage')
-
-
-def main():
- """ main entry point for module execution
- """
- backup_spec = dict(
- filename=dict(),
- dir_path=dict(type='path')
- )
- argument_spec = dict(
- src=dict(type='path'),
-
- lines=dict(aliases=['commands'], type='list'),
- parents=dict(type='list'),
-
- before=dict(type='list'),
- after=dict(type='list'),
-
- match=dict(default='line', choices=['line', 'strict', 'exact', 'none']),
- replace=dict(default='line', choices=['line', 'block']),
- multiline_delimiter=dict(default='@'),
-
- running_config=dict(aliases=['config']),
- intended_config=dict(),
-
- defaults=dict(type='bool', default=False),
- backup=dict(type='bool', default=False),
- backup_options=dict(type='dict', options=backup_spec),
- save_when=dict(choices=['always', 'never', 'modified', 'changed'], default='never'),
-
- diff_against=dict(choices=['startup', 'intended', 'running']),
- diff_ignore_lines=dict(type='list'),
- )
-
- argument_spec.update(ios_argument_spec)
-
- mutually_exclusive = [('lines', 'src'),
- ('parents', 'src')]
-
- required_if = [('match', 'strict', ['lines']),
- ('match', 'exact', ['lines']),
- ('replace', 'block', ['lines']),
- ('diff_against', 'intended', ['intended_config'])]
-
- module = AnsibleModule(argument_spec=argument_spec,
- mutually_exclusive=mutually_exclusive,
- required_if=required_if,
- supports_check_mode=True)
-
- result = {'changed': False}
-
- warnings = list()
- check_args(module, warnings)
- result['warnings'] = warnings
-
- diff_ignore_lines = module.params['diff_ignore_lines']
- config = None
- contents = None
- flags = get_defaults_flag(module) if module.params['defaults'] else []
- connection = get_connection(module)
-
- if module.params['backup'] or (module._diff and module.params['diff_against'] == 'running'):
- contents = get_config(module, flags=flags)
- config = NetworkConfig(indent=1, contents=contents)
- if module.params['backup']:
- result['__backup__'] = contents
-
- if any((module.params['lines'], module.params['src'])):
- match = module.params['match']
- replace = module.params['replace']
- path = module.params['parents']
-
- candidate = get_candidate_config(module)
- running = get_running_config(module, contents, flags=flags)
- try:
- response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path,
- diff_replace=replace)
- except ConnectionError as exc:
- module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
-
- config_diff = response['config_diff']
- banner_diff = response['banner_diff']
-
- if config_diff or banner_diff:
- commands = config_diff.split('\n')
-
- if module.params['before']:
- commands[:0] = module.params['before']
-
- if module.params['after']:
- commands.extend(module.params['after'])
-
- result['commands'] = commands
- result['updates'] = commands
- result['banners'] = banner_diff
-
- # send the configuration commands to the device and merge
- # them with the current running config
- if not module.check_mode:
- if commands:
- edit_config_or_macro(connection, commands)
- if banner_diff:
- connection.edit_banner(candidate=json.dumps(banner_diff), multiline_delimiter=module.params['multiline_delimiter'])
-
- result['changed'] = True
-
- running_config = module.params['running_config']
- startup_config = None
-
- if module.params['save_when'] == 'always':
- save_config(module, result)
- elif module.params['save_when'] == 'modified':
- output = run_commands(module, ['show running-config', 'show startup-config'])
-
- running_config = NetworkConfig(indent=1, contents=output[0], ignore_lines=diff_ignore_lines)
- startup_config = NetworkConfig(indent=1, contents=output[1], ignore_lines=diff_ignore_lines)
-
- if running_config.sha1 != startup_config.sha1:
- save_config(module, result)
- elif module.params['save_when'] == 'changed' and result['changed']:
- save_config(module, result)
-
- if module._diff:
- if not running_config:
- output = run_commands(module, 'show running-config')
- contents = output[0]
- else:
- contents = running_config
-
- # recreate the object in order to process diff_ignore_lines
- running_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
-
- if module.params['diff_against'] == 'running':
- if module.check_mode:
- module.warn("unable to perform diff against running-config due to check mode")
- contents = None
- else:
- contents = config.config_text
-
- elif module.params['diff_against'] == 'startup':
- if not startup_config:
- output = run_commands(module, 'show startup-config')
- contents = output[0]
- else:
- contents = startup_config.config_text
-
- elif module.params['diff_against'] == 'intended':
- contents = module.params['intended_config']
-
- if contents is not None:
- base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
-
- if running_config.sha1 != base_config.sha1:
- if module.params['diff_against'] == 'intended':
- before = running_config
- after = base_config
- elif module.params['diff_against'] in ('startup', 'running'):
- before = base_config
- after = running_config
-
- result.update({
- 'changed': True,
- 'diff': {'before': str(before), 'after': str(after)}
- })
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_facts.py b/lib/ansible/modules/network/ios/ios_facts.py
deleted file mode 100644
index e2f147e669..0000000000
--- a/lib/ansible/modules/network/ios/ios_facts.py
+++ /dev/null
@@ -1,239 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_facts
-version_added: "2.2"
-author:
- - "Peter Sprygada (@privateip)"
- - "Sumit Jaiswal (@justjais)"
-short_description: Collect facts from remote devices running Cisco IOS
-description:
- - Collects a base set of device facts from a remote device that
- is running IOS. This module prepends all of the
- base network fact keys with C(ansible_net_<fact>). The facts
- module will always collect a base set of facts from the device
- and can enable or disable collection of additional facts.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- gather_subset:
- description:
- - When supplied, this argument restricts the facts collected
- to a given subset.
- - Possible values for this argument include
- C(all), C(min), C(hardware), C(config), and C(interfaces).
- - Specify a list of values to include a larger subset.
- - Use a value with an initial C(!) to collect all facts except that subset.
- required: false
- default: '!config'
- gather_network_resources:
- description:
- - When supplied, this argument will restrict the facts collected
- to a given subset. Possible values for this argument include
- all and the resources like interfaces, vlans etc.
- Can specify a list of values to include a larger subset.
- Values can also be used with an initial C(M(!)) to specify that
- a specific subset should not be collected.
- Valid subsets are 'all', 'interfaces', 'l2_interfaces', 'vlans',
- 'lag_interfaces', 'lacp', 'lacp_interfaces', 'lldp_global',
- 'lldp_interfaces', 'l3_interfaces', 'acl_interfaces', 'static_routes', 'acls'.
- version_added: "2.9"
-"""
-
-EXAMPLES = """
-- name: Gather all legacy facts
- ios_facts:
- gather_subset: all
-
-- name: Gather only the config and default facts
- ios_facts:
- gather_subset:
- - config
-
-- name: Do not gather hardware facts
- ios_facts:
- gather_subset:
- - "!hardware"
-
-- name: Gather legacy and resource facts
- ios_facts:
- gather_subset: all
- gather_network_resources: all
-
-- name: Gather only the interfaces resource facts and no legacy facts
- ios_facts:
- gather_subset:
- - '!all'
- - '!min'
- gather_network_resources:
- - interfaces
-
-- name: Gather interfaces resource and minimal legacy facts
- ios_facts:
- gather_subset: min
- gather_network_resources: interfaces
-
-- name: Gather L2 interfaces resource and minimal legacy facts
- ios_facts:
- gather_subset: min
- gather_network_resources: l2_interfaces
-
-- name: Gather L3 interfaces resource and minimal legacy facts
- ios_facts:
- gather_subset: min
- gather_network_resources: l3_interfaces
-
-"""
-
-RETURN = """
-ansible_net_gather_subset:
- description: The list of fact subsets collected from the device
- returned: always
- type: list
-
-ansible_net_gather_network_resources:
- description: The list of fact for network resource subsets collected from the device
- returned: when the resource is configured
- type: list
-
-# default
-ansible_net_model:
- description: The model name returned from the device
- returned: always
- type: str
-ansible_net_serialnum:
- description: The serial number of the remote device
- returned: always
- type: str
-ansible_net_version:
- description: The operating system version running on the remote device
- returned: always
- type: str
-ansible_net_iostype:
- description: The operating system type (IOS or IOS-XE) running on the remote device
- returned: always
- type: str
-ansible_net_hostname:
- description: The configured hostname of the device
- returned: always
- type: str
-ansible_net_image:
- description: The image file the device is running
- returned: always
- type: str
-ansible_net_stacked_models:
- description: The model names of each device in the stack
- returned: when multiple devices are configured in a stack
- type: list
-ansible_net_stacked_serialnums:
- description: The serial numbers of each device in the stack
- returned: when multiple devices are configured in a stack
- type: list
-ansible_net_api:
- description: The name of the transport
- returned: always
- type: str
-ansible_net_python_version:
- description: The Python version Ansible controller is using
- returned: always
- type: str
-
-# hardware
-ansible_net_filesystems:
- description: All file system names available on the device
- returned: when hardware is configured
- type: list
-ansible_net_filesystems_info:
- description: A hash of all file systems containing info about each file system (e.g. free and total space)
- returned: when hardware is configured
- type: dict
-ansible_net_memfree_mb:
- description: The available free memory on the remote device in Mb
- returned: when hardware is configured
- type: int
-ansible_net_memtotal_mb:
- description: The total memory on the remote device in Mb
- returned: when hardware is configured
- type: int
-
-# config
-ansible_net_config:
- description: The current active config from the device
- returned: when config is configured
- type: str
-
-# interfaces
-ansible_net_all_ipv4_addresses:
- description: All IPv4 addresses configured on the device
- returned: when interfaces is configured
- type: list
-ansible_net_all_ipv6_addresses:
- description: All IPv6 addresses configured on the device
- returned: when interfaces is configured
- type: list
-ansible_net_interfaces:
- description: A hash of all interfaces running on the system
- returned: when interfaces is configured
- type: dict
-ansible_net_neighbors:
- description:
- - The list of CDP and LLDP neighbors from the remote device. If both,
- CDP and LLDP neighbor data is present on one port, CDP is preferred.
- returned: when interfaces is configured
- type: dict
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.facts.facts import FactsArgs
-from ansible.module_utils.network.ios.facts.facts import Facts
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: ansible_facts
- """
- argument_spec = FactsArgs.argument_spec
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- warnings = []
- if module.params["gather_subset"] == "!config":
- warnings.append('default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards')
-
- result = Facts(module).get_facts()
-
- ansible_facts, additional_warnings = result
- warnings.extend(additional_warnings)
-
- module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_interfaces.py b/lib/ansible/modules/network/ios/ios_interfaces.py
deleted file mode 100644
index 4988f029be..0000000000
--- a/lib/ansible/modules/network/ios/ios_interfaces.py
+++ /dev/null
@@ -1,405 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_interfaces
-version_added: 2.9
-short_description: Manages interface attributes of Cisco IOS network devices
-description: This module manages the interface attributes of Cisco IOS network devices.
-author: Sumit Jaiswal (@justjais)
-notes:
-- Tested against Cisco IOSv Version 15.2 on VIRL
-- This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of interface options
- type: list
- suboptions:
- name:
- description:
- - Full name of interface, e.g. GigabitEthernet0/2, loopback999.
- type: str
- required: True
- description:
- description:
- - Interface description.
- type: str
- enabled:
- description:
- - Administrative state of the interface.
- - Set the value to C(true) to administratively enable the interface or C(false) to disable it.
- type: bool
- default: True
- speed:
- description:
- - Interface link speed. Applicable for Ethernet interfaces only.
- type: str
- mtu:
- description:
- - MTU for a specific interface. Applicable for Ethernet interfaces only.
- - Refer to vendor documentation for valid values.
- type: int
- duplex:
- description:
- - Interface link status. Applicable for Ethernet interfaces only, either in half duplex,
- full duplex or in automatic state which negotiates the duplex automatically.
- type: str
- choices: ['full', 'half', 'auto']
- state:
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
- description:
- - The state of the configuration after module completion
- type: str
-"""
-
-EXAMPLES = """
----
-
-# Using merged
-
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# no ip address
-# duplex auto
-# speed auto
-
-- name: Merge provided configuration with device configuration
- ios_interfaces:
- config:
- - name: GigabitEthernet0/2
- description: 'Configured and Merged by Ansible Network'
- enabled: True
- - name: GigabitEthernet0/3
- description: 'Configured and Merged by Ansible Network'
- mtu: 2800
- enabled: False
- speed: 100
- duplex: full
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured and Merged by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured and Merged by Ansible Network
-# mtu 2800
-# no ip address
-# shutdown
-# duplex full
-# speed 100
-
-# Using replaced
-
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# mtu 2000
-# no ip address
-# shutdown
-# duplex full
-# speed 100
-
-- name: Replaces device configuration of listed interfaces with provided configuration
- ios_interfaces:
- config:
- - name: GigabitEthernet0/3
- description: 'Configured and Replaced by Ansible Network'
- enabled: False
- duplex: auto
- mtu: 2500
- speed: 1000
- state: replaced
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured and Replaced by Ansible Network
-# mtu 2500
-# no ip address
-# shutdown
-# duplex full
-# speed 1000
-
-# Using overridden
-
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface#
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible
-# mtu 2800
-# no ip address
-# shutdown
-# duplex full
-# speed 100
-
-- name: Override device configuration of all interfaces with provided configuration
- ios_interfaces:
- config:
- - name: GigabitEthernet0/2
- description: 'Configured and Overridden by Ansible Network'
- speed: 1000
- - name: GigabitEthernet0/3
- description: 'Configured and Overridden by Ansible Network'
- enabled: False
- duplex: full
- mtu: 2000
- state: overridden
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured and Overridden by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured and Overridden by Ansible Network
-# mtu 2000
-# no ip address
-# shutdown
-# duplex full
-# speed 100
-
-# Using Deleted
-
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# mtu 2500
-# no ip address
-# shutdown
-# duplex full
-# speed 1000
-
-- name: "Delete module attributes of given interfaces (Note: This won't delete the interface itself)"
- ios_interfaces:
- config:
- - name: GigabitEthernet0/2
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# mtu 2500
-# no ip address
-# shutdown
-# duplex full
-# speed 1000
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
-
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# mtu 2500
-# no ip address
-# shutdown
-# duplex full
-# speed 1000
-
-- name: "Delete module attributes of all interfaces (Note: This won't delete the interface itself)"
- ios_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/3
-# no ip address
-# duplex auto
-# speed auto
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['interface GigabitEthernet 0/1', 'description This is test', 'speed 100']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.interfaces.interfaces import InterfacesArgs
-from ansible.module_utils.network.ios.config.interfaces.interfaces import Interfaces
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=InterfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_l2_interfaces.py b/lib/ansible/modules/network/ios/ios_l2_interfaces.py
deleted file mode 100644
index 19eadb8426..0000000000
--- a/lib/ansible/modules/network/ios/ios_l2_interfaces.py
+++ /dev/null
@@ -1,390 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_l2_interfaces
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_l2_interfaces
-version_added: 2.9
-short_description: Manage Layer-2 interface on Cisco IOS devices.
-description: This module provides declarative management of Layer-2 interface on Cisco IOS devices.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of Layer-2 interface options
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
- type: str
- required: True
- access:
- description:
- - Switchport mode access command to configure the interface as a layer 2 access.
- type: dict
- suboptions:
- vlan:
- description:
- - Configure given VLAN in access port. It's used as the access VLAN ID.
- type: int
- voice:
- description:
- - Switchport mode voice command to configure the interface with a voice vlan.
- type: dict
- suboptions:
- vlan:
- description:
- - Configure given voice VLAN on access port. It's used as the voice VLAN ID.
- type: int
- trunk:
- description:
- - Switchport mode trunk command to configure the interface as a Layer 2 trunk.
- Note The encapsulation is always set to dot1q.
- type: dict
- suboptions:
- allowed_vlans:
- description:
- - List of allowed VLANs in a given trunk port. These are the only VLANs that will be
- configured on the trunk.
- type: list
- native_vlan:
- description:
- - Native VLAN to be configured in trunk port. It's used as the trunk native VLAN ID.
- type: int
- encapsulation:
- description:
- - Trunking encapsulation when interface is in trunking mode.
- choices: ['dot1q','isl','negotiate']
- type: str
- pruning_vlans:
- description:
- - Pruning VLAN to be configured in trunk port. It's used as the trunk pruning VLAN ID.
- type: list
- mode:
- description:
- - Mode in which interface needs to be configured.
- - An interface whose trunk encapsulation is "Auto" can not be configured to "trunk" mode.
- version_added: '2.10'
- type: str
- choices: ['access', 'trunk']
- state:
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
- description:
- - The state of the configuration after module completion
- type: str
-"""
-
-EXAMPLES = """
----
-
-# Using merged
-
-# Before state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# media-type rj45
-# negotiation auto
-
-- name: Merge provided configuration with device configuration
- ios_l2_interfaces:
- config:
- - name: GigabitEthernet0/1
- mode: access
- access:
- vlan: 10
- voice:
- vlan: 40
- - name: GigabitEthernet0/2
- mode: trunk
- trunk:
- allowed_vlans: 10-20,40
- native_vlan: 20
- pruning_vlans: 10,20
- encapsulation: dot1q
- state: merged
-
-# After state:
-# ------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport access vlan 10
-# switchport access vlan 40
-# switchport mode access
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport trunk allowed vlan 10-20,40
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 20
-# switchport trunk pruning vlan 10,20
-# switchport mode trunk
-# media-type rj45
-# negotiation auto
-
-# Using replaced
-
-# Before state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport access vlan 20
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# media-type rj45
-# negotiation auto
-
-- name: Replaces device configuration of listed l2 interfaces with provided configuration
- ios_l2_interfaces:
- config:
- - name: GigabitEthernet0/2
- trunk:
- - allowed_vlans: 20-25,40
- native_vlan: 20
- pruning_vlans: 10
- encapsulation: isl
- state: replaced
-
-# After state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport access vlan 20
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport trunk allowed vlan 20-25,40
-# switchport trunk encapsulation isl
-# switchport trunk native vlan 20
-# switchport trunk pruning vlan 10
-# media-type rj45
-# negotiation auto
-
-# Using overridden
-
-# Before state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 20
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 20
-# media-type rj45
-# negotiation auto
-
-- name: Override device configuration of all l2 interfaces with provided configuration
- ios_l2_interfaces:
- config:
- - name: GigabitEthernet0/2
- access:
- vlan: 20
- voice:
- vlan: 40
- state: overridden
-
-# After state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# switchport voice vlan 40
-# media-type rj45
-# negotiation auto
-
-# Using Deleted
-
-# Before state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport access vlan 20
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# switchport trunk allowed vlan 20-40,60,80
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 10
-# switchport trunk pruning vlan 10
-# media-type rj45
-# negotiation auto
-
-- name: Delete IOS L2 interfaces as in given arguments
- ios_l2_interfaces:
- config:
- - name: GigabitEthernet0/1
- state: deleted
-
-# After state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# switchport trunk allowed vlan 20-40,60,80
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 10
-# switchport trunk pruning vlan 10
-# media-type rj45
-# negotiation auto
-
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
-
-# Before state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# switchport access vlan 20
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# switchport access vlan 20
-# switchport trunk allowed vlan 20-40,60,80
-# switchport trunk encapsulation dot1q
-# switchport trunk native vlan 10
-# switchport trunk pruning vlan 10
-# media-type rj45
-# negotiation auto
-
-- name: Delete IOS L2 interfaces as in given arguments
- ios_l2_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# viosl2#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# negotiation auto
-# interface GigabitEthernet0/2
-# description This is test
-# media-type rj45
-# negotiation auto
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['interface GigabitEthernet0/1', 'switchport access vlan 20']
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import L2_InterfacesArgs
-from ansible.module_utils.network.ios.config.l2_interfaces.l2_interfaces import L2_Interfaces
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=L2_InterfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = L2_Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_l3_interfaces.py b/lib/ansible/modules/network/ios/ios_l3_interfaces.py
deleted file mode 100644
index 9fd054ef75..0000000000
--- a/lib/ansible/modules/network/ios/ios_l3_interfaces.py
+++ /dev/null
@@ -1,442 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-##############################################
-# WARNING
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#
-##############################################
-
-"""
-The module file for ios_l3_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_l3_interfaces
-version_added: 2.9
-short_description: Manage Layer-3 interface on Cisco IOS devices.
-description:
-- This module provides declarative management of Layer-3 interface
- on Cisco IOS devices.
-author: Sumit Jaiswal (@justjais)
-options:
- config:
- description: A dictionary of Layer-3 interface options
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - Full name of the interface excluding any logical unit number,
- i.e. GigabitEthernet0/1.
- type: str
- required: True
- ipv4:
- description:
- - IPv4 address to be set for the Layer-3 interface mentioned in
- I(name) option. The address format is <ipv4 address>/<mask>,
- the mask is number in range 0-32 eg. 192.168.0.1/24.
- type: list
- elements: dict
- suboptions:
- address:
- description:
- - Configures the IPv4 address for Interface.
- type: str
- secondary:
- description:
- - Configures the IP address as a secondary address.
- type: bool
- dhcp_client:
- description:
- - Configures and specifies client-id to use over DHCP ip.
- Note, This option shall work only when dhcp is configured
- as IP.
- - GigabitEthernet interface number
- type: int
- dhcp_hostname:
- description:
- - Configures and specifies value for hostname option over
- DHCP ip. Note, This option shall work only when dhcp is
- configured as IP.
- type: str
- ipv6:
- description:
- - IPv6 address to be set for the Layer-3 interface mentioned in
- I(name) option.
- - The address format is <ipv6 address>/<mask>, the mask is number
- in range 0-128 eg. fd5d:12c9:2201:1::1/64
- type: list
- elements: dict
- suboptions:
- address:
- description:
- - Configures the IPv6 address for Interface.
- type: str
- state:
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
- description:
- - The state of the configuration after module completion
- type: str
-"""
-
-EXAMPLES = """
----
-# Using merged
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# ip address 10.1.1.1 255.255.255.0
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# no ip address
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-
-- name: Merge provided configuration with device configuration
- ios_l3_interfaces:
- config:
- - name: GigabitEthernet0/1
- ipv4:
- - address: 192.168.0.1/24
- secondary: True
- - name: GigabitEthernet0/2
- ipv4:
- - address: 192.168.0.2/24
- - name: GigabitEthernet0/3
- ipv6:
- - address: fd5d:12c9:2201:1::1/64
- - name: GigabitEthernet0/3.100
- ipv4:
- - address: 192.168.0.3/24
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# ip address 10.1.1.1 255.255.255.0
-# ip address 192.168.0.1 255.255.255.0 secondary
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# ip address 192.168.0.2 255.255.255.0
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ipv6 address FD5D:12C9:2201:1::1/64
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.3 255.255.255.0
-
-# Using replaced
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# ip address 10.1.1.1 255.255.255.0
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# no ip address
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ip address 192.168.2.0 255.255.255.0
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.2 255.255.255.0
-
-- name: Replaces device configuration of listed interfaces with provided configuration
- ios_l3_interfaces:
- config:
- - name: GigabitEthernet0/2
- ipv4:
- - address: 192.168.2.0/24
- - name: GigabitEthernet0/3
- ipv4:
- - address: dhcp
- dhcp_client: 2
- dhcp_hostname: test.com
- - name: GigabitEthernet0/3.100
- ipv4:
- - address: 192.168.0.3/24
- secondary: True
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# ip address 10.1.1.1 255.255.255.0
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# ip address 192.168.2.1 255.255.255.0
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ip address dhcp client-id GigabitEthernet0/2 hostname test.com
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.2 255.255.255.0
-# ip address 192.168.0.3 255.255.255.0 secondary
-
-# Using overridden
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# ip address 10.1.1.1 255.255.255.0
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# ip address 192.168.2.1 255.255.255.0
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ipv6 address FD5D:12C9:2201:1::1/64
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.2 255.255.255.0
-
-- name: Override device configuration of all interfaces with provided configuration
- ios_l3_interfaces:
- config:
- - name: GigabitEthernet0/2
- ipv4:
- - address: 192.168.0.1/24
- - name: GigabitEthernet0/3.100
- ipv6:
- - address: autoconfig
- state: overridden
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# description Configured by Ansible
-# no ip address
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description This is test
-# ip address 192.168.0.1 255.255.255.0
-# duplex auto
-# speed 1000
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ipv6 address autoconfig
-
-# Using Deleted
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# ip address 192.0.2.10 255.255.255.0
-# shutdown
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# ip address 192.168.1.0 255.255.255.0
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ip address 192.168.0.1 255.255.255.0
-# shutdown
-# duplex full
-# speed 10
-# ipv6 address FD5D:12C9:2201:1::1/64
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.2 255.255.255.0
-
-- name: "Delete attributes of given interfaces (NOTE: This won't delete the interface itself)"
- ios_l3_interfaces:
- config:
- - name: GigabitEthernet0/2
- - name: GigabitEthernet0/3.100
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# shutdown
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ip address 192.168.0.1 255.255.255.0
-# shutdown
-# duplex full
-# speed 10
-# ipv6 address FD5D:12C9:2201:1::1/64
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured L3 resource module attributes from each configured interface)"
-
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# ip address 192.0.2.10 255.255.255.0
-# shutdown
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# ip address 192.168.1.0 255.255.255.0
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# ip address 192.168.0.1 255.255.255.0
-# shutdown
-# duplex full
-# speed 10
-# ipv6 address FD5D:12C9:2201:1::1/64
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-# ip address 192.168.0.2 255.255.255.0
-
-- name: "Delete L3 attributes of ALL interfaces together (NOTE: This won't delete the interface itself)"
- ios_l3_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface GigabitEthernet0/1
-# no ip address
-# shutdown
-# duplex auto
-# speed auto
-# interface GigabitEthernet0/2
-# description Configured by Ansible Network
-# no ip address
-# interface GigabitEthernet0/3
-# description Configured by Ansible Network
-# shutdown
-# duplex full
-# speed 10
-# interface GigabitEthernet0/3.100
-# encapsulation dot1Q 20
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['interface GigabitEthernet0/1', 'ip address 192.168.0.2 255.255.255.0']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import L3_InterfacesArgs
-from ansible.module_utils.network.ios.config.l3_interfaces.l3_interfaces import L3_Interfaces
-
-
-def main():
- """
- Main entry point for module execution
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=L3_InterfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = L3_Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lacp.py b/lib/ansible/modules/network/ios/ios_lacp.py
deleted file mode 100644
index 1ebe3b3cef..0000000000
--- a/lib/ansible/modules/network/ios/ios_lacp.py
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_lacp
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'
-}
-
-DOCUMENTATION = """
----
-module: ios_lacp
-version_added: 2.9
-short_description: Manage Global Link Aggregation Control Protocol (LACP) on Cisco IOS devices.
-description: This module provides declarative management of Global LACP on Cisco IOS network devices.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli),
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: The provided configurations.
- type: dict
- suboptions:
- system:
- description: This option sets the default system parameters for LACP.
- type: dict
- suboptions:
- priority:
- description:
- - LACP priority for the system.
- - Refer to vendor documentation for valid values.
- type: int
- required: True
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - deleted
- default: merged
-"""
-
-EXAMPLES = """
-
-# Using merged
-#
-# Before state:
-# -------------
-#
-# vios#show lacp sys-id
-# 32768, 5e00.0000.8000
-
-- name: Merge provided configuration with device configuration
- ios_lacp:
- config:
- system:
- priority: 123
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show lacp sys-id
-# 123, 5e00.0000.8000
-
-# Using replaced
-#
-# Before state:
-# -------------
-#
-# vios#show lacp sys-id
-# 500, 5e00.0000.8000
-
-- name: Replaces Global LACP configuration
- ios_lacp:
- config:
- system:
- priority: 123
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#show lacp sys-id
-# 123, 5e00.0000.8000
-
-# Using Deleted
-#
-# Before state:
-# -------------
-#
-# vios#show lacp sys-id
-# 500, 5e00.0000.8000
-
-- name: Delete Global LACP attribute
- ios_lacp:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show lacp sys-id
-# 32768, 5e00.0000.8000
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-commands:
- description: The set of commands pushed to the remote device.
- returned: always
- type: list
- sample: ['lacp system-priority 10']
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.lacp.lacp import LacpArgs
-from ansible.module_utils.network.ios.config.lacp.lacp import Lacp
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',))]
-
- module = AnsibleModule(argument_spec=LacpArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Lacp(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lacp_interfaces.py b/lib/ansible/modules/network/ios/ios_lacp_interfaces.py
deleted file mode 100644
index d9e52e39cf..0000000000
--- a/lib/ansible/modules/network/ios/ios_lacp_interfaces.py
+++ /dev/null
@@ -1,363 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_lacp_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'
-}
-
-
-DOCUMENTATION = """
----
-module: ios_lacp_interfaces
-version_added: 2.9
-short_description: Manage Link Aggregation Control Protocol (LACP) on Cisco IOS devices interface.
-description: This module provides declarative management of LACP on Cisco IOS network devices lacp_interfaces.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL.
- - This module works with connection C(network_cli),
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of LACP lacp_interfaces option
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - Name of the Interface for configuring LACP.
- type: str
- required: True
- port_priority:
- description:
- - LACP priority on this interface.
- - Refer to vendor documentation for valid port values.
- type: int
- fast_switchover:
- description:
- - LACP fast switchover supported on this port channel.
- type: bool
- max_bundle:
- description:
- - LACP maximum number of ports to bundle in this port channel.
- - Refer to vendor documentation for valid port values.
- type: int
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
-"""
-
-EXAMPLES = """
-
-# Using merged
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-
-- name: Merge provided configuration with device configuration
- ios_lacp_interfaces:
- config:
- - name: GigabitEthernet0/1
- port_priority: 10
- - name: GigabitEthernet0/2
- port_priority: 20
- - name: GigabitEthernet0/3
- port_priority: 30
- - name: Port-channel10
- fast_switchover: True
- max_bundle: 5
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp fast-switchover
-# lacp max-bundle 5
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-# Using overridden
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp fast-switchover
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-- name: Override device configuration of all lacp_interfaces with provided configuration
- ios_lacp_interfaces:
- config:
- - name: GigabitEthernet0/1
- port_priority: 20
- - name: Port-channel10
- max_bundle: 2
- state: overridden
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp max-bundle 2
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-
-# Using replaced
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp max-bundle 5
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-- name: Replaces device configuration of listed lacp_interfaces with provided configuration
- ios_lacp_interfaces:
- config:
- - name: GigabitEthernet0/3
- port_priority: 40
- - name: Port-channel10
- fast_switchover: True
- max_bundle: 2
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp fast-switchover
-# lacp max-bundle 2
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 40
-
-# Using Deleted
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# flowcontrol receive on
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-- name: "Delete LACP attributes of given interfaces (Note: This won't delete the interface itself)"
- ios_lacp_interfaces:
- config:
- - name: GigabitEthernet0/1
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-# Using Deleted without any config passed
-# "(NOTE: This will delete all of configured LLDP module attributes)"
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# lacp fast-switchover
-# interface Port-channel20
-# lacp max-bundle 2
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# lacp port-priority 10
-# interface GigabitEthernet0/2
-# shutdown
-# lacp port-priority 20
-# interface GigabitEthernet0/3
-# shutdown
-# lacp port-priority 30
-
-- name: "Delete LACP attributes for all configured interfaces (Note: This won't delete the interface itself)"
- ios_lacp_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-commands:
- description: The set of commands pushed to the remote device.
- returned: always
- type: list
- sample: ['interface GigabitEthernet 0/1', 'lacp port-priority 30']
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import Lacp_InterfacesArgs
-from ansible.module_utils.network.ios.config.lacp_interfaces.lacp_interfaces import Lacp_Interfaces
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=Lacp_InterfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Lacp_Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lag_interfaces.py b/lib/ansible/modules/network/ios/ios_lag_interfaces.py
deleted file mode 100644
index b5351c6dd8..0000000000
--- a/lib/ansible/modules/network/ios/ios_lag_interfaces.py
+++ /dev/null
@@ -1,390 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat Inc.
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-##############################################
-# WARNING
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#
-##############################################
-
-"""
-The module file for ios_l3_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_lag_interfaces
-version_added: 2.9
-short_description: Manage Link Aggregation on Cisco IOS devices.
-description: This module manages properties of Link Aggregation Group on Cisco IOS devices.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A list of link aggregation group configurations.
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - ID of Ethernet Channel of interfaces.
- - Refer to vendor documentation for valid port values.
- type: str
- required: True
- members:
- description:
- - Interface options for the link aggregation group.
- type: list
- suboptions:
- member:
- description:
- - Interface member of the link aggregation group.
- type: str
- mode:
- description:
- - Etherchannel Mode of the interface for link aggregation.
- type: str
- choices:
- - 'auto'
- - 'on'
- - 'desirable'
- - 'active'
- - 'passive'
- link:
- description:
- - Assign a link identifier used for load-balancing.
- - Refer to vendor documentation for valid values.
- - NOTE, parameter only supported on Cisco IOS XE platform.
- type: int
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
-"""
-
-EXAMPLES = """
----
-# Using merged
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-# interface GigabitEthernet0/4
-# shutdown
-
-- name: Merge provided configuration with device configuration
- ios_lag_interfaces:
- config:
- - name: 10
- members:
- - member: GigabitEthernet0/1
- mode: auto
- - member: GigabitEthernet0/2
- mode: auto
- - name: 20
- members:
- - member: GigabitEthernet0/3
- mode: on
- - name: 30
- members:
- - member: GigabitEthernet0/4
- mode: active
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-# Using overridden
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-- name: Override device configuration of all interfaces with provided configuration
- ios_lag_interfaces:
- config:
- - name: 20
- members:
- - member: GigabitEthernet0/2
- mode: auto
- - member: GigabitEthernet0/3
- mode: auto
- state: overridden
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 20 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode auto
-# interface GigabitEthernet0/4
-# shutdown
-
-# Using replaced
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-- name: Replaces device configuration of listed interfaces with provided configuration
- ios_lag_interfaces:
- config:
- - name: 40
- members:
- - member: GigabitEthernet0/3
- mode: auto
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface Port-channel40
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 40 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-# Using Deleted
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-- name: "Delete LAG attributes of given interfaces (Note: This won't delete the interface itself)"
- ios_lag_interfaces:
- config:
- - name: 10
- - name: 20
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured LLDP module attributes)"
-
-#
-# Before state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/2
-# shutdown
-# channel-group 10 mode auto
-# interface GigabitEthernet0/3
-# shutdown
-# channel-group 20 mode on
-# interface GigabitEthernet0/4
-# shutdown
-# channel-group 30 mode active
-
-- name: "Delete all configured LAG attributes for interfaces (Note: This won't delete the interface itself)"
- ios_lag_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show running-config | section ^interface
-# interface Port-channel10
-# interface Port-channel20
-# interface Port-channel30
-# interface GigabitEthernet0/1
-# shutdown
-# interface GigabitEthernet0/2
-# shutdown
-# interface GigabitEthernet0/3
-# shutdown
-# interface GigabitEthernet0/4
-# shutdown
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['interface GigabitEthernet0/1', 'channel-group 1 mode active']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
-from ansible.module_utils.network.ios.config.lag_interfaces.lag_interfaces import Lag_interfaces
-
-
-def main():
- """
- Main entry point for module execution
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=Lag_interfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Lag_interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_linkagg.py b/lib/ansible/modules/network/ios/ios_linkagg.py
deleted file mode 100644
index 61620e6b57..0000000000
--- a/lib/ansible/modules/network/ios/ios_linkagg.py
+++ /dev/null
@@ -1,318 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_linkagg
-version_added: "2.5"
-author: "Trishna Guha (@trishnaguha)"
-short_description: Manage link aggregation groups on Cisco IOS network devices
-description:
- - This module provides declarative management of link aggregation groups
- on Cisco IOS network devices.
-notes:
- - Tested against IOS 15.2
-options:
- group:
- description:
- - Channel-group number for the port-channel
- Link aggregation group. Range 1-255.
- mode:
- description:
- - Mode of the link aggregation group.
- choices: ['active', 'on', 'passive', 'auto', 'desirable']
- members:
- description:
- - List of members of the link aggregation group.
- aggregate:
- description: List of link aggregation definitions.
- state:
- description:
- - State of the link aggregation group.
- default: present
- choices: ['present', 'absent']
- purge:
- description:
- - Purge links not defined in the I(aggregate) parameter.
- default: no
- type: bool
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: create link aggregation group
- ios_linkagg:
- group: 10
- state: present
-
-- name: delete link aggregation group
- ios_linkagg:
- group: 10
- state: absent
-
-- name: set link aggregation group to members
- ios_linkagg:
- group: 200
- mode: active
- members:
- - GigabitEthernet0/0
- - GigabitEthernet0/1
-
-- name: remove link aggregation group from GigabitEthernet0/0
- ios_linkagg:
- group: 200
- mode: active
- members:
- - GigabitEthernet0/1
-
-- name: Create aggregate of linkagg definitions
- ios_linkagg:
- aggregate:
- - { group: 3, mode: on, members: [GigabitEthernet0/1] }
- - { group: 100, mode: passive, members: [GigabitEthernet0/2] }
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always, except for the platforms that use Netconf transport to manage the device.
- type: list
- sample:
- - interface port-channel 30
- - interface GigabitEthernet0/3
- - channel-group 30 mode on
- - no interface port-channel 30
-"""
-
-import re
-from copy import deepcopy
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.config import CustomNetworkConfig
-from ansible.module_utils.network.common.utils import remove_default_spec
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def search_obj_in_list(group, lst):
- for o in lst:
- if o['group'] == group:
- return o
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
- want, have = updates
- purge = module.params['purge']
-
- for w in want:
- group = w['group']
- mode = w['mode']
- members = w.get('members') or []
- state = w['state']
- del w['state']
-
- obj_in_have = search_obj_in_list(group, have)
-
- if state == 'absent':
- if obj_in_have:
- commands.append('no interface port-channel {0}'.format(group))
-
- elif state == 'present':
- cmd = ['interface port-channel {0}'.format(group),
- 'end']
- if not obj_in_have:
- if not group:
- module.fail_json(msg='group is a required option')
- commands.extend(cmd)
-
- if members:
- for m in members:
- commands.append('interface {0}'.format(m))
- commands.append('channel-group {0} mode {1}'.format(group, mode))
-
- else:
- if members:
- if 'members' not in obj_in_have.keys():
- for m in members:
- commands.extend(cmd)
- commands.append('interface {0}'.format(m))
- commands.append('channel-group {0} mode {1}'.format(group, mode))
-
- elif set(members) != set(obj_in_have['members']):
- missing_members = list(set(members) - set(obj_in_have['members']))
- for m in missing_members:
- commands.extend(cmd)
- commands.append('interface {0}'.format(m))
- commands.append('channel-group {0} mode {1}'.format(group, mode))
-
- superfluous_members = list(set(obj_in_have['members']) - set(members))
- for m in superfluous_members:
- commands.extend(cmd)
- commands.append('interface {0}'.format(m))
- commands.append('no channel-group {0} mode {1}'.format(group, mode))
-
- if purge:
- for h in have:
- obj_in_want = search_obj_in_list(h['group'], want)
- if not obj_in_want:
- commands.append('no interface port-channel {0}'.format(h['group']))
-
- return commands
-
-
-def map_params_to_obj(module):
- obj = []
-
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- d = item.copy()
- d['group'] = str(d['group'])
-
- obj.append(d)
- else:
- obj.append({
- 'group': str(module.params['group']),
- 'mode': module.params['mode'],
- 'members': module.params['members'],
- 'state': module.params['state']
- })
-
- return obj
-
-
-def parse_mode(module, config, group, member):
- mode = None
- netcfg = CustomNetworkConfig(indent=1, contents=config)
- parents = ['interface {0}'.format(member)]
- body = netcfg.get_section(parents)
-
- match_int = re.findall(r'interface {0}\n'.format(member), body, re.M)
- if match_int:
- match = re.search(r'channel-group {0} mode (\S+)'.format(group), body, re.M)
- if match:
- mode = match.group(1)
-
- return mode
-
-
-def parse_members(module, config, group):
- members = []
-
- for line in config.strip().split('!'):
- l = line.strip()
- if l.startswith('interface'):
- match_group = re.findall(r'channel-group {0} mode'.format(group), l, re.M)
- if match_group:
- match = re.search(r'interface (\S+)', l, re.M)
- if match:
- members.append(match.group(1))
-
- return members
-
-
-def get_channel(module, config, group):
- match = re.findall(r'^interface (\S+)', config, re.M)
-
- if not match:
- return {}
-
- channel = {}
- for item in set(match):
- member = item
- channel['mode'] = parse_mode(module, config, group, member)
- channel['members'] = parse_members(module, config, group)
-
- return channel
-
-
-def map_config_to_obj(module):
- objs = list()
- config = get_config(module)
-
- for line in config.split('\n'):
- l = line.strip()
- match = re.search(r'interface Port-channel(\S+)', l, re.M)
- if match:
- obj = {}
- group = match.group(1)
- obj['group'] = group
- obj.update(get_channel(module, config, group))
- objs.append(obj)
-
- return objs
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- group=dict(type='int'),
- mode=dict(choices=['active', 'on', 'passive', 'auto', 'desirable']),
- members=dict(type='list'),
- state=dict(default='present',
- choices=['present', 'absent'])
- )
-
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['group'] = dict(required=True)
-
- required_one_of = [['group', 'aggregate']]
- required_together = [['members', 'mode']]
- mutually_exclusive = [['group', 'aggregate']]
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec,
- required_together=required_together),
- purge=dict(default=False, type='bool')
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_one_of=required_one_of,
- required_together=required_together,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- warnings = list()
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands((want, have), module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lldp.py b/lib/ansible/modules/network/ios/ios_lldp.py
deleted file mode 100644
index 7ba7bf385a..0000000000
--- a/lib/ansible/modules/network/ios/ios_lldp.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_lldp
-version_added: "2.5"
-author: "Ganesh Nalawade (@ganeshrn)"
-short_description: Manage LLDP configuration on Cisco IOS network devices.
-description:
- - This module provides declarative management of LLDP service
- on Cisco IOS network devices.
-notes:
- - Tested against IOS 15.2
-options:
- state:
- description:
- - State of the LLDP configuration. If value is I(present) lldp will be enabled
- else if it is I(absent) it will be disabled.
- default: present
- choices: ['present', 'absent']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: Enable LLDP service
- ios_lldp:
- state: present
-
-- name: Disable LLDP service
- ios_lldp:
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always, except for the platforms that use Netconf transport to manage the device.
- type: list
- sample:
- - lldp run
-"""
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import load_config, run_commands
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def has_lldp(module):
- output = run_commands(module, ['show lldp'])
-
- is_lldp_enable = False
- if len(output) > 0 and "LLDP is not enabled" not in output[0]:
- is_lldp_enable = True
-
- return is_lldp_enable
-
-
-def main():
- """ main entry point for module execution
- """
- argument_spec = dict(
- state=dict(default='present',
- choices=['present', 'absent',
- 'enabled', 'disabled'])
- )
-
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- warnings = list()
-
- result = {'changed': False}
-
- if warnings:
- result['warnings'] = warnings
-
- HAS_LLDP = has_lldp(module)
-
- commands = []
-
- if module.params['state'] == 'absent' and HAS_LLDP:
- commands.append('no lldp run')
- elif module.params['state'] == 'present' and not HAS_LLDP:
- commands.append('lldp run')
-
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
-
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lldp_global.py b/lib/ansible/modules/network/ios/ios_lldp_global.py
deleted file mode 100644
index 49c146f8d2..0000000000
--- a/lib/ansible/modules/network/ios/ios_lldp_global.py
+++ /dev/null
@@ -1,256 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_lldp_global
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_lldp_global
-version_added: 2.9
-short_description: Configure and manage Link Layer Discovery Protocol(LLDP) attributes on IOS platforms.
-description: This module configures and manages the Link Layer Discovery Protocol(LLDP) attributes on IOS platforms.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli),
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of LLDP options
- type: dict
- suboptions:
- holdtime:
- description:
- - LLDP holdtime (in sec) to be sent in packets.
- - Refer to vendor documentation for valid values.
- type: int
- reinit:
- description:
- - Specify the delay (in secs) for LLDP to initialize.
- - Refer to vendor documentation for valid values.
- - NOTE, if LLDP reinit is configured with a starting
- value, idempotency won't be maintained as the Cisco
- device doesn't record the starting reinit configured
- value. As such, Ansible cannot verify if the respective
- starting reinit value is already configured or not from
- the device side. If you try to apply starting reinit
- value in every play run, Ansible will show changed as True.
- For any other reinit value, idempotency will be maintained
- since any other reinit value is recorded in the Cisco device.
- type: int
- enabled:
- description:
- - Enable LLDP
- type: bool
- timer:
- description:
- - Specify the rate at which LLDP packets are sent (in sec).
- - Refer to vendor documentation for valid values.
- type: int
- tlv_select:
- description:
- - Selection of LLDP TLVs i.e. type-length-value to send
- - NOTE, if tlv-select is configured idempotency won't be maintained
- as Cisco device doesn't record configured tlv-select options. As
- such, Ansible cannot verify if the respective tlv-select options is
- already configured or not from the device side. If you try to apply
- tlv-select option in every play run, Ansible will show changed as True.
- type: dict
- suboptions:
- four_wire_power_management:
- description:
- - Cisco 4-wire Power via MDI TLV
- type: bool
- mac_phy_cfg:
- description:
- - IEEE 802.3 MAC/Phy Configuration/status TLV
- type: bool
- management_address:
- description:
- - Management Address TLV
- type: bool
- port_description:
- description:
- - Port Description TLV
- type: bool
- port_vlan:
- description:
- - Port VLAN ID TLV
- type: bool
- power_management:
- description:
- - IEEE 802.3 DTE Power via MDI TLV
- type: bool
- system_capabilities:
- description:
- - System Capabilities TLV
- type: bool
- system_description:
- description:
- - System Description TLV
- type: bool
- system_name:
- description:
- - System Name TLV
- type: bool
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - deleted
- default: merged
-"""
-
-EXAMPLES = """
----
-
-# Using merged
-
-# Before state:
-# -------------
-# vios#sh running-config | section ^lldp
-# vios1#
-
-
-- name: Merge provided configuration with device configuration
- ios_lldp_global:
- config:
- holdtime: 10
- enabled: True
- reinit: 3
- timer: 10
- state: merged
-
-# After state:
-# ------------
-# vios#sh running-config | section ^lldp
-# lldp timer 10
-# lldp holdtime 10
-# lldp reinit 3
-# lldp run
-
-
-# Using replaced
-
-# Before state:
-# -------------
-# vios#sh running-config | section ^lldp
-# lldp timer 10
-# lldp holdtime 10
-# lldp reinit 3
-# lldp run
-
-
-- name: Replaces LLDP device configuration with provided configuration
- ios_lldp_global:
- config:
- holdtime: 20
- reinit: 5
- state: replaced
-
-# After state:
-# -------------
-# vios#sh running-config | section ^lldp
-# lldp holdtime 20
-# lldp reinit 5
-
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured LLDP module attributes)"
-
-# Before state:
-# -------------
-# vios#sh running-config | section ^lldp
-# lldp timer 10
-# lldp holdtime 10
-# lldp reinit 3
-# lldp run
-
-
-- name: "Delete LLDP attributes (Note: This won't delete the interface itself)"
- ios_lldp_global:
- state: deleted
-
-# After state:
-# -------------
-# vios#sh running-config | section ^lldp
-# vios1#
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: dict
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: dict
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['lldp holdtime 10', 'lldp run', 'lldp timer 10']
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.lldp_global.lldp_global import Lldp_globalArgs
-from ansible.module_utils.network.ios.config.lldp_global.lldp_global import Lldp_global
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',))]
-
- module = AnsibleModule(argument_spec=Lldp_globalArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Lldp_global(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_lldp_interfaces.py b/lib/ansible/modules/network/ios/ios_lldp_interfaces.py
deleted file mode 100644
index c1bbc274e4..0000000000
--- a/lib/ansible/modules/network/ios/ios_lldp_interfaces.py
+++ /dev/null
@@ -1,501 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_lldp_interfaces
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'
-}
-
-
-DOCUMENTATION = """
----
-module: ios_lldp_interfaces
-version_added: 2.9
-short_description: Manage link layer discovery protocol (LLDP) attributes of interfaces on Cisco IOS devices.
-description: This module manages link layer discovery protocol (LLDP) attributes of interfaces on Cisco IOS devices.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli),
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of LLDP options
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
- type: str
- required: True
- receive:
- description:
- - Enable LLDP reception on interface.
- type: bool
- transmit:
- description:
- - Enable LLDP transmission on interface.
- type: bool
- med_tlv_select:
- description:
- - Selection of LLDP MED TLVs to send
- - NOTE, if med-tlv-select is configured idempotency won't be maintained
- as Cisco device doesn't record configured med-tlv-select options. As
- such, Ansible cannot verify if the respective med-tlv-select options is
- already configured or not from the device side. If you try to apply
- med-tlv-select option in every play run, Ansible will show changed as
- True.
- type: dict
- suboptions:
- inventory_management:
- description:
- - LLDP MED Inventory Management TLV
- type: bool
- tlv_select:
- description:
- - Selection of LLDP type-length-value i.e. TLVs to send
- - NOTE, if tlv-select is configured idempotency won't be maintained
- as Cisco device doesn't record configured tlv-select options. As
- such, Ansible cannot verify if the respective tlv-select options is
- already configured or not from the device side. If you try to apply
- tlv-select option in every play run, Ansible will show changed as True.
- type: dict
- suboptions:
- power_management:
- description:
- - IEEE 802.3 DTE Power via MDI TLV
- type: bool
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
-"""
-
-EXAMPLES = """
-
-# Using merged
-#
-# Before state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-- name: Merge provided configuration with device configuration
- ios_lldp_interfaces:
- config:
- - name: GigabitEthernet0/1
- receive: True
- transmit: True
- - name: GigabitEthernet0/2
- receive: True
- - name: GigabitEthernet0/3
- transmit: True
- state: merged
-
-# After state:
-# ------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-# Using overridden
-#
-# Before state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-- name: Override device configuration of all lldp_interfaces with provided configuration
- ios_lldp_interfaces:
- config:
- - name: GigabitEthernet0/2
- receive: True
- transmit: True
- state: overridden
-
-# After state:
-# ------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-
-# Using replaced
-#
-# Before state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-- name: Replaces device configuration of listed lldp_interfaces with provided configuration
- ios_lldp_interfaces:
- config:
- - name: GigabitEthernet0/2
- receive: True
- transmit: True
- - name: GigabitEthernet0/3
- receive: True
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: disabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-# Using Deleted
-#
-# Before state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-- name: "Delete LLDP attributes of given interfaces (Note: This won't delete the interface itself)"
- ios_lldp_interfaces:
- config:
- - name: GigabitEthernet0/1
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-# Using Deleted without any config passed
-# "(NOTE: This will delete all of configured LLDP module attributes)"
-#
-# Before state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: enabled
-# Rx: enabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-- name: "Delete LLDP attributes for all configured interfaces (Note: This won't delete the interface itself)"
- ios_lldp_interfaces:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#sh lldp interface
-# GigabitEthernet0/0:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/1:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-# GigabitEthernet0/2:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: INIT
-#
-# GigabitEthernet0/3:
-# Tx: disabled
-# Rx: disabled
-# Tx state: IDLE
-# Rx state: WAIT FOR FRAME
-#
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-commands:
- description: The set of commands pushed to the remote device.
- returned: always
- type: list
- sample: ['interface GigabitEthernet 0/1', 'lldp transmit', 'lldp receive']
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import Lldp_InterfacesArgs
-from ansible.module_utils.network.ios.config.lldp_interfaces.lldp_interfaces import Lldp_Interfaces
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=Lldp_InterfacesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Lldp_Interfaces(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_logging.py b/lib/ansible/modules/network/ios/ios_logging.py
deleted file mode 100644
index b91f3ff2b9..0000000000
--- a/lib/ansible/modules/network/ios/ios_logging.py
+++ /dev/null
@@ -1,429 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-#
-# This file is part of Ansible by Red Hat
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_logging
-version_added: "2.4"
-author: "Trishna Guha (@trishnaguha)"
-short_description: Manage logging on network devices
-description:
- - This module provides declarative management of logging
- on Cisco Ios devices.
-notes:
- - Tested against IOS 15.6
-options:
- dest:
- description:
- - Destination of the logs.
- choices: ['on', 'host', 'console', 'monitor', 'buffered', 'trap']
- name:
- description:
- - The hostname or IP address of the destination.
- - Required when I(dest=host).
- size:
- description:
- - Size of buffer. The acceptable value is in range from 4096 to
- 4294967295 bytes.
- default: 4096
- facility:
- description:
- - Set logging facility.
- level:
- description:
- - Set logging severity levels.
- default: debugging
- choices: ['emergencies', 'alerts', 'critical', 'errors', 'warnings', 'notifications', 'informational', 'debugging']
- aggregate:
- description: List of logging definitions.
- state:
- description:
- - State of the logging configuration.
- default: present
- choices: ['present', 'absent']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: configure host logging
- ios_logging:
- dest: host
- name: 172.16.0.1
- state: present
-
-- name: remove host logging configuration
- ios_logging:
- dest: host
- name: 172.16.0.1
- state: absent
-
-- name: configure console logging level and facility
- ios_logging:
- dest: console
- facility: local7
- level: debugging
- state: present
-
-- name: enable logging to all
- ios_logging:
- dest : on
-
-- name: configure buffer size
- ios_logging:
- dest: buffered
- size: 5000
-
-- name: Configure logging using aggregate
- ios_logging:
- aggregate:
- - { dest: console, level: notifications }
- - { dest: buffered, size: 9000 }
-
-- name: remove logging using aggregate
- ios_logging:
- aggregate:
- - { dest: console, level: notifications }
- - { dest: buffered, size: 9000 }
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - logging facility local7
- - logging host 172.16.0.1
-"""
-
-import re
-
-from copy import deepcopy
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import remove_default_spec, validate_ip_address
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import get_capabilities
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def validate_size(value, module):
- if value:
- if not int(4096) <= int(value) <= int(4294967295):
- module.fail_json(msg='size must be between 4096 and 4294967295')
- else:
- return value
-
-
-def map_obj_to_commands(updates, module, os_version):
- dest_group = ('console', 'monitor', 'buffered', 'on', 'trap')
- commands = list()
- want, have = updates
- for w in want:
- dest = w['dest']
- name = w['name']
- size = w['size']
- facility = w['facility']
- level = w['level']
- state = w['state']
- del w['state']
-
- if facility:
- w['dest'] = 'facility'
-
- if state == 'absent' and w in have:
- if dest:
- if dest == 'host':
- if '12.' in os_version:
- commands.append('no logging {0}'.format(name))
- else:
- commands.append('no logging host {0}'.format(name))
-
- elif dest in dest_group:
- commands.append('no logging {0}'.format(dest))
-
- else:
- module.fail_json(msg='dest must be among console, monitor, buffered, host, on, trap')
-
- if facility:
- commands.append('no logging facility {0}'.format(facility))
-
- if state == 'present' and w not in have:
- if facility:
- present = False
-
- for entry in have:
- if entry['dest'] == 'facility' and entry['facility'] == facility:
- present = True
-
- if not present:
- commands.append('logging facility {0}'.format(facility))
-
- if dest == 'host':
- if '12.' in os_version:
- commands.append('logging {0}'.format(name))
- else:
- commands.append('logging host {0}'.format(name))
-
- elif dest == 'on':
- commands.append('logging on')
-
- elif dest == 'buffered' and size:
- present = False
-
- for entry in have:
- if entry['dest'] == 'buffered' and entry['size'] == size and entry['level'] == level:
- present = True
-
- if not present:
- if level and level != 'debugging':
- commands.append('logging buffered {0} {1}'.format(size, level))
- else:
- commands.append('logging buffered {0}'.format(size))
-
- else:
- if dest:
- dest_cmd = 'logging {0}'.format(dest)
- if level:
- dest_cmd += ' {0}'.format(level)
- commands.append(dest_cmd)
- return commands
-
-
-def parse_facility(line, dest):
- facility = None
- if dest == 'facility':
- match = re.search(r'logging facility (\S+)', line, re.M)
- if match:
- facility = match.group(1)
-
- return facility
-
-
-def parse_size(line, dest):
- size = None
-
- if dest == 'buffered':
- match = re.search(r'logging buffered(?: (\d+))?(?: [a-z]+)?', line, re.M)
- if match:
- if match.group(1) is not None:
- size = match.group(1)
- else:
- size = "4096"
-
- return size
-
-
-def parse_name(line, dest):
- if dest == 'host':
- match = re.search(r'logging host (\S+)', line, re.M)
- if match:
- name = match.group(1)
- else:
- name = None
-
- return name
-
-
-def parse_level(line, dest):
- level_group = ('emergencies', 'alerts', 'critical', 'errors', 'warnings',
- 'notifications', 'informational', 'debugging')
-
- if dest == 'host':
- level = 'debugging'
-
- else:
- if dest == 'buffered':
- match = re.search(r'logging buffered(?: \d+)?(?: ([a-z]+))?', line, re.M)
- else:
- match = re.search(r'logging {0} (\S+)'.format(dest), line, re.M)
-
- if match and match.group(1) in level_group:
- level = match.group(1)
- else:
- level = 'debugging'
-
- return level
-
-
-def map_config_to_obj(module):
- obj = []
- dest_group = ('console', 'host', 'monitor', 'buffered', 'on', 'facility', 'trap')
-
- data = get_config(module, flags=['| include logging'])
-
- for line in data.split('\n'):
- match = re.search(r'^logging (\S+)', line, re.M)
- if match:
- if match.group(1) in dest_group:
- dest = match.group(1)
-
- obj.append({
- 'dest': dest,
- 'name': parse_name(line, dest),
- 'size': parse_size(line, dest),
- 'facility': parse_facility(line, dest),
- 'level': parse_level(line, dest)
- })
- elif validate_ip_address(match.group(1)):
- dest = 'host'
- obj.append({
- 'dest': dest,
- 'name': match.group(1),
- 'size': parse_size(line, dest),
- 'facility': parse_facility(line, dest),
- 'level': parse_level(line, dest)
- })
- else:
- ip_match = re.search(r'\d+\.\d+\.\d+\.\d+', match.group(1), re.M)
- if ip_match:
- dest = 'host'
- obj.append({
- 'dest': dest,
- 'name': match.group(1),
- 'size': parse_size(line, dest),
- 'facility': parse_facility(line, dest),
- 'level': parse_level(line, dest)
- })
- return obj
-
-
-def map_params_to_obj(module, required_if=None):
- obj = []
- aggregate = module.params.get('aggregate')
-
- if aggregate:
- for item in aggregate:
- for key in item:
- if item.get(key) is None:
- item[key] = module.params[key]
-
- module._check_required_if(required_if, item)
-
- d = item.copy()
- if d['dest'] != 'host':
- d['name'] = None
-
- if d['dest'] == 'buffered':
- if 'size' in d:
- d['size'] = str(validate_size(d['size'], module))
- elif 'size' not in d:
- d['size'] = str(4096)
- else:
- pass
-
- if d['dest'] != 'buffered':
- d['size'] = None
-
- obj.append(d)
-
- else:
- if module.params['dest'] != 'host':
- module.params['name'] = None
-
- if module.params['dest'] == 'buffered':
- if not module.params['size']:
- module.params['size'] = str(4096)
- else:
- module.params['size'] = None
-
- if module.params['size'] is None:
- obj.append({
- 'dest': module.params['dest'],
- 'name': module.params['name'],
- 'size': module.params['size'],
- 'facility': module.params['facility'],
- 'level': module.params['level'],
- 'state': module.params['state']
- })
-
- else:
- obj.append({
- 'dest': module.params['dest'],
- 'name': module.params['name'],
- 'size': str(validate_size(module.params['size'], module)),
- 'facility': module.params['facility'],
- 'level': module.params['level'],
- 'state': module.params['state']
- })
- return obj
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- dest=dict(type='str', choices=['on', 'host', 'console', 'monitor', 'buffered', 'trap']),
- name=dict(type='str'),
- size=dict(type='int'),
- facility=dict(type='str'),
- level=dict(type='str', default='debugging', choices=['emergencies', 'alerts', 'critical', 'errors', 'warnings',
- 'notifications', 'informational', 'debugging']),
- state=dict(default='present', choices=['present', 'absent']),
- )
-
- aggregate_spec = deepcopy(element_spec)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- required_if = [('dest', 'host', ['name'])]
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- device_info = get_capabilities(module)
- os_version = device_info['device_info']['network_os_version']
-
- warnings = list()
-
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
-
- want = map_params_to_obj(module, required_if=required_if)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands((want, have), module, os_version)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_ntp.py b/lib/ansible/modules/network/ios/ios_ntp.py
deleted file mode 100644
index 682140c375..0000000000
--- a/lib/ansible/modules/network/ios/ios_ntp.py
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: ios_ntp
-extends_documentation_fragment: ios
-version_added: "2.8"
-short_description: Manages core NTP configuration.
-description:
- - Manages core NTP configuration.
-author:
- - Federico Olivieri (@Federico87)
-options:
- server:
- description:
- - Network address of NTP server.
- source_int:
- description:
- - Source interface for NTP packets.
- acl:
- description:
- - ACL for peer/server access restricition.
- logging:
- description:
- - Enable NTP logs. Data type boolean.
- type: bool
- default: False
- auth:
- description:
- - Enable NTP authentication. Data type boolean.
- type: bool
- default: False
- auth_key:
- description:
- - md5 NTP authentication key of tye 7.
- key_id:
- description:
- - auth_key id. Data type string
- state:
- description:
- - Manage the state of the resource.
- default: present
- choices: ['present', 'absent']
-'''
-
-EXAMPLES = '''
-# Set new NTP server and source interface
-- ios_ntp:
- server: 10.0.255.10
- source_int: Loopback0
- logging: false
- state: present
-
-# Remove NTP ACL and logging
-- ios_ntp:
- acl: NTP_ACL
- logging: true
- state: absent
-
-# Set NTP authentication
-- ios_ntp:
- key_id: 10
- auth_key: 15435A030726242723273C21181319000A
- auth: true
- state: present
-
-# Set new NTP configuration
-- ios_ntp:
- server: 10.0.255.10
- source_int: Loopback0
- acl: NTP_ACL
- logging: true
- key_id: 10
- auth_key: 15435A030726242723273C21181319000A
- auth: true
- state: present
-'''
-
-RETURN = '''
-commands:
- description: command sent to the device
- returned: always
- type: list
- sample: ["no ntp server 10.0.255.10", "no ntp source Loopback0"]
-'''
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def parse_server(line, dest):
- if dest == 'server':
- match = re.search(r'(ntp server )(\d+\.\d+\.\d+\.\d+)', line, re.M)
- if match:
- server = match.group(2)
- return server
-
-
-def parse_source_int(line, dest):
- if dest == 'source':
- match = re.search(r'(ntp source )(\S+)', line, re.M)
- if match:
- source = match.group(2)
- return source
-
-
-def parse_acl(line, dest):
- if dest == 'access-group':
- match = re.search(r'ntp access-group (?:peer|serve)(?:\s+)(\S+)', line, re.M)
- if match:
- acl = match.group(1)
- return acl
-
-
-def parse_logging(line, dest):
- if dest == 'logging':
- logging = dest
- return logging
-
-
-def parse_auth_key(line, dest):
- if dest == 'authentication-key':
- match = re.search(r'(ntp authentication-key \d+ md5 )(\w+)', line, re.M)
- if match:
- auth_key = match.group(2)
- return auth_key
-
-
-def parse_key_id(line, dest):
- if dest == 'trusted-key':
- match = re.search(r'(ntp trusted-key )(\d+)', line, re.M)
- if match:
- auth_key = match.group(2)
- return auth_key
-
-
-def parse_auth(dest):
- if dest == 'authenticate':
- return dest
-
-
-def map_config_to_obj(module):
-
- obj_dict = {}
- obj = []
- server_list = []
-
- config = get_config(module, flags=['| include ntp'])
-
- for line in config.splitlines():
- match = re.search(r'ntp (\S+)', line, re.M)
- if match:
- dest = match.group(1)
-
- server = parse_server(line, dest)
- source_int = parse_source_int(line, dest)
- acl = parse_acl(line, dest)
- logging = parse_logging(line, dest)
- auth = parse_auth(dest)
- auth_key = parse_auth_key(line, dest)
- key_id = parse_key_id(line, dest)
-
- if server:
- server_list.append(server)
- if source_int:
- obj_dict['source_int'] = source_int
- if acl:
- obj_dict['acl'] = acl
- if logging:
- obj_dict['logging'] = True
- if auth:
- obj_dict['auth'] = True
- if auth_key:
- obj_dict['auth_key'] = auth_key
- if key_id:
- obj_dict['key_id'] = key_id
-
- obj_dict['server'] = server_list
- obj.append(obj_dict)
-
- return obj
-
-
-def map_params_to_obj(module):
- obj = []
- obj.append({
- 'state': module.params['state'],
- 'server': module.params['server'],
- 'source_int': module.params['source_int'],
- 'logging': module.params['logging'],
- 'acl': module.params['acl'],
- 'auth': module.params['auth'],
- 'auth_key': module.params['auth_key'],
- 'key_id': module.params['key_id']
- })
-
- return obj
-
-
-def map_obj_to_commands(want, have, module):
-
- commands = list()
-
- server_have = have[0].get('server', None)
- source_int_have = have[0].get('source_int', None)
- acl_have = have[0].get('acl', None)
- logging_have = have[0].get('logging', None)
- auth_have = have[0].get('auth', None)
- auth_key_have = have[0].get('auth_key', None)
- key_id_have = have[0].get('key_id', None)
-
- for w in want:
- server = w['server']
- source_int = w['source_int']
- acl = w['acl']
- logging = w['logging']
- state = w['state']
- auth = w['auth']
- auth_key = w['auth_key']
- key_id = w['key_id']
-
- if state == 'absent':
- if server_have and server in server_have:
- commands.append('no ntp server {0}'.format(server))
- if source_int and source_int_have:
- commands.append('no ntp source {0}'.format(source_int))
- if acl and acl_have:
- commands.append('no ntp access-group peer {0}'.format(acl))
- if logging is True and logging_have:
- commands.append('no ntp logging')
- if auth is True and auth_have:
- commands.append('no ntp authenticate')
- if key_id and key_id_have:
- commands.append('no ntp trusted-key {0}'.format(key_id))
- if auth_key and auth_key_have:
- if key_id and key_id_have:
- commands.append('no ntp authentication-key {0} md5 {1} 7'.format(key_id, auth_key))
-
- elif state == 'present':
- if server is not None and server not in server_have:
- commands.append('ntp server {0}'.format(server))
- if source_int is not None and source_int != source_int_have:
- commands.append('ntp source {0}'.format(source_int))
- if acl is not None and acl != acl_have:
- commands.append('ntp access-group peer {0}'.format(acl))
- if logging is not None and logging != logging_have and logging is not False:
- commands.append('ntp logging')
- if auth is not None and auth != auth_have and auth is not False:
- commands.append('ntp authenticate')
- if key_id is not None and key_id != key_id_have:
- commands.append('ntp trusted-key {0}'.format(key_id))
- if auth_key is not None and auth_key != auth_key_have:
- if key_id is not None:
- commands.append('ntp authentication-key {0} md5 {1} 7'.format(key_id, auth_key))
-
- return commands
-
-
-def main():
-
- argument_spec = dict(
- server=dict(),
- source_int=dict(),
- acl=dict(),
- logging=dict(type='bool', default=False),
- auth=dict(type='bool', default=False),
- auth_key=dict(),
- key_id=dict(),
- state=dict(choices=['absent', 'present'], default='present')
- )
-
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- result = {'changed': False}
-
- warnings = list()
- if warnings:
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands(want, have, module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_ping.py b/lib/ansible/modules/network/ios/ios_ping.py
deleted file mode 100644
index 6b7fca9261..0000000000
--- a/lib/ansible/modules/network/ios/ios_ping.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# 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
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = r'''
----
-module: ios_ping
-short_description: Tests reachability using ping from Cisco IOS network devices
-description:
-- Tests reachability using ping from switch to a remote destination.
-- For a general purpose network module, see the M(net_ping) module.
-- For Windows targets, use the M(win_ping) module instead.
-- For targets running Python, use the M(ping) module instead.
-author:
-- Jacob McGill (@jmcgill298)
-version_added: '2.4'
-extends_documentation_fragment: ios
-options:
- count:
- description:
- - Number of packets to send.
- default: 5
- dest:
- description:
- - The IP Address or hostname (resolvable by switch) of the remote node.
- required: true
- source:
- description:
- - The source IP Address.
- state:
- description:
- - Determines if the expected result is success or fail.
- choices: [ absent, present ]
- default: present
- vrf:
- description:
- - The VRF to use for forwarding.
- default: default
-notes:
- - For a general purpose network module, see the M(net_ping) module.
- - For Windows targets, use the M(win_ping) module instead.
- - For targets running Python, use the M(ping) module instead.
-'''
-
-EXAMPLES = r'''
-- name: Test reachability to 10.10.10.10 using default vrf
- ios_ping:
- dest: 10.10.10.10
-
-- name: Test reachability to 10.20.20.20 using prod vrf
- ios_ping:
- dest: 10.20.20.20
- vrf: prod
-
-- name: Test unreachability to 10.30.30.30 using default vrf
- ios_ping:
- dest: 10.30.30.30
- state: absent
-
-- name: Test reachability to 10.40.40.40 using prod vrf and setting count and source
- ios_ping:
- dest: 10.40.40.40
- source: loopback0
- vrf: prod
- count: 20
-'''
-
-RETURN = '''
-commands:
- description: Show the command sent.
- returned: always
- type: list
- sample: ["ping vrf prod 10.40.40.40 count 20 source loopback0"]
-packet_loss:
- description: Percentage of packets lost.
- returned: always
- type: str
- sample: "0%"
-packets_rx:
- description: Packets successfully received.
- returned: always
- type: int
- sample: 20
-packets_tx:
- description: Packets successfully transmitted.
- returned: always
- type: int
- sample: 20
-rtt:
- description: Show RTT stats.
- returned: always
- type: dict
- sample: {"avg": 2, "max": 8, "min": 1}
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import run_commands
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-import re
-
-
-def main():
- """ main entry point for module execution
- """
- argument_spec = dict(
- count=dict(type="int"),
- dest=dict(type="str", required=True),
- source=dict(type="str"),
- state=dict(type="str", choices=["absent", "present"], default="present"),
- vrf=dict(type="str")
- )
-
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec)
-
- count = module.params["count"]
- dest = module.params["dest"]
- source = module.params["source"]
- vrf = module.params["vrf"]
-
- warnings = list()
-
- results = {}
- if warnings:
- results["warnings"] = warnings
-
- results["commands"] = [build_ping(dest, count, source, vrf)]
-
- ping_results = run_commands(module, commands=results["commands"])
- ping_results_list = ping_results[0].split("\n")
-
- stats = ""
- for line in ping_results_list:
- if line.startswith('Success'):
- stats = line
-
- success, rx, tx, rtt = parse_ping(stats)
- loss = abs(100 - int(success))
- results["packet_loss"] = str(loss) + "%"
- results["packets_rx"] = int(rx)
- results["packets_tx"] = int(tx)
-
- # Convert rtt values to int
- for k, v in rtt.items():
- if rtt[k] is not None:
- rtt[k] = int(v)
-
- results["rtt"] = rtt
-
- validate_results(module, loss, results)
-
- module.exit_json(**results)
-
-
-def build_ping(dest, count=None, source=None, vrf=None):
- """
- Function to build the command to send to the terminal for the switch
- to execute. All args come from the module's unique params.
- """
- if vrf is not None:
- cmd = "ping vrf {0} {1}".format(vrf, dest)
- else:
- cmd = "ping {0}".format(dest)
-
- if count is not None:
- cmd += " repeat {0}".format(str(count))
-
- if source is not None:
- cmd += " source {0}".format(source)
-
- return cmd
-
-
-def parse_ping(ping_stats):
- """
- Function used to parse the statistical information from the ping response.
- Example: "Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/8 ms"
- Returns the percent of packet loss, received packets, transmitted packets, and RTT dict.
- """
- rate_re = re.compile(r"^\w+\s+\w+\s+\w+\s+(?P<pct>\d+)\s+\w+\s+\((?P<rx>\d+)/(?P<tx>\d+)\)")
- rtt_re = re.compile(r".*,\s+\S+\s+\S+\s+=\s+(?P<min>\d+)/(?P<avg>\d+)/(?P<max>\d+)\s+\w+\s*$|.*\s*$")
-
- rate = rate_re.match(ping_stats)
- rtt = rtt_re.match(ping_stats)
-
- return rate.group("pct"), rate.group("rx"), rate.group("tx"), rtt.groupdict()
-
-
-def validate_results(module, loss, results):
- """
- This function is used to validate whether the ping results were unexpected per "state" param.
- """
- state = module.params["state"]
- if state == "present" and loss == 100:
- module.fail_json(msg="Ping failed unexpectedly", **results)
- elif state == "absent" and loss < 100:
- module.fail_json(msg="Ping succeeded unexpectedly", **results)
-
-
-if __name__ == "__main__":
- main()
diff --git a/lib/ansible/modules/network/ios/ios_static_route.py b/lib/ansible/modules/network/ios/ios_static_route.py
deleted file mode 100644
index 541a76a0c1..0000000000
--- a/lib/ansible/modules/network/ios/ios_static_route.py
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-#
-# This file is part of Ansible by Red Hat
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_static_route
-version_added: "2.4"
-author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
-short_description: Manage static IP routes on Cisco IOS network devices
-description:
- - This module provides declarative management of static
- IP routes on Cisco IOS network devices.
-notes:
- - Tested against IOS 15.6
-options:
- prefix:
- description:
- - Network prefix of the static route.
- mask:
- description:
- - Network prefix mask of the static route.
- next_hop:
- description:
- - Next hop IP of the static route.
- vrf:
- description:
- - VRF of the static route.
- version_added: "2.8"
- interface:
- description:
- - Interface of the static route.
- version_added: "2.8"
- name:
- description:
- - Name of the static route
- aliases: ['description']
- version_added: "2.8"
- admin_distance:
- description:
- - Admin distance of the static route.
- tag:
- description:
- - Set tag of the static route.
- version_added: "2.8"
- track:
- description:
- - Tracked item to depend on for the static route.
- version_added: "2.8"
- aggregate:
- description: List of static route definitions.
- state:
- description:
- - State of the static route configuration.
- default: present
- choices: ['present', 'absent']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: configure static route
- ios_static_route:
- prefix: 192.168.2.0
- mask: 255.255.255.0
- next_hop: 10.0.0.1
-
-- name: configure black hole in vrf blue depending on tracked item 10
- ios_static_route:
- prefix: 192.168.2.0
- mask: 255.255.255.0
- vrf: blue
- interface: null0
- track: 10
-
-- name: configure ultimate route with name and tag
- ios_static_route:
- prefix: 192.168.2.0
- mask: 255.255.255.0
- interface: GigabitEthernet1
- name: hello world
- tag: 100
-
-- name: remove configuration
- ios_static_route:
- prefix: 192.168.2.0
- mask: 255.255.255.0
- next_hop: 10.0.0.1
- state: absent
-
-- name: Add static route aggregates
- ios_static_route:
- aggregate:
- - { prefix: 172.16.32.0, mask: 255.255.255.0, next_hop: 10.0.0.8 }
- - { prefix: 172.16.33.0, mask: 255.255.255.0, next_hop: 10.0.0.8 }
-
-- name: Remove static route aggregates
- ios_static_route:
- aggregate:
- - { prefix: 172.16.32.0, mask: 255.255.255.0, next_hop: 10.0.0.8 }
- - { prefix: 172.16.33.0, mask: 255.255.255.0, next_hop: 10.0.0.8 }
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - ip route 192.168.2.0 255.255.255.0 10.0.0.1
-"""
-from copy import deepcopy
-from re import findall
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import remove_default_spec, validate_ip_address
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-
-
-def map_obj_to_commands(want, have):
- commands = list()
-
- for w in want:
- state = w['state']
- del w['state']
- # Try to match an existing config with the desired config
- for h in have:
- # To delete admin_distance param from have if not it want before comparing both fields
- if not w.get('admin_distance') and h.get('admin_distance'):
- del h['admin_distance']
- diff = list(set(w.items()) ^ set(h.items()))
- if not diff:
- break
- # if route is present with name or name already starts with wanted name it will not change
- elif len(diff) == 2 and diff[0][0] == diff[1][0] == 'name' and (not w['name'] or h['name'].startswith(w['name'])):
- break
- # If no matches found, clear `h`
- else:
- h = None
-
- command = 'ip route'
- prefix = w['prefix']
- mask = w['mask']
- vrf = w.get('vrf')
- if vrf:
- command = ' '.join((command, 'vrf', vrf, prefix, mask))
- else:
- command = ' '.join((command, prefix, mask))
-
- for key in ['interface', 'next_hop', 'admin_distance', 'tag', 'name', 'track']:
- if w.get(key):
- if key == 'name' and len(w.get(key).split()) > 1:
- command = ' '.join((command, key, '"%s"' % w.get(key))) # name with multiple words needs to be quoted
- elif key in ('name', 'tag', 'track'):
- command = ' '.join((command, key, w.get(key)))
- else:
- command = ' '.join((command, w.get(key)))
-
- if state == 'absent' and h:
- commands.append('no %s' % command)
- elif state == 'present' and not h:
- commands.append(command)
-
- return commands
-
-
-def map_config_to_obj(module):
- obj = []
-
- out = get_config(module, flags='| include ip route')
-
- for line in out.splitlines():
- splitted_line = findall(r'[^"\s]\S*|".+?"', line) # Split by whitespace but do not split quotes, needed for name parameter
-
- if splitted_line[2] == 'vrf':
- route = {'vrf': splitted_line[3]}
- del splitted_line[:4] # Removes the words ip route vrf vrf_name
- else:
- route = {}
- del splitted_line[:2] # Removes the words ip route
-
- prefix = splitted_line[0]
- mask = splitted_line[1]
- route.update({'prefix': prefix, 'mask': mask, 'admin_distance': '1'})
-
- next_word = None
- for word in splitted_line[2:]:
- if next_word:
- route[next_word] = word.strip('"') # Remove quotes which is needed for name
- next_word = None
- elif validate_ip_address(word):
- route.update(next_hop=word)
- elif word.isdigit():
- route.update(admin_distance=word)
- elif word in ('tag', 'name', 'track'):
- next_word = word
- else:
- route.update(interface=word)
-
- obj.append(route)
-
- return obj
-
-
-def map_params_to_obj(module, required_together=None):
- keys = ['prefix', 'mask', 'state', 'next_hop', 'vrf', 'interface', 'name', 'admin_distance', 'track', 'tag']
- obj = []
-
- aggregate = module.params.get('aggregate')
- if aggregate:
- for item in aggregate:
- route = item.copy()
- for key in keys:
- if route.get(key) is None:
- route[key] = module.params.get(key)
-
- route = dict((k, v) for k, v in route.items() if v is not None)
- module._check_required_together(required_together, route)
- obj.append(route)
- else:
- module._check_required_together(required_together, module.params)
- route = dict()
- for key in keys:
- if module.params.get(key) is not None:
- route[key] = module.params.get(key)
- obj.append(route)
-
- return obj
-
-
-def main():
- """ main entry point for module execution
- """
- element_spec = dict(
- prefix=dict(type='str'),
- mask=dict(type='str'),
- next_hop=dict(type='str'),
- vrf=dict(type='str'),
- interface=dict(type='str'),
- name=dict(type='str', aliases=['description']),
- admin_distance=dict(type='str'),
- track=dict(type='str'),
- tag=dict(type='str'),
- state=dict(default='present', choices=['present', 'absent'])
- )
-
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['prefix'] = dict(required=True)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec),
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- required_one_of = [['aggregate', 'prefix']]
- required_together = [['prefix', 'mask']]
- mutually_exclusive = [['aggregate', 'prefix']]
-
- module = AnsibleModule(argument_spec=argument_spec,
- required_one_of=required_one_of,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- warnings = list()
-
- result = {'changed': False}
- if warnings:
- result['warnings'] = warnings
- want = map_params_to_obj(module, required_together=required_together)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands(want, have)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
-
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_static_routes.py b/lib/ansible/modules/network/ios/ios_static_routes.py
deleted file mode 100644
index dc76d04ffe..0000000000
--- a/lib/ansible/modules/network/ios/ios_static_routes.py
+++ /dev/null
@@ -1,710 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_static_routes
-"""
-
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_static_routes
-version_added: "2.10"
-short_description: Configure and manage static routes on IOS devices.
-description: This module configures and manages the static routes on IOS platforms.
-author: Sumit Jaiswal (@justjais)
-notes:
-- Tested against Cisco IOSv Version 15.2 on VIRL
-- This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of static route options
- type: list
- elements: dict
- suboptions:
- vrf:
- description:
- - IP VPN Routing/Forwarding instance name.
- - NOTE, In case of IPV4/IPV6 VRF routing table should pre-exist before
- configuring.
- - NOTE, if the vrf information is not provided then the routes shall be
- configured under global vrf.
- type: str
- address_families:
- elements: dict
- description:
- - Address family to use for the static routes
- type: list
- suboptions:
- afi:
- description:
- - Top level address family indicator.
- required: true
- type: str
- choices:
- - ipv4
- - ipv6
- routes:
- description: Configuring static route
- type: list
- elements: dict
- suboptions:
- dest:
- description: Destination prefix with its subnet mask
- type: str
- required: true
- topology:
- description:
- - Configure static route for a Topology Routing/Forwarding instance
- - NOTE, VRF and Topology can be used together only with Multicast and
- Topology should pre-exist before it can be used
- type: str
- next_hops:
- description:
- - next hop address or interface
- type: list
- elements: dict
- suboptions:
- forward_router_address:
- description: Forwarding router's address
- type: str
- interface:
- description: Interface for directly connected static routes
- type: str
- dhcp:
- description: Default gateway obtained from DHCP
- type: bool
- distance_metric:
- description: Distance metric for this route
- type: int
- global:
- description: Next hop address is global
- type: bool
- name:
- description: Specify name of the next hop
- type: str
- multicast:
- description: multicast route
- type: bool
- permanent:
- description: permanent route
- type: bool
- tag:
- description:
- - Set tag for this route
- - Refer to vendor documentation for valid values.
- type: int
- track:
- description:
- - Install route depending on tracked item with tracked object number.
- - Tracking does not support multicast
- - Refer to vendor documentation for valid values.
- type: int
- running_config:
- description:
- - The module, by default, will connect to the remote device and
- retrieve the current running-config to use as a base for comparing
- against the contents of source. There are times when it is not
- desirable to have the task get the current running-config for
- every task in a playbook. The I(running_config) argument allows the
- implementer to pass in the configuration to use as the base
- config for comparison. This value of this option should be the
- output received from device by executing command
- C(show configuration commands | grep 'static route')
- type: str
- state:
- description:
- - The state the configuration should be left in
- - The states I(rendered), I(gathered) and I(parsed) does not perform any change on the
- device.
- - The state I(rendered) will transform the configuration in C(config) option to platform
- specific CLI commands which will be returned in the I(rendered) key within the result.
- For state I(rendered) active connection to remote host is not required.
- - The state I(gathered) will fetch the running configuration from device and transform
- it into structured data in the format as per the resource module argspec and the
- value is returned in the I(gathered) key within the result.
- - The state I(parsed) reads the configuration from C(running_config) option and transforms
- it into JSON format as per the resource module parameters and the value is returned in
- the I(parsed) key within the result. The value of C(running_config) option should be the
- same format as the output of command I(show running-config | include ip route|ipv6 route)
- executed on device. For state I(parsed) active connection to remote host is not required.
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- - gathered
- - rendered
- - parsed
- default: merged
-"""
-
-EXAMPLES = """
----
-
-# Using merged
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-
-- name: Merge provided configuration with device configuration
- ios_static_routes:
- config:
- - vrf: blue
- address_families:
- - afi: ipv4
- routes:
- - dest: 192.0.2.0/24
- next_hops:
- - forward_router_address: 192.0.2.1
- name: merged_blue
- tag: 50
- track: 150
- - address_families:
- - afi: ipv4
- routes:
- - dest: 198.51.100.0/24
- next_hops:
- - forward_router_address: 198.51.101.1
- name: merged_route_1
- distance_metric: 110
- tag: 40
- multicast: True
- - forward_router_address: 198.51.101.2
- name: merged_route_2
- distance_metric: 30
- - forward_router_address: 198.51.101.3
- name: merged_route_3
- - afi: ipv6
- routes:
- - dest: 2001:DB8:0:3::/64
- next_hops:
- - forward_router_address: 2001:DB8:0:3::2
- name: merged_v6
- tag: 105
- state: merged
-
-# Commands fired:
-# ---------------
-# ip route vrf blue 192.0.2.0 255.255.255.0 10.0.0.8 name merged_blue track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name merged_route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name merged_v6 tag 105
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name merged_route_1 multicast
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
-
-# Using replaced
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Replace provided configuration with device configuration
- ios_static_routes:
- config:
- - address_families:
- - afi: ipv4
- routes:
- - dest: 198.51.100.0/24
- next_hops:
- - forward_router_address: 198.51.101.1
- name: replaced_route
- distance_metric: 175
- tag: 70
- multicast: True
- state: replaced
-
-# Commands fired:
-# ---------------
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 name replaced_route track 150 tag 70
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 name replaced_route track 150 tag 70
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
-
-# Using overridden
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Override provided configuration with device configuration
- ios_static_routes:
- config:
- - vrf: blue
- address_families:
- - afi: ipv4
- routes:
- - dest: 192.0.2.0/24
- next_hops:
- - forward_router_address: 192.0.2.1
- name: override_vrf
- tag: 50
- track: 150
- state: overridden
-
-# Commands fired:
-# ---------------
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 198.51.101.8 name test_vrf track 150 tag 50
-# no ipv6 route FD5D:12C9:2201:1::/64 FD5D:12C9:2202::2 name test_v6 tag 105
-# ip route vrf blue 192.0.2.0 255.255.255.0 198.51.101.4 name override_vrf track 150 tag 50
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name override_vrf track 150
-
-# Using Deleted
-
-# Example 1:
-# ----------
-# To delete the exact static routes, with all the static routes explicitly mentioned in want
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Delete provided configuration from the device configuration
- ios_static_routes:
- config:
- - vrf: ansible_temp_vrf
- address_families:
- - afi: ipv4
- routes:
- - dest: 192.0.2.0/24
- next_hops:
- - forward_router_address: 192.0.2.1
- name: test_vrf
- tag: 50
- track: 150
- - address_families:
- - afi: ipv4
- routes:
- - dest: 198.51.100.0/24
- next_hops:
- - forward_router_address: 198.51.101.1
- name: route_1
- distance_metric: 110
- tag: 40
- multicast: True
- - forward_router_address: 198.51.101.2
- name: route_2
- distance_metric: 30
- - forward_router_address: 198.51.101.3
- name: route_3
- - afi: ipv6
- routes:
- - dest: 2001:DB8:0:3::/64
- next_hops:
- - forward_router_address: 2001:DB8:0:3::2
- name: test_v6
- tag: 105
- state: deleted
-
-# Commands fired:
-# ---------------
-# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 198.51.101.8 name test_vrf track 150 tag 50
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# no ipv6 route FD5D:12C9:2201:1::/64 FD5D:12C9:2202::2 name test_v6 tag 105
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-
-# Example 2:
-# ----------
-# To delete the destination specific static routes
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Delete provided configuration from the device configuration
- ios_static_routes:
- config:
- - address_families:
- - afi: ipv4
- routes:
- - dest: 198.51.100.0/24
- state: deleted
-
-# Commands fired:
-# ---------------
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
-
-
-# Example 3:
-# ----------
-# To delete the vrf specific static routes
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Delete provided configuration from the device configuration
- ios_static_routes:
- config:
- - vrf: ansible_temp_vrf
- state: deleted
-
-# Commands fired:
-# ---------------
-# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Delete ALL configured IOS static routes
- ios_static_routes:
- state: deleted
-
-# Commands fired:
-# ---------------
-# no ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
-# no ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
-
-# After state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-#
-
-# Using gathered
-
-# Before state:
-# -------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-- name: Gather listed static routes with provided configurations
- ios_static_routes:
- config:
- state: gathered
-
-# Module Execution Result:
-# ------------------------
-#
-# "gathered": [
-# {
-# "address_families": [
-# {
-# "afi": "ipv4",
-# "routes": [
-# {
-# "dest": "192.0.2.0/24",
-# "next_hops": [
-# {
-# "forward_router_address": "192.0.2.1",
-# "name": "test_vrf",
-# "tag": 50,
-# "track": 150
-# }
-# ]
-# }
-# ]
-# }
-# ],
-# "vrf": "ansible_temp_vrf"
-# },
-# {
-# "address_families": [
-# {
-# "afi": "ipv6",
-# "routes": [
-# {
-# "dest": "2001:DB8:0:3::/64",
-# "next_hops": [
-# {
-# "forward_router_address": "2001:DB8:0:3::2",
-# "name": "test_v6",
-# "tag": 105
-# }
-# ]
-# }
-# ]
-# },
-# {
-# "afi": "ipv4",
-# "routes": [
-# {
-# "dest": "198.51.100.0/24",
-# "next_hops": [
-# {
-# "distance_metric": 110,
-# "forward_router_address": "198.51.101.1",
-# "multicast": true,
-# "name": "route_1",
-# "tag": 40
-# },
-# {
-# "distance_metric": 30,
-# "forward_router_address": "198.51.101.2",
-# "name": "route_2"
-# },
-# {
-# "forward_router_address": "198.51.101.3",
-# "name": "route_3"
-# }
-# ]
-# }
-# ]
-# }
-# ]
-# }
-# ]
-
-# After state:
-# ------------
-#
-# vios#show running-config | include ip route|ipv6 route
-# ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50
-# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40
-# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
-# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
-# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105
-
-# Using rendered
-
-- name: Render the commands for provided configuration
- ios_static_routes:
- config:
- - vrf: ansible_temp_vrf
- address_families:
- - afi: ipv4
- routes:
- - dest: 192.0.2.0/24
- next_hops:
- - forward_router_address: 192.0.2.1
- name: test_vrf
- tag: 50
- track: 150
- - address_families:
- - afi: ipv4
- routes:
- - dest: 198.51.100.0/24
- next_hops:
- - forward_router_address: 198.51.101.1
- name: route_1
- distance_metric: 110
- tag: 40
- multicast: True
- - forward_router_address: 198.51.101.2
- name: route_2
- distance_metric: 30
- - forward_router_address: 198.51.101.3
- name: route_3
- - afi: ipv6
- routes:
- - dest: 2001:DB8:0:3::/64
- next_hops:
- - forward_router_address: 2001:DB8:0:3::2
- name: test_v6
- tag: 105
- state: rendered
-
-# Module Execution Result:
-# ------------------------
-#
-# "rendered": [
-# "ip route vrf ansible_temp_vrf 192.0.2.0 255.255.255.0 192.0.2.1 name test_vrf track 150 tag 50",
-# "ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 multicast name route_1 tag 40",
-# "ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2",
-# "ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3",
-# "ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 name test_v6 tag 105"
-# ]
-
-"""
-
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: The configuration returned will always be in the same format of the parameters above.
-commands:
- description: The set of commands pushed to the remote device
- returned: always
- type: list
- sample: ['ip route vrf test 172.31.10.0 255.255.255.0 10.10.10.2 name new_test multicast']
-rendered:
- description: The set of CLI commands generated from the value in C(config) option
- returned: When C(state) is I(rendered)
- type: list
- sample: ['interface Ethernet1/1', 'mtu 1800']
-gathered:
- description:
- - The configuration as structured data transformed for the running configuration
- fetched from remote host
- returned: When C(state) is I(gathered)
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-parsed:
- description:
- - The configuration as structured data transformed for the value of
- C(running_config) option
- returned: When C(state) is I(parsed)
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.static_routes.static_routes import Static_RoutesArgs
-from ansible.module_utils.network.ios.config.static_routes.static_routes import Static_Routes
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',)),
- ('state', 'rendered', ('config',)),
- ('state', 'parsed', ('running_config',))]
- mutually_exclusive = [('config', 'running_config')]
-
- module = AnsibleModule(argument_spec=Static_RoutesArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True,
- mutually_exclusive=mutually_exclusive)
-
- result = Static_Routes(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_system.py b/lib/ansible/modules/network/ios/ios_system.py
deleted file mode 100644
index cb1d7824c6..0000000000
--- a/lib/ansible/modules/network/ios/ios_system.py
+++ /dev/null
@@ -1,380 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_system
-version_added: "2.3"
-author: "Peter Sprygada (@privateip)"
-short_description: Manage the system attributes on Cisco IOS devices
-description:
- - This module provides declarative management of node system attributes
- on Cisco IOS devices. It provides an option to configure host system
- parameters or remove those parameters from the device active
- configuration.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- hostname:
- description:
- - Configure the device hostname parameter. This option takes an ASCII string value.
- domain_name:
- description:
- - Configure the IP domain name
- on the remote device to the provided value. Value
- should be in the dotted name form and will be
- appended to the C(hostname) to create a fully-qualified
- domain name.
- domain_search:
- description:
- - Provides the list of domain suffixes to
- append to the hostname for the purpose of doing name resolution.
- This argument accepts a list of names and will be reconciled
- with the current active configuration on the running node.
- lookup_source:
- description:
- - Provides one or more source
- interfaces to use for performing DNS lookups. The interface
- provided in C(lookup_source) must be a valid interface configured
- on the device.
- lookup_enabled:
- description:
- - Administrative control
- for enabling or disabling DNS lookups. When this argument is
- set to True, lookups are performed and when it is set to False,
- lookups are not performed.
- type: bool
- name_servers:
- description:
- - List of DNS name servers by IP address to use to perform name resolution
- lookups. This argument accepts either a list of DNS servers See
- examples.
- state:
- description:
- - State of the configuration
- values in the device's current active configuration. When set
- to I(present), the values should be configured in the device active
- configuration and when set to I(absent) the values should not be
- in the device active configuration
- default: present
- choices: ['present', 'absent']
-"""
-
-EXAMPLES = """
-- name: configure hostname and domain name
- ios_system:
- hostname: ios01
- domain_name: test.example.com
- domain_search:
- - ansible.com
- - redhat.com
- - cisco.com
-
-- name: remove configuration
- ios_system:
- state: absent
-
-- name: configure DNS lookup sources
- ios_system:
- lookup_source: MgmtEth0/0/CPU0/0
- lookup_enabled: yes
-
-- name: configure name servers
- ios_system:
- name_servers:
- - 8.8.8.8
- - 8.8.4.4
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - hostname ios01
- - ip domain name test.example.com
-"""
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.network.common.utils import ComplexList
-
-_CONFIGURED_VRFS = None
-
-
-def has_vrf(module, vrf):
- global _CONFIGURED_VRFS
- if _CONFIGURED_VRFS is not None:
- return vrf in _CONFIGURED_VRFS
- config = get_config(module)
- _CONFIGURED_VRFS = re.findall(r'vrf definition (\S+)', config)
- return vrf in _CONFIGURED_VRFS
-
-
-def requires_vrf(module, vrf):
- if not has_vrf(module, vrf):
- module.fail_json(msg='vrf %s is not configured' % vrf)
-
-
-def diff_list(want, have):
- adds = [w for w in want if w not in have]
- removes = [h for h in have if h not in want]
- return (adds, removes)
-
-
-def map_obj_to_commands(want, have, module):
- commands = list()
- state = module.params['state']
-
- def needs_update(x):
- return want.get(x) is not None and (want.get(x) != have.get(x))
-
- if state == 'absent':
- if have['hostname'] != 'Router':
- commands.append('no hostname')
-
- if have['lookup_source']:
- commands.append('no ip domain lookup source-interface %s' % have['lookup_source'])
-
- if have['lookup_enabled'] is False:
- commands.append('ip domain lookup')
-
- vrfs = set()
- for item in have['domain_name']:
- if item['vrf'] and item['vrf'] not in vrfs:
- vrfs.add(item['vrf'])
- commands.append('no ip domain name vrf %s' % item['vrf'])
- elif None not in vrfs:
- vrfs.add(None)
- commands.append('no ip domain name')
-
- vrfs = set()
- for item in have['domain_search']:
- if item['vrf'] and item['vrf'] not in vrfs:
- vrfs.add(item['vrf'])
- commands.append('no ip domain list vrf %s' % item['vrf'])
- elif None not in vrfs:
- vrfs.add(None)
- commands.append('no ip domain list')
-
- vrfs = set()
- for item in have['name_servers']:
- if item['vrf'] and item['vrf'] not in vrfs:
- vrfs.add(item['vrf'])
- commands.append('no ip name-server vrf %s' % item['vrf'])
- elif None not in vrfs:
- vrfs.add(None)
- commands.append('no ip name-server')
-
- elif state == 'present':
- if needs_update('hostname'):
- commands.append('hostname %s' % want['hostname'])
-
- if needs_update('lookup_source'):
- commands.append('ip domain lookup source-interface %s' % want['lookup_source'])
-
- if needs_update('lookup_enabled'):
- cmd = 'ip domain lookup'
- if want['lookup_enabled'] is False:
- cmd = 'no %s' % cmd
- commands.append(cmd)
-
- if want['domain_name']:
- adds, removes = diff_list(want['domain_name'], have['domain_name'])
- for item in removes:
- if item['vrf']:
- commands.append('no ip domain name vrf %s %s' % (item['vrf'], item['name']))
- else:
- commands.append('no ip domain name %s' % item['name'])
- for item in adds:
- if item['vrf']:
- requires_vrf(module, item['vrf'])
- commands.append('ip domain name vrf %s %s' % (item['vrf'], item['name']))
- else:
- commands.append('ip domain name %s' % item['name'])
-
- if want['domain_search']:
- adds, removes = diff_list(want['domain_search'], have['domain_search'])
- for item in removes:
- if item['vrf']:
- commands.append('no ip domain list vrf %s %s' % (item['vrf'], item['name']))
- else:
- commands.append('no ip domain list %s' % item['name'])
- for item in adds:
- if item['vrf']:
- requires_vrf(module, item['vrf'])
- commands.append('ip domain list vrf %s %s' % (item['vrf'], item['name']))
- else:
- commands.append('ip domain list %s' % item['name'])
-
- if want['name_servers']:
- adds, removes = diff_list(want['name_servers'], have['name_servers'])
- for item in removes:
- if item['vrf']:
- commands.append('no ip name-server vrf %s %s' % (item['vrf'], item['server']))
- else:
- commands.append('no ip name-server %s' % item['server'])
- for item in adds:
- if item['vrf']:
- requires_vrf(module, item['vrf'])
- commands.append('ip name-server vrf %s %s' % (item['vrf'], item['server']))
- else:
- commands.append('ip name-server %s' % item['server'])
-
- return commands
-
-
-def parse_hostname(config):
- match = re.search(r'^hostname (\S+)', config, re.M)
- return match.group(1)
-
-
-def parse_domain_name(config):
- match = re.findall(r'^ip domain[- ]name (?:vrf (\S+) )*(\S+)', config, re.M)
- matches = list()
- for vrf, name in match:
- if not vrf:
- vrf = None
- matches.append({'name': name, 'vrf': vrf})
- return matches
-
-
-def parse_domain_search(config):
- match = re.findall(r'^ip domain[- ]list (?:vrf (\S+) )*(\S+)', config, re.M)
- matches = list()
- for vrf, name in match:
- if not vrf:
- vrf = None
- matches.append({'name': name, 'vrf': vrf})
- return matches
-
-
-def parse_name_servers(config):
- match = re.findall(r'^ip name-server (?:vrf (\S+) )*(.*)', config, re.M)
- matches = list()
- for vrf, servers in match:
- if not vrf:
- vrf = None
- for server in servers.split():
- matches.append({'server': server, 'vrf': vrf})
- return matches
-
-
-def parse_lookup_source(config):
- match = re.search(r'ip domain[- ]lookup source-interface (\S+)', config, re.M)
- if match:
- return match.group(1)
-
-
-def map_config_to_obj(module):
- config = get_config(module)
- return {
- 'hostname': parse_hostname(config),
- 'domain_name': parse_domain_name(config),
- 'domain_search': parse_domain_search(config),
- 'lookup_source': parse_lookup_source(config),
- 'lookup_enabled': 'no ip domain lookup' not in config and 'no ip domain-lookup' not in config,
- 'name_servers': parse_name_servers(config)
- }
-
-
-def map_params_to_obj(module):
- obj = {
- 'hostname': module.params['hostname'],
- 'lookup_source': module.params['lookup_source'],
- 'lookup_enabled': module.params['lookup_enabled'],
- }
-
- domain_name = ComplexList(dict(
- name=dict(key=True),
- vrf=dict()
- ), module)
-
- domain_search = ComplexList(dict(
- name=dict(key=True),
- vrf=dict()
- ), module)
-
- name_servers = ComplexList(dict(
- server=dict(key=True),
- vrf=dict()
- ), module)
-
- for arg, cast in [('domain_name', domain_name),
- ('domain_search', domain_search),
- ('name_servers', name_servers)]:
-
- if module.params[arg]:
- obj[arg] = cast(module.params[arg])
- else:
- obj[arg] = None
-
- return obj
-
-
-def main():
- """ Main entry point for Ansible module execution
- """
- argument_spec = dict(
- hostname=dict(),
-
- domain_name=dict(type='list'),
- domain_search=dict(type='list'),
- name_servers=dict(type='list'),
-
- lookup_source=dict(),
- lookup_enabled=dict(type='bool'),
-
- state=dict(choices=['present', 'absent'], default='present')
- )
-
- argument_spec.update(ios_argument_spec)
-
- module = AnsibleModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- result = {'changed': False}
-
- warnings = list()
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands(want, have, module)
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == "__main__":
- main()
diff --git a/lib/ansible/modules/network/ios/ios_user.py b/lib/ansible/modules/network/ios/ios_user.py
deleted file mode 100644
index 37afe741dd..0000000000
--- a/lib/ansible/modules/network/ios/ios_user.py
+++ /dev/null
@@ -1,533 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2017, Ansible by Red Hat, inc
-#
-# This file is part of Ansible by Red Hat
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-DOCUMENTATION = """
----
-module: ios_user
-version_added: "2.4"
-author: "Trishna Guha (@trishnaguha)"
-short_description: Manage the aggregate of local users on Cisco IOS device
-description:
- - This module provides declarative management of the local usernames
- configured on network devices. It allows playbooks to manage
- either individual usernames or the aggregate of usernames in the
- current running config. It also supports purging usernames from the
- configuration that are not explicitly defined.
-notes:
- - Tested against IOS 15.6
-options:
- aggregate:
- description:
- - The set of username objects to be configured on the remote
- Cisco IOS device. The list entries can either be the username
- or a hash of username and properties. This argument is mutually
- exclusive with the C(name) argument.
- aliases: ['users', 'collection']
- name:
- description:
- - The username to be configured on the Cisco IOS device.
- This argument accepts a string value and is mutually exclusive
- with the C(aggregate) argument.
- Please note that this option is not same as C(provider username).
- configured_password:
- description:
- - The password to be configured on the Cisco IOS device. The
- password needs to be provided in clear and it will be encrypted
- on the device.
- Please note that this option is not same as C(provider password).
- update_password:
- description:
- - Since passwords are encrypted in the device running config, this
- argument will instruct the module when to change the password. When
- set to C(always), the password will always be updated in the device
- and when set to C(on_create) the password will be updated only if
- the username is created.
- default: always
- choices: ['on_create', 'always']
- password_type:
- description:
- - This argument determines whether a 'password' or 'secret' will be
- configured.
- default: secret
- choices: ['secret', 'password']
- version_added: "2.8"
- hashed_password:
- description:
- - This option allows configuring hashed passwords on Cisco IOS devices.
- suboptions:
- type:
- description:
- - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.)
- - For this to work, the device needs to support the desired hash type
- type: int
- required: True
- value:
- description:
- - The actual hashed password to be configured on the device
- required: True
- version_added: "2.8"
- privilege:
- description:
- - The C(privilege) argument configures the privilege level of the
- user when logged into the system. This argument accepts integer
- values in the range of 1 to 15.
- view:
- description:
- - Configures the view for the username in the
- device running configuration. The argument accepts a string value
- defining the view name. This argument does not check if the view
- has been configured on the device.
- aliases: ['role']
- sshkey:
- description:
- - Specifies one or more SSH public key(s) to configure
- for the given username.
- - This argument accepts a valid SSH key value.
- version_added: "2.7"
- nopassword:
- description:
- - Defines the username without assigning
- a password. This will allow the user to login to the system
- without being authenticated by a password.
- type: bool
- purge:
- description:
- - Instructs the module to consider the
- resource definition absolute. It will remove any previously
- configured usernames on the device with the exception of the
- `admin` user (the current defined set of users).
- type: bool
- default: false
- state:
- description:
- - Configures the state of the username definition
- as it relates to the device operational configuration. When set
- to I(present), the username(s) should be configured in the device active
- configuration and when set to I(absent) the username(s) should not be
- in the device active configuration
- default: present
- choices: ['present', 'absent']
-extends_documentation_fragment: ios
-"""
-
-EXAMPLES = """
-- name: create a new user
- ios_user:
- name: ansible
- nopassword: True
- sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- state: present
-
-- name: create a new user with multiple keys
- ios_user:
- name: ansible
- sshkey:
- - "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- - "{{ lookup('file', '~/path/to/public_key') }}"
- state: present
-
-- name: remove all users except admin
- ios_user:
- purge: yes
-
-- name: remove all users except admin and these listed users
- ios_user:
- aggregate:
- - name: testuser1
- - name: testuser2
- - name: testuser3
- purge: yes
-
-- name: set multiple users to privilege level 15
- ios_user:
- aggregate:
- - name: netop
- - name: netend
- privilege: 15
- state: present
-
-- name: set user view/role
- ios_user:
- name: netop
- view: network-operator
- state: present
-
-- name: Change Password for User netop
- ios_user:
- name: netop
- configured_password: "{{ new_password }}"
- update_password: always
- state: present
-
-- name: Aggregate of users
- ios_user:
- aggregate:
- - name: ansibletest2
- - name: ansibletest3
- view: network-admin
-
-- name: Add a user specifying password type
- ios_user:
- name: ansibletest4
- configured_password: "{{ new_password }}"
- password_type: password
-
-- name: Add a user with MD5 hashed password
- ios_user:
- name: ansibletest5
- hashed_password:
- type: 5
- value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/
-
-- name: Delete users with aggregate
- ios_user:
- aggregate:
- - name: ansibletest1
- - name: ansibletest2
- - name: ansibletest3
- state: absent
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - username ansible secret password
- - username admin secret admin
-"""
-import base64
-import hashlib
-import re
-from copy import deepcopy
-from functools import partial
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import remove_default_spec
-from ansible.module_utils.network.ios.ios import get_config, load_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.six import iteritems
-
-
-def validate_privilege(value, module):
- if value and not 1 <= value <= 15:
- module.fail_json(msg='privilege must be between 1 and 15, got %s' % value)
-
-
-def user_del_cmd(username):
- return {
- 'command': 'no username %s' % username,
- 'prompt': 'This operation will remove all username related configurations with same name',
- 'answer': 'y',
- 'newline': False,
- }
-
-
-def sshkey_fingerprint(sshkey):
- # IOS will accept a MD5 fingerprint of the public key
- # and is easier to configure in a single line
- # we calculate this fingerprint here
- if not sshkey:
- return None
- if ' ' in sshkey:
- # ssh-rsa AAA...== comment
- keyparts = sshkey.split(' ')
- keyparts[1] = hashlib.md5(base64.b64decode(keyparts[1])).hexdigest().upper()
- return ' '.join(keyparts)
- else:
- # just the key, assume rsa type
- return 'ssh-rsa %s' % hashlib.md5(base64.b64decode(sshkey)).hexdigest().upper()
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
- update_password = module.params['update_password']
- password_type = module.params['password_type']
-
- def needs_update(want, have, x):
- return want.get(x) and (want.get(x) != have.get(x))
-
- def add(command, want, x):
- command.append('username %s %s' % (want['name'], x))
-
- def add_hashed_password(command, want, x):
- command.append('username %s secret %s %s' % (want['name'], x.get('type'),
- x.get('value')))
-
- def add_ssh(command, want, x=None):
- command.append('ip ssh pubkey-chain')
- if x:
- command.append('username %s' % want['name'])
- for item in x:
- command.append('key-hash %s' % item)
- command.append('exit')
- else:
- command.append('no username %s' % want['name'])
- command.append('exit')
-
- for update in updates:
- want, have = update
-
- if want['state'] == 'absent':
- if have['sshkey']:
- add_ssh(commands, want)
- else:
- commands.append(user_del_cmd(want['name']))
-
- if needs_update(want, have, 'view'):
- add(commands, want, 'view %s' % want['view'])
-
- if needs_update(want, have, 'privilege'):
- add(commands, want, 'privilege %s' % want['privilege'])
-
- if needs_update(want, have, 'sshkey'):
- add_ssh(commands, want, want['sshkey'])
-
- if needs_update(want, have, 'configured_password'):
- if update_password == 'always' or not have:
- if have and password_type != have['password_type']:
- module.fail_json(msg='Can not have both a user password and a user secret.' +
- ' Please choose one or the other.')
- add(commands, want, '%s %s' % (password_type, want['configured_password']))
-
- if needs_update(want, have, 'hashed_password'):
- add_hashed_password(commands, want, want['hashed_password'])
-
- if needs_update(want, have, 'nopassword'):
- if want['nopassword']:
- add(commands, want, 'nopassword')
- else:
- add(commands, want, user_del_cmd(want['name']))
-
- return commands
-
-
-def parse_view(data):
- match = re.search(r'view (\S+)', data, re.M)
- if match:
- return match.group(1)
-
-
-def parse_sshkey(data, user):
- sshregex = r'username %s(\n\s+key-hash .+$)+' % user
- sshcfg = re.search(sshregex, data, re.M)
- key_list = []
- if sshcfg:
- match = re.findall(r'key-hash (\S+ \S+(?: .+)?)$', sshcfg.group(), re.M)
- if match:
- key_list = match
- return key_list
-
-
-def parse_privilege(data):
- match = re.search(r'privilege (\S+)', data, re.M)
- if match:
- return int(match.group(1))
-
-
-def parse_password_type(data):
- type = None
- if data and data.split()[-3] in ['password', 'secret']:
- type = data.split()[-3]
- return type
-
-
-def map_config_to_obj(module):
- data = get_config(module, flags=['| section username'])
-
- match = re.findall(r'(?:^(?:u|\s{2}u))sername (\S+)', data, re.M)
- if not match:
- return list()
-
- instances = list()
-
- for user in set(match):
- regex = r'username %s .+$' % user
- cfg = re.findall(regex, data, re.M)
- cfg = '\n'.join(cfg)
- obj = {
- 'name': user,
- 'state': 'present',
- 'nopassword': 'nopassword' in cfg,
- 'configured_password': None,
- 'hashed_password': None,
- 'password_type': parse_password_type(cfg),
- 'sshkey': parse_sshkey(data, user),
- 'privilege': parse_privilege(cfg),
- 'view': parse_view(cfg)
- }
- instances.append(obj)
-
- return instances
-
-
-def get_param_value(key, item, module):
- # if key doesn't exist in the item, get it from module.params
- if not item.get(key):
- value = module.params[key]
-
- # if key does exist, do a type check on it to validate it
- else:
- value_type = module.argument_spec[key].get('type', 'str')
- type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
- type_checker(item[key])
- value = item[key]
-
- # validate the param value (if validator func exists)
- validator = globals().get('validate_%s' % key)
- if all((value, validator)):
- validator(value, module)
-
- return value
-
-
-def map_params_to_obj(module):
- users = module.params['aggregate']
- if not users:
- if not module.params['name'] and module.params['purge']:
- return list()
- elif not module.params['name']:
- module.fail_json(msg='username is required')
- else:
- aggregate = [{'name': module.params['name']}]
- else:
- aggregate = list()
- for item in users:
- if not isinstance(item, dict):
- aggregate.append({'name': item})
- elif 'name' not in item:
- module.fail_json(msg='name is required')
- else:
- aggregate.append(item)
-
- objects = list()
-
- for item in aggregate:
- get_value = partial(get_param_value, item=item, module=module)
- item['configured_password'] = get_value('configured_password')
- item['hashed_password'] = get_value('hashed_password')
- item['nopassword'] = get_value('nopassword')
- item['privilege'] = get_value('privilege')
- item['view'] = get_value('view')
- item['sshkey'] = render_key_list(get_value('sshkey'))
- item['state'] = get_value('state')
- objects.append(item)
-
- return objects
-
-
-def render_key_list(ssh_keys):
- key_list = []
- if ssh_keys:
- for item in ssh_keys:
- key_list.append(sshkey_fingerprint(item))
- return key_list
-
-
-def update_objects(want, have):
- updates = list()
- for entry in want:
- item = next((i for i in have if i['name'] == entry['name']), None)
- if all((item is None, entry['state'] == 'present')):
- updates.append((entry, {}))
- elif item:
- for key, value in iteritems(entry):
- if value and value != item[key]:
- updates.append((entry, item))
- return updates
-
-
-def main():
- """ main entry point for module execution
- """
- hashed_password_spec = dict(
- type=dict(type='int', required=True),
- value=dict(no_log=True, required=True)
- )
-
- element_spec = dict(
- name=dict(),
-
- configured_password=dict(no_log=True),
- hashed_password=dict(no_log=True, type='dict', options=hashed_password_spec),
- nopassword=dict(type='bool'),
- update_password=dict(default='always', choices=['on_create', 'always']),
- password_type=dict(default='secret', choices=['secret', 'password']),
-
- privilege=dict(type='int'),
- view=dict(aliases=['role']),
-
- sshkey=dict(type='list'),
-
- state=dict(default='present', choices=['present', 'absent'])
- )
- aggregate_spec = deepcopy(element_spec)
- aggregate_spec['name'] = dict(required=True)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(type='list', elements='dict', options=aggregate_spec, aliases=['users', 'collection']),
- purge=dict(type='bool', default=False)
- )
-
- argument_spec.update(element_spec)
- argument_spec.update(ios_argument_spec)
-
- mutually_exclusive = [('name', 'aggregate'), ('nopassword', 'hashed_password', 'configured_password')]
-
- module = AnsibleModule(argument_spec=argument_spec,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- warnings = list()
- result = {'changed': False, 'warnings': warnings}
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
-
- commands = map_obj_to_commands(update_objects(want, have), module)
-
- if module.params['purge']:
- want_users = [x['name'] for x in want]
- have_users = [x['name'] for x in have]
- for item in set(have_users).difference(want_users):
- if item != 'admin':
- commands.append(user_del_cmd(item))
-
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_vlans.py b/lib/ansible/modules/network/ios/ios_vlans.py
deleted file mode 100644
index 7de87dbb52..0000000000
--- a/lib/ansible/modules/network/ios/ios_vlans.py
+++ /dev/null
@@ -1,464 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-#############################################
-# WARNING #
-#############################################
-#
-# This file is auto generated by the resource
-# module builder playbook.
-#
-# Do not edit this file manually.
-#
-# Changes to this file will be over written
-# by the resource module builder.
-#
-# Changes should be made in the model used to
-# generate this file or in the resource module
-# builder template.
-#
-#############################################
-
-"""
-The module file for ios_vlans
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'
-}
-
-DOCUMENTATION = """
-module: ios_vlans
-version_added: 2.9
-short_description: Manage VLANs on Cisco IOS devices.
-description: This module provides declarative management of VLANs on Cisco IOS network devices.
-author: Sumit Jaiswal (@justjais)
-notes:
- - Tested against Cisco IOSv Version 15.2 on VIRL
- - This module works with connection C(network_cli).
- See L(IOS Platform Options,../network/user_guide/platform_ios.html).
-options:
- config:
- description: A dictionary of VLANs options
- type: list
- elements: dict
- suboptions:
- name:
- description:
- - Ascii name of the VLAN.
- - NOTE, I(name) should not be named/appended with I(default) as it is reserved for device default vlans.
- type: str
- vlan_id:
- description:
- - ID of the VLAN. Range 1-4094
- type: int
- required: True
- mtu:
- description:
- - VLAN Maximum Transmission Unit.
- - Refer to vendor documentation for valid values.
- type: int
- state:
- description:
- - Operational state of the VLAN
- type: str
- choices:
- - active
- - suspend
- remote_span:
- description:
- - Configure as Remote SPAN VLAN
- type: bool
- shutdown:
- description:
- - Shutdown VLAN switching.
- type: str
- choices:
- - enabled
- - disabled
- state:
- description:
- - The state of the configuration after module completion
- type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- default: merged
-"""
-EXAMPLES = """
----
-# Using merged
-
-# Before state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-
-- name: Merge provided configuration with device configuration
- ios_vlans:
- config:
- - name: Vlan_10
- vlan_id: 10
- state: active
- shutdown: disabled
- remote_span: 10
- - name: Vlan_20
- vlan_id: 20
- mtu: 610
- state: active
- shutdown: enabled
- - name: Vlan_30
- vlan_id: 30
- state: suspend
- shutdown: enabled
- state: merged
-
-# After state:
-# ------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 vlan_20 act/lshut
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 610 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-# Using overridden
-
-# Before state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 vlan_20 act/lshut
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 610 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-- name: Override device configuration of all VLANs with provided configuration
- ios_vlans:
- config:
- - name: Vlan_10
- vlan_id: 10
- mtu: 1000
- state: overridden
-
-# After state:
-# ------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 10 Vlan_10 active
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 10 enet 100010 1000 - - - - - 0 0
-
-# Using replaced
-
-# Before state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 vlan_20 act/lshut
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 610 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-- name: Replaces device configuration of listed VLANs with provided configuration
- ios_vlans:
- config:
- - vlan_id: 20
- name: Test_VLAN20
- mtu: 700
- shutdown: disabled
- - vlan_id: 30
- name: Test_VLAN30
- mtu: 1000
- state: replaced
-
-# After state:
-# ------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 Test_VLAN20 active
-# 30 Test_VLAN30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 700 - - - - - 0 0
-# 30 enet 100030 1000 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-# Using deleted
-
-# Before state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 vlan_20 act/lshut
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 610 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-- name: Delete attributes of given VLANs
- ios_vlans:
- config:
- - vlan_id: 10
- - vlan_id: 20
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-
-# Using Deleted without any config passed
-#"(NOTE: This will delete all of configured vlans attributes)"
-
-# Before state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 10 vlan_10 active
-# 20 vlan_20 act/lshut
-# 30 vlan_30 sus/lshut
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 10 enet 100010 1500 - - - - - 0 0
-# 20 enet 100020 610 - - - - - 0 0
-# 30 enet 100030 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-#
-# Remote SPAN VLANs
-# ------------------------------------------------------------------------------
-# 10
-
-- name: Delete attributes of ALL VLANs
- ios_vlans:
- state: deleted
-
-# After state:
-# -------------
-#
-# vios#show vlan
-# VLAN Name Status Ports
-# ---- -------------------------------- --------- -------------------------------
-# 1 default active Gi0/1, Gi0/2
-# 1002 fddi-default act/unsup
-# 1003 token-ring-default act/unsup
-# 1004 fddinet-default act/unsup
-# 1005 trnet-default act/unsup
-#
-# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
-# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
-# 1 enet 100001 1500 - - - - - 0 0
-# 1002 fddi 101002 1500 - - - - - 0 0
-# 1003 tr 101003 1500 - - - - - 0 0
-# 1004 fdnet 101004 1500 - - - ieee - 0 0
-# 1005 trnet 101005 1500 - - - ibm - 0 0
-
-"""
-RETURN = """
-before:
- description: The configuration as structured data prior to module invocation.
- returned: always
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-after:
- description: The configuration as structured data after module completion.
- returned: when changed
- type: list
- sample: >
- The configuration returned will always be in the same format
- of the parameters above.
-commands:
- description: The set of commands pushed to the remote device.
- returned: always
- type: list
- sample: ['vlan 20', 'name vlan_20', 'mtu 600', 'remote-span']
-"""
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.ios.argspec.vlans.vlans import VlansArgs
-from ansible.module_utils.network.ios.config.vlans.vlans import Vlans
-
-
-def main():
- """
- Main entry point for module execution
-
- :returns: the result form module invocation
- """
- required_if = [('state', 'merged', ('config',)),
- ('state', 'replaced', ('config',)),
- ('state', 'overridden', ('config',))]
-
- module = AnsibleModule(argument_spec=VlansArgs.argument_spec,
- required_if=required_if,
- supports_check_mode=True)
-
- result = Vlans(module).execute_module()
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/ios/ios_vrf.py b/lib/ansible/modules/network/ios/ios_vrf.py
deleted file mode 100644
index 1ac01e1339..0000000000
--- a/lib/ansible/modules/network/ios/ios_vrf.py
+++ /dev/null
@@ -1,719 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'network'}
-
-
-DOCUMENTATION = """
----
-module: ios_vrf
-version_added: "2.3"
-author: "Peter Sprygada (@privateip)"
-short_description: Manage the collection of VRF definitions on Cisco IOS devices
-description:
- - This module provides declarative management of VRF definitions on
- Cisco IOS devices. It allows playbooks to manage individual or
- the entire VRF collection. It also supports purging VRF definitions from
- the configuration that are not explicitly defined.
-extends_documentation_fragment: ios
-notes:
- - Tested against IOS 15.6
-options:
- vrfs:
- description:
- - The set of VRF definition objects to be configured on the remote
- IOS device. Ths list entries can either be the VRF name or a hash
- of VRF definitions and attributes. This argument is mutually
- exclusive with the C(name) argument.
- name:
- description:
- - The name of the VRF definition to be managed on the remote IOS
- device. The VRF definition name is an ASCII string name used
- to uniquely identify the VRF. This argument is mutually exclusive
- with the C(vrfs) argument
- description:
- description:
- - Provides a short description of the VRF definition in the
- current active configuration. The VRF definition value accepts
- alphanumeric characters used to provide additional information
- about the VRF.
- rd:
- description:
- - The router-distinguisher value uniquely identifies the VRF to
- routing processes on the remote IOS system. The RD value takes
- the form of C(A:B) where C(A) and C(B) are both numeric values.
- interfaces:
- description:
- - Identifies the set of interfaces that
- should be configured in the VRF. Interfaces must be routed
- interfaces in order to be placed into a VRF.
- associated_interfaces:
- description:
- - This is a intent option and checks the operational state of the for given vrf C(name)
- for associated interfaces. If the value in the C(associated_interfaces) does not match with
- the operational state of vrf interfaces on device it will result in failure.
- version_added: "2.5"
- delay:
- description:
- - Time in seconds to wait before checking for the operational state on remote
- device.
- version_added: "2.4"
- default: 10
- purge:
- description:
- - Instructs the module to consider the
- VRF definition absolute. It will remove any previously configured
- VRFs on the device.
- default: false
- type: bool
- state:
- description:
- - Configures the state of the VRF definition
- as it relates to the device operational configuration. When set
- to I(present), the VRF should be configured in the device active
- configuration and when set to I(absent) the VRF should not be
- in the device active configuration
- default: present
- choices: ['present', 'absent']
- route_both:
- description:
- - Adds an export and import list of extended route target communities to the VRF.
- version_added: "2.5"
- route_export:
- description:
- - Adds an export list of extended route target communities to the VRF.
- version_added: "2.5"
- route_import:
- description:
- - Adds an import list of extended route target communities to the VRF.
- version_added: "2.5"
- route_both_ipv4:
- description:
- - Adds an export and import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_export_ipv4:
- description:
- - Adds an export list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_import_ipv4:
- description:
- - Adds an import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_both_ipv6:
- description:
- - Adds an export and import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_export_ipv6:
- description:
- - Adds an export list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
- route_import_ipv6:
- description:
- - Adds an import list of extended route target communities in address-family configuration submode to the VRF.
- version_added: "2.7"
-
-"""
-EXAMPLES = """
-- name: configure a vrf named management
- ios_vrf:
- name: management
- description: oob mgmt vrf
- interfaces:
- - Management1
-
-- name: remove a vrf named test
- ios_vrf:
- name: test
- state: absent
-
-- name: configure set of VRFs and purge any others
- ios_vrf:
- vrfs:
- - red
- - blue
- - green
- purge: yes
-
-- name: Creates a list of import RTs for the VRF with the same parameters
- ios_vrf:
- name: test_import
- rd: 1:100
- route_import:
- - 1:100
- - 3:100
-
-- name: Creates a list of import RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_import_ipv4
- rd: 1:100
- route_import_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of import RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_import_ipv6
- rd: 1:100
- route_import_ipv6:
- - 1:100
- - 3:100
-
-- name: Creates a list of export RTs for the VRF with the same parameters
- ios_vrf:
- name: test_export
- rd: 1:100
- route_export:
- - 1:100
- - 3:100
-
-- name: Creates a list of export RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_export_ipv4
- rd: 1:100
- route_export_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of export RTs in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_export_ipv6
- rd: 1:100
- route_export_ipv6:
- - 1:100
- - 3:100
-
-- name: Creates a list of import and export route targets for the VRF with the same parameters
- ios_vrf:
- name: test_both
- rd: 1:100
- route_both:
- - 1:100
- - 3:100
-
-- name: Creates a list of import and export route targets in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_both_ipv4
- rd: 1:100
- route_both_ipv4:
- - 1:100
- - 3:100
-
-- name: Creates a list of import and export route targets in address-family configuration submode for the VRF with the same parameters
- ios_vrf:
- name: test_both_ipv6
- rd: 1:100
- route_both_ipv6:
- - 1:100
- - 3:100
-
-"""
-
-RETURN = """
-commands:
- description: The list of configuration mode commands to send to the device
- returned: always
- type: list
- sample:
- - vrf definition ansible
- - description management vrf
- - rd: 1:100
-start:
- description: The time the job started
- returned: always
- type: str
- sample: "2016-11-16 10:38:15.126146"
-end:
- description: The time the job ended
- returned: always
- type: str
- sample: "2016-11-16 10:38:25.595612"
-delta:
- description: The time elapsed to perform all operations
- returned: always
- type: str
- sample: "0:00:10.469466"
-"""
-import re
-import time
-from functools import partial
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import exec_command
-from ansible.module_utils.network.ios.ios import load_config, get_config
-from ansible.module_utils.network.ios.ios import ios_argument_spec
-from ansible.module_utils.network.common.config import NetworkConfig
-from ansible.module_utils.six import iteritems
-
-
-def get_interface_type(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 add_command_to_vrf(name, cmd, commands):
- if 'vrf definition %s' % name not in commands:
- commands.extend(['vrf definition %s' % name])
- commands.append(cmd)
-
-
-def map_obj_to_commands(updates, module):
- commands = list()
-
- for update in updates:
- want, have = update
-
- def needs_update(want, have, x):
- if isinstance(want.get(x), list) and isinstance(have.get(x), list):
- return want.get(x) and (want.get(x) != have.get(x)) and not all(elem in have.get(x) for elem in want.get(x))
- return want.get(x) and (want.get(x) != have.get(x))
-
- if want['state'] == 'absent':
- commands.append('no vrf definition %s' % want['name'])
- continue
-
- if not have.get('state'):
- commands.extend(['vrf definition %s' % want['name']])
- ipv6 = len([k for k, v in module.params.items() if (k.endswith('_ipv6') or k.endswith('_both')) and v]) != 0
- ipv4 = len([k for k, v in module.params.items() if (k.endswith('_ipv4') or k.endswith('_both')) and v]) != 0
- if ipv4:
- commands.extend(['address-family ipv4', 'exit'])
- if ipv6:
- commands.extend(['address-family ipv6', 'exit'])
-
- if needs_update(want, have, 'description'):
- cmd = 'description %s' % want['description']
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'rd'):
- cmd = 'rd %s' % want['rd']
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_import'):
- for route in want['route_import']:
- cmd = 'route-target import %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_export'):
- for route in want['route_export']:
- cmd = 'route-target export %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_import_ipv4'):
- cmd = 'address-family ipv4'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_import_ipv4']:
- cmd = 'route-target import %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_export_ipv4'):
- cmd = 'address-family ipv4'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_export_ipv4']:
- cmd = 'route-target export %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_import_ipv6'):
- cmd = 'address-family ipv6'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_import_ipv6']:
- cmd = 'route-target import %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if needs_update(want, have, 'route_export_ipv6'):
- cmd = 'address-family ipv6'
- add_command_to_vrf(want['name'], cmd, commands)
- for route in want['route_export_ipv6']:
- cmd = 'route-target export %s' % route
- add_command_to_vrf(want['name'], cmd, commands)
- cmd = 'exit-address-family'
- add_command_to_vrf(want['name'], cmd, commands)
-
- if want['interfaces'] is not None:
- # handle the deletes
- for intf in set(have.get('interfaces', [])).difference(want['interfaces']):
- commands.extend(['interface %s' % intf,
- 'no vrf forwarding %s' % want['name']])
-
- # handle the adds
- for intf in set(want['interfaces']).difference(have.get('interfaces', [])):
- cfg = get_config(module)
- configobj = NetworkConfig(indent=1, contents=cfg)
- children = configobj['interface %s' % intf].children
- intf_config = '\n'.join(children)
-
- commands.extend(['interface %s' % intf,
- 'vrf forwarding %s' % want['name']])
-
- match = re.search('ip address .+', intf_config, re.M)
- if match:
- commands.append(match.group())
-
- return commands
-
-
-def parse_description(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'description (.+)$', cfg, re.M)
- if match:
- return match.group(1)
-
-
-def parse_rd(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- match = re.search(r'rd (.+)$', cfg, re.M)
- if match:
- return match.group(1)
-
-
-def parse_interfaces(configobj):
- vrf_cfg = 'vrf forwarding'
- interfaces = dict()
- for intf in set(re.findall('^interface .+', str(configobj), re.M)):
- for line in configobj[intf].children:
- if vrf_cfg in line:
- try:
- interfaces[line.split()[-1]].append(intf.split(' ')[1])
- except KeyError:
- interfaces[line.split()[-1]] = [intf.split(' ')[1]]
- return interfaces
-
-
-def parse_import(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- matches = re.findall(r'route-target\s+import\s+(.+)', cfg, re.M)
- return matches
-
-
-def parse_export(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- cfg = '\n'.join(cfg.children)
- matches = re.findall(r'route-target\s+export\s+(.+)', cfg, re.M)
- return matches
-
-
-def parse_both(configobj, name, address_family='global'):
- rd_pattern = re.compile('(?P<rd>.+:.+)')
- matches = list()
- export_match = None
- import_match = None
- if address_family == "global":
- export_match = parse_export(configobj, name)
- import_match = parse_import(configobj, name)
- elif address_family == "ipv4":
- export_match = parse_export_ipv4(configobj, name)
- import_match = parse_import_ipv4(configobj, name)
- elif address_family == "ipv6":
- export_match = parse_export_ipv6(configobj, name)
- import_match = parse_import_ipv6(configobj, name)
- if import_match and export_match:
- for ex in export_match:
- exrd = rd_pattern.search(ex)
- exrd = exrd.groupdict().get('rd')
- for im in import_match:
- imrd = rd_pattern.search(im)
- imrd = imrd.groupdict().get('rd')
- if exrd == imrd:
- matches.extend([exrd]) if exrd not in matches else None
- matches.extend([imrd]) if imrd not in matches else None
- return matches
-
-
-def parse_import_ipv4(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv4']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+import\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_export_ipv4(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv4']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+export\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_import_ipv6(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv6']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+import\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def parse_export_ipv6(configobj, name):
- cfg = configobj['vrf definition %s' % name]
- try:
- subcfg = cfg['address-family ipv6']
- subcfg = '\n'.join(subcfg.children)
- matches = re.findall(r'route-target\s+export\s+(.+)', subcfg, re.M)
- return matches
- except KeyError:
- pass
-
-
-def map_config_to_obj(module):
- config = get_config(module)
- configobj = NetworkConfig(indent=1, contents=config)
- match = re.findall(r'^vrf definition (\S+)', config, re.M)
- if not match:
- return list()
-
- instances = list()
-
- interfaces = parse_interfaces(configobj)
-
- for item in set(match):
- obj = {
- 'name': item,
- 'state': 'present',
- 'description': parse_description(configobj, item),
- 'rd': parse_rd(configobj, item),
- 'interfaces': interfaces.get(item),
- 'route_import': parse_import(configobj, item),
- 'route_export': parse_export(configobj, item),
- 'route_both': parse_both(configobj, item),
- 'route_import_ipv4': parse_import_ipv4(configobj, item),
- 'route_export_ipv4': parse_export_ipv4(configobj, item),
- 'route_both_ipv4': parse_both(configobj, item, address_family='ipv4'),
- 'route_import_ipv6': parse_import_ipv6(configobj, item),
- 'route_export_ipv6': parse_export_ipv6(configobj, item),
- 'route_both_ipv6': parse_both(configobj, item, address_family='ipv6'),
- }
- instances.append(obj)
- return instances
-
-
-def get_param_value(key, item, module):
- # if key doesn't exist in the item, get it from module.params
- if not item.get(key):
- value = module.params[key]
-
- # if key does exist, do a type check on it to validate it
- else:
- value_type = module.argument_spec[key].get('type', 'str')
- type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
- type_checker(item[key])
- value = item[key]
-
- # validate the param value (if validator func exists)
- validator = globals().get('validate_%s' % key)
- if validator:
- validator(value, module)
-
- return value
-
-
-def map_params_to_obj(module):
- vrfs = module.params.get('vrfs')
- if not vrfs:
- if not module.params['name'] and module.params['purge']:
- return list()
- elif not module.params['name']:
- module.fail_json(msg='name is required')
- collection = [{'name': module.params['name']}]
- else:
- collection = list()
- for item in vrfs:
- if not isinstance(item, dict):
- collection.append({'name': item})
- elif 'name' not in item:
- module.fail_json(msg='name is required')
- else:
- collection.append(item)
-
- objects = list()
- for item in collection:
- get_value = partial(get_param_value, item=item, module=module)
- item['description'] = get_value('description')
- item['rd'] = get_value('rd')
- item['interfaces'] = get_value('interfaces')
- item['state'] = get_value('state')
- item['route_import'] = get_value('route_import')
- item['route_export'] = get_value('route_export')
- item['route_both'] = get_value('route_both')
- item['route_import_ipv4'] = get_value('route_import_ipv4')
- item['route_export_ipv4'] = get_value('route_export_ipv4')
- item['route_both_ipv4'] = get_value('route_both_ipv4')
- item['route_import_ipv6'] = get_value('route_import_ipv6')
- item['route_export_ipv6'] = get_value('route_export_ipv6')
- item['route_both_ipv6'] = get_value('route_both_ipv6')
- both_addresses_family = ["", "_ipv6", "_ipv4"]
- for address_family in both_addresses_family:
- if item["route_both%s" % address_family]:
- if not item["route_export%s" % address_family]:
- item["route_export%s" % address_family] = list()
- if not item["route_import%s" % address_family]:
- item["route_import%s" % address_family] = list()
- item["route_export%s" % address_family].extend(get_value("route_both%s" % address_family))
- item["route_import%s" % address_family].extend(get_value("route_both%s" % address_family))
- item['associated_interfaces'] = get_value('associated_interfaces')
- objects.append(item)
-
- return objects
-
-
-def update_objects(want, have):
- updates = list()
- for entry in want:
- item = next((i for i in have if i['name'] == entry['name']), None)
- if all((item is None, entry['state'] == 'present')):
- updates.append((entry, {}))
- else:
- for key, value in iteritems(entry):
- if value:
- try:
- if isinstance(value, list):
- if sorted(value) != sorted(item[key]):
- if (entry, item) not in updates:
- updates.append((entry, item))
- elif value != item[key]:
- if (entry, item) not in updates:
- updates.append((entry, item))
- except TypeError:
- pass
- return updates
-
-
-def check_declarative_intent_params(want, module, result):
- if module.params['associated_interfaces']:
-
- if result['changed']:
- time.sleep(module.params['delay'])
-
- name = module.params['name']
- rc, out, err = exec_command(module, 'show vrf | include {0}'.format(name))
-
- if rc == 0:
- data = out.strip().split()
- # data will be empty if the vrf was just added
- if not data:
- return
- vrf = data[0]
- interface = data[-1]
-
- for w in want:
- if w['name'] == vrf:
- if w.get('associated_interfaces') is None:
- continue
- for i in w['associated_interfaces']:
- if get_interface_type(i) is not get_interface_type(interface):
- module.fail_json(msg="Interface %s not configured on vrf %s" % (interface, name))
-
-
-def main():
- """ main entry point for module execution
- """
- argument_spec = dict(
- vrfs=dict(type='list'),
-
- name=dict(),
- description=dict(),
- rd=dict(),
- route_export=dict(type='list'),
- route_import=dict(type='list'),
- route_both=dict(type='list'),
- route_export_ipv4=dict(type='list'),
- route_import_ipv4=dict(type='list'),
- route_both_ipv4=dict(type='list'),
- route_export_ipv6=dict(type='list'),
- route_import_ipv6=dict(type='list'),
- route_both_ipv6=dict(type='list'),
-
-
- interfaces=dict(type='list'),
- associated_interfaces=dict(type='list'),
-
- delay=dict(default=10, type='int'),
- purge=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent'])
- )
-
- argument_spec.update(ios_argument_spec)
-
- mutually_exclusive = [('name', 'vrfs')]
- module = AnsibleModule(argument_spec=argument_spec,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True)
-
- result = {'changed': False}
-
- warnings = list()
- result['warnings'] = warnings
-
- want = map_params_to_obj(module)
- have = map_config_to_obj(module)
- commands = map_obj_to_commands(update_objects(want, have), module)
-
- if module.params['purge']:
- want_vrfs = [x['name'] for x in want]
- have_vrfs = [x['name'] for x in have]
- for item in set(have_vrfs).difference(want_vrfs):
- cmd = 'no vrf definition %s' % item
- if cmd not in commands:
- commands.append(cmd)
-
- result['commands'] = commands
-
- if commands:
- if not module.check_mode:
- load_config(module, commands)
- result['changed'] = True
-
- check_declarative_intent_params(want, module, result)
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/plugins/action/ios.py b/lib/ansible/plugins/action/ios.py
deleted file mode 100644
index 5ab0c60287..0000000000
--- a/lib/ansible/plugins/action/ios.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import sys
-import copy
-
-from ansible.plugins.action.network import ActionModule as ActionNetworkModule
-from ansible.module_utils.network.common.utils import load_provider
-from ansible.module_utils.network.ios.ios import ios_provider_spec
-from ansible.utils.display import Display
-
-display = Display()
-
-
-class ActionModule(ActionNetworkModule):
-
- def run(self, tmp=None, task_vars=None):
- del tmp # tmp no longer has any effect
-
- module_name = self._task.action.split('.')[-1]
- self._config_module = True if module_name == 'ios_config' else False
- persistent_connection = self._play_context.connection.split('.')[-1]
- warnings = []
-
- if persistent_connection == 'network_cli':
- provider = self._task.args.get('provider', {})
- if any(provider.values()):
- display.warning('provider is unnecessary when using network_cli and will be ignored')
- del self._task.args['provider']
- elif self._play_context.connection == 'local':
- provider = load_provider(ios_provider_spec, self._task.args)
- pc = copy.deepcopy(self._play_context)
- pc.connection = 'ansible.netcommon.network_cli'
- pc.network_os = 'cisco.ios.ios'
- pc.remote_addr = provider['host'] or self._play_context.remote_addr
- pc.port = int(provider['port'] or self._play_context.port or 22)
- pc.remote_user = provider['username'] or self._play_context.connection_user
- pc.password = provider['password'] or self._play_context.password
- pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
- pc.become = provider['authorize'] or False
- if pc.become:
- pc.become_method = 'enable'
- pc.become_pass = provider['auth_pass']
-
- connection = self._shared_loader_obj.connection_loader.get('ansible.netcommon.persistent', pc, sys.stdin,
- task_uuid=self._task._uuid)
-
- # TODO: Remove below code after ansible minimal is cut out
- if connection is None:
- pc.connection = 'network_cli'
- pc.network_os = 'ios'
- connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid)
-
- display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr)
-
- command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout')
- connection.set_options(direct={'persistent_command_timeout': command_timeout})
-
- socket_path = connection.run()
- display.vvvv('socket_path: %s' % socket_path, pc.remote_addr)
- if not socket_path:
- return {'failed': True,
- 'msg': 'unable to open shell. Please see: ' +
- 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
-
- task_vars['ansible_socket'] = socket_path
- warnings.append(['connection local support for this module is deprecated and will be removed in version 2.14, use connection %s' % pc.connection])
- else:
- return {'failed': True, 'msg': 'Connection type %s is not valid for this module' % self._play_context.connection}
-
- result = super(ActionModule, self).run(task_vars=task_vars)
- if warnings:
- if 'warnings' in result:
- result['warnings'].extend(warnings)
- else:
- result['warnings'] = warnings
- return result
diff --git a/lib/ansible/plugins/cliconf/ios.py b/lib/ansible/plugins/cliconf/ios.py
deleted file mode 100644
index c057a8386c..0000000000
--- a/lib/ansible/plugins/cliconf/ios.py
+++ /dev/null
@@ -1,387 +0,0 @@
-#
-# (c) 2017 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = """
----
-author: Ansible Networking Team
-cliconf: ios
-short_description: Use ios cliconf to run command on Cisco IOS platform
-description:
- - This ios plugin provides low level abstraction apis for
- sending and receiving CLI commands from Cisco IOS network devices.
-version_added: "2.4"
-"""
-
-import re
-import time
-import json
-
-from ansible.errors import AnsibleConnectionFailure
-from ansible.module_utils._text import to_text
-from ansible.module_utils.common._collections_compat import Mapping
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.config import NetworkConfig, dumps
-from ansible.module_utils.network.common.utils import to_list
-from ansible.plugins.cliconf import CliconfBase, enable_mode
-
-
-class Cliconf(CliconfBase):
-
- @enable_mode
- def get_config(self, source='running', flags=None, format=None):
- if source not in ('running', 'startup'):
- raise ValueError("fetching configuration from %s is not supported" % source)
-
- if format:
- raise ValueError("'format' value %s is not supported for get_config" % format)
-
- if not flags:
- flags = []
- if source == 'running':
- cmd = 'show running-config '
- else:
- cmd = 'show startup-config '
-
- cmd += ' '.join(to_list(flags))
- cmd = cmd.strip()
-
- return self.send_command(cmd)
-
- def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- """
- Generate diff between candidate and running configuration. If the
- remote host supports onbox diff capabilities ie. supports_onbox_diff in that case
- candidate and running configurations are not required to be passed as argument.
- In case if onbox diff capability is not supported candidate argument is mandatory
- and running argument is optional.
- :param candidate: The configuration which is expected to be present on remote host.
- :param running: The base configuration which is used to generate diff.
- :param diff_match: Instructs how to match the candidate configuration with current device configuration
- Valid values are 'line', 'strict', 'exact', 'none'.
- 'line' - commands are matched line by line
- 'strict' - command lines are matched with respect to position
- 'exact' - command lines must be an equal match
- 'none' - will not compare the candidate configuration with the running configuration
- :param diff_ignore_lines: Use this argument to specify one or more lines that should be
- ignored during the diff. This is used for lines in the configuration
- that are automatically updated by the system. This argument takes
- a list of regular expressions or exact line matches.
- :param path: The ordered set of parents that uniquely identify the section or hierarchy
- the commands should be checked against. If the parents argument
- is omitted, the commands are checked against the set of top
- level or global commands.
- :param diff_replace: Instructs on the way to perform the configuration on the device.
- If the replace argument is set to I(line) then the modified lines are
- pushed to the device in configuration mode. If the replace argument is
- set to I(block) then the entire command block is pushed to the device in
- configuration mode if any line is not correct.
- :return: Configuration diff in json format.
- {
- 'config_diff': '',
- 'banner_diff': {}
- }
-
- """
- diff = {}
- device_operations = self.get_device_operations()
- option_values = self.get_option_values()
-
- if candidate is None and device_operations['supports_generate_diff']:
- raise ValueError("candidate configuration is required to generate diff")
-
- if diff_match not in option_values['diff_match']:
- raise ValueError("'match' value %s in invalid, valid values are %s" % (diff_match, ', '.join(option_values['diff_match'])))
-
- if diff_replace not in option_values['diff_replace']:
- raise ValueError("'replace' value %s in invalid, valid values are %s" % (diff_replace, ', '.join(option_values['diff_replace'])))
-
- # prepare candidate configuration
- candidate_obj = NetworkConfig(indent=1)
- want_src, want_banners = self._extract_banners(candidate)
- candidate_obj.load(want_src)
-
- if running and diff_match != 'none':
- # running configuration
- have_src, have_banners = self._extract_banners(running)
- running_obj = NetworkConfig(indent=1, contents=have_src, ignore_lines=diff_ignore_lines)
- configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace)
-
- else:
- configdiffobjs = candidate_obj.items
- have_banners = {}
-
- diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
- banners = self._diff_banners(want_banners, have_banners)
- diff['banner_diff'] = banners if banners else {}
- return diff
-
- @enable_mode
- def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
- resp = {}
- operations = self.get_device_operations()
- self.check_edit_config_capability(operations, candidate, commit, replace, comment)
-
- results = []
- requests = []
- if commit:
- self.send_command('configure terminal')
- for line in to_list(candidate):
- if not isinstance(line, Mapping):
- line = {'command': line}
-
- cmd = line['command']
- if cmd != 'end' and cmd[0] != '!':
- results.append(self.send_command(**line))
- requests.append(cmd)
-
- self.send_command('end')
- else:
- raise ValueError('check mode is not supported')
-
- resp['request'] = requests
- resp['response'] = results
- return resp
-
- def edit_macro(self, candidate=None, commit=True, replace=None, comment=None):
- """
- ios_config:
- lines: "{{ macro_lines }}"
- parents: "macro name {{ macro_name }}"
- after: '@'
- match: line
- replace: block
- """
- resp = {}
- operations = self.get_device_operations()
- self.check_edit_config_capability(operations, candidate, commit, replace, comment)
-
- results = []
- requests = []
- if commit:
- commands = ''
- self.send_command('config terminal')
- time.sleep(0.1)
- # first item: macro command
- commands += (candidate.pop(0) + '\n')
- multiline_delimiter = candidate.pop(-1)
- for line in candidate:
- commands += (' ' + line + '\n')
- commands += (multiline_delimiter + '\n')
- obj = {'command': commands, 'sendonly': True}
- results.append(self.send_command(**obj))
- requests.append(commands)
-
- time.sleep(0.1)
- self.send_command('end', sendonly=True)
- time.sleep(0.1)
- results.append(self.send_command('\n'))
- requests.append('\n')
-
- resp['request'] = requests
- resp['response'] = results
- return resp
-
- def get(self, command=None, prompt=None, answer=None, sendonly=False, output=None, newline=True, check_all=False):
- if not command:
- raise ValueError('must provide value of command to execute')
- if output:
- raise ValueError("'output' value %s is not supported for get" % output)
-
- return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all)
-
- def get_device_info(self):
- device_info = {}
-
- device_info['network_os'] = 'ios'
- reply = self.get(command='show version')
- data = to_text(reply, errors='surrogate_or_strict').strip()
-
- match = re.search(r'Version (\S+)', data)
- if match:
- device_info['network_os_version'] = match.group(1).strip(',')
-
- model_search_strs = [r'^[Cc]isco (.+) \(revision', r'^[Cc]isco (\S+).+bytes of .*memory']
- for item in model_search_strs:
- match = re.search(item, data, re.M)
- if match:
- version = match.group(1).split(' ')
- device_info['network_os_model'] = version[0]
- break
-
- match = re.search(r'^(.+) uptime', data, re.M)
- if match:
- device_info['network_os_hostname'] = match.group(1)
-
- match = re.search(r'image file is "(.+)"', data)
- if match:
- device_info['network_os_image'] = match.group(1)
-
- return device_info
-
- def get_device_operations(self):
- return {
- 'supports_diff_replace': True,
- 'supports_commit': False,
- 'supports_rollback': False,
- 'supports_defaults': True,
- 'supports_onbox_diff': False,
- 'supports_commit_comment': False,
- 'supports_multiline_delimiter': True,
- 'supports_diff_match': True,
- 'supports_diff_ignore_lines': True,
- 'supports_generate_diff': True,
- 'supports_replace': False
- }
-
- def get_option_values(self):
- return {
- 'format': ['text'],
- 'diff_match': ['line', 'strict', 'exact', 'none'],
- 'diff_replace': ['line', 'block'],
- 'output': []
- }
-
- def get_capabilities(self):
- result = super(Cliconf, self).get_capabilities()
- result['rpc'] += ['edit_banner', 'get_diff', 'run_commands', 'get_defaults_flag']
- result['device_operations'] = self.get_device_operations()
- result.update(self.get_option_values())
- return json.dumps(result)
-
- def edit_banner(self, candidate=None, multiline_delimiter="@", commit=True):
- """
- Edit banner on remote device
- :param banners: Banners to be loaded in json format
- :param multiline_delimiter: Line delimiter for banner
- :param commit: Boolean value that indicates if the device candidate
- configuration should be pushed in the running configuration or discarded.
- :param diff: Boolean flag to indicate if configuration that is applied on remote host should
- generated and returned in response or not
- :return: Returns response of executing the configuration command received
- from remote host
- """
- resp = {}
- banners_obj = json.loads(candidate)
- results = []
- requests = []
- if commit:
- for key, value in iteritems(banners_obj):
- key += ' %s' % multiline_delimiter
- self.send_command('config terminal', sendonly=True)
- for cmd in [key, value, multiline_delimiter]:
- obj = {'command': cmd, 'sendonly': True}
- results.append(self.send_command(**obj))
- requests.append(cmd)
-
- self.send_command('end', sendonly=True)
- time.sleep(0.1)
- results.append(self.send_command('\n'))
- requests.append('\n')
-
- resp['request'] = requests
- resp['response'] = results
-
- return resp
-
- def run_commands(self, commands=None, check_rc=True):
- if commands is None:
- raise ValueError("'commands' value is required")
-
- responses = list()
- for cmd in to_list(commands):
- if not isinstance(cmd, Mapping):
- cmd = {'command': cmd}
-
- output = cmd.pop('output', None)
- if output:
- raise ValueError("'output' value %s is not supported for run_commands" % output)
-
- try:
- out = self.send_command(**cmd)
- except AnsibleConnectionFailure as e:
- if check_rc:
- raise
- out = getattr(e, 'err', to_text(e))
-
- responses.append(out)
-
- return responses
-
- def get_defaults_flag(self):
- """
- The method identifies the filter that should be used to fetch running-configuration
- with defaults.
- :return: valid default filter
- """
- out = self.get('show running-config ?')
- out = to_text(out, errors='surrogate_then_replace')
-
- commands = set()
- for line in out.splitlines():
- if line.strip():
- commands.add(line.strip().split()[0])
-
- if 'all' in commands:
- return 'all'
- else:
- return 'full'
-
- def set_cli_prompt_context(self):
- """
- Make sure we are in the operational cli mode
- :return: None
- """
- if self._connection.connected:
- out = self._connection.get_prompt()
-
- if out is None:
- raise AnsibleConnectionFailure(message=u'cli prompt is not identified from the last received'
- u' response window: %s' % self._connection._last_recv_window)
-
- if re.search(r'config.*\)#', to_text(out, errors='surrogate_then_replace').strip()):
- self._connection.queue_message('vvvv', 'wrong context, sending end to device')
- self._connection.send_command('end')
-
- def _extract_banners(self, config):
- banners = {}
- banner_cmds = re.findall(r'^banner (\w+)', config, re.M)
- for cmd in banner_cmds:
- regex = r'banner %s \^C(.+?)(?=\^C)' % cmd
- match = re.search(regex, config, re.S)
- if match:
- key = 'banner %s' % cmd
- banners[key] = match.group(1).strip()
-
- for cmd in banner_cmds:
- regex = r'banner %s \^C(.+?)(?=\^C)' % cmd
- match = re.search(regex, config, re.S)
- if match:
- config = config.replace(str(match.group(1)), '')
-
- config = re.sub(r'banner \w+ \^C\^C', '!! banner removed', config)
- return config, banners
-
- def _diff_banners(self, want, have):
- candidate = {}
- for key, value in iteritems(want):
- if value != have.get(key):
- candidate[key] = value
- return candidate
diff --git a/lib/ansible/plugins/doc_fragments/ios.py b/lib/ansible/plugins/doc_fragments/ios.py
deleted file mode 100644
index 49e723516e..0000000000
--- a/lib/ansible/plugins/doc_fragments/ios.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-
-class ModuleDocFragment(object):
-
- # Standard files documentation fragment
- DOCUMENTATION = r'''
-options:
- provider:
- description:
- - B(Deprecated)
- - "Starting with Ansible 2.5 we recommend using C(connection: network_cli)."
- - For more information please see the L(IOS Platform Options guide, ../network/user_guide/platform_ios.html).
- - HORIZONTALLINE
- - A dict object containing connection details.
- type: dict
- suboptions:
- host:
- description:
- - Specifies the DNS host name or address for connecting to the remote
- device over the specified transport. The value of host is used as
- the destination address for the transport.
- type: str
- required: true
- port:
- description:
- - Specifies the port to use when building the connection to the remote device.
- type: int
- default: 22
- username:
- description:
- - Configures the username to use to authenticate the connection to
- the remote device. This value is used to authenticate
- the SSH session. If the value is not specified in the task, the
- value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
- type: str
- password:
- description:
- - Specifies the password to use to authenticate the connection to
- the remote device. This value is used to authenticate
- the SSH session. If the value is not specified in the task, the
- value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
- type: str
- timeout:
- description:
- - Specifies the timeout in seconds for communicating with the network device
- for either connecting or sending commands. If the timeout is
- exceeded before the operation is completed, the module will error.
- type: int
- default: 10
- ssh_keyfile:
- description:
- - Specifies the SSH key to use to authenticate the connection to
- the remote device. This value is the path to the
- key used to authenticate the SSH session. If the value is not specified
- in the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
- will be used instead.
- type: path
- authorize:
- description:
- - Instructs the module to enter privileged mode on the remote device
- before sending any commands. If not specified, the device will
- attempt to execute all commands in non-privileged mode. If the value
- is not specified in the task, the value of environment variable
- C(ANSIBLE_NET_AUTHORIZE) will be used instead.
- type: bool
- default: no
- auth_pass:
- description:
- - Specifies the password to use if required to enter privileged mode
- on the remote device. If I(authorize) is false, then this argument
- does nothing. If the value is not specified in the task, the value of
- environment variable C(ANSIBLE_NET_AUTH_PASS) will be used instead.
- type: str
-notes:
- - For more information on using Ansible to manage network devices see the :ref:`Ansible Network Guide <network_guide>`
- - For more information on using Ansible to manage Cisco devices see the `Cisco integration page <https://www.ansible.com/integrations/networks/cisco>`_.
-'''
diff --git a/lib/ansible/plugins/terminal/ios.py b/lib/ansible/plugins/terminal/ios.py
deleted file mode 100644
index d797357738..0000000000
--- a/lib/ansible/plugins/terminal/ios.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-import re
-
-from ansible.errors import AnsibleConnectionFailure
-from ansible.module_utils._text import to_text, to_bytes
-from ansible.plugins.terminal import TerminalBase
-from ansible.utils.display import Display
-
-display = Display()
-
-
-class TerminalModule(TerminalBase):
-
- terminal_stdout_re = [
- re.compile(br"[\r\n]?[\w\+\-\.:\/\[\]]+(?:\([^\)]+\)){0,3}(?:[>#]) ?$")
- ]
-
- terminal_stderr_re = [
- re.compile(br"% ?Error"),
- # re.compile(br"^% \w+", re.M),
- re.compile(br"% ?Bad secret"),
- re.compile(br"[\r\n%] Bad passwords"),
- re.compile(br"invalid input", re.I),
- re.compile(br"(?:incomplete|ambiguous) command", re.I),
- re.compile(br"connection timed out", re.I),
- re.compile(br"[^\r\n]+ not found"),
- re.compile(br"'[^']' +returned error code: ?\d+"),
- re.compile(br"Bad mask", re.I),
- re.compile(br"% ?(\S+) ?overlaps with ?(\S+)", re.I),
- re.compile(br"[%\S] ?Error: ?[\s]+", re.I),
- re.compile(br"[%\S] ?Informational: ?[\s]+", re.I),
- re.compile(br"Command authorization failed")
- ]
-
- def on_open_shell(self):
- try:
- self._exec_cli_command(b'terminal length 0')
- except AnsibleConnectionFailure:
- raise AnsibleConnectionFailure('unable to set terminal parameters')
-
- try:
- self._exec_cli_command(b'terminal width 512')
- try:
- self._exec_cli_command(b'terminal width 0')
- except AnsibleConnectionFailure:
- pass
- except AnsibleConnectionFailure:
- display.display('WARNING: Unable to set terminal width, command responses may be truncated')
-
- def on_become(self, passwd=None):
- if self._get_prompt().endswith(b'#'):
- return
-
- cmd = {u'command': u'enable'}
- if passwd:
- # Note: python-3.5 cannot combine u"" and r"" together. Thus make
- # an r string and use to_text to ensure it's text on both py2 and py3.
- cmd[u'prompt'] = to_text(r"[\r\n]?(?:.*)?[Pp]assword: ?$", errors='surrogate_or_strict')
- cmd[u'answer'] = passwd
- cmd[u'prompt_retry_check'] = True
- try:
- self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict'))
- prompt = self._get_prompt()
- if prompt is None or not prompt.endswith(b'#'):
- raise AnsibleConnectionFailure('failed to elevate privilege to enable mode still at prompt [%s]' % prompt)
- except AnsibleConnectionFailure as e:
- prompt = self._get_prompt()
- raise AnsibleConnectionFailure('unable to elevate privilege to enable mode, at prompt [%s] with error: %s' % (prompt, e.message))
-
- def on_unbecome(self):
- prompt = self._get_prompt()
- if prompt is None:
- # if prompt is None most likely the terminal is hung up at a prompt
- return
-
- if b'(config' in prompt:
- self._exec_cli_command(b'end')
- self._exec_cli_command(b'disable')
-
- elif prompt.endswith(b'#'):
- self._exec_cli_command(b'disable')