summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/cisco/ios/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/ios/plugins')
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/action/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/action/ios.py135
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/ios.py464
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py81
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py83
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py404
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py910
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py27
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py64
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py80
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py75
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py64
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py66
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py79
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py74
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py73
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py200
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py547
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py807
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py100
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py71
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py415
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py301
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py452
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py353
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py478
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py435
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py224
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py314
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py404
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py275
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py328
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py165
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py225
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py324
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py713
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py337
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py133
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py127
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py97
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py130
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py110
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py138
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py148
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py88
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py112
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py128
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py423
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py100
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py115
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py95
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py99
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py180
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py272
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py168
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py205
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py84
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py158
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py225
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py168
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py72
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py128
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py284
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py1835
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py895
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py1947
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py3132
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py385
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py598
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py1415
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py188
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py509
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py2139
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py215
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py593
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py236
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py597
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py568
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py581
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py560
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py382
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py605
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py273
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py508
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py534
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py363
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py113
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py356
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py666
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py511
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py326
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py1101
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py1691
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py1974
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py242
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py372
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py692
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py382
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py616
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py416
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py748
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py750
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/ios.py116
167 files changed, 44264 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/ios.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/ios.py
new file mode 100644
index 00000000..6e06c47f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/action/ios.py
@@ -0,0 +1,135 @@
+#
+# (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_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ load_provider,
+)
+from ansible_collections.cisco.ios.plugins.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 in ["ios_config", "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/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/ios.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/ios.py
new file mode 100644
index 00000000..e816389a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/cliconf/ios.py
@@ -0,0 +1,464 @@
+#
+# (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: 1.0.0
+"""
+
+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_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+ dumps,
+)
+from ansible_collections.ansible.netcommon.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py
new file mode 100644
index 00000000..0bb9cae5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+# 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
+ port:
+ description:
+ - Specifies the port to use when building the connection to the remote device.
+ type: int
+ 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
+ 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: false
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
new file mode 100644
index 00000000..24b32d7b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,83 @@
+#
+# -*- 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py
new file mode 100644
index 00000000..87faedb0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py
@@ -0,0 +1,404 @@
+#
+# -*- 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"},
+ "evaluate": {"type": "str"},
+ "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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py
new file mode 100644
index 00000000..3666a359
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py
@@ -0,0 +1,910 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the
+# cli_rm_builder.
+#
+# Manually editing this file is not advised.
+#
+# To update the argspec make the desired changes
+# in the module docstring and re-run
+# cli_rm_builder.
+#
+#############################################
+
+"""
+The arg spec for the cisco.ios_bgp_global module
+"""
+
+
+class Bgp_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the cisco.ios_bgp_global module
+ """
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str", "required": True},
+ "aggregate_address": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise_map": {"type": "str"},
+ "as_confed_set": {"type": "bool"},
+ "as_set": {"type": "bool"},
+ "attribute_map": {"type": "str"},
+ "summary_only": {"type": "bool"},
+ "suppress_map": {"type": "str"},
+ },
+ },
+ "auto_summary": {"type": "bool"},
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "install": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "select": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "best_external": {"type": "bool"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "send": {"type": "bool"},
+ },
+ },
+ "advertise_best_external": {"type": "bool"},
+ "aggregate_timer": {"type": "int"},
+ "always_compare_med": {"type": "bool"},
+ "asnotation": {"type": "bool"},
+ "bestpath": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "aigp": {"type": "bool"},
+ "compare_routerid": {"type": "bool"},
+ "cost_community": {"type": "bool"},
+ "igp_metric": {"type": "bool"},
+ "med": {
+ "type": "dict",
+ "options": {
+ "confed": {"type": "bool"},
+ "missing_as_worst": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "client_to_client": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ "intra_cluster": {"type": "str"},
+ },
+ },
+ "cluster_id": {"type": "bool"},
+ "confederation": {
+ "type": "dict",
+ "options": {
+ "identifier": {"type": "str"},
+ "peers": {"type": "str"},
+ },
+ },
+ "consistency_checker": {
+ "type": "dict",
+ "options": {
+ "auto_repair": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "interval": {"type": "int"},
+ },
+ },
+ "error_message": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "interval": {"type": "int"},
+ },
+ },
+ },
+ },
+ "dampening": {
+ "type": "dict",
+ "options": {
+ "penalty_half_time": {"type": "int"},
+ "reuse_route_val": {"type": "int"},
+ "suppress_route_val": {"type": "int"},
+ "max_suppress": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "deterministic_med": {"type": "bool"},
+ "dmzlink_bw": {"type": "bool"},
+ "enforce_first_as": {"type": "bool"},
+ "enhanced_error": {"type": "bool"},
+ "fast_external_fallover": {"type": "bool"},
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "extended": {"type": "bool"},
+ "restart_time": {"type": "int"},
+ "stalepath_time": {"type": "int"},
+ },
+ },
+ "graceful_shutdown": {
+ "type": "dict",
+ "options": {
+ "neighbors": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "activate": {"type": "bool"},
+ },
+ },
+ "vrfs": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "activate": {"type": "bool"},
+ },
+ },
+ "community": {"type": "str"},
+ "local_preference": {"type": "int"},
+ },
+ },
+ "inject_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map_name": {"type": "str"},
+ "copy_attributes": {"type": "bool"},
+ },
+ },
+ "listen": {
+ "type": "dict",
+ "options": {
+ "limit": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "ipv4_with_subnet": {"type": "str"},
+ "ipv6_with_subnet": {"type": "str"},
+ "peer_group": {"type": "str"},
+ },
+ },
+ },
+ },
+ "log_neighbor_changes": {"type": "bool"},
+ "maxas_limit": {"type": "int"},
+ "maxcommunity_limit": {"type": "int"},
+ "maxextcommunity_limit": {"type": "int"},
+ "nexthop": {
+ "type": "dict",
+ "options": {
+ "route_map": {"type": "str"},
+ "trigger": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "enable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "nopeerup_delay": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "cold_boot": {"type": "int"},
+ "nsf_switchover": {"type": "int"},
+ "post_boot": {"type": "int"},
+ "user_initiated": {"type": "int"},
+ },
+ },
+ "recursion": {"type": "bool"},
+ "redistribute_internal": {"type": "bool"},
+ "refresh": {
+ "type": "dict",
+ "options": {
+ "max_eor_time": {"type": "int"},
+ "stalepath_time": {"type": "int"},
+ },
+ },
+ "regexp": {"type": "bool"},
+ "route_map": {"type": "bool"},
+ "router_id": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "interface": {"type": "str"},
+ "vrf": {"type": "bool"},
+ },
+ },
+ "scan_time": {"type": "int"},
+ "slow_peer": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {"type": "bool"},
+ "permanent": {"type": "int"},
+ },
+ },
+ },
+ },
+ "snmp": {"type": "bool"},
+ "sso": {"type": "bool"},
+ "soft_reconfig_backup": {"type": "bool"},
+ "suppress_inactive": {"type": "bool"},
+ "transport": {"type": "bool"},
+ "update_delay": {"type": "int"},
+ "update_group": {"type": "bool"},
+ "upgrade_cli": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "af_mode": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "bmp": {
+ "type": "dict",
+ "options": {
+ "buffer_size": {"type": "int"},
+ "initial_refresh": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "skip": {"type": "bool"},
+ },
+ },
+ "server": {"type": "int"},
+ },
+ },
+ "default_information": {"type": "bool"},
+ "default_metric": {"type": "int"},
+ "distance": {
+ "type": "dict",
+ "options": {
+ "admin": {
+ "type": "dict",
+ "options": {
+ "distance": {"type": "int"},
+ "address": {"type": "str"},
+ "wildcard_bit": {"type": "str"},
+ "acl": {"type": "str"},
+ },
+ },
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "routes_external": {"type": "int"},
+ "routes_internal": {"type": "int"},
+ "routes_local": {"type": "int"},
+ },
+ },
+ "mbgp": {
+ "type": "dict",
+ "options": {
+ "routes_external": {"type": "int"},
+ "routes_internal": {"type": "int"},
+ "routes_local": {"type": "int"},
+ },
+ },
+ },
+ },
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ "interface": {"type": "str"},
+ },
+ },
+ "maximum_paths": {
+ "type": "dict",
+ "options": {
+ "paths": {"type": "int"},
+ "eibgp": {"type": "int"},
+ "ibgp": {"type": "int"},
+ },
+ },
+ "maximum_secondary_paths": {
+ "type": "dict",
+ "options": {
+ "paths": {"type": "int"},
+ "eibgp": {"type": "int"},
+ "ibgp": {"type": "int"},
+ },
+ },
+ "neighbor": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "tag": {"type": "str"},
+ "ipv6_adddress": {"type": "str"},
+ "activate": {"type": "bool"},
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "advertise": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "best_external": {"type": "bool"},
+ "diverse_path": {
+ "type": "dict",
+ "options": {
+ "backup": {"type": "bool"},
+ "mpath": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "advertise_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map": {"type": "str"},
+ "non_exist_map": {"type": "str"},
+ },
+ },
+ "advertisement_interval": {"type": "int"},
+ "aigp": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "send": {
+ "type": "dict",
+ "options": {
+ "cost_community": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "poi": {
+ "type": "dict",
+ "options": {
+ "igp_cost": {
+ "type": "bool"
+ },
+ "pre_bestpath": {
+ "type": "bool"
+ },
+ "transitive": {
+ "type": "bool"
+ },
+ },
+ },
+ },
+ },
+ "med": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "allow_policy": {"type": "bool"},
+ "allowas_in": {"type": "int"},
+ "as_override": {"type": "bool"},
+ "bmp_activate": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "server": {"type": "int"},
+ },
+ },
+ "capability": {
+ "type": "dict",
+ "options": {
+ "both": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "cluster_id": {"type": "str"},
+ "default_originate": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "description": {"type": "str"},
+ "disable_connected_check": {"type": "bool"},
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "dmzlink_bw": {"type": "bool"},
+ "ebgp_multihop": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "hop_count": {"type": "int"},
+ },
+ },
+ "fall_over": {
+ "type": "dict",
+ "options": {
+ "bfd": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "multi_hop": {"type": "bool"},
+ "single_hop": {"type": "bool"},
+ },
+ },
+ "route_map": {"type": "str"},
+ },
+ },
+ "filter_list": {
+ "type": "dict",
+ "options": {
+ "path_acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "ha_mode": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "inherit": {"type": "str"},
+ "local_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "number": {"type": "int"},
+ "dual_as": {"type": "bool"},
+ "no_prepend": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "log_neighbor_changes": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "maximum_prefix": {
+ "type": "dict",
+ "options": {
+ "max_no": {"type": "int"},
+ "threshold_val": {"type": "int"},
+ "restart": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "next_hop_self": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ },
+ },
+ "next_hop_unchanged": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "allpaths": {"type": "bool"},
+ },
+ },
+ "password": {"type": "str"},
+ "path_attribute": {
+ "type": "dict",
+ "options": {
+ "discard": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ "treat_as_withdraw": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "peer_group": {"type": "str"},
+ "remote_as": {"type": "int"},
+ "remove_private_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ "route_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "route_reflector_client": {"type": "bool"},
+ "route_server_client": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "context": {"type": "str"},
+ },
+ },
+ "send_community": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "both": {"type": "bool"},
+ "extended": {"type": "bool"},
+ "standard": {"type": "bool"},
+ },
+ },
+ "send_label": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "explicit_null": {"type": "bool"},
+ },
+ },
+ "shutdown": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "graceful": {"type": "int"},
+ },
+ },
+ "slow_peer": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ "static": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "soft_reconfiguration": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "interval": {"type": "int"},
+ "holdtime": {"type": "int"},
+ "min_holdtime": {"type": "int"},
+ },
+ },
+ "translate_update": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "nlri": {
+ "type": "dict",
+ "options": {
+ "multicast": {"type": "bool"},
+ "unicast": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "transport": {
+ "type": "dict",
+ "options": {
+ "connection_mode": {
+ "type": "dict",
+ "options": {
+ "active": {"type": "bool"},
+ "passive": {"type": "bool"},
+ },
+ },
+ "multi_session": {"type": "bool"},
+ "path_mtu_discovery": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "ttl_security": {"type": "int"},
+ "unsuppress_map": {"type": "str"},
+ "version": {"type": "int"},
+ "weight": {"type": "int"},
+ },
+ },
+ "redistribute": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "application": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "connected": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "eigrp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "isis": {
+ "type": "dict",
+ "options": {
+ "area_tag": {"type": "str"},
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "iso_igrp": {
+ "type": "dict",
+ "options": {
+ "area_tag": {"type": "str"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "lisp": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "mobile": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "odr": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "ospf": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "nssa_external": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ "vrf": {"type": "str"},
+ },
+ },
+ "ospfv3": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "nssa_external": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "rip": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "static": {
+ "type": "dict",
+ "options": {
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "vrf": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "global": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "route_server_context": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "address_family": {
+ "type": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ },
+ "modifier": {
+ "type": "str",
+ "choices": ["multicast", "unicast"],
+ },
+ "import_map": {"type": "str"},
+ },
+ },
+ "description": {"type": "str"},
+ },
+ },
+ "scope": {
+ "type": "dict",
+ "options": {
+ "global": {"type": "bool"},
+ "vrf": {"type": "str"},
+ },
+ },
+ "synchronization": {"type": "bool"},
+ "table_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "filter": {"type": "bool"},
+ },
+ },
+ "template": {
+ "type": "dict",
+ "options": {
+ "peer_policy": {"type": "str"},
+ "peer_session": {"type": "str"},
+ },
+ },
+ "timers": {
+ "type": "dict",
+ "options": {
+ "keepalive": {"type": "int"},
+ "holdtime": {"type": "int"},
+ "min_holdtime": {"type": "int"},
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "purged",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py
new file mode 100644
index 00000000..935fee75
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py
@@ -0,0 +1,27 @@
+#
+# -*- 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", elements="str"
+ ),
+ "gather_network_resources": dict(type="list", elements="str"),
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py
new file mode 100644
index 00000000..5dbdda17
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py
@@ -0,0 +1,64 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
new file mode 100644
index 00000000..0f21f3a3
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,80 @@
+#
+# -*- 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", "elements": "str"},
+ "encapsulation": {
+ "type": "str",
+ "choices": ["dot1q", "isl", "negotiate"],
+ },
+ "native_vlan": {"type": "int"},
+ "pruning_vlans": {"type": "list", "elements": "str"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
new file mode 100644
index 00000000..ce8e1396
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,75 @@
+#
+# -*- 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": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "address": {"type": "str"},
+ "secondary": {"type": "bool"},
+ "dhcp_client": {"type": "int"},
+ "dhcp_hostname": {"type": "str"},
+ },
+ },
+ "ipv6": {
+ "elements": "dict",
+ "type": "list",
+ "options": {"address": {"type": "str"}},
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py
new file mode 100644
index 00000000..09f40b28
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py
@@ -0,0 +1,64 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 00000000..b0af01a5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,66 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
new file mode 100644
index 00000000..03021fed
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,79 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py
new file mode 100644
index 00000000..9133305e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py
@@ -0,0 +1,74 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 00000000..f4ad39f5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,73 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 00000000..b705c4b5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+#############################################
+# 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 cisco.ios_ospf_interfaces module
+"""
+
+
+class Ospf_InterfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the cisco.ios_ospf_interfaces module
+ """
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ "required": True,
+ },
+ "process": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "area_id": {"type": "str"},
+ "secondaries": {"type": "bool"},
+ "instance_id": {"type": "int"},
+ },
+ },
+ "adjacency": {"type": "bool"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str"},
+ "message_digest": {"type": "bool"},
+ "null": {"type": "bool"},
+ },
+ },
+ "bfd": {"type": "bool"},
+ "cost": {
+ "type": "dict",
+ "options": {
+ "interface_cost": {"type": "int"},
+ "dynamic_cost": {
+ "type": "dict",
+ "options": {
+ "default": {"type": "int"},
+ "hysteresis": {
+ "type": "dict",
+ "options": {
+ "percent": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "weight": {
+ "type": "dict",
+ "options": {
+ "l2_factor": {"type": "int"},
+ "latency": {"type": "int"},
+ "oc": {"type": "bool"},
+ "resources": {"type": "int"},
+ "throughput": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "database_filter": {"type": "bool"},
+ "dead_interval": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "minimal": {"type": "int"},
+ },
+ },
+ "demand_circuit": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "ignore": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "flood_reduction": {"type": "bool"},
+ "hello_interval": {"type": "int"},
+ "lls": {"type": "bool"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cost": {
+ "type": "dict",
+ "options": {
+ "percent": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "link_metrics": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "cost_threshold": {"type": "int"},
+ },
+ },
+ },
+ },
+ "mtu_ignore": {"type": "bool"},
+ "multi_area": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "cost": {"type": "int"},
+ },
+ },
+ "neighbor": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "cost": {"type": "int"},
+ "database_filter": {"type": "bool"},
+ "poll_interval": {"type": "int"},
+ "priority": {"type": "int"},
+ },
+ },
+ "network": {
+ "type": "dict",
+ "options": {
+ "broadcast": {"type": "bool"},
+ "manet": {"type": "bool"},
+ "non_broadcast": {"type": "bool"},
+ "point_to_multipoint": {"type": "bool"},
+ "point_to_point": {"type": "bool"},
+ },
+ },
+ "prefix_suppression": {"type": "bool"},
+ "priority": {"type": "int"},
+ "resync_timeout": {"type": "int"},
+ "retransmit_interval": {"type": "int"},
+ "shutdown": {"type": "bool"},
+ "transmit_delay": {"type": "int"},
+ "ttl_security": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "hops": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py
new file mode 100644
index 00000000..fb053745
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py
@@ -0,0 +1,547 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospfv2 module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class Ospfv2Args(object):
+ """The arg spec for the ios_ospfv2 module
+ """
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "processes": {
+ "elements": "dict",
+ "options": {
+ "address_family": {
+ "options": {
+ "default": {"type": "bool"},
+ "snmp_context": {"type": "str"},
+ "topology": {
+ "options": {
+ "base": {"type": "bool"},
+ "name": {"type": "str"},
+ "tid": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "adjacency": {
+ "options": {
+ "max_adjacency": {"type": "int"},
+ "min_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "areas": {
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "options": {
+ "enable": {"type": "bool"},
+ "message_digest": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "capability": {"type": "bool"},
+ "default_cost": {"type": "int"},
+ "filter_list": {
+ "elements": "dict",
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "nssa": {
+ "options": {
+ "default_information_originate": {
+ "options": {
+ "metric": {"type": "int"},
+ "metric_type": {
+ "choices": [1, 2],
+ "type": "int",
+ },
+ "nssa_only": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "no_ext_capability": {"type": "bool"},
+ "no_redistribution": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "set": {"type": "bool"},
+ "translate": {
+ "choices": [
+ "always",
+ "suppress-fa",
+ ],
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ranges": {
+ "options": {
+ "address": {"type": "str"},
+ "advertise": {"type": "bool"},
+ "cost": {"type": "int"},
+ "netmask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ },
+ "type": "list",
+ "elements": "dict",
+ },
+ "sham_link": {
+ "options": {
+ "cost": {"type": "int"},
+ "destination": {"type": "str"},
+ "source": {"type": "str"},
+ "ttl_security": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "stub": {
+ "options": {
+ "no_ext_capability": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "auto_cost": {
+ "options": {
+ "reference_bandwidth": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bfd": {"type": "bool"},
+ "capability": {
+ "options": {
+ "lls": {"type": "bool"},
+ "opaque": {"type": "bool"},
+ "transit": {"type": "bool"},
+ "vrf_lite": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "compatible": {
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "default_information": {
+ "options": {
+ "always": {"type": "bool"},
+ "metric": {"type": "int"},
+ "metric_type": {"type": "int"},
+ "originate": {"type": "bool"},
+ "route_map": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "default_metric": {"type": "int"},
+ "discard_route": {
+ "options": {
+ "external": {"type": "int"},
+ "internal": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "distance": {
+ "options": {
+ "admin_distance": {
+ "options": {
+ "acl": {"type": "str"},
+ "address": {"type": "str"},
+ "distance": {"type": "int"},
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "ospf": {
+ "options": {
+ "external": {"type": "int"},
+ "inter_area": {"type": "int"},
+ "intra_area": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "distribute_list": {
+ "options": {
+ "acls": {
+ "elements": "dict",
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "interface": {"type": "str"},
+ "name": {
+ "required": True,
+ "type": "str",
+ },
+ "protocol": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "prefix": {
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "gateway_name": {"type": "str"},
+ "interface": {"type": "str"},
+ "name": {
+ "required": True,
+ "type": "str",
+ },
+ "protocol": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "route_map": {
+ "options": {
+ "name": {
+ "required": True,
+ "type": "str",
+ }
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "domain_id": {
+ "options": {
+ "ip_address": {
+ "options": {
+ "address": {"type": "str"},
+ "secondary": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "null": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "domain_tag": {"type": "int"},
+ "event_log": {
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "help": {"type": "bool"},
+ "ignore": {"type": "bool"},
+ "interface_id": {"type": "bool"},
+ "ispf": {"type": "bool"},
+ "limit": {
+ "options": {
+ "dc": {
+ "options": {
+ "disable": {"type": "bool"},
+ "number": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "non_dc": {
+ "options": {
+ "disable": {"type": "bool"},
+ "number": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "local_rib_criteria": {
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "log_adjacency_changes": {
+ "options": {
+ "detail": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "max_lsa": {
+ "options": {
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "number": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "max_metric": {
+ "options": {
+ "external_lsa": {"type": "int"},
+ "include_stub": {"type": "bool"},
+ "on_startup": {
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "router_lsa": {
+ "required": True,
+ "type": "bool",
+ },
+ "summary_lsa": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "maximum_paths": {"type": "int"},
+ "mpls": {
+ "options": {
+ "ldp": {
+ "options": {
+ "autoconfig": {
+ "options": {
+ "area": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "sync": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "traffic_eng": {
+ "options": {
+ "area": {"type": "str"},
+ "autoroute_exclude": {"type": "str"},
+ "interface": {
+ "options": {
+ "area": {"type": "int"},
+ "interface_type": {
+ "type": "str"
+ },
+ },
+ "type": "dict",
+ },
+ "mesh_group": {
+ "options": {
+ "area": {"type": "str"},
+ "id": {"type": "int"},
+ "interface": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "multicast_intact": {"type": "bool"},
+ "router_id_interface": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "neighbor": {
+ "options": {
+ "address": {"type": "str"},
+ "cost": {"type": "int"},
+ "database_filter": {"type": "bool"},
+ "poll_interval": {"type": "int"},
+ "priority": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "network": {
+ "options": {
+ "address": {"type": "str"},
+ "area": {"type": "str"},
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "list",
+ "elements": "dict",
+ },
+ "nsf": {
+ "options": {
+ "cisco": {
+ "options": {
+ "disable": {"type": "bool"},
+ "helper": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "ietf": {
+ "options": {
+ "disable": {"type": "bool"},
+ "helper": {"type": "bool"},
+ "strict_lsa_checking": {
+ "type": "bool"
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "passive_interface": {"type": "str"},
+ "prefix_suppression": {"type": "bool"},
+ "priority": {"type": "int"},
+ "process_id": {"required": True, "type": "int"},
+ "queue_depth": {
+ "options": {
+ "hello": {
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "update": {
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {"type": "bool"},
+ "summary_address": {
+ "options": {
+ "address": {"type": "str"},
+ "mask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ "nssa_only": {"type": "bool"},
+ "tag": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "timers": {
+ "options": {
+ "lsa": {"type": "int"},
+ "pacing": {
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "throttle": {
+ "options": {
+ "lsa": {
+ "options": {
+ "first_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ "min_delay": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "spf": {
+ "options": {
+ "between_delay": {
+ "type": "int"
+ },
+ "max_delay": {"type": "int"},
+ "receive_delay": {
+ "type": "int"
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "traffic_share": {"type": "bool"},
+ "ttl_security": {
+ "options": {
+ "hops": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "vrf": {"type": "str"},
+ },
+ "type": "list",
+ }
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py
new file mode 100644
index 00000000..6b31ecd4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py
@@ -0,0 +1,807 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+#############################################
+# 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 cisco.ios_ospfv3 module
+"""
+
+
+class Ospfv3Args(object): # pylint: disable=R0903
+ """The arg spec for the cisco.ios_ospfv3 module
+ """
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "processes": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "process_id": {"required": True, "type": "int"},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ },
+ "unicast": {"type": "bool"},
+ "vrf": {"type": "str"},
+ "adjacency": {
+ "type": "dict",
+ "options": {
+ "min_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ "max_adjacency": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "areas": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str"},
+ "null": {"type": "bool"},
+ },
+ },
+ "default_cost": {"type": "int"},
+ "filter_list": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "direction": {
+ "type": "str",
+ "choices": ["in", "out"],
+ "required": True,
+ },
+ },
+ },
+ "normal": {"type": "bool"},
+ "nssa": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "default_information_originate": {
+ "type": "dict",
+ "options": {
+ "metric": {
+ "type": "int"
+ },
+ "metric_type": {
+ "type": "int",
+ "choices": [1, 2],
+ },
+ "nssa_only": {
+ "type": "bool"
+ },
+ },
+ },
+ "no_redistribution": {
+ "type": "bool"
+ },
+ "no_summary": {"type": "bool"},
+ "translate": {
+ "type": "str",
+ "choices": [
+ "always",
+ "suppress-fa",
+ ],
+ },
+ },
+ },
+ "ranges": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise": {"type": "bool"},
+ "cost": {"type": "int"},
+ "not_advertise": {
+ "type": "bool"
+ },
+ },
+ },
+ "sham_link": {
+ "type": "dict",
+ "options": {
+ "source": {"type": "str"},
+ "destination": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {
+ "type": "str"
+ },
+ "null": {
+ "type": "bool"
+ },
+ },
+ },
+ "cost": {"type": "int"},
+ "ttl_security": {
+ "type": "int"
+ },
+ },
+ },
+ "stub": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "deployment": {"type": "bool"},
+ "normal": {"type": "bool"},
+ },
+ },
+ "auto_cost": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "reference_bandwidth": {"type": "int"},
+ },
+ },
+ "bfd": {
+ "type": "dict",
+ "options": {
+ "all_interfaces": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "capability": {"type": "bool"},
+ "compatible": {
+ "type": "dict",
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ },
+ "default_information": {
+ "type": "dict",
+ "options": {
+ "originate": {"type": "bool"},
+ "always": {"type": "bool"},
+ "metric": {"type": "int"},
+ "metric_type": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "default_metric": {"type": "int"},
+ "discard_route": {
+ "type": "dict",
+ "options": {
+ "sham_link": {"type": "bool"},
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ },
+ },
+ "distance": {"type": "int"},
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acls": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {
+ "type": "str",
+ "required": True,
+ },
+ "direction": {
+ "type": "str",
+ "required": True,
+ "choices": ["in", "out"],
+ },
+ "interface": {"type": "str"},
+ "protocol": {"type": "str"},
+ },
+ },
+ "prefix": {
+ "type": "dict",
+ "options": {
+ "name": {
+ "type": "str",
+ "required": True,
+ },
+ "gateway_name": {
+ "type": "str"
+ },
+ "direction": {
+ "type": "str",
+ "required": True,
+ "choices": ["in", "out"],
+ },
+ "interface": {"type": "str"},
+ "protocol": {"type": "str"},
+ },
+ },
+ "route_map": {
+ "type": "dict",
+ "options": {
+ "name": {
+ "type": "str",
+ "required": True,
+ }
+ },
+ },
+ },
+ },
+ "event_log": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ },
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "strict_lsa_checking": {
+ "type": "bool"
+ },
+ },
+ },
+ "interface_id": {
+ "type": "dict",
+ "options": {
+ "ios_if_index": {"type": "bool"},
+ "snmp_if_index": {"type": "bool"},
+ },
+ },
+ "limit": {
+ "type": "dict",
+ "options": {
+ "dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "non_dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "local_rib_criteria": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ },
+ "log_adjacency_changes": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "detail": {"type": "bool"},
+ },
+ },
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {
+ "type": "int"
+ },
+ "update": {"type": "int"},
+ },
+ },
+ "hello": {
+ "type": "dict",
+ "options": {
+ "multicast": {"type": "bool"},
+ "unicast": {"type": "bool"},
+ },
+ },
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "per_interface": {
+ "type": "bool"
+ },
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "max_lsa": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "max_metric": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "external_lsa": {"type": "int"},
+ "inter_area_lsas": {"type": "int"},
+ "on_startup": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {
+ "type": "bool"
+ },
+ },
+ },
+ "stub_prefix_lsa": {"type": "bool"},
+ },
+ },
+ "maximum_paths": {"type": "int"},
+ "passive_interface": {"type": "str"},
+ "prefix_suppression": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "queue_depth": {
+ "type": "dict",
+ "options": {
+ "hello": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ },
+ "update": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "summary_prefix": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "mask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ "nssa_only": {"type": "bool"},
+ "tag": {"type": "int"},
+ },
+ },
+ "timers": {
+ "type": "dict",
+ "options": {
+ "lsa": {"type": "int"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {
+ "type": "int"
+ },
+ "redundancy": {
+ "type": "int"
+ },
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {
+ "type": "bool"
+ },
+ "per_interface": {
+ "type": "bool"
+ },
+ "redundancy": {
+ "type": "int"
+ },
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "pacing": {
+ "type": "dict",
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {
+ "type": "int"
+ },
+ },
+ },
+ "throttle": {
+ "type": "dict",
+ "options": {
+ "lsa": {
+ "type": "dict",
+ "options": {
+ "first_delay": {
+ "type": "int"
+ },
+ "min_delay": {
+ "type": "int"
+ },
+ "max_delay": {
+ "type": "int"
+ },
+ },
+ },
+ "spf": {
+ "type": "dict",
+ "options": {
+ "receive_delay": {
+ "type": "int"
+ },
+ "between_delay": {
+ "type": "int"
+ },
+ "max_delay": {
+ "type": "int"
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "adjacency": {
+ "type": "dict",
+ "options": {
+ "min_adjacency": {"type": "int"},
+ "max_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ },
+ },
+ "areas": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str"},
+ "ipsec": {
+ "type": "dict",
+ "options": {
+ "spi": {"type": "int"},
+ "md5": {"type": "int"},
+ "sha1": {"type": "int"},
+ "hex_string": {"type": "str"},
+ },
+ },
+ },
+ },
+ "default_cost": {"type": "int"},
+ "nssa": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "default_information_originate": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "metric_type": {
+ "type": "int",
+ "choices": [1, 2],
+ },
+ "nssa_only": {"type": "bool"},
+ },
+ },
+ "no_redistribution": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "translate": {
+ "type": "str",
+ "choices": [
+ "always",
+ "suppress-fa",
+ ],
+ },
+ },
+ },
+ "stub": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "authentication": {"type": "bool"},
+ "auto_cost": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "reference_bandwidth": {"type": "int"},
+ },
+ },
+ "bfd": {"type": "bool"},
+ "compatible": {
+ "type": "dict",
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ },
+ "event_log": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ },
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "strict_lsa_checking": {"type": "bool"},
+ },
+ },
+ "help": {"type": "bool"},
+ "interface_id": {"type": "bool"},
+ "limit": {
+ "type": "dict",
+ "options": {
+ "dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "non_dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "local_rib_criteria": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ },
+ "log_adjacency_changes": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "detail": {"type": "bool"},
+ },
+ },
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {"type": "int"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "per_interface": {"type": "bool"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "max_lsa": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "max_metric": {
+ "type": "dict",
+ "options": {
+ "router_lsa": {
+ "type": "bool",
+ "required": True,
+ },
+ "external_lsa": {"type": "int"},
+ "include_stub": {"type": "bool"},
+ "on_startup": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {"type": "bool"},
+ },
+ },
+ "summary_lsa": {"type": "int"},
+ },
+ },
+ "passive_interface": {"type": "str"},
+ "prefix_suppression": {"type": "bool"},
+ "queue_depth": {
+ "type": "dict",
+ "options": {
+ "hello": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ }
+ },
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "lsa": {"type": "int"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {
+ "type": "int"
+ },
+ "redundancy": {"type": "int"},
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "per_interface": {
+ "type": "bool"
+ },
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "pacing": {
+ "type": "dict",
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {"type": "int"},
+ },
+ },
+ "throttle": {
+ "type": "dict",
+ "options": {
+ "lsa": {
+ "type": "dict",
+ "options": {
+ "first_delay": {"type": "int"},
+ "min_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ },
+ },
+ "spf": {
+ "type": "dict",
+ "options": {
+ "receive_delay": {
+ "type": "int"
+ },
+ "between_delay": {
+ "type": "int"
+ },
+ "max_delay": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py
new file mode 100644
index 00000000..e7dc942f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py
@@ -0,0 +1,100 @@
+#
+# -*- 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py
new file mode 100644
index 00000000..29528962
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py
@@ -0,0 +1,71 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
new file mode 100644
index 00000000..a650b295
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,415 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible.module_utils.six import iteritems
+from ansible_collections.cisco.ios.plugins.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_acl_name = []
+ if w_access_group:
+ # get the user input afi and acls
+ for each in w_access_group:
+ want_acls = each.get("acls")
+ 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"):
+ acl_name = acl.get("name")
+ acl_direction = acl.get("direction")
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py
new file mode 100644
index 00000000..b5f7e1dc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py
@@ -0,0 +1,301 @@
+#
+# -*- 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_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.acls import (
+ AclsTemplate,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import (
+ ResourceModule,
+)
+
+
+class Acls(ResourceModule):
+ """
+ The ios_acls class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["acls"]
+
+ def __init__(self, module):
+ super(Acls, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="acls",
+ tmplt=AclsTemplate(),
+ )
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from moduel execution
+ """
+ self.gen_config()
+ self.run_commands()
+ return self.result
+
+ def gen_config(self):
+ """ Select the appropriate function based on the state provided
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+
+ if self.want:
+ wantd = self.want
+ else:
+ wantd = {}
+ if self.have:
+ haved = self.have
+ else:
+ haved = {}
+
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ temp_have = copy.deepcopy(haved)
+ temp = []
+ temp_acls = {}
+
+ for each in wantd:
+ want_in_have = False
+ for each_have in temp_have:
+ if each.get("afi") == each_have.get("afi"):
+ temp_acls["acls"] = []
+ for each_acls in each.get("acls"):
+ want_acls_in_have = False
+ for each_have_acls in each_have.get("acls"):
+ if each_acls["name"] == each_have_acls["name"]:
+ aces = []
+ for each_ace in each_acls["aces"]:
+ each_ace_sequence = each_ace.get(
+ "sequence"
+ )
+ if each_ace_sequence:
+ for (
+ each_have_ace
+ ) in each_have_acls["aces"]:
+ if (
+ each_ace_sequence
+ == each_have_ace.get(
+ "sequence"
+ )
+ ):
+ aces.append(
+ dict(
+ dict_merge(
+ each_have_ace,
+ each_ace,
+ )
+ )
+ )
+ break
+ if aces:
+ temp_acls["acls"].append(
+ {
+ "aces": aces,
+ "name": each_acls["name"],
+ }
+ )
+ else:
+ temp_acls["acls"].append(
+ dict(
+ dict_merge(
+ each_have_acls, each_acls
+ )
+ )
+ )
+ want_acls_in_have = True
+ if not want_acls_in_have:
+ temp_acls["acls"].append(each_acls)
+ temp_acls.update({"afi": each.get("afi")})
+ # temp.append(dict(dict_merge(each, each_have)))
+ temp.append(temp_acls)
+ want_in_have = True
+ if not want_in_have:
+ temp.append(each)
+ if temp:
+ wantd = temp
+
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted":
+ if wantd:
+ for each_have in haved:
+ count = 0
+ for every_have in each_have.get("acls"):
+ del_want = False
+ for each_want in wantd:
+ want_acls = each_want.get("acls")
+ want_afi = each_want.get("afi")
+ if want_acls:
+ for every_want in each_want.get("acls"):
+ if every_want.get(
+ "name"
+ ) == every_have.get("name"):
+ del_want = True
+ break
+ elif want_afi and want_afi == each_have["afi"]:
+ del_want = True
+ if not del_want:
+ del each_have.get("acls")[count]
+ count += 1
+ wantd = {}
+ for each in haved:
+ for every_acls in each.get("acls"):
+ every_acls.update({"afi": each.get("afi")})
+ self.addcmd(every_acls, "acls_name", True)
+
+ # remove superfluous config for overridden and deleted
+ if self.state in ["overridden"] and wantd:
+ for each_have in haved:
+ count = 0
+ for every_have in each_have.get("acls"):
+ del_want = False
+ for each_want in wantd:
+ for every_want in each_want.get("acls"):
+ if every_want.get("name") == every_have.get(
+ "name"
+ ):
+ del_want = True
+ break
+ if not del_want:
+ every_have.update({"afi": each_have.get("afi")})
+ self.addcmd(every_have, "acls_name", True)
+ count += 1
+
+ for w in wantd:
+ want_in_have = False
+ if haved:
+ for h in haved:
+ if w["afi"] == h["afi"]:
+ want_in_have = True
+ for e_w in w["acls"]:
+ set_want = True
+ for e_h in h["acls"]:
+ if e_w["name"] == e_h["name"]:
+ e_w.update({"afi": w.get("afi")})
+ e_h.update({"afi": h.get("afi")})
+ self._compare(want=e_w, have=e_h)
+ set_want = False
+ break
+ if set_want:
+ e_w.update({"afi": w.get("afi")})
+ self._compare(want=e_w, have={})
+ if not haved or not want_in_have:
+ for e_w in w["acls"]:
+ e_w.update({"afi": w["afi"]})
+ self._compare(want=e_w, have={})
+
+ def _compare(self, want, have):
+ """Leverages the base class `compare()` method and
+ populates the list of commands to be run by comparing
+ the `want` and `have` data with the `parsers` defined
+ for the Ospf_interfaces network resource.
+ """
+ parsers = ["aces"]
+
+ if want.get("aces"):
+ cmd_added = True
+ for each in want.get("aces"):
+ set_want = True
+ if have.get("aces"):
+ for each_have in have.get("aces"):
+ if each.get("source") == each_have.get(
+ "source"
+ ) and each.get("destination") == each_have.get(
+ "destination"
+ ):
+ set_want = False
+ if each.get("sequence") and not each_have.get(
+ "sequence"
+ ):
+ each_have.update(
+ {"sequence": each.get("sequence")}
+ )
+ elif not each.get("sequence") and each_have.get(
+ "sequence"
+ ):
+ each.update(
+ {"sequence": each_have.get("sequence")}
+ )
+ if each.get("protocol") and not each_have.get(
+ "protocol"
+ ):
+ each_have.update(
+ {"protocol": each.get("protocol")}
+ )
+ elif not each.get("protocol") and each_have.get(
+ "protocol"
+ ):
+ each.update(
+ {"protocol": each_have.get("protocol")}
+ )
+ if each != each_have:
+ if cmd_added:
+ self.addcmd(have, "acls_name", False)
+ cmd_added = False
+ self.compare(
+ parsers=parsers,
+ want={"aces": each, "afi": want["afi"]},
+ have={
+ "aces": each_have,
+ "afi": have["afi"],
+ },
+ )
+ elif each.get("sequence") == each_have.get("sequence"):
+ if cmd_added:
+ self.addcmd(have, "acls_name", False)
+ cmd_added = False
+ self.compare(
+ parsers=parsers,
+ want={},
+ have={"aces": each_have, "afi": have["afi"]},
+ )
+ self.compare(
+ parsers=parsers,
+ want={"aces": each, "afi": want["afi"]},
+ have={},
+ )
+ set_want = False
+ else:
+ if cmd_added:
+ self.addcmd(want, "acls_name", False)
+ cmd_added = False
+ self.compare(
+ parsers=parsers,
+ want={"aces": each, "afi": want["afi"]},
+ have=dict(),
+ )
+ set_want = False
+ if set_want:
+ if cmd_added:
+ self.addcmd(want, "acls_name", False)
+ cmd_added = False
+ self.compare(
+ parsers=parsers,
+ want={"aces": each, "afi": want["afi"]},
+ have=dict(),
+ )
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py
new file mode 100644
index 00000000..6a20e23b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py
@@ -0,0 +1,452 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The cisco.ios_bgp_global config file.
+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 ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import (
+ ResourceModule,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.bgp_global import (
+ Bgp_globalTemplate,
+)
+
+
+class Bgp_global(ResourceModule):
+ """
+ The cisco.ios_bgp_global config class
+ """
+
+ parsers = [
+ "as_number",
+ "bgp.additional_paths",
+ "bgp.dampening",
+ "bgp.graceful_shutdown",
+ "route_server_context",
+ "synchronization",
+ "table_map",
+ "timers",
+ ]
+
+ def __init__(self, module):
+ super(Bgp_global, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="bgp_global",
+ tmplt=Bgp_globalTemplate(),
+ )
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ if self.state not in ["parsed", "gathered"]:
+ self.generate_commands()
+ self.run_commands()
+ return self.result
+
+ def generate_commands(self):
+ """ Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ if self.want:
+ wantd = {self.want["as_number"]: self.want}
+ else:
+ wantd = {}
+ if self.have:
+ haved = {self.have["as_number"]: self.have}
+ else:
+ haved = {}
+
+ wantd, haved = self.list_to_dict(wantd, haved)
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted" and self.have:
+ if (
+ not self.want
+ or self.have.get("as_number") == self.want.get("as_number")
+ and len(self.have) > 1
+ ):
+ self.addcmd(
+ {"as_number": haved[list(haved)[0]].pop("as_number")},
+ "as_number",
+ False,
+ )
+ self.compare(
+ parsers=self.parsers, want={}, have=haved[list(haved)[0]]
+ )
+ self._compare(want={}, have=haved[list(haved)[0]])
+ self._list_params_compare(want={}, have=haved[list(haved)[0]])
+ wantd = {}
+
+ if self.state == "purged" and self.have:
+ if (
+ not self.want
+ or (self.have.get("as_number") == self.want.get("as_number"))
+ and len(self.have) >= 1
+ ):
+ self.addcmd(
+ {"as_number": haved[list(haved)[0]].pop("as_number")},
+ "as_number",
+ True,
+ )
+ wantd = {}
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ """Leverages the base class `compare()` method and
+ populates the list of commands to be run by comparing
+ the `want` and `have` data with the `parsers` defined
+ for the Ospf_interfaces network resource.
+ """
+ if want != have and self.state != "deleted":
+ self.addcmd(have, "as_number", False)
+ self.compare(parsers=self.parsers, want=want, have=have)
+ self._bgp_config_compare(want.get("bgp"), have.get("bgp"))
+ self._list_params_compare(want, have)
+ elif self.state == "deleted":
+ self._bgp_config_compare(dict(), have.get("bgp"))
+
+ def _bgp_config_compare(self, want, have):
+ if want and have and want != have and isinstance(want, dict):
+ set_have = True
+ for k, val in iteritems(want):
+ if isinstance(val, dict):
+ if k in have:
+ self.compare(
+ parsers=["bgp.config"],
+ want={"bgp": {k: val}},
+ have={"bgp": {k: have[k]}},
+ )
+ if k in have and self.state == "replaced":
+ if set_have:
+ self.compare(
+ parsers=["bgp.config"],
+ want=dict(),
+ have={"bgp": {k: have[k]}},
+ )
+ self.compare(
+ parsers=["bgp.config"],
+ want={"bgp": {k: val}},
+ have={"bgp": {k: have[k]}},
+ )
+ else:
+ self.compare(
+ parsers=["bgp.config"],
+ want={"bgp": {k: val}},
+ have=dict(),
+ )
+ elif want and not have:
+ for k, val in iteritems(want):
+ if not isinstance(val, list):
+ self.compare(
+ parsers=["bgp.config"],
+ want={"bgp": {k: val}},
+ have=dict(),
+ )
+ elif not want and have:
+ for k, val in iteritems(have):
+ if not isinstance(val, list):
+ self.compare(
+ parsers=["bgp.config"],
+ want=dict(),
+ have={"bgp": {k: val}},
+ )
+
+ def _list_params_compare(self, want, have):
+ def multi_compare(parser, want, have):
+ if want:
+ dict_iter = want
+ else:
+ dict_iter = have
+ for k, v in iteritems(dict_iter):
+ if parser == "neighbor":
+ type = None
+ if want.get("address") or have.get("address"):
+ type = "address"
+ want_type_val = want.get("address")
+ have_type_val = have.get("address")
+ if want.get("tag") or have.get("tag"):
+ type = "tag"
+ want_type_val = want.get("tag")
+ have_type_val = have.get("tag")
+ if want.get("ipv6_adddress") or have.get("ipv6_address"):
+ type = "ipv6_adddress"
+ want_type_val = want.get("ipv6_adddress")
+ have_type_val = have.get("ipv6_adddress")
+ if want and have:
+ self.compare(
+ parsers=[parser],
+ want={parser: {k: v, type: want_type_val}},
+ have={
+ parser: {
+ k: have.get(k, {}),
+ type: have_type_val,
+ }
+ },
+ )
+ elif not have:
+ self.compare(
+ parsers=[parser],
+ want={parser: {k: v, type: want_type_val}},
+ have=dict(),
+ )
+ elif not want:
+ self.compare(
+ parsers=[parser],
+ want=dict(),
+ have={parser: {k: v, type: have_type_val}},
+ )
+ if parser == "redistribute":
+ if want and have:
+ self.compare(
+ parsers=[parser],
+ want={parser: {k: v}},
+ have={parser: {k: have.get(k, {})}},
+ )
+ elif not have:
+ self.compare(
+ parsers=[parser],
+ want={parser: {k: v}},
+ have=dict(),
+ )
+ elif not want:
+ self.compare(
+ parsers=[parser],
+ want=dict(),
+ have={parser: {k: v}},
+ )
+
+ for every in ["bgp", "neighbor", "redistribute"]:
+
+ param_want = want.get(every)
+ param_have = have.get(every)
+ if param_want and param_want != param_have:
+ set_have = True
+ if every == "bgp":
+ for each in ["bestpath", "nopeerup_delay"]:
+ set_have = True
+ for k, v in iteritems(param_want.get(each)):
+ if (
+ param_have
+ and k in param_have.get(each)
+ and self.state == "merged"
+ ):
+ if k in param_have.get(each):
+ self.compare(
+ parsers=[every + "." + each],
+ want={"bgp": {each: {k: v}}},
+ have={
+ "bgp": {
+ each: {
+ k: param_have.get(
+ each, {}
+ )[k]
+ }
+ }
+ },
+ )
+
+ elif param_have and self.state == "replaced":
+ if set_have and param_have.get(each):
+ if isinstance(each, dict):
+ for key_have, val_have in iteritems(
+ param_have.get(each)
+ ):
+ multi_compare(
+ parser=every,
+ want=dict(),
+ have=val_have,
+ )
+ else:
+ # q(param_have, param_want)
+ temp_have = {
+ each: {i: param_have[each][i]}
+ for i in list(param_have[each])
+ if i not in param_want[each]
+ }
+ temp_want = {
+ each: {i: param_want[each][i]}
+ for i in list(param_want[each])
+ if i not in param_have[each]
+ }
+ # q(temp_have)
+ if temp_have:
+ self.compare(
+ parsers=[every + "." + each],
+ want=dict(),
+ have={"bgp": temp_have},
+ )
+ if temp_want:
+ self.compare(
+ parsers=[every + "." + each],
+ want={"bgp": temp_want},
+ have=dict(),
+ )
+ set_have = False
+ else:
+ self.compare(
+ parsers=[every + "." + each],
+ want={"bgp": {each: {k: v}}},
+ have=dict(),
+ )
+ if every == "neighbor" or every == "redistribute":
+ for k, v in iteritems(param_want):
+ if every == "neighbor":
+ if param_have and self.state == "merged":
+ multi_compare(
+ parser=every,
+ want=v,
+ have=param_have.pop(k, {}),
+ )
+ elif param_have and self.state == "replaced":
+ if set_have:
+ for key_have, val_have in iteritems(
+ param_have
+ ):
+ multi_compare(
+ parser=every,
+ want=dict(),
+ have=val_have,
+ )
+ set_have = False
+ multi_compare(
+ parser=every, want=v, have=dict()
+ )
+ else:
+ multi_compare(
+ parser=every, want=v, have=dict()
+ )
+ self.commands = (
+ [
+ each
+ for each in self.commands
+ if "neighbor" not in each
+ ]
+ + [
+ each
+ for each in self.commands
+ if "remote-as" in each
+ and "neighbor" in each
+ ]
+ + [
+ each
+ for each in self.commands
+ if "remote-as" not in each
+ and "neighbor" in each
+ ]
+ )
+ elif every == "redistribute":
+ if param_have and self.state == "merged":
+ multi_compare(
+ parser=every,
+ want={k: v},
+ have={k: param_have.pop(k, {})},
+ )
+ if param_have and self.state == "replaced":
+ if set_have:
+ for key_have, val_have in iteritems(
+ param_have
+ ):
+ multi_compare(
+ parser=every,
+ want=dict(),
+ have=val_have,
+ )
+ set_have = False
+ multi_compare(
+ parser=every, want={k: v}, have=dict()
+ )
+ else:
+ multi_compare(
+ parser=every, want={k: v}, have=dict()
+ )
+ elif param_have and self.state == "deleted":
+ del_config_have = True
+ if param_have:
+ for k, v in iteritems(param_have):
+ if every == "bgp" and del_config_have:
+ for each in ["bestpath", "nopeerup_delay"]:
+ for k, v in iteritems(param_have.get(each)):
+ self.compare(
+ parsers=[every + "." + each],
+ want=dict(),
+ have={"bgp": {each: {k: v}}},
+ )
+ del_config_have = False
+ elif every == "neighbor":
+ multi_compare(parser=every, want=dict(), have=v)
+ elif every == "redistribute":
+ if param_have:
+ multi_compare(
+ parser=every, want=dict(), have={k: v}
+ )
+
+ def list_to_dict(self, wantd, haved):
+ for thing in wantd, haved:
+ if thing:
+ for key, val in iteritems(thing):
+ for every in ["bgp", "neighbor", "redistribute"]:
+ value = val.get(every)
+ if value:
+ if isinstance(value, dict):
+ for k, v in iteritems(val.get(every)):
+ if isinstance(v, list):
+ temp = dict()
+ temp[k] = {}
+ for each in v:
+ temp[k].update(each)
+ val[every][k] = temp[k]
+ elif isinstance(value, list):
+ temp = dict()
+ temp[every] = {}
+ for each in value:
+ if every == "neighbor":
+ if each.get("address"):
+ temp[every].update(
+ {each.get("address"): each}
+ )
+ elif each.get("tag"):
+ temp[every].update(
+ {each.get("tag"): each}
+ )
+ elif each.get("ipv6_adddress"):
+ temp[every].update(
+ {
+ each.get(
+ "ipv6_adddress"
+ ): each
+ }
+ )
+ elif every == "redistribute":
+ temp[every].update(each)
+ val[every] = temp[every]
+ return wantd, haved
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py
new file mode 100644
index 00000000..a449f5f0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py
@@ -0,0 +1,353 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ remove_command_from_config_list,
+ add_command_to_config_list,
+)
+from ansible_collections.cisco.ios.plugins.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, 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
+ )
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_interfaces_facts = self.get_interfaces_facts()
+ else:
+ existing_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_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_interfaces_facts = self.get_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_interfaces_facts(data=running_config)
+ else:
+ changed_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = 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
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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 = []
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state == "merged" or self.state == "rendered":
+ commands = self._state_merged(want, have)
+ elif self.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
+ if 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
+ if 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
new file mode 100644
index 00000000..b9451fe0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,478 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ remove_command_from_config_list,
+ add_command_to_config_list,
+)
+from ansible_collections.cisco.ios.plugins.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",
+ "pruning_vlans_add": "switchport trunk pruning vlan add",
+ "native_vlan": "switchport trunk native vlan",
+ "allowed_vlans": "switchport trunk allowed vlan",
+ "allowed_vlans_add": "switchport trunk allowed vlan add",
+ }
+
+ def get_l2_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
+ )
+ l2_interfaces_facts = facts["ansible_network_resources"].get(
+ "l2_interfaces"
+ )
+ if not l2_interfaces_facts:
+ return []
+
+ return l2_interfaces_facts
+
+ def execute_module(self):
+ """ Execute the module
+ :rtype: A dictionary
+ :returns: The result from moduel execution
+ """
+ result = {"changed": False}
+ commands = []
+ warnings = []
+ if self.state in self.ACTION_STATES:
+ existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
+ else:
+ existing_l2_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_l2_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_l2_interfaces_facts = self.get_l2_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_l2_interfaces_facts(
+ data=running_config
+ )
+ else:
+ changed_l2_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_l2_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_l2_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_l2_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
+ """
+
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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 = []
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have, self._module)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state == "merged" or self.state == "rendered":
+ commands = self._state_merged(want, have, self._module)
+ elif self.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:
+ # configuring non-existing interface
+ 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
+ :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
+ ):
+ diff = None
+ if self.state == "merged":
+ have_trunk = have.get("trunk")
+ if have_trunk and have_trunk.get("allowed_vlans"):
+ have_allowed_vlans = have_trunk.get(
+ "allowed_vlans"
+ )
+ allowed_vlans = list(allowed_vlans)
+ diff = set(allowed_vlans).difference(
+ set(have_allowed_vlans)
+ )
+ allowed_vlans = list(diff) if diff else tuple()
+ allowed_vlans = ",".join(allowed_vlans)
+ if allowed_vlans:
+ trunk_cmd = (
+ self.trunk_cmds["allowed_vlans_add"]
+ if self.state == "merged" and diff
+ else self.trunk_cmds["allowed_vlans"]
+ )
+ cmd = trunk_cmd + " {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
+ ):
+ diff = None
+ if self.state == "merged":
+ have_trunk = have.get("trunk")
+ if have_trunk and have_trunk.get("pruning_vlans"):
+ have_pruning_vlans = have_trunk.get(
+ "pruning_vlans"
+ )
+ pruning_vlans = list(pruning_vlans)
+ diff = set(pruning_vlans).difference(
+ set(have_pruning_vlans)
+ )
+ pruning_vlans = list(diff) if diff else tuple()
+ pruning_vlans = ",".join(pruning_vlans)
+ if pruning_vlans:
+ trunk_cmd = (
+ self.trunk_cmds["pruning_vlans_add"]
+ if self.state == "merged" and diff
+ else self.trunk_cmds["pruning_vlans"]
+ )
+ cmd = trunk_cmd + " {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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
new file mode 100644
index 00000000..3d45588b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,435 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+ remove_empties,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ remove_command_from_config_list,
+ add_command_to_config_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ filter_dict_having_none_value,
+ remove_duplicate_interface,
+)
+from ansible_collections.cisco.ios.plugins.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, 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
+ )
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_l3_interfaces_facts = self.get_l3_interfaces_facts()
+ else:
+ existing_l3_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_l3_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_l3_interfaces_facts = self.get_l3_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_l3_interfaces_facts(
+ data=running_config
+ )
+ else:
+ changed_l3_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_l3_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_l3_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_l3_interfaces_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_l3_interfaces_facts):
+ """ Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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 = []
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have, self._module)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have, self._module)
+ elif self.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)
+ )
+ if self.state == "rendered":
+ 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
+ if 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 = remove_empties(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
+ if (
+ each_want.get("dhcp_client")
+ != every_have.get("dhcp_client")
+ and each_want.get("dhcp_client") is not None
+ ):
+ diff = True
+ break
+ if (
+ each_want.get("dhcp_hostname")
+ != every_have.get("dhcp_hostname")
+ and each_want.get("dhcp_hostname") is not None
+ ):
+ diff = True
+ break
+ if 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 "/" in interface:
+ dhcp_interface = want["name"].split("/")[0] + "/"
+ elif "gigabitethernet" in interface.lower():
+ dhcp_interface = "GigabitEthernet"
+ if ipv4_dict.get(
+ "dhcp_client"
+ ) is not None and ipv4_dict.get("dhcp_hostname"):
+ cmd = "ip address dhcp client-id {0}{1} hostname {2}".format(
+ dhcp_interface,
+ 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 {0}{1}".format(
+ dhcp_interface, 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py
new file mode 100644
index 00000000..6adab3bd
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py
@@ -0,0 +1,224 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.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, 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
+ )
+ lacp_facts = facts["ansible_network_resources"].get("lacp")
+ if not lacp_facts:
+ return dict()
+
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_facts = self.get_lacp_facts()
+ else:
+ existing_lacp_facts = dict()
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lacp_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_lacp_facts = self.get_lacp_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_lacp_facts(data=running_config)
+ else:
+ changed_lacp_facts = dict()
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lacp_facts
+ if result["changed"]:
+ result["after"] = changed_lacp_facts
+ elif self.state == "gathered":
+ result["gathered"] = 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
+ """
+ if self.state in ("merged", "replaced", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ self.state
+ )
+ )
+
+ if self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 00000000..3d21b635
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,314 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ remove_command_from_config_list,
+ add_command_to_config_list,
+)
+from ansible_collections.cisco.ios.plugins.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, 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
+ )
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
+ else:
+ existing_lacp_interfaces_facts = []
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lacp_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_lacp_interfaces_facts = self.get_lacp_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_lacp_interfaces_facts(
+ data=running_config
+ )
+ else:
+ changed_lacp_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lacp_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_lacp_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lacp_interfaces_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lacp_interfaces_facts):
+ """ Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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 = []
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.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:
+ 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
+
+ :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 " + want["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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
new file mode 100644
index 00000000..40482fc0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,404 @@
+#
+# -*- 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.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ 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, 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
+ )
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
+ else:
+ existing_lag_interfaces_facts = []
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lag_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_lag_interfaces_facts = self.get_lag_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_lag_interfaces_facts(
+ data=running_config
+ )
+ else:
+ changed_lag_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lag_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_lag_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = 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
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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
+ """
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ module = self._module
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have, module)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have, module)
+ elif self.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
+ continue
+ if match:
+ have_dict = self.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 = self.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:
+ if interface.get("members"):
+ 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
+ commands.extend(
+ self._clear_config(interface, each)
+ )
+ continue
+ if match:
+ have_dict = self.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 = self.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:
+ if self.state == "rendered":
+ 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.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 filter_dict_having_none_value(self, want, have):
+ # Generate dict with have dict value which is None in want dict
+ test_dict = dict()
+ test_key_dict = dict()
+ test_dict["name"] = want.get("name")
+ for k, v in iteritems(want):
+ if isinstance(v, dict):
+ for key, value in iteritems(v):
+ if value is None:
+ dict_val = have.get(k).get(key)
+ test_key_dict.update({key: dict_val})
+ test_dict.update({k: test_key_dict})
+ if v is None:
+ val = have.get(k)
+ test_dict.update({k: val})
+ return test_dict
+
+ 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 want.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py
new file mode 100644
index 00000000..b4e6a322
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py
@@ -0,0 +1,275 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+)
+from ansible_collections.cisco.ios.plugins.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, data=None):
+ """ Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset, self.gather_network_resources, data=data
+ )
+ lldp_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()
+
+ if self.state in self.ACTION_STATES:
+ existing_lldp_global_facts = self.get_lldp_global_facts()
+ else:
+ existing_lldp_global_facts = dict()
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lldp_global_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_lldp_global_facts = self.get_lldp_global_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_lldp_global_facts(data=running_config)
+ else:
+ changed_lldp_global_facts = dict()
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lldp_global_facts
+ if result["changed"]:
+ result["after"] = changed_lldp_global_facts
+ elif self.state == "gathered":
+ result["gathered"] = 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 = []
+ if self.state in ("merged", "replaced", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.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 = []
+
+ 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
+ :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 lldp global 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 lldp global 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 00000000..479f626c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,328 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ dict_to_set,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ remove_command_from_config_list,
+ add_command_to_config_list,
+)
+from ansible_collections.cisco.ios.plugins.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, data=None):
+ """ Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset, self.gather_network_resources, data=data
+ )
+ lldp_interfaces_facts = facts["ansible_network_resources"].get(
+ "lldp_interfaces"
+ )
+ if not lldp_interfaces_facts:
+ return []
+ return lldp_interfaces_facts
+
+ def 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_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
+ else:
+ existing_lldp_interfaces_facts = []
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lldp_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_lldp_interfaces_facts = self.get_lldp_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_lldp_interfaces_facts(
+ data=running_config
+ )
+ else:
+ changed_lldp_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lldp_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_lldp_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lldp_interfaces_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lldp_interfaces_facts):
+ """ Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ 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
+ """
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.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:
+ if self.state == "rendered":
+ 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
+
+ :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 " + 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)
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 00000000..3640207d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,165 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The cisco.ios_ospf_interfaces config file.
+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 ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import (
+ ResourceModule,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospf_interfaces import (
+ Ospf_InterfacesTemplate,
+)
+
+
+class Ospf_Interfaces(ResourceModule):
+ """
+ The cisco.ios_ospf_interfaces config class
+ """
+
+ def __init__(self, module):
+ super(Ospf_Interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospf_interfaces",
+ tmplt=Ospf_InterfacesTemplate(),
+ )
+ self.parsers = []
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ if self.state not in ["parsed", "gathered"]:
+ self.generate_commands()
+ self.run_commands()
+ return self.result
+
+ def generate_commands(self):
+ """ Generate configuration commands to send based on
+ want, have and desired state.
+ """
+
+ wantd = {}
+ haved = {}
+ if self.want:
+ wantd = {(entry["name"]): entry for entry in self.want}
+ else:
+ wantd = {}
+ if self.have:
+ haved = {(entry["name"]): entry for entry in self.have}
+ else:
+ haved = {}
+
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted":
+ haved = {
+ k: v for k, v in iteritems(haved) if k in wantd or not wantd
+ }
+ wantd = {}
+
+ # remove superfluous config for overridden and deleted
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self._compare(want={}, have=have)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ """Leverages the base class `compare()` method and
+ populates the list of commands to be run by comparing
+ the `want` and `have` data with the `parsers` defined
+ for the Ospf_interfaces network resource.
+ """
+ parsers = [
+ "name",
+ "process",
+ "adjacency",
+ "authentication",
+ "bfd",
+ "cost_ip",
+ "cost_ipv6_dynamic_cost",
+ "database_filter",
+ "dead_interval",
+ "demand_circuit",
+ "flood_reduction",
+ "hello_interval",
+ "lls",
+ "manet",
+ "mtu_ignore",
+ "multi_area",
+ "neighbor",
+ "network",
+ "prefix_suppression",
+ "priority",
+ "resync_timeout",
+ "retransmit_interval",
+ "shutdown",
+ "transmit_delay",
+ "ttl_security",
+ ]
+
+ if (
+ want != have
+ ): # and (want.get('address_family') or self.state == 'deleted'):
+ if have.get("address_family"):
+ self.addcmd(have, "name", False)
+ elif want.get("address_family"):
+ self.addcmd(want, "name", False)
+
+ if want.get("address_family"):
+ for each in want["address_family"]:
+ set_want = True
+ if have.get("address_family"):
+ have_elements = len(have.get("address_family"))
+ while have_elements:
+ if have.get("address_family")[have_elements - 1].get(
+ "afi"
+ ) == each.get("afi"):
+ set_want = False
+ h_each = have["address_family"].pop(
+ have_elements - 1
+ )
+ self.compare(
+ parsers=parsers, want=each, have=h_each
+ )
+ have_elements -= 1
+ else:
+ h_each = dict()
+ self.compare(parsers=parsers, want=each, have=h_each)
+ set_want = False
+ if set_want:
+ self.compare(parsers=parsers, want=each, have=dict())
+ if self.state in ["overridden", "deleted"]:
+ if have.get("address_family"):
+ for each in have["address_family"]:
+ self.compare(parsers=parsers, want=dict(), have=each)
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py
new file mode 100644
index 00000000..08c0af36
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_ospfv2 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.six import iteritems
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv2 import (
+ Ospfv2Template,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import (
+ ResourceModule,
+)
+
+
+class Ospfv2(ResourceModule):
+ """
+ The ios_ospfv2 class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospfv2"]
+
+ def __init__(self, module):
+ super(Ospfv2, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospfv2",
+ tmplt=Ospfv2Template(),
+ )
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ self.gen_config()
+ self.run_commands()
+ return self.result
+
+ def gen_config(self):
+ """ Select the appropriate function based on the state provided
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ if self.want:
+ wantd = {
+ (entry["process_id"], entry.get("vrf")): entry
+ for entry in self.want.get("processes", [])
+ }
+ else:
+ wantd = {}
+ if self.have:
+ haved = {
+ (entry["process_id"], entry.get("vrf")): entry
+ for entry in self.have.get("processes", [])
+ }
+ else:
+ haved = {}
+
+ # turn all lists of dicts into dicts prior to merge
+ for thing in wantd, haved:
+ for _pid, proc in iteritems(thing):
+ for area in proc.get("areas", []):
+ ranges = {
+ entry["address"]: entry
+ for entry in area.get("ranges", [])
+ }
+ if bool(ranges):
+ area["ranges"] = ranges
+ filter_list = {
+ entry["direction"]: entry
+ for entry in area.get("filter_list", [])
+ }
+ if bool(filter_list):
+ area["filter_list"] = filter_list
+ proc["areas"] = {
+ entry["area_id"]: entry for entry in proc.get("areas", [])
+ }
+ if proc.get("distribute_list"):
+ if "acls" in proc.get("distribute_list"):
+ proc["distribute_list"]["acls"] = {
+ entry["name"]: entry
+ for entry in proc["distribute_list"].get(
+ "acls", []
+ )
+ }
+
+ # if state is merged, merge want onto have
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, limit the have to anything in want
+ # set want to nothing
+ if self.state == "deleted":
+ haved = {
+ k: v for k, v in iteritems(haved) if k in wantd or not wantd
+ }
+ wantd = {}
+
+ # delete processes first so we do run into "more than one" errors
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self.addcmd(have, "pid", True)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ parsers = [
+ "adjacency",
+ "address_family",
+ "auto_cost",
+ "bfd",
+ "capability",
+ "compatible",
+ "default_information",
+ "default_metric",
+ "discard_route",
+ "distance.admin_distance",
+ "distance.ospf",
+ "distribute_list.acls",
+ "distribute_list.prefix",
+ "distribute_list.route_map",
+ "domain_id",
+ "domain_tag",
+ "event_log",
+ "help",
+ "ignore",
+ "interface_id",
+ "ispf",
+ "limit",
+ "local_rib_criteria",
+ "log_adjacency_changes",
+ "max_lsa",
+ "max_metric",
+ "maximum_paths",
+ "mpls.ldp",
+ "mpls.traffic_eng",
+ "neighbor",
+ "network",
+ "nsf.cisco",
+ "nsf.ietf",
+ "passive_interface",
+ "prefix_suppression",
+ "priority",
+ "queue_depth.hello",
+ "queue_depth.update",
+ "router_id",
+ "shutdown",
+ "summary_address",
+ "timers.throttle.lsa",
+ "timers.throttle.spf",
+ "traffic_share",
+ "ttl_security",
+ ]
+
+ if want != have:
+ self.addcmd(want or have, "pid", False)
+ self.compare(parsers, want, have)
+ self._areas_compare(want, have)
+
+ def _areas_compare(self, want, have):
+ wareas = want.get("areas", {})
+ hareas = have.get("areas", {})
+ for name, entry in iteritems(wareas):
+ self._area_compare(want=entry, have=hareas.pop(name, {}))
+ for name, entry in iteritems(hareas):
+ self._area_compare(want={}, have=entry)
+
+ def _area_compare(self, want, have):
+ parsers = [
+ "area.authentication",
+ "area.capability",
+ "area.default_cost",
+ "area.nssa",
+ "area.nssa.translate",
+ "area.ranges",
+ "area.sham_link",
+ "area.stub",
+ ]
+ self.compare(parsers=parsers, want=want, have=have)
+ self._area_compare_filters(want, have)
+
+ def _area_compare_filters(self, wantd, haved):
+ for name, entry in iteritems(wantd):
+ h_item = haved.pop(name, {})
+ if entry != h_item and name == "filter_list":
+ filter_list_entry = {}
+ filter_list_entry["area_id"] = wantd["area_id"]
+ if h_item:
+ li_diff = [
+ item
+ for item in entry + h_item
+ if item not in entry or item not in h_item
+ ]
+ else:
+ li_diff = entry
+ filter_list_entry["filter_list"] = li_diff
+ self.addcmd(filter_list_entry, "area.filter_list", False)
+ for name, entry in iteritems(haved):
+ if name == "filter_list":
+ self.addcmd(entry, "area.filter_list", True)
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py
new file mode 100644
index 00000000..f3c1e3d2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py
@@ -0,0 +1,324 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_ospfv3 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.six import iteritems
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv3 import (
+ Ospfv3Template,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import (
+ ResourceModule,
+)
+
+
+class Ospfv3(ResourceModule):
+ """
+ The ios_ospfv3 class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospfv3"]
+
+ def __init__(self, module):
+ super(Ospfv3, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospfv3",
+ tmplt=Ospfv3Template(),
+ )
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ self.gen_config()
+ self.run_commands()
+ return self.result
+
+ def gen_config(self):
+ """ Select the appropriate function based on the state provided
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ if self.want:
+ wantd = {
+ (entry["process_id"], entry.get("vrf")): entry
+ for entry in self.want.get("processes", [])
+ }
+ else:
+ wantd = {}
+ if self.have:
+ haved = {
+ (entry["process_id"], entry.get("vrf")): entry
+ for entry in self.have.get("processes", [])
+ }
+ else:
+ haved = {}
+
+ # turn all lists of dicts into dicts prior to merge
+ for thing in wantd, haved:
+ for _pid, proc in iteritems(thing):
+ for area in proc.get("areas", []):
+ ranges = {
+ entry["address"]: entry
+ for entry in area.get("ranges", [])
+ }
+ if bool(ranges):
+ area["ranges"] = ranges
+ filter_list = {
+ entry["direction"]: entry
+ for entry in area.get("filter_list", [])
+ }
+ if bool(filter_list):
+ area["filter_list"] = filter_list
+ proc["areas"] = {
+ entry["area_id"]: entry for entry in proc.get("areas", [])
+ }
+ if proc.get("distribute_list"):
+ if "acls" in proc.get("distribute_list"):
+ proc["distribute_list"]["acls"] = {
+ entry["name"]: entry
+ for entry in proc["distribute_list"].get(
+ "acls", []
+ )
+ }
+
+ # if state is merged, merge want onto have
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, limit the have to anything in want
+ # set want to nothing
+ if self.state == "deleted":
+ haved = {
+ k: v for k, v in iteritems(haved) if k in wantd or not wantd
+ }
+ wantd = {}
+
+ # delete processes first so we do run into "more than one" errors
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self.addcmd(have, "pid", True)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ parsers = [
+ "adjacency",
+ "auto_cost",
+ "bfd",
+ "compatible",
+ "event_log",
+ "help",
+ "interface_id",
+ "limit",
+ "local_rib_criteria",
+ "log_adjacency_changes",
+ "manet",
+ "max_lsa",
+ "max_metric",
+ "passive_interface",
+ "prefix_suppression",
+ "queue_depth.hello",
+ "queue_depth.update",
+ "router_id",
+ "shutdown",
+ "timers.throttle.lsa",
+ "timers.throttle.spf",
+ ]
+
+ if want != have:
+ self.addcmd(want or have, "pid", False)
+ self.compare(parsers, want, have)
+ self._areas_compare(want, have)
+ self._address_family_compare(want, have)
+
+ if len(self.commands) == 1 and "router" in self.commands[0]:
+ del self.commands[0]
+
+ def _areas_compare(self, want, have):
+ wareas = want.get("areas", {})
+ hareas = have.get("areas", {})
+ for name, entry in iteritems(wareas):
+ self._area_compare(want=entry, have=hareas.pop(name, {}))
+ for name, entry in iteritems(hareas):
+ self._area_compare(want={}, have=entry)
+
+ def _area_compare(self, want, have):
+ parsers = [
+ "area.authentication",
+ "area.capability",
+ "area.default_cost",
+ "area.nssa",
+ "area.nssa.translate",
+ "area.ranges",
+ "area.sham_link",
+ "area.stub",
+ ]
+ self.compare(parsers=parsers, want=want, have=have)
+ self._area_compare_filters(want, have)
+
+ def _area_compare_filters(self, wantd, haved):
+ for name, entry in iteritems(wantd):
+ h_item = haved.pop(name, {})
+ if entry != h_item and name == "filter_list":
+ filter_list_entry = {}
+ filter_list_entry["area_id"] = wantd["area_id"]
+ if h_item:
+ li_diff = [
+ item
+ for item in entry + h_item
+ if item not in entry or item not in h_item
+ ]
+ else:
+ li_diff = entry
+ filter_list_entry["filter_list"] = li_diff
+ self.addcmd(filter_list_entry, "area.filter_list", False)
+ for name, entry in iteritems(haved):
+ if name == "filter_list":
+ self.addcmd(entry, "area.filter_list", True)
+
+ def _address_family_compare(self, want, have):
+ if want["process_id"] == have.get("process_id") or want["process_id"]:
+ af_parsers = [
+ "address_family.adjacency",
+ "address_family.auto_cost",
+ "address_family.bfd",
+ "address_family.capability",
+ "address_family.compatible",
+ "address_family.default_information",
+ "address_family.default_metric",
+ "address_family.distance.admin_distance",
+ "address_family.distance.ospf",
+ "address_family.distribute_list.acls",
+ "address_family.distribute_list.prefix",
+ "address_family.distribute_list.route_map",
+ "address_family.event_log",
+ "address_family.graceful_restart",
+ "address_family.interface_id",
+ "address_family.limit",
+ "address_family.local_rib_criteria",
+ "address_family.log_adjacency_changes",
+ "address_family.manet",
+ "address_family.max_lsa",
+ "address_family.max_metric",
+ "address_family.maximum_paths",
+ "address_family.passive_interface",
+ "address_family.prefix_suppression",
+ "address_family.queue_depth.hello",
+ "address_family.queue_depth.update",
+ "address_family.router_id",
+ "address_family.shutdown",
+ "address_family.summary_prefix",
+ "address_family.timers.throttle.lsa",
+ "address_family.timers.throttle.spf",
+ ]
+ delete_exit_family = False
+ for each_want_af in want["address_family"]:
+ if have.get("address_family"):
+ for each_have_af in have["address_family"]:
+ if each_have_af.get("vrf") == each_want_af.get(
+ "vrf"
+ ) and each_have_af.get("afi") == each_want_af.get(
+ "afi"
+ ):
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ self.compare(
+ parsers=af_parsers,
+ want=each_want_af,
+ have=each_have_af,
+ )
+ elif each_have_af.get("afi") == each_want_af.get(
+ "afi"
+ ):
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ self.compare(
+ parsers=af_parsers,
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ if each_want_af.get("areas"):
+ af_want_areas = {}
+ af_have_areas = {}
+ for each_area in each_want_af["areas"]:
+ af_want_areas.update(
+ {each_area["area_id"]: each_area}
+ )
+ if each_have_af.get("areas"):
+ for each_area in each_have_af["areas"]:
+ af_have_areas.update(
+ {each_area["area_id"]: each_area}
+ )
+
+ if "exit-address-family" in self.commands:
+ del self.commands[
+ self.commands.index("exit-address-family")
+ ]
+ delete_exit_family = True
+
+ if af_have_areas:
+ self._areas_compare(
+ {"areas": af_want_areas},
+ {"areas": af_have_areas},
+ )
+ else:
+ self._areas_compare(
+ {"areas": af_want_areas}, dict()
+ )
+ if delete_exit_family:
+ self.commands.append("exit-address-family")
+ else:
+ temp_cmd_before = self.commands
+ self.commands = []
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have=dict(),
+ )
+ self.compare(
+ parsers=af_parsers, want=each_want_af, have=dict()
+ )
+ if each_want_af.get("areas"):
+ af_areas = {}
+ for each_area in each_want_af["areas"]:
+ af_areas.update({each_area["area_id"]: each_area})
+ self._areas_compare({"areas": af_areas}, dict())
+ del self.commands[
+ self.commands.index("exit-address-family")
+ ]
+ self.commands.append("exit-address-family")
+ self.commands[0:0] = temp_cmd_before
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py
new file mode 100644
index 00000000..15053f44
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py
@@ -0,0 +1,713 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py
new file mode 100644
index 00000000..1e6edec8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py
@@ -0,0 +1,337 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.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_vlans_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
+ )
+ 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()
+
+ if self.state in self.ACTION_STATES:
+ existing_vlans_facts = self.get_vlans_facts()
+ else:
+ existing_vlans_facts = []
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_vlans_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_vlans_facts = self.get_vlans_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_vlans_facts(data=running_config)
+ else:
+ changed_vlans_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_vlans_facts
+ if result["changed"]:
+ result["after"] = changed_vlans_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_vlans_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_vlans_facts):
+ """ Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ want = self._module.params["config"]
+ have = existing_vlans_facts
+ resp = self.set_state(want, have)
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """ Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+
+ if (
+ self.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(
+ self.state
+ )
+ )
+
+ if self.state == "overridden":
+ commands = self._state_overridden(want, have)
+ elif self.state == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.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
+ 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):
+ """ 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))
+ 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
+ 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):
+ """ 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
+ check = False
+ continue
+ if check:
+ commands.extend(self._clear_config(each, every))
+ else:
+ for each in have:
+ commands.extend(self._clear_config(dict(), each))
+
+ 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):
+ # 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 self.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
new file mode 100644
index 00000000..03d65e94
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,133 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+)
+from ansible_collections.cisco.ios.plugins.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 = ("\n" + data).split("\ninterface ")
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py
new file mode 100644
index 00000000..7ef73e7e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py
@@ -0,0 +1,127 @@
+# pylint: skip-file
+# -*- 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
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.acls import (
+ AclsTemplate,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+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)
+
+ rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=AclsTemplate())
+ current = rmmod.parse()
+
+ temp_v4 = []
+ temp_v6 = []
+ if current.get("acls"):
+ for k, v in iteritems(current.get("acls")):
+ if v.get("afi") == "ipv4":
+ del v["afi"]
+ temp_v4.append(v)
+ elif v.get("afi") == "ipv6":
+ del v["afi"]
+ temp_v6.append(v)
+ temp_v4 = sorted(temp_v4, key=lambda i: str(i["name"]))
+ temp_v6 = sorted(temp_v6, key=lambda i: str(i["name"]))
+ for each in temp_v4:
+ for each_ace in each.get("aces"):
+ if each["acl_type"] == "standard":
+ each_ace["source"] = each_ace.pop("std_source")
+ if each_ace.get("icmp_igmp_tcp_protocol"):
+ each_ace["protocol_options"] = {
+ each_ace["protocol"]: {
+ each_ace.pop("icmp_igmp_tcp_protocol").replace(
+ "-", "_"
+ ): True
+ }
+ }
+ if each_ace.get("std_source") == {}:
+ del each_ace["std_source"]
+ for each in temp_v6:
+ for each_ace in each.get("aces"):
+ if each_ace.get("std_source") == {}:
+ del each_ace["std_source"]
+ if each_ace.get("icmp_igmp_tcp_protocol"):
+ each_ace["protocol_options"] = {
+ each_ace["protocol"]: {
+ each_ace.pop("icmp_igmp_tcp_protocol").replace(
+ "-", "_"
+ ): True
+ }
+ }
+
+ objs = []
+ if temp_v4:
+ objs.append({"afi": "ipv4", "acls": temp_v4})
+ if temp_v6:
+ objs.append({"afi": "ipv6", "acls": temp_v6})
+ # objs['ipv6'] = {'acls': temp_v6}
+ 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
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py
new file mode 100644
index 00000000..d10002c6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The cisco.ios bgp_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 copy import deepcopy
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.bgp_global import (
+ Bgp_globalTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+
+
+class Bgp_globalFacts(object):
+ """ The cisco.ios bgp_global facts class
+ """
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Bgp_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 get_bgp_global_data(self, connection):
+ return connection.get("sh running-config | section ^router bgp")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for Bgp_global network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+
+ if not data:
+ data = self.get_bgp_global_data(connection)
+
+ # parse native config using the Bgp_global template
+ bgp_global_parser = Bgp_globalTemplate(lines=data.splitlines())
+ objs = bgp_global_parser.parse()
+
+ objs = utils.remove_empties(objs)
+ if "neighbor" in objs:
+ temp_neighbor = []
+ temp = {}
+ temp["address"] = None
+ for each in objs["neighbor"]:
+ if temp["address"] != each["address"]:
+ if temp["address"]:
+ temp_neighbor.append(temp)
+ temp = {}
+ temp["address"] = each.pop("address")
+ if each:
+ temp.update(each)
+ else:
+ each.pop("address")
+ temp.update(each)
+ if temp:
+ temp_neighbor.append(temp)
+ objs["neighbor"] = temp_neighbor
+ if objs:
+ ansible_facts["ansible_network_resources"].pop("bgp_global", None)
+
+ params = utils.remove_empties(
+ utils.validate_config(self.argument_spec, {"config": objs})
+ )
+ facts["bgp_global"] = params["config"]
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py
new file mode 100644
index 00000000..91c00404
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py
@@ -0,0 +1,130 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import (
+ FactsBase,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.interfaces.interfaces import (
+ InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.l2_interfaces.l2_interfaces import (
+ L2_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vlans.vlans import (
+ VlansFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import (
+ Lag_interfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lacp.lacp import (
+ LacpFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import (
+ Lacp_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lldp_global.lldp_global import (
+ Lldp_globalFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lldp_interfaces.lldp_interfaces import (
+ Lldp_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.l3_interfaces.l3_interfaces import (
+ L3_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.acl_interfaces.acl_interfaces import (
+ Acl_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.static_routes.static_routes import (
+ Static_RoutesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.acls.acls import (
+ AclsFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospfv2.ospfv2 import (
+ Ospfv2Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospfv3.ospfv3 import (
+ Ospfv3Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospf_interfaces.ospf_interfaces import (
+ Ospf_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.bgp_global.bgp_global import (
+ Bgp_globalFacts,
+)
+from ansible_collections.cisco.ios.plugins.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,
+ ospfv2=Ospfv2Facts,
+ ospfv3=Ospfv3Facts,
+ ospf_interfaces=Ospf_InterfacesFacts,
+ bgp_global=Bgp_globalFacts,
+)
+
+
+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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py
new file mode 100644
index 00000000..098b3707
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py
@@ -0,0 +1,110 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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 get_interfaces_data(self, connection):
+ return connection.get("sh running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ objs = []
+
+ if not data:
+ data = self.get_interfaces_data(connection)
+ # operate on a collection of resource x
+ config = ("\n" + data).split("\ninterface ")
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
new file mode 100644
index 00000000..a507b2d1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,138 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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 get_l2_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ objs = []
+ if not data:
+ data = self.get_l2_interfaces_data(connection)
+
+ # operate on a collection of resource x
+ config = ("\n" + data).split("\ninterface ")
+ 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, "switchport trunk 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
new file mode 100644
index 00000000..8a709765
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,148 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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 = ("\n" + data).split("\ninterface ")
+ 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:
+ try:
+ each_ipv4["dhcp_client"] = int(
+ each.split(" hostname ")[0].split("/")[-1]
+ )
+ except ValueError:
+ obj = re.search("\\d+", each)
+ if obj:
+ dhcp_client = obj.group()
+ each_ipv4["dhcp_client"] = int(dhcp_client)
+ if "hostname" in each:
+ each_ipv4["dhcp_hostname"] = each.split(" hostname ")[-1]
+ if "client-id" in each and each_ipv4["dhcp_client"] is None:
+ try:
+ each_ipv4["dhcp_client"] = int(each.split("/")[-1])
+ except ValueError:
+ obj = re.search("\\d+", each)
+ if obj:
+ dhcp_client = obj.group()
+ each_ipv4["dhcp_client"] = int(dhcp_client)
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py
new file mode 100644
index 00000000..d67bd1bd
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py
@@ -0,0 +1,88 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 00000000..a1e4d6c4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,112 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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 = ("\n" + data).split("\ninterface ")
+
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
new file mode 100644
index 00000000..364d4e61
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,128 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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 = ("\n" + data).split("\ninterface ")
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py
new file mode 100644
index 00000000..520a402f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py
@@ -0,0 +1,423 @@
+#
+# -*- 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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ run_commands,
+ get_capabilities,
+)
+from ansible_collections.cisco.ios.plugins.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", "show virtual switch"]
+
+ 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)
+ data = self.responses[1]
+ vss_errs = ["Invalid input", "Switch Mode : Standalone"]
+ if data and not any(err in data for err in vss_errs):
+ self.parse_virtual_switch(data)
+
+ def parse_iostype(self, data):
+ match = re.search(r"\sIOS-XE\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
+
+ if "stacked_models" in self.facts:
+ self.facts["virtual_switch"] = "STACK"
+
+ def parse_virtual_switch(self, data):
+ match = re.search(
+ r"^Virtual switch domain number : ([0-9]+)", data, re.M
+ )
+ if match:
+ self.facts["virtual_switch"] = "VSS"
+ self.facts["virtual_switch_domain"] = match.group(1)
+
+ 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["platform"] = self.parse_cdp_platform(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
+ if 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)
+
+ def parse_cdp_platform(self, data):
+ match = re.search(r"^Platform: (.+),", data, re.M)
+ if match:
+ return match.group(1)
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py
new file mode 100644
index 00000000..4c8ff3c1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py
@@ -0,0 +1,100 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.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 get_lldp_global_data(self, connection):
+ return connection.get("show running-config | section ^lldp")
+
+ 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 = self.get_lldp_global_data(connection)
+ # 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 00000000..11a67238
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,115 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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
+ """
+
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 00000000..dcf96605
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The cisco.ios ospf_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 copy import deepcopy
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospf_interfaces import (
+ Ospf_InterfacesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospf_interfaces.ospf_interfaces import (
+ Ospf_InterfacesArgs,
+)
+
+
+class Ospf_InterfacesFacts(object):
+ """ The cisco.ios ospf_interfaces facts class
+ """
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospf_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_ospf_interfaces_data(self, connection):
+ return connection.get("sh running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for Ospf_interfaces network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = []
+
+ if not data:
+ data = self.get_ospf_interfaces_data(connection)
+
+ # parse native config using the Ospf_interfaces template
+ ospf_interfaces_parser = Ospf_InterfacesTemplate(
+ lines=data.splitlines()
+ )
+
+ objs = ospf_interfaces_parser.parse()
+ final_objs = []
+ for key, value in iteritems(objs):
+ temp_af = []
+ if value["address_family"].get("ip"):
+ temp_af.append(value["address_family"].get("ip"))
+ if value["address_family"].get("ipv6"):
+ temp_af.append(value["address_family"].get("ipv6"))
+ if temp_af:
+ value["address_family"] = temp_af
+ if value:
+ value = utils.remove_empties(value)
+ final_objs.append(value)
+ ansible_facts["ansible_network_resources"].pop("ospf_interfaces", None)
+
+ params = utils.remove_empties(
+ utils.validate_config(self.argument_spec, {"config": final_objs})
+ )
+
+ facts["ospf_interfaces"] = params["config"]
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py
new file mode 100644
index 00000000..7c67e3b7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios ospfv2 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv2 import (
+ Ospfv2Template,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+class Ospfv2Facts(object):
+ """ The ios ospfv2 fact class
+ """
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv2Args.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_ospfv2_data(self, connection):
+ return connection.get("sh running-config | section ^router ospf")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for ospfv2
+ :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_ospfv2_data(connection)
+
+ ipv4 = {"processes": []}
+ rmmod = NetworkTemplate(
+ lines=data.splitlines(), tmplt=Ospfv2Template()
+ )
+ current = rmmod.parse()
+
+ # convert some of the dicts to lists
+ for key, sortv in [("processes", "process_id")]:
+ if key in current and current[key]:
+ current[key] = current[key].values()
+ current[key] = sorted(
+ current[key], key=lambda k, sk=sortv: k[sk]
+ )
+
+ for process in current.get("processes", []):
+ if "areas" in process:
+ process["areas"] = list(process["areas"].values())
+ process["areas"] = sorted(
+ process["areas"], key=lambda k, sk="area_id": k[sk]
+ )
+ for area in process["areas"]:
+ if "filters" in area:
+ area["filters"].sort()
+ ipv4["processes"].append(process)
+
+ ansible_facts["ansible_network_resources"].pop("ospfv2", None)
+ facts = {}
+ if current:
+ params = utils.validate_config(
+ self.argument_spec, {"config": ipv4}
+ )
+ params = utils.remove_empties(params)
+
+ facts["ospfv2"] = params["config"]
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py
new file mode 100644
index 00000000..50d3f32f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios ospfv3 fact class
+It is in this file the configuration is collected from the device
+for a given resource, parsed, and the facts tree is populated
+based on the configuration.
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import re
+from copy import deepcopy
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv3 import (
+ Ospfv3Template,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+class Ospfv3Facts(object):
+ """ The ios ospfv3 fact class
+ """
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv3Args.argument_spec
+
+ def get_ospfv3_data(self, connection):
+ return connection.get("sh running-config | section ^router ospfv3")
+
+ def parse(self, net_template_obj):
+ """ Overrided network template parse
+ """
+ result = {}
+ shared = {}
+ temp_pid = None
+ for line in net_template_obj._lines:
+ for parser in net_template_obj._tmplt.PARSERS:
+ cap = re.match(parser["getval"], line)
+ if cap:
+ capdict = cap.groupdict()
+
+ capdict = {
+ k: v for k, v in iteritems(capdict) if v is not None
+ }
+ if "address-family" in line:
+ capdict.update({"id": temp_pid})
+ if (
+ "manet" in line
+ and "pid" not in shared
+ and shared.get("unicast")
+ ):
+ del shared["unicast"]
+
+ if "router ospfv3" in line:
+ temp_pid = None
+ if parser.get("shared"):
+ shared = capdict
+ if not temp_pid and (
+ shared.get("pid") or shared.get("id")
+ ):
+ temp_pid = shared.get("pid") or shared.get("id")
+ vals = utils.dict_merge(capdict, shared)
+ try:
+ res = net_template_obj._deepformat(
+ deepcopy(parser["result"]), vals
+ )
+ except Exception:
+ continue
+ result = utils.dict_merge(result, res)
+ break
+ return result
+
+ def parse_for_address_family(self, current):
+ """ Parsing and Fishing out address family contents
+ """
+ pid_addr_family_dict = {}
+ temp_dict = {}
+ temp_pid = None
+ temp = []
+ if current.get("address_family"):
+ for each in current.pop("address_family"):
+ each = utils.remove_empties(each)
+ if each.get("exit"):
+ if temp_pid == each.get("exit")["pid"]:
+ temp.append(temp_dict)
+ pid_addr_family_dict[temp_pid] = temp
+ temp_dict = dict()
+ else:
+ temp_pid = each.get("exit")["pid"]
+ pid_addr_family_dict[temp_pid] = [temp_dict]
+ temp = []
+ temp.append(temp_dict)
+ temp_dict = dict()
+ elif each.get("manet") and temp_dict.get("manet"):
+ for k, v in iteritems(each.get("manet")):
+ if k in temp_dict.get("manet"):
+ temp_dict.get("manet")[k].update(v)
+ else:
+ temp_dict["manet"].update(each.get("manet"))
+ elif each.get("manet") and not temp_dict.get("manet"):
+ temp_dict["manet"] = each.get("manet")
+ else:
+ temp_dict.update(each)
+ return pid_addr_family_dict
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for ospfv3
+ :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_ospfv3_data(connection)
+
+ ipv4 = {"processes": []}
+ rmmod = NetworkTemplate(
+ lines=data.splitlines(), tmplt=Ospfv3Template()
+ )
+ current = self.parse(rmmod)
+ address_family = self.parse_for_address_family(current)
+ if address_family:
+ for k, v in iteritems(current["processes"]):
+ temp = address_family.pop(k)
+ v.update({"address_family": temp})
+ # convert some of the dicts to lists
+ for key, sortv in [("processes", "process_id")]:
+ if key in current and current[key]:
+ current[key] = current[key].values()
+ current[key] = sorted(
+ current[key], key=lambda k, sk=sortv: k[sk]
+ )
+
+ for process in current.get("processes", []):
+ if "areas" in process:
+ process["areas"] = list(process["areas"].values())
+ process["areas"] = sorted(
+ process["areas"], key=lambda k, sk="area_id": k[sk]
+ )
+ for area in process["areas"]:
+ if "filters" in area:
+ area["filters"].sort()
+ if "address_family" in process:
+ for each in process["address_family"]:
+ if "areas" in each:
+ each["areas"] = list(each["areas"].values())
+ each["areas"] = sorted(
+ each["areas"], key=lambda k, sk="area_id": k[sk]
+ )
+ for area in each["areas"]:
+ if "filters" in area:
+ area["filters"].sort()
+ ipv4["processes"].append(process)
+
+ ansible_facts["ansible_network_resources"].pop("ospfv3", None)
+ facts = {}
+ if current:
+ params = utils.validate_config(
+ self.argument_spec, {"config": ipv4}
+ )
+ params = utils.remove_empties(params)
+
+ facts["ospfv3"] = params["config"]
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py
new file mode 100644
index 00000000..09805ef0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py
@@ -0,0 +1,272 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ netmask_to_cidr,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.static_routes.static_routes import (
+ Static_RoutesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ is_valid_ip,
+)
+
+
+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 | section ^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 and "ospf" not in 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:
+ 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_non_vrf = utils.parse_conf_arg(i, ip_str)
+ if (
+ "::" not in filter_non_vrf
+ ): # "/" not in filter_non_vrf and
+ filter_non_vrf, dest = self.update_netmask_to_cidr(
+ filter_non_vrf, 0, 1
+ )
+ else:
+ dest = filter_non_vrf.split(" ")[0]
+ if dest not in same_dest.keys():
+ same_dest[dest] = []
+ same_dest[dest].append(filter_non_vrf)
+ elif "vrf" in same_dest[dest][0]:
+ same_dest[dest] = []
+ same_dest[dest].append(filter_non_vrf)
+ else:
+ same_dest[dest].append(filter_non_vrf)
+ 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:
+ if is_valid_ip(route[3]):
+ hops["forward_router_address"] = route[3]
+ afi["afi"] = "ipv4"
+ else:
+ hops["interface"] = route[3]
+ afi["afi"] = "ipv4"
+ if is_valid_ip(route[4]):
+ hops["forward_router_address"] = route[4]
+ else:
+
+ if "::" in conf:
+ if is_valid_ip(route[1]):
+ hops["forward_router_address"] = route[1]
+ afi["afi"] = "ipv6"
+ else:
+ hops["interface"] = route[1]
+ afi["afi"] = "ipv6"
+ if is_valid_ip(route[2]):
+ hops["forward_router_address"] = route[2]
+ elif "." in conf:
+ if is_valid_ip(route[1]):
+ hops["forward_router_address"] = route[1]
+ afi["afi"] = "ipv4"
+ else:
+ hops["interface"] = route[1]
+ afi["afi"] = "ipv4"
+ if is_valid_ip(route[2]):
+ hops["forward_router_address"] = route[2]
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py
new file mode 100644
index 00000000..d2959182
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py
@@ -0,0 +1,168 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.cisco.ios.plugins.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 get_vlans_data(self, connection):
+ return connection.get("show vlan")
+
+ 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
+ """
+
+ objs = []
+ mtu_objs = []
+ remote_objs = []
+ final_objs = []
+ if not data:
+ data = self.get_vlans_data(connection)
+ # operate on a collection of resource x
+ config = data.split("\n")
+ # Get individual vlan configs separately
+ vlan_info = ""
+ temp = ""
+ vlan_name = True
+ for conf in config:
+ if len(list(filter(None, conf.split(" ")))) <= 2 and vlan_name:
+ temp = temp + conf
+ if len(list(filter(None, temp.split(" ")))) <= 2:
+ continue
+ if "VLAN Name" in conf:
+ vlan_info = "Name"
+ elif "VLAN Type" in conf:
+ vlan_info = "Type"
+ vlan_name = False
+ elif "Remote SPAN" in conf:
+ vlan_info = "Remote"
+ vlan_name = False
+ elif "VLAN AREHops" in conf or "STEHops" in conf:
+ vlan_info = "Hops"
+ vlan_name = False
+ if temp:
+ conf = temp
+ temp = ""
+ 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 "VLAN Name" not in conf:
+ conf = list(filter(None, conf.split(" ")))
+ config["vlan_id"] = int(conf[0])
+ config["name"] = conf[1]
+ try:
+ 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"
+ except IndexError:
+ pass
+ elif vlan_info == "Type" and "VLAN 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py
new file mode 100644
index 00000000..18f87a09
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py
@@ -0,0 +1,205 @@
+# 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.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+import json
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import env_fallback
+from ansible_collections.ansible.netcommon.plugins.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(
+ default=False,
+ 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_at_date="2022-06-01",
+ removed_from_collection="cisco.ios",
+ )
+}
+
+
+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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py
new file mode 100644
index 00000000..848542bb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py
@@ -0,0 +1,84 @@
+#
+# (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
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.ansible.netcommon.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py
new file mode 100644
index 00000000..0e0ce1ab
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py
@@ -0,0 +1,158 @@
+#
+# (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
+import re
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ CliProvider,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
new file mode 100644
index 00000000..4db23b9d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
@@ -0,0 +1,225 @@
+#
+# (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
+import re
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py
new file mode 100644
index 00000000..9512d9d2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py
@@ -0,0 +1,168 @@
+#
+# (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
+import re
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ register_provider,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ CliProvider,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.neighbors import (
+ Neighbors,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.address_family import (
+ AddressFamily,
+)
+from ansible.module_utils.common.network import to_netmask
+
+REDISTRIBUTE_PROTOCOLS = [
+ "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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py
new file mode 100644
index 00000000..cc516ff1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py
@@ -0,0 +1,72 @@
+#
+# (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
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import Connection
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py
new file mode 100644
index 00000000..485eb383
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py
@@ -0,0 +1,128 @@
+#
+# (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
+import json
+
+from threading import RLock
+
+from ansible.module_utils.six import itervalues
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_list,
+)
+from ansible_collections.ansible.netcommon.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py
new file mode 100644
index 00000000..f9d64a58
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The acls parser templates file. This contains
+a list of parser definitions and associated functions that
+facilitates both facts gathering and native command generation for
+the given network resource.
+"""
+import re
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_access_list_name(config_data):
+ try:
+ acl_id = int(config_data.get("name"))
+ if not config_data.get("acl_type"):
+ if acl_id >= 1 and acl_id <= 99:
+ config_data["acl_type"] = "standard"
+ if acl_id >= 100 and acl_id <= 199:
+ config_data["acl_type"] = "extended"
+ except ValueError:
+ pass
+ afi = config_data.get("afi")
+ if afi == "ipv4":
+ command = "ip access-list {acl_type} {name}".format(**config_data)
+ elif afi == "ipv6":
+ command = "ipv6 access-list {name}".format(**config_data)
+ return command
+
+
+def _tmplt_access_list_entries(config_data):
+ if "aces" in config_data:
+ command = []
+
+ def source_destination_common_config(config_data, command, type):
+ if config_data[type].get("address"):
+ command += " {address}".format(**config_data[type])
+ if config_data[type].get("wildcard_bits"):
+ command += " {wildcard_bits}".format(
+ **config_data["source"]
+ )
+ elif config_data[type].get("any"):
+ command += " any".format(**config_data[type])
+ elif config_data[type].get("host"):
+ command += " host {host}".format(**config_data[type])
+ if config_data[type].get("port_protocol"):
+ port_proto_type = list(
+ config_data[type]["port_protocol"].keys()
+ )[0]
+ command += " {0} {1}".format(
+ port_proto_type,
+ config_data[type]["port_protocol"][port_proto_type],
+ )
+ return command
+
+ command = ""
+ proto_option = None
+ if config_data.get("aces"):
+ aces = config_data["aces"]
+ if aces.get("sequence") and config_data.get("afi") == "ipv4":
+ command += "{sequence}".format(**aces)
+ if (
+ aces.get("grant")
+ and aces.get("sequence")
+ and config_data.get("afi") == "ipv4"
+ ):
+ command += " {grant}".format(**aces)
+ elif (
+ aces.get("grant")
+ and aces.get("sequence")
+ and config_data.get("afi") == "ipv6"
+ ):
+ command += "{grant}".format(**aces)
+ elif aces.get("grant"):
+ command += "{grant}".format(**aces)
+ if aces.get("protocol_options"):
+ if "protocol_number" in aces["protocol_options"]:
+ command += " {protocol_number}".format(
+ **aces["protocol_options"]
+ )
+ else:
+ command += " {0}".format(list(aces["protocol_options"])[0])
+ proto_option = aces["protocol_options"].get(
+ list(aces["protocol_options"])[0]
+ )
+ elif aces.get("protocol"):
+ command += " {protocol}".format(**aces)
+ if aces.get("source"):
+ command = source_destination_common_config(
+ aces, command, "source"
+ )
+ if aces.get("destination"):
+ command = source_destination_common_config(
+ aces, command, "destination"
+ )
+ if proto_option:
+ command += " {0}".format(list(proto_option.keys())[0])
+ if aces.get("dscp"):
+ command += " dscp {dscp}".format(**aces)
+ if aces.get("sequence") and config_data.get("afi") == "ipv6":
+ command += " sequence {sequence}".format(**aces)
+ if aces.get("fragments"):
+ command += " fragments {fragments}".format(**aces)
+ if aces.get("log"):
+ command += " log {log}".format(**aces)
+ if aces.get("log_input"):
+ command += " log-input {log_input}".format(**aces)
+ if aces.get("option"):
+ option_val = list(aces.get("option").keys())[0]
+ command += " option {0}".format(option_val)
+ if aces.get("precedence"):
+ command += " precedence {precedence}".format(**aces)
+ if aces.get("time_range"):
+ command += " time-range {time_range}".format(**aces)
+ if aces.get("tos"):
+ command += " tos"
+ if aces["tos"].get("service_value"):
+ command += " {service_value}".format(**aces["tos"])
+ elif aces["tos"].get("max_reliability"):
+ command += " max-reliability"
+ elif aces["tos"].get("max_throughput"):
+ command += " max-throughput"
+ elif aces["tos"].get("min_delay"):
+ command += " min-delay"
+ elif aces["tos"].get("min_monetary_cost"):
+ command += " min-monetary-cost"
+ elif aces["tos"].get("normal"):
+ command += " normal"
+ if aces.get("ttl"):
+ command += " ttl {0}".format(list(aces["ttl"])[0])
+ proto_option = aces["ttl"].get(list(aces["ttl"])[0])
+ command += " {0}".format(proto_option)
+ return command
+ return command
+
+
+class AclsTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(AclsTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "acls_name",
+ "getval": re.compile(
+ r"""^(?P<acl_type>Standard|Extended)*
+ \s*(?P<afi>IP|IPv6)*
+ \s*access*
+ \s*list*
+ \s*(?P<acl_name>\S+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "setval": _tmplt_access_list_name,
+ "result": {
+ "acls": {
+ "{{ acl_name }}": {
+ "name": "{{ acl_name }}",
+ "acl_type": "{{ acl_type.lower() if acl_type is defined }}",
+ "afi": "{{ 'ipv4' if afi == 'IP' else 'ipv6' }}",
+ }
+ }
+ },
+ "shared": True,
+ },
+ {
+ "name": "aces",
+ "getval": re.compile(
+ r"""\s*(?P<sequence>\d+)*
+ \s*(?P<grant>deny|permit)*
+ \s*(?P<std_source>any|(?:[0-9]{1,3}\.){3}[0-9]{1,3},\swildcard\sbits\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(?:[0-9]{1,3}\.){3}[0-9]{1,3}|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3})*
+ \s*(?P<evaluate>evaluate\s\S+)*
+ \s*(?P<protocol>ahp|eigrp|esp|gre|icmp|igmp|ip|ipinip|nos|object-group|ospf|pcp|pim|sctp|tcp|udp)*
+ \s*(?P<protocol_num>\d+\s)*
+ \s*(?P<source>any|(?:[0-9]{1,3}\.){3}[0-9]{1,3}\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|object-group\s\S+)*
+ \s*(?P<source_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+))*
+ \s*(?P<destination>any|(?:[0-9]{1,3}\.){3}[0-9]{1,3}\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|object-group\s\S+)*
+ \s*(?P<dest_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+))*
+ \s*(?P<icmp_igmp_tcp_protocol>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|dvmrp|host-query|mtrace-resp|mtrace-route|pim|trace|v1host-report|v2host-report|v2leave-group|v3host-report|ack|established|fin|psh|rst|syn|urg)*
+ \s*(?P<dscp>dscp\s\S+)*
+ \s*(?P<fragment>fragments\s\S+)*
+ \s*(?P<log>log\s\S+)*
+ \s*(?P<log_input>log-input\s\S+)*
+ \s*(?P<option>option\s\S+|option\s\d+)*
+ \s*(?P<precedence>precedence\s\S+|precedence\s\d+)*
+ \s*(?P<time_range>time-range\s\S+)*
+ \s*(?P<tos>tos\s\S+|tos\s\d+)*
+ \s*(?P<ttl>ttl\s\S+\s\d+|ttl\s\d+\s\d+)*
+ \s*(?P<sequence_ipv6>sequence\s\d+)*
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_access_list_entries,
+ "compval": "aces",
+ "result": {
+ "acls": {
+ "{{ acl_name }}": {
+ "name": "{{ acl_name }}",
+ "aces": [
+ {
+ "sequence": "{% if sequence is defined %}{{ sequence \
+ }}{% elif sequence_ipv6 is defined %}{{ sequence_ipv6.split('sequence ')[1] }}{% endif %}",
+ "grant": "{{ grant }}",
+ "remark": "{{ remark.split('remark ')[1] if remark is defined }}",
+ "evaluate": "{{ evaluate.split(' ')[1] if evaluate is defined }}",
+ "protocol": "{{ protocol if protocol is defined }}",
+ "protocol_number": "{{ protocol_num if protocol_num is defined }}",
+ "icmp_igmp_tcp_protocol": "{{ icmp_igmp_tcp_protocol if icmp_igmp_tcp_protocol is defined }}",
+ "std_source": {
+ "address": "{% if std_source is defined and 'wildcard' in std_source and std_source.split(',')|length == 2 %}{{\
+ std_source.split(',')[0]\
+ }}{% elif std_source is defined and '.' in std_source and std_source.split(' ')|length == 1 %}{{\
+ std_source }}{% endif %}",
+ "wildcard_bits": "{% if std_source is defined and 'wildcard' in std_source and std_source.split(',')|length == 2 %}{{\
+ std_source.split('wildcard bits ')[1] }}{% endif %}",
+ "host": "{% if std_source is defined and 'host' in std_source %}{{ std_source.split(' ')[1] }}{% endif %}",
+ "any": "{{ True if std_source is defined and std_source == 'any' }}",
+ },
+ "source": {
+ "address": "{% if source is defined and '.' in source and 'host' not in source %}{{\
+ source.split(' ')[0] }}{% elif source is defined and '::' in source %}{{ source }}{% endif %}",
+ "wildcard_bits": "{{ source.split(' ')[1] if source is defined and '.' in source and 'host' not in source }}",
+ "any": "{{ True if source is defined and source == 'any' }}",
+ "host": "{{ source.split(' ')[1] if source is defined and 'host' in source }}",
+ "object_group": "{{ source.split(' ')[1] if source is defined and 'object-group' in source }}",
+ "port_protocol": {
+ "{{ source_port_protocol.split(' ')[0] if source_port_protocol is defined else None }}": "{{\
+ source_port_protocol.split(' ')[1] if source_port_protocol is defined else None }}"
+ },
+ },
+ "destination": {
+ "address": "{% if destination is defined and '.' in destination and 'host' not in destination %}{{\
+ destination.split(' ')[0] }}{% elif std_dest is defined and '.' in std_dest and 'host' not in std_dest %}{{\
+ std_dest.split(' ')[0] }}{% elif destination is defined and '::' in destination %}{{ destination }}{% endif %}",
+ "wildcard_bits": "{% if destination is defined and '.' in destination and 'host' not in destination %}{{\
+ destination.split(' ')[1] }}{% elif std_dest is defined and '.' in std_dest and 'host' not in std_dest %}{{\
+ std_dest.split(' ')[1] }}{% endif %}",
+ "any": "{{ True if destination is defined and destination == 'any' else None }}",
+ "host": "{{ destination.split(' ')[1] if destination is defined and 'host' in destination }}",
+ "object_group": "{{ destination.split(' ')[1] if destination is defined and 'object-group' in destination else None }}",
+ "port_protocol": {
+ "{{ dest_port_protocol.split(' ')[0] if dest_port_protocol is defined else None }}": "{{\
+ dest_port_protocol.split(' ')[1] if dest_port_protocol is defined else None }}"
+ },
+ },
+ "dscp": "{{ dscp.split(' ')[1] if dscp is defined }}",
+ "fragments": "{{ fragments.split(' ')[1] if fragments is defined }}",
+ "log": "{{ log.split('log ')[1] if log is defined }}",
+ "log_input": "{{ log_input.split(' ')[1] if log_input is defined }}",
+ "option": {
+ "{% if option is defined %}{{ option.split(' ')[1] if option is defined }}{% endif %}": "{{ True if option is defined }}"
+ },
+ "precedence": "{{ precedence.split(' ')[1] if precedence is defined }}",
+ "time_range": "{{ time_range.split(' ')[1] if time_range is defined }}",
+ "tos": {
+ "max_reliability": "{{ True if tos is defined and 'max-reliability' in tos }}",
+ "max_throughput": "{{ True if tos is defined and 'max-throughput' in tos }}",
+ "min_delay": "{{ True if tos is defined and 'min-delay' in tos }}",
+ "min_monetary_cost": "{{ True if tos is defined and 'min-monetary-cost' in tos }}",
+ "normal": "{{ True if tos is defined and 'normal' in tos }}",
+ "service_value": "{{ tos.split(' ')[1] if tos is defined }}",
+ },
+ "ttl": {
+ "eq": "{{ ttl.split(' ')[2] if ttl is defined and 'eq' in ttl }}",
+ "gt": "{{ ttl.split(' ')[2] if ttl is defined and 'gt' in ttl }}",
+ "lt": "{{ ttl.split(' ')[2] if ttl is defined and 'lt' in ttl }}",
+ "neq": "{{ ttl.split(' ')[2] if ttl is defined and 'neq' in ttl }}",
+ },
+ }
+ ],
+ }
+ }
+ },
+ },
+ ]
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py
new file mode 100644
index 00000000..f96d3467
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py
@@ -0,0 +1,1835 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The Bgp_global parser templates file. This contains
+a list of parser definitions and associated functions that
+facilitates both facts gathering and native command generation for
+the given network resource.
+"""
+
+import re
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_bgp_additional_paths(config_data):
+ if "bgp" in config_data:
+ if "additional_paths" in config_data["bgp"]:
+ cmd = "bgp additional-paths"
+ if "install" in config_data["bgp"]["additional_paths"]:
+ cmd += " install"
+ elif "select" in config_data["bgp"]["additional_paths"]:
+ cmd += " select"
+ if "all" in config_data["bgp"]["additional_paths"]["select"]:
+ cmd += " all"
+ elif (
+ "best" in config_data["bgp"]["additional_paths"]["select"]
+ ):
+ cmd += " best {best}".format(
+ **config_data["bgp"]["additional_paths"]["select"]
+ )
+ elif (
+ "best_external"
+ in config_data["bgp"]["additional_paths"]["select"]
+ ):
+ cmd += " best-external"
+ elif (
+ "group_best"
+ in config_data["bgp"]["additional_paths"]["select"]
+ ):
+ cmd += " group-best"
+ if "receive" in config_data["bgp"]["additional_paths"]:
+ cmd += " receive"
+ if "send" in config_data["bgp"]["additional_paths"]:
+ cmd += " send"
+ return cmd
+
+
+def _tmplt_bgp_bestpath(config_data):
+ if "bgp" in config_data and "bestpath" in config_data["bgp"]:
+ commands = []
+ val = config_data["bgp"]["bestpath"]
+ cmd = "bgp bestpath"
+ if val.get("aigp"):
+ commands.append("{0} aigp ignore".format(cmd))
+ elif val.get("compare_routerid"):
+ commands.append("{0} compare-routerid".format(cmd))
+ elif val.get("cost_community"):
+ commands.append("{0} cost-community ignore".format(cmd))
+ elif val.get("igp_metric"):
+ commands.append("{0} igp-metric ignore".format(cmd))
+ elif "med" in val:
+ self_cmd = "{0} med".format(cmd)
+ if "confed" in val["med"]:
+ self_cmd += " confed"
+ elif "missing_as_worst" in val["med"]:
+ self_cmd += " missing-as-worst"
+ commands.append(self_cmd)
+ return commands
+
+
+def _tmplt_bgp_config(config_data):
+ if "bgp" in config_data:
+ cmd = []
+ command = "bgp"
+ if config_data["bgp"].get("advertise_best_external"):
+ cmd.append("bgp advertise-best-external")
+ if config_data["bgp"].get("aggregate_timer"):
+ cmd.append(
+ "bgp aggregate-timer {aggregate_timer}".format(
+ **config_data["bgp"]
+ )
+ )
+ if config_data["bgp"].get("always_compare_med"):
+ cmd.append("bgp always-compare-med")
+ if config_data["bgp"].get("asnotation"):
+ cmd.append("bgp asnotation dot")
+ if "client_to_client" in config_data["bgp"]:
+ command = "bgp client-to-client reflection"
+ if "all" in config_data["bgp"]["client_to_client"]:
+ command += " all"
+ elif "intra_cluster" in config_data["bgp"]["client_to_client"]:
+ command += " intra-cluster cluster-id {intra_cluster}".format(
+ **config_data["bgp"]["client_to_client"]
+ )
+ cmd.append(command)
+ if config_data["bgp"].get("cluster_id"):
+ cmd.append(
+ "bgp cluster-id {cluster_id}".format(**config_data["bgp"])
+ )
+ if "confederation" in config_data["bgp"]:
+ command = "bgp confederation"
+ if "identifier" in config_data["bgp"]["confederation"]:
+ command += "bgp identifier {identifier}".format(
+ **config_data["bgp"]["confederation"]
+ )
+ elif "peers" in config_data["bgp"]["confederation"]:
+ command += "bgp peers {peers}".format(
+ **config_data["bgp"]["confederation"]
+ )
+ cmd.append(command)
+ if "consistency_checker" in config_data["bgp"]:
+ command = "bgp consistency-checker"
+ if "auto_repair" in config_data["bgp"]["consistency_checker"]:
+ command += " auto-repair"
+ if (
+ "interval"
+ in config_data["bgp"]["consistency_checker"]["auto_repair"]
+ ):
+ command += " interval {interval}".format(
+ **config_data["bgp"]["consistency_checker"][
+ "auto_repair"
+ ]
+ )
+ elif "error-message" in config_data["bgp"]["consistency_checker"]:
+ command += " error-message"
+ if (
+ "interval"
+ in config_data["bgp"]["consistency_checker"][
+ "error_message"
+ ]
+ ):
+ command += " interval {interval}".format(
+ **config_data["bgp"]["consistency_checker"][
+ "error_message"
+ ]
+ )
+ if config_data["bgp"].get("deterministic_med"):
+ cmd.append("bgp deterministic-med")
+ if config_data["bgp"].get("dmzlink_bw"):
+ cmd.append("bgp dmzlink-bw")
+ if config_data["bgp"].get("enforce_first_as"):
+ cmd.append("bgp enforce-first-as")
+ if config_data["bgp"].get("enhanced_error"):
+ cmd.append("bgp enhanced-error")
+ if config_data["bgp"].get("fast_external_fallover"):
+ cmd.append("bgp fast-external-fallover")
+ if "graceful_restart" in config_data["bgp"]:
+ command = "bgp graceful-restart"
+ if config_data["bgp"]["graceful_restart"].get("extended"):
+ command += " extended"
+ elif config_data["bgp"]["graceful_restart"].get("restart_time"):
+ command += " restart-time {restart_time}".format(
+ **config_data["bgp"]["graceful_restart"]
+ )
+ elif config_data["bgp"]["graceful_restart"].get("stalepath_time"):
+ command += " stalepath-time {stalepath_time}".format(
+ **config_data["bgp"]["graceful_restart"]
+ )
+ cmd.append(command)
+ if "inject_map" in config_data["bgp"]:
+ command = "bgp inject-map {name} exist-map {exist_map_name}".format(
+ **config_data["bgp"]["inject_map"]
+ )
+ if config_data["bgp"]["inject_map"].get("copy_attributes"):
+ command += "copy-attributes"
+ cmd.append(command)
+ if "listen" in config_data["bgp"]:
+ command = "bgp listen"
+ if "limit" in config_data["bgp"]["listen"]:
+ command += " limit {limit}".format(
+ **config_data["bgp"]["listen"]
+ )
+ elif "range" in config_data["bgp"]["listen"]:
+ if config_data["bgp"]["listen"]["range"].get(
+ "ipv4_with_subnet"
+ ):
+ command += " range {ipv4_with_subnet}".format(
+ **config_data["bgp"]["listen"]["range"]
+ )
+ elif config_data["bgp"]["listen"]["range"].get(
+ "ipv6_with_subnet"
+ ):
+ command += " range {ipv6_with_subnet}".format(
+ **config_data["bgp"]["listen"]["range"]
+ )
+ if config_data["bgp"]["listen"]["range"].get("peer_group"):
+ command += " peer-group {peer_group}".format(
+ **config_data["bgp"]["listen"]["range"]
+ )
+ cmd.append(command)
+ if config_data["bgp"].get("log_neighbor_changes"):
+ cmd.append("bgp log-neighbor-changes")
+ if config_data["bgp"].get("maxas_limit"):
+ cmd.append(
+ "bgp maxas-limit {maxas_limit}".format(**config_data["bgp"])
+ )
+ if config_data["bgp"].get("maxextcommunity_limit"):
+ cmd.append(
+ "bgp maxextcommunity-limit {maxextcommunity_limit}".format(
+ **config_data["bgp"]
+ )
+ )
+ if "nexthop" in config_data["bgp"]:
+ command = "bgp nexthop"
+ if "route_map" in config_data["bgp"]["nexthop"]:
+ command += " route-map {route_map}".format(
+ **config_data["bgp"]["nexthop"]
+ )
+ elif "trigger" in config_data["bgp"]["nexthop"]:
+ if config_data["bgp"]["nexthop"]["trigger"].get("delay"):
+ command += " trigger delay {delay}".format(
+ **config_data["bgp"]["nexthop"]["trigger"]
+ )
+ elif config_data["bgp"]["nexthop"]["trigger"].get("delay"):
+ command += " trigger enable"
+ cmd.append(command)
+ if config_data["bgp"].get("recursion"):
+ cmd.append("bgp recursion host")
+ if config_data["bgp"].get("redistribute_internal"):
+ cmd.append("bgp redistribute-internal")
+ if "refresh" in config_data["bgp"]:
+ command = "bgp refresh"
+ if "max_eor_time" in config_data["bgp"]["refresh"]:
+ command += " max-eor-time {max_eor_time}".format(
+ **config_data["bgp"]["refresh"]
+ )
+ elif "stalepath_time" in config_data["bgp"]["refresh"]:
+ command += " stalepath-time {stalepath_time}".format(
+ **config_data["bgp"]["refresh"]
+ )
+ cmd.append(command)
+ if config_data["bgp"].get("regexp"):
+ cmd.append("bgp regexp deterministic")
+ if config_data["bgp"].get("route_map"):
+ cmd.append("bgp route-map priority")
+ if "router_id" in config_data["bgp"]:
+ command = "bgp router-id"
+ if "address" in config_data["bgp"]["router_id"]:
+ command += " {address}".format(
+ **config_data["bgp"]["router_id"]
+ )
+ elif "interface" in config_data["bgp"]["router_id"]:
+ command += " interface {interface}".format(
+ **config_data["bgp"]["router_id"]
+ )
+ elif "vrf" in config_data["bgp"]["router_id"]:
+ command += " vrf auto-assign"
+ cmd.append(command)
+ if config_data["bgp"].get("scan_time"):
+ cmd.append(
+ "bgp scan-time {scan_time}".format(**config_data["bgp"])
+ )
+ if "slow_peer" in config_data["bgp"]:
+ command = "bgp slow-peer"
+ if "detection" in config_data["bgp"]["slow_peer"]:
+ command += " detection"
+ if "threshold" in config_data["bgp"]["slow_peer"]["detection"]:
+ command += " threshold {threshold}".format(
+ **config_data["bgp"]["slow_peer"]["detection"]
+ )
+ elif "split_update_group" in config_data["bgp"]["slow_peer"]:
+ if (
+ "dynamic"
+ in config_data["bgp"]["slow_peer"]["split_update_group"]
+ ):
+ command += " dynamic"
+ if (
+ "permanent"
+ in config_data["bgp"]["slow_peer"][
+ "split_update_group"
+ ]
+ ):
+ command += " permanent {permanent}".format(
+ **config_data["bgp"]["slow_peer"][
+ "split_update_group"
+ ]
+ )
+ cmd.append(command)
+ if config_data["bgp"].get("snmp"):
+ cmd.append("bgp snmp traps add-type")
+ if config_data["bgp"].get("sso"):
+ cmd.append("bgp sso route-refresh-enable")
+ if config_data["bgp"].get("soft_reconfig_backup"):
+ cmd.append("bgp soft-reconfig-backup")
+ if config_data["bgp"].get("suppress_inactive"):
+ cmd.append("bgp suppress-inactive")
+ if config_data["bgp"].get("transport"):
+ cmd.append("bgp transport path-mtu-discovery")
+ if config_data["bgp"].get("update_delay"):
+ cmd.append(
+ "bgp update-delay {update_delay}".format(**config_data["bgp"])
+ )
+ if config_data["bgp"].get("update_group"):
+ cmd.append("bgp update-group split as-override")
+ if config_data["bgp"].get("upgrade_cli"):
+ command += "bgp upgrade-cli"
+ if config_data["bgp"]["upgrade_cli"].get("af_mode"):
+ command += " af-mode"
+ return cmd
+
+
+def _tmplt_bgp_dampening(config_data):
+ if "bgp" in config_data and "dampening" in config_data["bgp"]:
+ if config_data["bgp"]["dampening"].get("penalty_half_time"):
+ command = "bgp dampening {penalty_half_time}".format(
+ **config_data["bgp"]["dampening"]
+ )
+ if config_data["bgp"]["dampening"].get("reuse_route_val"):
+ command += " {reuse_route_val}".format(
+ **config_data["bgp"]["dampening"]
+ )
+ if config_data["bgp"]["dampening"].get("suppress_route_val"):
+ command += " {suppress_route_val}".format(
+ **config_data["bgp"]["dampening"]
+ )
+ if config_data["bgp"]["dampening"].get("max_suppress"):
+ command += " {max_suppress}".format(
+ **config_data["bgp"]["dampening"]
+ )
+ elif config_data["bgp"]["dampening"].get("route_map"):
+ command = "bgp dampening {route_map}".format(
+ **config_data["bgp"]["dampening"]
+ )
+ return command
+
+
+def _tmplt_bgp_graceful_shutdown(config_data):
+ if "bgp" in config_data and "graceful_shutdown" in config_data["bgp"]:
+ command = "bgp graceful-shutdown all"
+ if config_data["bgp"]["graceful_shutdown"].get("neighbors"):
+ command += " neighbors"
+ if config_data["bgp"]["graceful_shutdown"]["neighbors"].get(
+ "activate"
+ ):
+ command += " activate"
+ elif config_data["bgp"]["graceful_shutdown"]["neighbors"].get(
+ "time"
+ ):
+ command += " {time}".format(
+ **config_data["bgp"]["graceful_shutdown"]["neighbors"]
+ )
+ elif config_data["bgp"]["graceful_shutdown"].get("vrfs"):
+ command += " vrfs"
+ if config_data["bgp"]["graceful_shutdown"]["vrfs"].get("activate"):
+ command += " activate"
+ elif config_data["bgp"]["graceful_shutdown"]["neighbors"].get(
+ "time"
+ ):
+ command += " {time}".format(
+ **config_data["bgp"]["graceful_shutdown"]["vrfs"]
+ )
+ if config_data["bgp"]["graceful_shutdown"].get("local_preference"):
+ command += " local-preference {local_preference}".format(
+ **config_data["bgp"]["graceful_shutdown"]
+ )
+ if config_data["bgp"]["graceful_shutdown"].get("community"):
+ command += " community {community}".format(
+ **config_data["bgp"]["graceful_shutdown"]
+ )
+ return command
+
+
+def _tmplt_bgp_nopeerup_delay(config_data):
+ if "bgp" in config_data and "nopeerup_delay" in config_data["bgp"]:
+ commands = []
+ val = config_data["bgp"]["nopeerup_delay"]
+ cmd = "bgp nopeerup-delay"
+ if val.get("cold_boot"):
+ commands.append("{0} cold-boot {cold_boot}".format(cmd, **val))
+ elif val.get("post_boot"):
+ commands.append("{0} post-boot {post_boot}".format(cmd, **val))
+ elif val.get("nsf_switchover"):
+ commands.append(
+ "{0} nsf-switchover {nsf_switchover}".format(cmd, **val)
+ )
+ elif val.get("user_initiated"):
+ commands.append(
+ "{0} user-initiated {user_initiated}".format(cmd, **val)
+ )
+ return commands
+
+
+def _tmplt_neighbor(config_data):
+ if "neighbor" in config_data:
+ commands = []
+ cmd = "neighbor"
+ if "address" in config_data["neighbor"]:
+ cmd += " {address}".format(**config_data["neighbor"])
+ elif "tag" in config_data["neighbor"]:
+ cmd += " {tag}".format(**config_data["neighbor"])
+ elif "ipv6_adddress" in config_data["neighbor"]:
+ cmd += " {ipv6_adddress}".format(**config_data["neighbor"])
+ if "remote_as" in config_data["neighbor"]:
+ commands.append(
+ "{0} remote-as {remote_as}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "activate" in config_data["neighbor"]:
+ commands.append("{0} activate".format(cmd))
+ if "additional_paths" in config_data["neighbor"]:
+ self_cmd = "{0} additional-paths".format(cmd)
+ if "disable" in config_data["neighbor"]["additional_paths"]:
+ self_cmd += " disable"
+ elif "receive" in config_data["neighbor"]["additional_paths"]:
+ self_cmd += " receive"
+ elif "send" in config_data["neighbor"]["additional_paths"]:
+ self_cmd += " send"
+ commands.append(self_cmd)
+ if "advertise" in config_data["neighbor"]:
+ self_cmd = "{0} advertise".format(cmd)
+ if "additional_paths" in config_data["neighbor"]["advertise"]:
+ self_cmd += " additional-paths"
+ if (
+ "all"
+ in config_data["neighbor"]["advertise"]["additional_paths"]
+ ):
+ self_cmd += " all"
+ elif (
+ "best"
+ in config_data["neighbor"]["advertise"]["additional_paths"]
+ ):
+ self_cmd += " best {best}".format(
+ **config_data["neighbor"]["advertise"][
+ "additional_paths"
+ ]
+ )
+ elif (
+ "group_best"
+ in config_data["neighbor"]["advertise"]["additional_paths"]
+ ):
+ self_cmd += " group-best"
+ elif "best_external" in config_data["neighbor"]["advertise"]:
+ self_cmd += " best-external"
+ elif "diverse_path" in config_data["neighbor"]["advertise"]:
+ self_cmd += "diverse-path"
+ if (
+ "backup"
+ in config_data["neighbor"]["advertise"]["diverse_path"]
+ ):
+ self_cmd += " backup"
+ elif (
+ "mpath"
+ in config_data["neighbor"]["advertise"]["diverse_path"]
+ ):
+ self_cmd += " mpath"
+ commands.append(self_cmd)
+ if config_data["neighbor"].get("advertise_map"):
+ self_cmd = "{0} advertise-map {name}".format(
+ cmd, **config_data["neighbor"]["advertise_map"]
+ )
+ if "exist_map" in config_data["neighbor"]["advertise_map"]:
+ self_cmd += " exist-map {exist_map}".format(
+ **config_data["neighbor"]["advertise_map"]
+ )
+ elif "non_exist_map" in config_data["neighbor"]["advertise_map"]:
+ self_cmd += " exist-map {non_exist_map}".format(
+ **config_data["neighbor"]["advertise_map"]
+ )
+ commands.append(self_cmd)
+ if config_data["neighbor"].get("advertisement_interval"):
+ commands.append(
+ "{0} advertisement-interval {advertisement_interval}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if config_data["neighbor"].get("aigp"):
+ self_cmd = "{0} aigp".format(cmd)
+ if config_data["neighbor"]["aigp"].get("send"):
+ self_cmd += " send"
+ if config_data["neighbor"]["aigp"]["send"].get(
+ "cost_community"
+ ):
+ self_cmd += " cost-community {id}".format(
+ **config_data["neighbor"]["aigp"]["send"][
+ "cost_community"
+ ]
+ )
+ if config_data["neighbor"]["aigp"]["send"][
+ "cost_community"
+ ].get("poi"):
+ self_cmd += " poi"
+ if config_data["neighbor"]["aigp"]["send"][
+ "cost_community"
+ ]["poi"].get("igp_cost"):
+ self_cmd += " igp-cost"
+ if config_data["neighbor"]["aigp"]["send"][
+ "cost_community"
+ ]["poi"].get("pre_bestpath"):
+ self_cmd += " pre-bestpath"
+ if config_data["neighbor"]["aigp"]["send"][
+ "cost_community"
+ ]["poi"].get("transitive"):
+ self_cmd += " transitive"
+ if config_data["neighbor"]["aigp"]["send"].get("med"):
+ self_cmd += " med"
+ commands.append(self_cmd)
+ if config_data["neighbor"].get("allow_policy"):
+ commands.append("{0} allow-policy".format(cmd))
+ if config_data["neighbor"].get("allowas_in"):
+ commands.append(
+ "{0} allowas-in {allowas_in}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if config_data["neighbor"].get("as_override"):
+ commands.append("{0} as-override".format(cmd))
+ if "bmp_activate" in config_data["neighbor"]:
+ self_cmd = "{0} bmp-activate".format(cmd)
+ if config_data["neighbor"]["bmp_activate"].get("all"):
+ self_cmd += " all"
+ if "server" in config_data["neighbor"]["bmp_activate"]:
+ self_cmd += " server {server}".format(
+ **config_data["neighbor"]["bmp_activate"]
+ )
+ commands.append(self_cmd)
+ if "capability" in config_data["neighbor"]:
+ self_cmd = "{0} capability".format(cmd)
+ if config_data["neighbor"]["capability"].get("both"):
+ self_cmd += " both"
+ elif config_data["neighbor"]["capability"].get("receive"):
+ self_cmd += " receive"
+ elif config_data["neighbor"]["capability"].get("send"):
+ self_cmd += " send"
+ commands.append(self_cmd)
+ if config_data["neighbor"].get("cluster_id"):
+ commands.append(
+ "{0} cluster-id {cluster_id}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "default_originate" in config_data["neighbor"]:
+ self_cmd = "{0} default-originate".format(cmd)
+ if config_data["neighbor"]["default_originate"].get("route_map"):
+ self_cmd += " route-map {route_map}".format(
+ **config_data["neighbor"]["default_originate"]
+ )
+ commands.append(self_cmd)
+ if "description" in config_data["neighbor"]:
+ commands.append(
+ "{0} description {description}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if config_data["neighbor"].get("disable_connected_check"):
+ commands.append("{0} disable-connected-check".format(cmd))
+ if "distribute_list" in config_data["neighbor"]:
+ self_cmd = "{0} distribute-list".format(cmd)
+ if "acl" in config_data["neighbor"]["distribute_list"]:
+ self_cmd += " {acl}".format(
+ **config_data["neighbor"]["distribute_list"]
+ )
+ if config_data["neighbor"]["distribute_list"].get("in"):
+ self_cmd += " in"
+ elif config_data["neighbor"]["distribute_list"].get("out"):
+ self_cmd += " out"
+ commands.append(self_cmd)
+ if config_data["neighbor"].get("dmzlink_bw"):
+ commands.append("{0} dmzlink-bw".format(cmd))
+ if "ebgp_multihop" in config_data["neighbor"]:
+ self_cmd = "{0} ebgp-multihop".format(cmd)
+ if "hop_count" in config_data["neighbor"]["ebgp_multihop"]:
+ self_cmd += " {hop_count}".format(
+ **config_data["neighbor"]["ebgp_multihop"]
+ )
+ commands.append(self_cmd)
+ if "fall_over" in config_data["neighbor"]:
+ self_cmd = "{0} fall-over".format(cmd)
+ if "bfd" in config_data["neighbor"]["fall_over"]:
+ self_cmd += " bfd"
+ if config_data["neighbor"]["fall_over"]["bfd"].get(
+ "multi_hop"
+ ):
+ self_cmd += " multi-hop"
+ elif config_data["neighbor"]["fall_over"]["bfd"].get(
+ "single_hop"
+ ):
+ self_cmd += " single-hop"
+ elif "route_map" in config_data["neighbor"]["fall_over"]:
+ self_cmd += " {route_map}".format(
+ **config_data["neighbor"]["route_map"]
+ )
+ commands.append(self_cmd)
+ if "filter_list" in config_data["neighbor"]:
+ self_cmd = "{0} filter-list".format(cmd)
+ if "path_acl" in config_data["neighbor"]["filter_list"]:
+ self_cmd += " {path_acl}".format(
+ **config_data["neighbor"]["filter_list"]
+ )
+ if config_data["neighbor"]["filter_list"].get("in"):
+ self_cmd += " in"
+ elif config_data["neighbor"]["filter_list"].get("out"):
+ self_cmd += " out"
+ commands.append(self_cmd)
+ if "ha_mode" in config_data["neighbor"]:
+ self_cmd = "{0} ha-mode".format(cmd)
+ if config_data["neighbor"]["ha_mode"].get("disable"):
+ self_cmd += " disable"
+ commands.append(self_cmd)
+ if "inherit" in config_data["neighbor"]:
+ self_cmd = "{0} inherit {inherit}".format(
+ cmd, **config_data["neighbor"]
+ )
+ commands.append(self_cmd)
+ if "local_as" in config_data["neighbor"]:
+ self_cmd = "{0} local-as".format(cmd)
+ if "number" in config_data["neighbor"]["local_as"]:
+ self_cmd += " {number}".format(
+ **config_data["neighbor"]["local_as"]
+ )
+ if config_data["neighbor"]["local_as"].get("dual_as"):
+ self_cmd += " dual-as"
+ elif config_data["neighbor"]["local_as"].get("no_prepend"):
+ self_cmd += " no-prepend"
+ if config_data["neighbor"]["local_as"]["no_prepend"]:
+ self_cmd += " replace-as"
+ commands.append(self_cmd)
+ if "log_neighbor_changes" in config_data["neighbor"]:
+ self_cmd = "{0} log-neighbor-changes".format(cmd)
+ if config_data["neighbor"]["log_neighbor_changes"].get("disable"):
+ self_cmd += " disable"
+ commands.append(self_cmd)
+ if "maximum_prefix" in config_data["neighbor"]:
+ self_cmd = "{0} maximum-prefix".format(cmd)
+ if "max_no" in config_data["neighbor"]["maximum_prefix"]:
+ self_cmd += " {max_no}".format(
+ **config_data["neighbor"]["maximum_prefix"]
+ )
+ if "threshold_val" in config_data["neighbor"]["maximum_prefix"]:
+ self_cmd += " {threshold_val}".format(
+ **config_data["neighbor"]["maximum_prefix"]
+ )
+ if config_data["neighbor"]["maximum_prefix"].get("restart"):
+ self_cmd += " restart {restart}".format(
+ **config_data["neighbor"]["maximum_prefix"]
+ )
+ elif config_data["neighbor"]["filter_list"].get("warning_only"):
+ self_cmd += " warning-only"
+ commands.append(self_cmd)
+ if "next_hop_self" in config_data["neighbor"]:
+ self_cmd = "{0} next-hop-self".format(cmd)
+ if config_data["neighbor"]["next_hop_self"].get("all"):
+ self_cmd += " all"
+ commands.append(self_cmd)
+ if "next_hop_unchanged" in config_data["neighbor"]:
+ self_cmd = "{0} next-hop-unchanged".format(cmd)
+ if config_data["neighbor"]["next_hop_unchanged"].get("allpaths"):
+ self_cmd += " allpaths"
+ commands.append(self_cmd)
+ if "password" in config_data["neighbor"]:
+ commands.append(
+ "{0} password {password}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "path_attribute" in config_data["neighbor"]:
+ self_cmd = "{0} path-attribute".format(cmd)
+ if "discard" in config_data["neighbor"]["path_attribute"]:
+ self_cmd += " discard"
+ if (
+ "type"
+ in config_data["neighbor"]["path_attribute"]["discard"]
+ ):
+ self_cmd += " {type}".format(
+ **config_data["neighbor"]["path_attribute"]["discard"]
+ )
+ elif (
+ "range"
+ in config_data["neighbor"]["path_attribute"]["discard"]
+ ):
+ self_cmd += " range"
+ if (
+ "start"
+ in config_data["neighbor"]["path_attribute"][
+ "discard"
+ ]["range"]
+ ):
+ self_cmd += " {start}".format(
+ **config_data["neighbor"]["path_attribute"][
+ "discard"
+ ]["range"]
+ )
+ elif (
+ "end"
+ in config_data["neighbor"]["path_attribute"][
+ "discard"
+ ]["range"]
+ ):
+ self_cmd += " {start}".format(
+ **config_data["neighbor"]["path_attribute"][
+ "discard"
+ ]["range"]
+ )
+ if (
+ "in"
+ in config_data["neighbor"]["path_attribute"]["discard"]
+ ):
+ self_cmd += " in"
+ if (
+ "treat_as_withdraw"
+ in config_data["neighbor"]["path_attribute"]
+ ):
+ self_cmd += " treat-as-withdraw"
+ if (
+ "type"
+ in config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]
+ ):
+ self_cmd += " {type}".format(
+ **config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]
+ )
+ elif (
+ "range"
+ in config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]
+ ):
+ self_cmd += " range"
+ if (
+ "start"
+ in config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]["range"]
+ ):
+ self_cmd += " {start}".format(
+ **config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]["range"]
+ )
+ elif (
+ "end"
+ in config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]["range"]
+ ):
+ self_cmd += " {start}".format(
+ **config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]["range"]
+ )
+ if (
+ "in"
+ in config_data["neighbor"]["path_attribute"][
+ "treat_as_withdraw"
+ ]
+ ):
+ self_cmd += " in"
+ commands.append(self_cmd)
+ if "peer_group" in config_data["neighbor"]:
+ commands.append(
+ "{0} peer-group {peer_group}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "remove_private_as" in config_data["neighbor"]:
+ self_cmd = "{0} remove-private-as".format(cmd)
+ if config_data["neighbor"]["remove_private_as"].get("all"):
+ self_cmd += " all"
+ elif config_data["neighbor"]["remove_private_as"].get(
+ "replace_as"
+ ):
+ self_cmd += " replace_as"
+ commands.append(self_cmd)
+ if "route_map" in config_data["neighbor"]:
+ self_cmd = "{0} route-map".format(cmd)
+ if "name" in config_data["neighbor"]["route_map"]:
+ self_cmd += " {name}".format(
+ **config_data["neighbor"]["route_map"]
+ )
+ if "in" in config_data["neighbor"]["route_map"]:
+ self_cmd += " in"
+ elif "out" in config_data["neighbor"]["route_map"]:
+ self_cmd += " out"
+ commands.append(self_cmd)
+ if "route_reflector_client" in config_data["neighbor"]:
+ commands.append("{0} route-reflector-client".format(cmd))
+ if "route_server_client" in config_data["neighbor"]:
+ self_cmd = "{0} route-server-client".format(cmd)
+ if "context" in config_data["neighbor"]["route_map"]:
+ self_cmd += " context {context}".format(
+ **config_data["neighbor"]["route_server_client"]
+ )
+ commands.append(self_cmd)
+ if "send_community" in config_data["neighbor"]:
+ self_cmd = "{0} send-community".format(cmd)
+ if config_data["neighbor"]["send_community"].get("both"):
+ self_cmd += " both"
+ elif config_data["neighbor"]["send_community"].get("extended"):
+ self_cmd += " extended"
+ elif config_data["neighbor"]["send_community"].get("standard"):
+ self_cmd += " standard"
+ commands.append(self_cmd)
+ if "send_label" in config_data["neighbor"]:
+ self_cmd = "{0} send-label".format(cmd)
+ if config_data["neighbor"]["send_label"].get("explicit_null"):
+ self_cmd += " explicit-null"
+ commands.append(self_cmd)
+ if "shutdown" in config_data["neighbor"]:
+ self_cmd = "{0} shutdown".format(cmd)
+ if "graceful" in config_data["neighbor"]["route_map"]:
+ self_cmd += " graceful {graceful}".format(
+ **config_data["neighbor"]["shutdown"]
+ )
+ commands.append(self_cmd)
+ if "slow_peer" in config_data["neighbor"]:
+ self_cmd = "{0} slow-peer".format(cmd)
+ if "detection" in config_data["neighbor"]["slow_peer"]:
+ self_cmd += " detection"
+ if (
+ "disable"
+ in config_data["neighbor"]["slow_peer"]["detection"]
+ ):
+ self_cmd += " disable"
+ elif (
+ "threshold"
+ in config_data["neighbor"]["slow_peer"]["detection"]
+ ):
+ self_cmd += " threshold {threshold}".format(
+ **config_data["neighbor"]["slow_peer"]["detection"]
+ )
+ elif "split_update_group" in config_data["neighbor"]["slow_peer"]:
+ self_cmd += " split-update-group"
+ if (
+ "dynamic"
+ in config_data["neighbor"]["slow_peer"][
+ "split_update_group"
+ ]
+ ):
+ self_cmd += " dynamic"
+ if (
+ "disable"
+ in config_data["neighbor"]["slow_peer"][
+ "split_update_group"
+ ]["dynamic"]
+ ):
+ self_cmd += " disable"
+ elif (
+ "permanent"
+ in config_data["neighbor"]["slow_peer"][
+ "split_update_group"
+ ]["dynamic"]
+ ):
+ self_cmd += " permanent"
+ elif (
+ "static"
+ in config_data["neighbor"]["slow_peer"][
+ "split_update_group"
+ ]
+ ):
+ self_cmd += " static"
+ commands.append(self_cmd)
+ if "soft_reconfiguration" in config_data["neighbor"]:
+ commands.append("{0} soft-reconfiguration".format(cmd))
+ if "timers" in config_data["neighbor"]:
+ self_cmd = "{0} timers {interval} {holdtime}".format(
+ cmd, **config_data["neighbor"]["timers"]
+ )
+ if "min_holdtime" in config_data["neighbor"]["timers"]:
+ self_cmd += " {min_holdtime}".format(
+ **config_data["neighbor"]["timers"]
+ )
+ commands.append(self_cmd)
+ if "translate_update" in config_data["neighbor"]:
+ self_cmd = "{0} translate-update".format(cmd)
+ if config_data["neighbor"]["send_community"].get("nlri"):
+ self_cmd += " nlri"
+ if config_data["neighbor"]["nlri"].get("multicast"):
+ self_cmd += "multicast"
+ if config_data["neighbor"]["nlri"].get("unicast"):
+ self_cmd += "unicast"
+ commands.append(self_cmd)
+ if "transport" in config_data["neighbor"]:
+ self_cmd = "{0} transport".format(cmd)
+ if config_data["neighbor"]["transport"].get("connection_mode"):
+ self_cmd += " connection-mode"
+ if config_data["neighbor"]["transport"]["connection_mode"].get(
+ "active"
+ ):
+ self_cmd += " active"
+ elif config_data["neighbor"]["transport"][
+ "connection_mode"
+ ].get("passive"):
+ self_cmd += " passive"
+ elif config_data["neighbor"]["transport"].get("multi_session"):
+ self_cmd += " multi-session"
+ elif config_data["neighbor"]["transport"].get(
+ "path_mtu_discovery"
+ ):
+ self_cmd += " path-mtu-discovery"
+ if config_data["neighbor"]["transport"][
+ "path_mtu_discovery"
+ ].get("disable"):
+ self_cmd += " disable"
+ commands.append(self_cmd)
+ if "ttl_security" in config_data["neighbor"]:
+ commands.append(
+ "{0} ttl-security {ttl_security}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "unsuppress_map" in config_data["neighbor"]:
+ commands.append(
+ "{0} unsuppress-map {unsuppress_map}".format(
+ cmd, **config_data["neighbor"]
+ )
+ )
+ if "version" in config_data["neighbor"]:
+ commands.append(
+ "{0} version {version}".format(cmd, **config_data["neighbor"])
+ )
+ if "weight" in config_data["neighbor"]:
+ commands.append(
+ "{0} weight {weight}".format(cmd, **config_data["neighbor"])
+ )
+ return commands
+
+
+def _tmplt_redistribute(config_data):
+ if "redistribute" in config_data:
+
+ def common_config(command, param):
+ if config_data["redistribute"][param].get("metric"):
+ command += " metric {metric}".format(
+ **config_data["redistribute"][param]
+ )
+ if config_data["redistribute"][param].get("route_map"):
+ command += " route-map {route_map}".format(
+ **config_data["redistribute"][param]
+ )
+ return command
+
+ command = "redistribute"
+ if config_data["redistribute"].get("application"):
+ command += " application {name}".format(
+ **config_data["redistribute"]["application"]
+ )
+ command = common_config(command, "application")
+ elif config_data["redistribute"].get("bgp"):
+ command += " bgp {as_number}".format(
+ **config_data["redistribute"]["bgp"]
+ )
+ command = common_config(command, "bgp")
+ elif config_data["redistribute"].get("connected"):
+ command += " connected"
+ command = common_config(command, "connected")
+ elif config_data["redistribute"].get("eigrp"):
+ command += " eigrp {as_number}".format(
+ **config_data["redistribute"]["eigrp"]
+ )
+ command = common_config(command, "eigrp")
+ elif config_data["redistribute"].get("isis"):
+ command += " isis {area_tag}".format(
+ **config_data["redistribute"]["isis"]
+ )
+ if config_data["redistribute"]["isis"].get("clns"):
+ command += " clns"
+ elif config_data["redistribute"]["isis"].get("ip"):
+ command += " ip"
+ command = common_config(command, "isis")
+ elif config_data["redistribute"].get("iso_igrp"):
+ command += " iso-igrp {area_tag}".format(
+ **config_data["redistribute"]["iso_igrp"]
+ )
+ if config_data["redistribute"]["iso_igrp"].get("route_map"):
+ command += " route-map {route_map}".format(
+ **config_data["redistribute"]["iso_igrp"]
+ )
+ elif config_data["redistribute"].get("lisp"):
+ command += " lisp"
+ command = common_config(command, "lisp")
+ elif config_data["redistribute"].get("mobile"):
+ command += " mobile"
+ command = common_config(command, "mobile")
+ elif config_data["redistribute"].get("odr"):
+ command += " odr"
+ command = common_config(command, "odr")
+ elif config_data["redistribute"].get("rip"):
+ command += " rip"
+ command = common_config(command, "rip")
+ elif config_data["redistribute"].get("ospf"):
+ command += " ospf {process_id}".format(
+ **config_data["redistribute"]["ospf"]
+ )
+ if config_data["redistribute"]["ospf"].get("match"):
+ command += " match"
+ if config_data["redistribute"]["ospf"]["match"].get(
+ "external"
+ ):
+ command += " external"
+ if config_data["redistribute"]["ospf"]["match"].get(
+ "internal"
+ ):
+ command += " internal"
+ if config_data["redistribute"]["ospf"]["match"].get(
+ "nssa_external"
+ ):
+ command += " nssa-external"
+ if config_data["redistribute"]["ospf"]["match"].get("type_1"):
+ command += " 1"
+ elif config_data["redistribute"]["ospf"]["match"].get(
+ "type_2"
+ ):
+ command += " 2"
+ if config_data["redistribute"]["ospf"].get("vrf"):
+ command += " vrf"
+ command = common_config(command, "ospf")
+ elif config_data["redistribute"].get("ospfv3"):
+ command += " ospfv3 {process_id}".format(
+ **config_data["redistribute"]["ospfv3"]
+ )
+ if config_data["redistribute"]["ospfv3"].get("match"):
+ command += " match"
+ if config_data["redistribute"]["ospfv3"]["match"].get(
+ "external"
+ ):
+ command += " external"
+ if config_data["redistribute"]["ospfv3"]["match"].get(
+ "internal"
+ ):
+ command += " internal"
+ if config_data["redistribute"]["ospfv3"]["match"].get(
+ "nssa_external"
+ ):
+ command += " nssa-external"
+ if config_data["redistribute"]["ospfv3"]["match"].get(
+ "type_1"
+ ):
+ command += " 1"
+ elif config_data["redistribute"]["ospfv3"]["match"].get(
+ "type_2"
+ ):
+ command += " 2"
+ command = common_config(command, "ospf")
+ elif config_data["redistribute"].get("static"):
+ command += " static"
+ command = common_config(command, "static")
+ elif config_data["redistribute"].get("vrf"):
+ if config_data["redistribute"]["vrf"].get("name"):
+ command += " vrf {name}".format(
+ **config_data["redistribute"]["vrf"]
+ )
+ elif config_data["redistribute"]["vrf"].get("global"):
+ command += " vrf global"
+
+ return command
+
+
+def _tmplt_bgp_timers(config_data):
+ if "timers" in config_data:
+ command = "timers bgp"
+ if config_data["timers"].get("keepalive"):
+ command += " {keepalive}".format(**config_data["timers"])
+ if config_data["timers"].get("holdtime"):
+ command += " {holdtime}".format(**config_data["timers"])
+ if config_data["timers"].get("min_holdtime"):
+ command += " {min_holdtime}".format(**config_data["timers"])
+ return command
+
+
+class Bgp_globalTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(Bgp_globalTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "as_number",
+ "getval": re.compile(
+ r"""^router*
+ \s*bgp*
+ \s*(?P<as_number>\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "as_number",
+ "setval": "router bgp {{ as_number }}",
+ "result": {"as_number": "{{ as_number }}"},
+ "shared": True,
+ },
+ {
+ "name": "bgp.additional_paths",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*additional-paths*
+ \s*(?P<install>install)*
+ \s*(?P<receive>receive)*
+ \s*(?P<select>select)*
+ \s*(?P<select_all>all)*
+ \s*(?P<select_backup>backup)*
+ \s*(?P<select_best>best\s\d)*
+ \s*(?P<select_best_external>best-external)*
+ \s*(?P<select_group_best>group-best)*
+ \s*(?P<send>send)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_additional_paths,
+ "result": {
+ "bgp": {
+ "additional_paths": {
+ "install": "{{ True if install is defined }}",
+ "receive": "{{ True if receive is defined }}",
+ "select": {
+ "all": "{{ True if select_all is defined }}",
+ "backup": "{{ True if select_backup is defined }}",
+ "best": "{{ select_best.split('best ')[1] if select_best is defined }}",
+ "best_external": "{{ True if select_best_external is defined }}",
+ "group_best": "{{ True if select_group_best is defined }}",
+ },
+ "send": "{{ True if send is defined }}",
+ }
+ }
+ },
+ },
+ {
+ "name": "bgp.bestpath",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*bestpath*
+ \s*(?P<aigp>aigp\signore)*
+ \s*(?P<compare_routerid>compare-routerid)*
+ \s*(?P<cost_community>cost-community\signore)*
+ \s*(?P<med>med\s(confed|missing-as-worst|confed\smissing-as-worst))*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_bestpath,
+ "result": {
+ "bgp": {
+ "bestpath": [
+ {
+ "aigp": "{{ True if aigp is defined }}",
+ "compare_routerid": "{{ True if compare_routerid is defined }}",
+ "cost_community": "{{ True if cost_community is defined }}",
+ "med": {
+ "confed": "{{ True if med is defined and 'confed' in med }}",
+ "missing_as_worst": "{{ True if med is defined and 'missing-as-worst' in med }}",
+ },
+ }
+ ]
+ }
+ },
+ },
+ {
+ "name": "bgp.config",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*(?P<advertise_best_external>advertise-best-external)*
+ \s*(?P<aggregate_timer>aggregate-timer\s\d+)*
+ \s*(?P<always_compare_med>always-compare-med)*
+ \s*(?P<asnotation>asnotation\sdot)*
+ \s*(?P<client_to_client>client-to-client\sreflection\s(all|intra-cluster))*
+ \s*(?P<cluster_id>cluster-id\s.*)*
+ \s*(?P<confederation>confederation\s(identifier\s\d+|peers\s\d+))*
+ \s*(?P<consistency_checker>consistency-checker\s((auto-repair\sinterval\s\d+|auto-repair)|(error-message\sinterval\s\d+|error-message)))*
+ \s*(?P<deterministic_med>deterministic-med)*
+ \s*(?P<dmzlink_bw>dmzlink-bw)*
+ \s*(?P<enforce_first_as>enforce-first-as)*
+ \s*(?P<enhanced_error>enhanced-error)*
+ \s*(?P<fast_external_fallover>fast-external-fallover)*
+ \s*(?P<graceful_restart>graceful-restart(\sextended|\srestart-time\s\d+|\sstalepath-time\s\d+))*
+ \s*(?P<inject_map>inject-map\s\S+\sexist-map\s\S+\scopy-attributes|inject-map\s\S+\sexist-map\s\S+)*
+ \s*(?P<listen>listen\s(limit\s\d+|(range\s.*peer-group\s\S+|range\s.*)))*
+ \s*(?P<log_neighbor_changes>log-neighbor-changes)*
+ \s*(?P<maxas_limit>maxas-limit\s\d+)*
+ \s*(?P<maxcommunity_limit>maxas-limit\s\d+)*
+ \s*(?P<maxextcommunity_limit>maxextcommunity-limit\s\d+)*
+ \s*(?P<nexthop>nexthop\s(route-map\s\S+|trigger\s(delay\s\d+|enable)))*
+ \s*(?P<recursion>recursion\shost)*
+ \s*(?P<redistribute_internal>redistribute-internal)*
+ \s*(?P<refresh>refresh\s(max-eor-time\s\d+|stalepath-time\s\d+))*
+ \s*(?P<regexp>regexp\sdeterministic)*
+ \s*(?P<router_id>router-id\s((?:[0-9]{1,3}\.){3}[0-9]{1,3}|interface\s\S+\s\S+|vrf\sauto-assign))*
+ \s*(?P<route_map>route-map\spriority)*
+ \s*(?P<scan_time>scan-time\s\d+)*
+ \s*(?P<slow_peer>slow-peer((\sdetection\sthreshold\d+|\sdetection)|(\ssplit-update-group\sdynamic\spermanent|\ssplit-update-group\sdynamic)))*
+ \s*(?P<snmp>snmp\straps\sadd-type)*
+ \s*(?P<sso>sso\sroute-refresh-enable)*
+ \s*(?P<soft_reconfig_backup>soft-reconfig-backup)*
+ \s*(?P<suppress_inactive>suppress-inactive)*
+ \s*(?P<transport>transport\spath-mtu-discovery)*
+ \s*(?P<update_delay>update-delay\s\d+)*
+ \s*(?P<update_group>update-group\ssplit\sas-override)*
+ \s*(?P<upgrade_cli>upgrade-cli\saf-mode|upgrade-cli)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_config,
+ "compval": "bgp",
+ "result": {
+ "bgp": {
+ "advertise_best_external": "{{ True if advertise_best_external is defined }}",
+ "aggregate_timer": "{{ aggregate_timer.split('aggregate-timer ')[1] if aggregate_timer is defined }}",
+ "always_compare_med": "{{ True if always_compare_med is defined }}",
+ "asnotation": "{{ True if asnotation is defined }}",
+ "client_to_client": {
+ "set": "{{ True if client_to_client is defined and client_to_client.split(' ')|length == 2 }}",
+ "all": "{{ True if client_to_client is defined and 'all' in client_to_client }}",
+ "intra_cluster": "{{\
+ client_to_client.split('cluster-id ')[1]\
+ if client_to_client is defined and 'intra-cluster' in client_to_client }}",
+ },
+ "cluster_id": "{{ cluster_id.split('cluster-id ')[1] if cluster_id is defined }}",
+ "confederation": {
+ "identifier": "{{ confederation.split('confederation identifier ')[1] if confederation is defined }}",
+ "peers": "{{ confederation.split('confederation peers ')[1] if confederation is defined }}",
+ },
+ "consistency_checker": {
+ "auto_repair": {
+ "set": "{{\
+ True if consistency_checker is defined and\
+ 'auto-repair' in consistency_checker and\
+ consistency_checker.split(' ')|length == 2 }}",
+ "interval": "{{\
+ consistency_checker.split('interval ')[1] if consistency_checker is defined and\
+ consistency_checker.split(' ')|length > 2 }}",
+ },
+ "error_message": {
+ "set": "{{\
+ True if consistency_checker is defined and\
+ 'error-message' in consistency_checker and consistency_checker.split(' ')|length == 2 }}",
+ "interval": "{{\
+ consistency_checker.split('interval ')[1] if consistency_checker is defined and\
+ consistency_checker.split(' ')|length > 2 }}",
+ },
+ },
+ "deterministic_med": "{{ True if deterministic_med is defined }}",
+ "dmzlink_bw": "{{ True if dmzlink_bw is defined }}",
+ "enforce_first_as": "{{ True if enforce_first_as is defined }}",
+ "enhanced_error": "{{ True if enhanced_error is defined }}",
+ "fast_external_fallover": "{{ True if fast_external_fallover is defined }}",
+ "graceful_restart": {
+ "set": "{{ True if graceful_restart is defined and graceful_restart.split(' ')|length == 2 }}",
+ "extended": "{{ True if graceful_restart is defined and 'extended' in graceful_restart }}",
+ "restart_time": "{{\
+ graceful_restart.split('graceful-restart restart-time ')[1] if graceful_restart is defined and\
+ 'restart-time' in graceful_restart }}",
+ "stalepath_time": "{{\
+ graceful_restart.split('graceful-restart stalepath-time ')[1] if graceful_restart is defined and\
+ 'stalepath-time' in graceful_restart }}",
+ },
+ "inject_map": {
+ "name": "{{ inject_map.split(' ')[1] if inject_map is defined }}",
+ "exist_map_name": "{{ inject_map.split('exist-map ')[1].split(' ')[0] if inject_map is defined and 'exist-map' in inject_map }}",
+ "copy_attributes": "{{ True if inject_map is defined and 'copy-attributes' in inject_map }}",
+ },
+ "listen": {
+ "limit": "{{ listen.split('limit ')[1] if listen is defined and 'limit' in listen }}",
+ "range": {
+ "ipv4_with_subnet": "{{ listen.split('range ')[1].split(' ')[0] if listen is defined and ':' not in listen and '.' in listen }}",
+ "ipv6_with_subnet": "{{ listen.split('range ')[1].split(' ')[0] if listen is defined and ':' in listen and '.' in listen }}",
+ "peer_group": "{{ listen.split('peer-group ')[1] if listen is defined and 'peer-group' in listen }}",
+ },
+ },
+ "log_neighbor_changes": "{{ True if log_neighbor_changes is defined }}",
+ "maxas_limit": "{{ maxas_limit.split('maxas-limit ')[1] if maxas_limit is defined }}",
+ "maxcommunity_limit": "{{ maxcommunity_limit.split('maxcommunity-limit ')[1] if maxcommunity_limit is defined }}",
+ "maxextcommunity_limit": "{{ maxextcommunity_limit.split('maxextcommunity-limit ')[1] if maxextcommunity_limit is defined }}",
+ "nexthop": {
+ "route_map": "{{ nexthop.split('route-map ')[1] if nexthop is defined and 'route-map' in nexthop }}",
+ "trigger": {
+ "delay": "{{ nexthop.split('delay ')[1] if nexthop is defined and 'delay' in nexthop }}",
+ "enable": "{{ True if nexthop is defined and 'enable' in nexthop }}",
+ },
+ },
+ "recursion": "{{ True if recursion is defined }}",
+ "redistribute_internal": "{{ True if redistribute_internal is defined }}",
+ "refresh": {
+ "max_eor_time": "{{ refresh.split('max-eor-time ')[1] if refresh is defined }}",
+ "stalepath_time": "{{ refresh.split('stalepath-time ')[1] if refresh is defined }}",
+ },
+ "regexp": "{{ True if regexp is defined }}",
+ "router_id": {
+ "address": "{{ router_id.split(' ')[1] if router_id is defined and '.' in router_id }}",
+ "interface": "{{ router_id.split('interface ')[1] if router_id is defined and 'interface' in router_id }}",
+ "vrf": "{{ True if router_id is defined and 'vrf auto-assign' in router_id }}",
+ },
+ "route_map": "{{ True if route_map is defined }}",
+ "scan_time": "{{ scan_time.split('scan-time ')[1] if scan_time is defined }}",
+ "slow_peer": {
+ "detection": {
+ "set": "{{ True if slow_peer is defined and 'detection' in slow_peer and 'threshold' not in slow_peer }}",
+ "threshold": "{{ slow_peer.split('threshold ')[1] if slow_peer is defined and 'threshold' in slow_peer }}",
+ },
+ "split_update_group": {
+ "dynamic": "{{ True if split_dynamic is defined and split_dynamic.split('dynamic ')[1] == 'disable' }}",
+ "static": "{{ True if split_static is defined }}",
+ },
+ },
+ "snmp": "{{ True if snmp is defined }}",
+ "sso": "{{ True if sso is defined }}",
+ "soft_reconfig_backup": "{{ True if soft_reconfig_backup is defined }}",
+ "suppress_inactive": "{{ True if suppress_inactive is defined }}",
+ "transport": "{{ True if transport is defined }}",
+ "update_delay": "{{ update_delay.split('update-delay ')[1] if update_delay is defined }}",
+ "update_group": "{{ True if update_group is defined }}",
+ "upgrade_cli": {
+ "set": "{{ True if graceful_restart is defined and graceful_restart.split(' ')|length == 2 }}",
+ "af_mode": "{{ True if upgrade_cli is defined and 'af-mode' in upgrade_cli }}",
+ },
+ }
+ },
+ },
+ {
+ "name": "bgp.dampening",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*dampening*
+ \s*(?P<penalty_half_time>\d+)*
+ \s*(?P<reuse_route_val>\d+)*
+ \s*(?P<suppress_route_val>\d+)*
+ \s*(?P<max_suppress>\d+)*
+ \s*(?P<route_map>\S+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_dampening,
+ "result": {
+ "bgp": {
+ "dampening": {
+ "penalty_half_time": "{{ penalty_half_time if penalty_half_time is defined }}",
+ "reuse_route_val": "{{ reuse_route_val if penalty_half_time is defined }}",
+ "suppress_route_val": "{{ suppress_route_val if penalty_half_time is defined }}",
+ "max_suppress": "{{ max_suppress if penalty_half_time is defined }}",
+ "route_map": "{{ dampening.split('route-map ')[1] if dampening is defined and 'route-map' in dampening }}",
+ }
+ }
+ },
+ },
+ {
+ "name": "bgp.graceful_shutdown",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*graceful-shutdown\sall*
+ \s*(?P<neighbors>neighbors\s(\d+|activate))*
+ \s*(?P<vrfs>vrfs\s(\d+|activate))*
+ \s*(?P<local_preference>local-preference\s\d+)*
+ \s*(?P<community>community\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_graceful_shutdown,
+ "result": {
+ "bgp": {
+ "graceful_shutdown": {
+ "neighbors": {
+ "time": "{{ neighbors.split('neighbors ')[1] if neighbors is defined and 'activate' not in neighbors }}",
+ "activate": "{{ True if neighbors is defined and 'activate' in neighbors }}",
+ },
+ "vrfs": {
+ "time": "{{ vrfs.split('vrfs ')[1] if vrfs is defined and 'activate' not in vrfs }}",
+ "activate": "{{ True if vrfs is defined and 'activate' in vrfs }}",
+ },
+ "community": "{{ community.split('community ')[1] if community is defined }}",
+ "local_preference": "{{ local_preference.split('local-preference ')[1] if local_preference is defined }}",
+ }
+ }
+ },
+ },
+ {
+ "name": "bgp.nopeerup_delay",
+ "getval": re.compile(
+ r"""\s*bgp*
+ \s*nopeerup-delay*
+ \s*(?P<cold_boot>cold-boot\s\d+)*
+ \s*(?P<nsf_switchover>nsf-switchover\s\d+)*
+ \s*(?P<post_boot>post-boot\s\d+)*
+ \s*(?P<user_initiated>user-initiated\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_bgp_nopeerup_delay,
+ "result": {
+ "bgp": {
+ "nopeerup_delay": [
+ {
+ "cold_boot": "{{ cold_boot.split('cold-boot ')[1] if cold_boot is defined }}",
+ "nsf_switchover": "{{ nsf_switchover.split('nsf-switchover ')[1] if nsf_switchover is defined }}",
+ "post_boot": "{{ post_boot.split('post-boot ')[1] if post_boot is defined }}",
+ "user_initiated": "{{ user_initiated.split('user-initiated ')[1] if user_initiated is defined }}",
+ }
+ ]
+ }
+ },
+ },
+ {
+ "name": "neighbor",
+ "getval": re.compile(
+ r"""\s*neighbor*
+ \s*(?P<neighbor>(?:[0-9]{1,3}\.){3}[0-9]{1,3}|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+|\S+)*
+ \s*(?P<activate>activate)*
+ \s*(?P<additional_paths>additional-paths\s(disable|receive|send))*
+ \s*(?P<advertise>advertise\sadditional-paths\sall\sbest\s\d+\sgroup-best|advertise\sadditional-paths\sbest\s\d+\sgroup-best|advertise\sadditional-paths\sall\sgroup-best|advertise\sbest-external|advertise\sdiverse-path\sbackup\smpath|advertise\sdiverse-path\sbackup|advertise\sdiverse-path\smpath)*
+ \s*(?P<advertisement_interval>advertisement-interval\s\d+)*
+ \s*(?P<aigp>aigp\ssend\scost-community\s\d+\spoi\sigp-cost\stransitive|aigp\ssend\scost-community\s\d+\spoi\spre-bestpath\stransitive|aigp\ssend\smed|aigp)*
+ \s*(?P<allow_policy>allow-policy)*
+ \s*(?P<allowas_in>allowas-in\s\d+)*
+ \s*(?P<as_override>as-override)*
+ \s*(?P<bmp_activate>bmp-activate\s(all|server\s\d+))*
+ \s*(?P<capability>capability\s(both|receive|send))*
+ \s*(?P<cluster_id>cluster-id\s\S+)*
+ \s*(?P<default_originate>default-originate\sroute-map|default-originate)*
+ \s*(?P<description>description\s\S.+)*
+ \s*(?P<disable_connected_check>disable-connected-check)*
+ \s*(?P<distribute_list>distribute-list\s\d+\s(in|out))*
+ \s*(?P<dmzlink_bw>dmzlink-bw)*
+ \s*(?P<ebgp_multihop>(ebgp-multihop\s\d+|ebgp-multihop))*
+ \s*(?P<fall_over>fall-over\s((bfd\s(single-hop|multi-hop)|bfd)|route-map\s\S+))*
+ \s*(?P<filter_list>filter-list\s\d+\s(in|out))*
+ \s*(?P<ha_mode>ha-mode\s(graceful-restart\sdisable|graceful-restart))*
+ \s*(?P<inherit>inherit\speer-session\s\S+)*
+ \s*(?P<local_as>(local-as\s\d+\s(dual-as|(no-prepend\sreplace-as|no-prepend))|local-as))*
+ \s*(?P<log_neighbor_changes>log-neighbor-changes\sdisable|log-neighbor-changes)*
+ \s*(?P<maximum_prefix>maximum-prefix\s(\d+\s\d+\s(restart\s\d+|warning-only)|\d+\s(restart\s\d+|warning-only)))*
+ \s*(?P<next_hop_self>next-hop-self\sall|next-hop-self)*
+ \s*(?P<next_hop_unchanged>next-hop-unchanged\sallpaths|next-hop-unchanged)*
+ \s*(?P<password>password\s\S+)*
+ \s*(?P<path_attribute>path-attribute\s(discard\srange\s\d+\s\d+\sin|discard\s\d+\sin)|path-attribute\s(treat-as-withdraw\srange\s\d+\s\d+\sin|treat-as-withdraw\s\d+\sin))*
+ \s*(?P<peer_group>peer-group\s\S+)*
+ \s*(?P<remote_as>remote-as\s\d+)*
+ \s*(?P<remove_private_as>remove-private-as\sall\sreplace-as|remove-private-as\sall|remove-private-as)*
+ \s*(?P<route_map>route-map\s\S+\s(in|out))*
+ \s*(?P<route_reflector_client>route-reflector-client)*
+ \s*(?P<route_server_client>route-server-client\scontext\s\S+|route-server-client)*
+ \s*(?P<send_community>send-community\s(both|extended|standard)|send-community)*
+ #\s*(?P<send_label>send-label\sexplicit-null|send-label)*
+ \s*(?P<soft_reconfiguration>soft-reconfiguration\sinbound)*
+ \s*(?P<slow_peer>slow-peer\s(detection.*|split-update-group.*))*
+ \s*(?P<timers>(timers\s\d+\s\d+\s\d+|timers\s\d+\s\d+))*
+ \s*(?P<transport>(transport\s(connection-mode\sactive|connection-mode\spassive)|transport\smulti-session|transport\s(path-mtu-discovery\sdisable|path-mtu-discovery)))*
+ \s*(?P<ttl_security>ttl-security\shops\s\d+)*
+ \s*(?P<unsuppress_map>unsuppress-map\s\S+)*
+ \s*(?P<version>version\s\d+)*
+ \s*(?P<weight>weight\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_neighbor,
+ "compval": "neighbor",
+ "result": {
+ "neighbor": [
+ {
+ "address": "{{ neighbor if ':' not in neighbor and '.' in neighbor }}",
+ "ipv6_address": "{{ neighbor if ':' in neighbor and '.' in neighbor }}",
+ "tag": "{{ neighbor if ':' not in neighbor and '.' not in neighbor }}",
+ "activate": "{{ True if activate is defined }}",
+ "additional_paths": {
+ "disable": "{{ True if additional_paths is defined and 'disable' in additional_paths }}",
+ "receive": "{{ True if additional_paths is defined and 'receive' in additional_paths }}",
+ "send": "{{ True if additional_paths is defined and 'send' in additional_paths }}",
+ },
+ "advertise": {
+ "additional_paths": {
+ "all": "{{ True if advertise is defined and 'additional-paths' in advertise and 'all' in advertise }}",
+ "best": "{{\
+ advertise.split('best ')[1].split(' ')[0] if advertise is defined and\
+ 'additional-paths' in advertise and 'best' in advertise }}",
+ "group_best": "{{ True if advertise is defined and 'additional-paths' in advertise and 'group-best' in advertise }}",
+ },
+ "best_external": "{{ True if advertise is defined and 'best-external' in advertise }}",
+ "diverse_path": {
+ "backup": "{{ True if advertise is defined and 'diverse-path' in advertise and 'backup' in advertise }}",
+ "mpath": "{{ True if advertise is defined and 'diverse-path' in advertise and 'mpath' in advertise }}",
+ },
+ },
+ "advertisement_interval": "{{ advertisement_interval.split('advertisement-interval ')[1] if advertisement_interval is defined }}",
+ "aigp": {
+ "enable": "{{ True if aigp is defined and aigp.split(' ')|length == 1 }}",
+ "send": {
+ "cost_community": {
+ "id": "{{ aigp.split('send cost-community ')[1].split(' ')[0] if aigp is defined and 'send cost-community' in aigp }}",
+ "poi": {
+ "igp_cost": "{{ True if aigp is defined and 'poi igp-cost' in aigp }}",
+ "pre_bestpath": "{{ True if aigp is defined and 'poi pre-bestpath' in aigp }}",
+ "transitive": "{{ True if aigp is defined and 'transitive' in aigp }}",
+ },
+ },
+ "med": "{{ True if aigp is defined and 'send med' in aigp }}",
+ },
+ },
+ "allow_policy": "{{ True if allow_policy is defined }}",
+ "allowas_in": "{{ allowas_in.split('allowas-in ')[1] if allowas_in is defined }}",
+ "as_override": "{{ True if as_override is defined }}",
+ "bmp_activate": {
+ "all": "{{ True if bmp_activate is defined and 'all' in bmp_activate }}",
+ "server": "{{ bmp_activate.split('server ')[1] if bmp_activate is defined and 'server' in bmp_activate }}",
+ },
+ "capability": {
+ "both": "{{ True if capability is defined and 'both' in capability }}",
+ "receive": "{{ True if capability is defined and 'receive' in capability }}",
+ "send": "{{ True if capability is defined and 'send' in capability }}",
+ },
+ "cluster_id": "{{ cluster_id.split('cluster-id ')[1] if bmp_activate is defined }}",
+ "default_originate": {
+ "set": "{{ True if default_originate is defined and default_originate.split(' ')|length == 1 }}",
+ "route_map": "{{ default_originate.split(' ')[1] if default_originate is defined and default_originate.split(' ')|length > 1 }}",
+ },
+ "description": "{{ description.split('description ')[1] if description is defined }}",
+ "disable_connected_check": "{{ True if disable_connected_check is defined }}",
+ "distribute_list": {
+ "acl": "{{ distribute_list.split(' ')[1] if distribute_list is defined }}",
+ "in": "{{ True if distribute_list is defined and 'in' in distribute_list }}",
+ "out": "{{ True if distribute_list is defined and 'out' in distribute_list }}",
+ },
+ "dmzlink_bw": "{{ True if dmzlink_bw is defined }}",
+ "ebgp_multihop": {
+ "enable": "{{ True if ebgp_multihop is defined and ebgp_multihop.split(' ')|length == 1 }}",
+ "hop_count": "{{ ebgp_multihop.split(' ')[1] if ebgp_multihop is defined and len(ebgp_multihop.split(' ')) > 1 }}",
+ },
+ "fall_over": {
+ "bfd": {
+ "set": "{{ True if fall_over is defined and\
+ 'bfd' in fall_over and 'single-hop' not in fall_over and 'multi-hop' not in fall_over }}",
+ "multi_hop": "{{ True if fall_over is defined and 'bfd' in fall_over and 'multi-hop' in fall_over }}",
+ "single_hop": "{{ True if fall_over is defined and 'bfd' in fall_over and 'single-hop' in fall_over }}",
+ },
+ "route_map": "{{ fall_over.split('fall-over route-map ')[1] if fall_over is defined and 'route-map' in fall_over }}",
+ },
+ "filter_list": {
+ "acl": "{{ filter_list.split(' ')[1] if filter_list is defined }}",
+ "in": "{{ True if filter_list is defined and 'in' in filter_list }}",
+ "out": "{{ True if filter_list is defined and 'out' in filter_list }}",
+ },
+ "ha_mode": {
+ "set": "{{ True if ha_mode is defined and 'disable' not in ha_mode }}",
+ "disable": "{{ True if ha_mode is defined and 'disable' in ha_mode }}",
+ },
+ "inherit": "{{ inherit.split('inherit peer-session ')[1] if inherit is defined }}",
+ "local_as": {
+ "set": "{{ True if local_as is defined and local_as.split(' ')|length == 1 }}",
+ "number": "{{ local_as.split(' ')[1] if local_as is defined and local_as.split(' ')|length > 1 }}",
+ "dual_as": "{{ True if local_as is defined and local_as.split(' ')|length > 2 and 'dual-as' in local_as }}",
+ "no_prepend": {
+ "set": "{{\
+ True if local_as is defined and\
+ local_as.split(' ')|length > 2 and 'no-prepend' in local_as and\
+ 'replace-as' not in local_as }}",
+ "replace_as": "{{ True if local_as is defined and\
+ local_as.split(' ')|length > 2 and 'no-prepend' in local_as and 'replace-as' in local_as }}",
+ },
+ },
+ "log_neighbor_changes": {
+ "set": "{{ True if log_neighbor_changes is defined and 'disable' not in log_neighbor_changes }}",
+ "disable": "{{ True if log_neighbor_changes is defined and 'disable' in log_neighbor_changes }}",
+ },
+ "maximum_prefix": {
+ "max_no": "{{ maximum_prefix.split(' ')[1] if maximum_prefix is defined }}",
+ "threshold_val": "{{ maximum_prefix.split(' ')[2] if maximum_prefix is defined and\
+ maximum_prefix.split(' ')|length > 3 and maximum_prefix.split(' ')[1] != 'restart' }}",
+ "restart": "{{ maximum_prefix.split('restart ')[1] if maximum_prefix is defined and 'restart' in maximum_prefix }}",
+ "warning_only": "{{ True if maximum_prefix is defined and 'warning-only' in maximum_prefix }}",
+ },
+ "next_hop_self": {
+ "set": "{{ True if next_hop_self is defined and next_hop_self.split(' ')|length == 1 }}",
+ "all": "{{ True if next_hop_self is defined and next_hop_self.split(' ')|length > 1 }}",
+ },
+ "next_hop_unchanged": {
+ "set": "{{ True if next_hop_unchanged is defined and next_hop_unchanged.split(' ')|length == 1 }}",
+ "allpaths": "{{ True if next_hop_unchanged is defined and next_hop_unchanged.split(' ')|length > 1 }}",
+ },
+ "password": "{{ password.split(' ')[1] if password is defined }}",
+ "path_attribute": {
+ "discard": {
+ "type": "{% if path_attribute is defined and 'discard range' in path_attribute and\
+ path_attribute.split(' ')|length <= 5 %}{{ path_attribute.split(' ')[3] }}{% endif %}",
+ "range": {
+ "start": "{% if path_attribute is defined and 'discard range' in path_attribute and\
+ path_attribute.split(' ')|length > 5 %}{{ path_attribute.split(' ')[3] }}{% endif %}",
+ "end": "{% if path_attribute is defined and 'discard range' in path_attribute and\
+ path_attribute.split(' ')|length > 5 %}{{ path_attribute.split(' ')[4] }}{% endif %}",
+ },
+ "in": "{% if path_attribute is defined and 'discard range' in path_attribute and\
+ 'in' in path_attribute %}{{ True }}{% endif %}",
+ },
+ "treat_as_withdraw": {
+ "type": "{% if path_attribute is defined and 'discard treat-as-withdraw' in path_attribute and\
+ path_attribute.split(' ')|length <= 5 %}{{ path_attribute.split(' ')[3] }}{% endif %}",
+ "range": {
+ "start": "{% if path_attribute is defined and 'discard treat-as-withdraw' in path_attribute and\
+ path_attribute.split(' ')|length > 5 %}{{ path_attribute.split(' ')[3] }}{% endif %}",
+ "end": "{% if path_attribute is defined and 'discard treat-as-withdraw' in path_attribute and\
+ path_attribute.split(' ')|length > 5 %}{{ path_attribute.split(' ')[4] }}{% endif %}",
+ },
+ "in": "{% if path_attribute is defined and 'discard treat-as-withdraw' in path_attribute and\
+ 'in' in path_attribute %}{{ True }}{% endif %}",
+ },
+ },
+ "peer_group": "{{ listen.split('peer-group ')[1] if listen is defined and 'peer-group' in listen }}",
+ "remote_as": "{{ remote_as.split('remote-as ')[1] if remote_as is defined }}",
+ "remove_private_as": {
+ "set": "{{ True if remove_private_as is defined and remove_private_as.split(' ')|length == 1 }}",
+ "all": "{{ True if remove_private_as is defined and remove_private_as.split(' ')|length > 1 and 'all' in remove_private_as }}",
+ "replace_as": "{{ True if remove_private_as is defined and remove_private_as.split(' ')|length > 1 and\
+ 'replace-as' in remove_private_as }}",
+ },
+ "route_map": {
+ "name": "{{ route_map.split(' ')[1] if route_map is defined }}",
+ "in": "{{ True if route_map is defined and 'in' in route_map.split(' ') }}",
+ "out": "{{ True if route_map is defined and 'out' in route_map.split(' ') }}",
+ },
+ "route_reflector_client": "{{ True if route_reflector_client is defined }}",
+ "route_server_client": {
+ "set": "{{ True if route_server_client is defined and route_server_client.split(' ')|length == 1 }}",
+ "context": "{{ route_server_client.split('route-server-client context ')[1] if route_server_client is defined }}",
+ },
+ "send_community": {
+ "set": "{{ True if send_community is defined and send_community.split(' ')|length == 1 }}",
+ "both": "{{ True if send_community is defined and 'both' in send_community }}",
+ "extended": "{{ True if send_community is defined and 'extended' in send_community }}",
+ "standard": "{{ True if send_community is defined and 'standard' in send_community }}",
+ },
+ "send_label": {
+ "set": "{{ True if send_label is defined and send_label.split(' ')|length == 1 }}",
+ "explicit_null": "{{ True if send_label is defined and 'explicit-null' in send_label }}",
+ },
+ "slow_peer": {
+ "detection": {
+ "enable": "{{ True if slow_peer is defined and 'disable' not in slow_peer and 'threshold' not in slow_peer }}",
+ "disable": "{{ True if slow_peer is defined and 'disable' in slow_peer }}",
+ "threshold": "{{ slow_peer.split('threshold ')[1] if slow_peer is defined and 'threshold' in slow_peer }}",
+ },
+ "split_update_group": {
+ "dynamic": {
+ "enable": "{{ True if slow_peer is defined and 'split-update-group' in slow_peer and\
+ 'disable' not in slow_peer and 'threshold' not in slow_peer }}",
+ "disable": "{{ True if slow_peer is defined and 'split-update-group' in slow_peer and 'disable' in slow_peer }}",
+ "permanent": "{{ True if slow_peer is defined and 'split-update-group' in slow_peer and 'permanent' in slow_peer }}",
+ },
+ "static": "{{ True if slow_peer is defined and 'split-update-group' in slow_peer and 'static' in slow_peer }}",
+ },
+ },
+ "soft_reconfiguration": "{{ True if soft_reconfiguration is defined }}",
+ "timers": {
+ "interval": "{{ timers.split(' ')[1] if timers is defined }}",
+ "holdtime": "{{ timers.split(' ')[2] if timers is defined }}",
+ "min_holdtime": "{{ timers.split(' ')[3] if timers is defined and timers.split(' ')|length > 3 }}",
+ },
+ "translate_update": {
+ "set": "{{ True if translate_update is defined and translate_update.split(' ')|length == 1 }}",
+ "nlri": {
+ "multicast": "{{ True if translate_update is defined and 'nlri multicast' in translate_update }}",
+ "unicast": "{{ True if translate_update is defined and 'nlri unicast' in translate_update }}",
+ },
+ },
+ "transport": {
+ "connection_mode": {
+ "active": "{{ True if transport is defined and 'connection-mode active' in transport }}",
+ "passive": "{{ True if transport is defined and 'connection-mode passive' in transport }}",
+ },
+ "multi_session": "{{ True if transport is defined and 'multi-session' in transport }}",
+ "path_mtu_discovery": {
+ "set": "{{ True if transport is defined and 'path-mtu-discovery' in transport and 'disable' not in transport }}",
+ "disable": "{{ True if transport is defined and 'path-mtu-discovery' in transport and 'disable' in transport }}",
+ },
+ },
+ "ttl_security": "{{ ttl_security.split('ttl-security hops ')[1] if ttl_security is defined }}",
+ "unsuppress_map": "{{ unsuppress_map.split('unsuppress-map ')[1] if unsuppress_map is defined }}",
+ "version": "{{ version.split('version ')[1] if version is defined }}",
+ "weight": "{{ weight.split('weight ')[1] if weight is defined }}",
+ }
+ ]
+ },
+ },
+ {
+ "name": "redistribute",
+ "getval": re.compile(
+ r"""\s*redistribute*
+ \s*(?P<application>application\s\S+\smetric\s\d+\sroute-map\s\S+|application\s\S+\s(metric\s\d+|route-map\s\S+))*
+ \s*(?P<bgp>bgp\s\d+\smetric\s\d+\sroute-map\s\S+|bgp\s\d+\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<connected>connected\s(metric\s\d+\sroute-map\s\S+|metric\s\d+))*
+ \s*(?P<eigrp>eigrp\s\d+\smetric\s\d+\sroute-map\s\S+|eigrp\s\d+\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<isis>isis\s\S+\sclns\smetric\s\d+\sroute-map\s\S+|isis\s\S+\sip\smetric\s\d+\sroute-map\s\S+|isis\s\S+\s(clns|ip)\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<iso_igrp>iso-igrp\s\S+\sroute-map\s\S+|iso-igrp\s\S+)*
+ \s*(?P<lisp>lisp\smetric\s\d+\sroute-map\s\S+|lisp\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<mobile>mobile\smetric\s\d+\sroute-map\s\S+|mobile\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<odr>odr\smetric\s\d+\sroute-map\s\S+|odr\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<ospf>ospf\s\d+(\s.*))*
+ \s*(?P<ospfv3>ospfv3\s\d+(\s.*))*
+ \s*(?P<rip>rip\smetric\s\d+\sroute-map\s\S+|rip\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<static>static\sclns\smetric\s\d+\sroute-map\s\S+|static\sip\smetric\s\d+\sroute-map\s\S+|static\s(clns|ip)\s(metric\s\d+\sroute-map\s\S+))*
+ \s*(?P<vrf>vrf\s\S+|vrf\sglobal)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "redistribute",
+ "setval": _tmplt_redistribute,
+ "result": {
+ "redistribute": [
+ {
+ "application": {
+ "name": "{{ application.split(' ')[1] if application is defined }}",
+ "metric": "{{ application.split('metric ')[1].split(' ')[0] if application is defined and 'metric' in application }}",
+ "route_map": "{{ application.split('route-map ')[1].split(' ')[0] if application is defined and 'route-map' in application }}",
+ },
+ "bgp": {
+ "as_number": "{{ bgp.split(' ')[1] if bgp is defined }}",
+ "metric": "{{ bgp.split('metric ')[1].split(' ')[0] if bgp is defined and 'metric' in bgp }}",
+ "route_map": "{{ bgp.split('route-map ')[1].split(' ')[0] if bgp is defined and 'route-map' in bgp }}",
+ },
+ "connected": {
+ "metric": "{{ connected.split('metric ')[1].split(' ')[0] if connected is defined and 'metric' in connected }}",
+ "route_map": "{{ connected.split('route-map ')[1].split(' ')[0] if connected is defined and 'route-map' in connected }}",
+ },
+ "eigrp": {
+ "as_number": "{{ eigrp.split(' ')[1] if eigrp is defined }}",
+ "metric": "{{ eigrp.split('metric ')[1].split(' ')[0] if eigrp is defined and 'metric' in eigrp }}",
+ "route_map": "{{ eigrp.split('route-map ')[1].split(' ')[0] if eigrp is defined and 'route-map' in eigrp }}",
+ },
+ "isis": {
+ "area_tag": "{{ isis.split(' ')[1] if isis is defined }}",
+ "clns": "{{ True if isis is defined and 'clns' in isis }}",
+ "ip": "{{ True if isis is defined and 'ip' in isis }}",
+ "metric": "{{ isis.split('metric ')[1].split(' ')[0] if isis is defined and 'metric' in isis }}",
+ "route_map": "{{ isis.split('route-map ')[1].split(' ')[0] if isis is defined and 'route-map' in isis }}",
+ },
+ "iso_igrp": {
+ "area_tag": "{{ iso_igrp.split(' ')[1] if iso_igrp is defined }}",
+ "route_map": "{{ iso_igrp.split('route-map ')[1].split(' ')[0] if iso_igrp is defined and 'route-map' in iso_igrp }}",
+ },
+ "lisp": {
+ "metric": "{{ lisp.split('metric ')[1].split(' ')[0] if lisp is defined and 'metric' in lisp }}",
+ "route_map": "{{ lisp.split('route-map ')[1].split(' ')[0] if lisp is defined and 'route-map' in lisp }}",
+ },
+ "mobile": {
+ "metric": "{{ mobile.split('metric ')[1].split(' ')[0] if mobile is defined and 'metric' in mobile }}",
+ "route_map": "{{ mobile.split('route-map ')[1].split(' ')[0] if mobile is defined and 'route-map' in mobile }}",
+ },
+ "odr": {
+ "metric": "{{ odr.split('metric ')[1].split(' ')[0] if odr is defined and 'metric' in odr }}",
+ "route_map": "{{ odr.split('route-map ')[1].split(' ')[0] if odr is defined and 'route-map' in odr }}",
+ },
+ "ospf": {
+ "process_id": "{{ ospf.split(' ')[1] if ospf is defined }}",
+ "match": {
+ "external": "{{ True if ospf is defined and 'external' in ospf }}",
+ "internal": "{{ True if ospf is defined and 'internal' in ospf }}",
+ "nssa_external": "{{ True if ospf is defined and 'nssa-external' in ospf }}",
+ "type_1": "{{ True if ospf is defined and '1' in ospf }}",
+ "type_2": "{{ True if ospf is defined and '2' in ospf }}",
+ },
+ "metric": "{{ ospf.split('metric ')[1].split(' ')[0] if ospf is defined and 'metric' in ospf }}",
+ "route_map": "{{ ospf.split('route-map ')[1].split(' ')[0] if ospf is defined and 'route-map' in ospf }}",
+ "vrf": "{{ ospf.split('vrf ')[1].split(' ')[0] if ospf is defined and 'vrf' in ospf }}",
+ },
+ "ospfv3": {
+ "process_id": "{{ ospfv3.split(' ')[1] if ospf is defined }}",
+ "match": {
+ "external": "{{ True if ospfv3 is defined and 'external' in ospfv3 }}",
+ "internal": "{{ True if ospfv3 is defined and 'internal' in ospfv3 }}",
+ "nssa_external": "{{ True if ospfv3 is defined and 'nssa-external' in ospfv3 }}",
+ "type_1": "{{ True if ospfv3 is defined and '1' in ospfv3 }}",
+ "type_2": "{{ True if ospfv3 is defined and '2' in ospfv3 }}",
+ },
+ "metric": "{{ ospfv3.split('metric ')[1].split(' ')[0] if ospfv3 is defined and 'metric' in ospfv3 }}",
+ "route_map": "{{ ospfv3.split('route-map ')[1].split(' ')[0] if ospfv3 is defined and 'route-map' in ospfv3 }}",
+ "vrf": "{{ ospfv3.split('vrf ')[1].split(' ')[0] if ospfv3 is defined and 'vrf' in ospfv3 }}",
+ },
+ "rip": {
+ "metric": "{{ rip.split('metric ')[1].split(' ')[0] if rip is defined and 'metric' in rip }}",
+ "route_map": "{{ rip.split('route-map ')[1].split(' ')[0] if rip is defined and 'route-map' in rip }}",
+ },
+ "static": {
+ "clns": "{{ True if static is defined and 'clns' in static }}",
+ "ip": "{{ True if static is defined and 'ip' in static }}",
+ "metric": "{{ static.split('metric ')[1].split(' ')[0] if static is defined and 'metric' in static }}",
+ "route_map": "{{ static.split('route-map ')[1].split(' ')[0] if static is defined and 'route-map' in static }}",
+ },
+ "vrf": {
+ "name": "{{ vrf.split('vrf ')[1].split(' ')[0] if vrf is defined and 'vrf' in vrf and 'global' not in vrf }}",
+ "global": "{{ True if vrf is defined and 'vrf' in vrf and 'global' in vrf }}",
+ },
+ }
+ ]
+ },
+ },
+ {
+ "name": "route_server_context",
+ "getval": re.compile(
+ r"""\s*(?P<route_server_context>route-server-context\s\S+)""",
+ re.VERBOSE,
+ ),
+ "compval": "route_server_context",
+ "setval": "",
+ "result": {
+ "route_server_context": "{{ route_server_context.split('route-server-context ')[1] if route_server_context is defined }}"
+ },
+ },
+ {
+ "name": "synchronization",
+ "getval": re.compile(
+ r"""\s*(?P<synchronization>synchronization)""", re.VERBOSE
+ ),
+ "compval": "synchronization",
+ "setval": "synchronization",
+ "result": {
+ "synchronization": "{{ Trues if synchronization is defined }}"
+ },
+ },
+ {
+ "name": "table_map",
+ "getval": re.compile(
+ r"""\s*(?P<table_map>route-server-context\s\S+)""", re.VERBOSE
+ ),
+ "compval": "table_map",
+ "setval": "",
+ "result": {
+ "table_map": "{{ table_map.split('route-server-context ')[1] if table_map is defined }}"
+ },
+ },
+ {
+ "name": "timers",
+ "getval": re.compile(
+ r"""\s*(?P<timers>timers\sbgp\s\d+\s\d+\s\d+)""", re.VERBOSE
+ ),
+ "compval": "timers",
+ "setval": _tmplt_bgp_timers,
+ "result": {
+ "timers": {
+ "keepalive": "{{ timers.split(' ')[2] if timers is defined }}",
+ "holdtime": "{{ timers.split(' ')[3] if timers is defined }}",
+ "min_holdtime": "{{ timers.split(' ')[4] if timers is defined and timers.split(' ')|length > 4 }}",
+ }
+ },
+ },
+ ]
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py
new file mode 100644
index 00000000..419c4859
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py
@@ -0,0 +1,895 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The Ospf_interfaces parser templates file. This contains
+a list of parser definitions and associated functions that
+facilitates both facts gathering and native command generation for
+the given network resource.
+"""
+
+import re
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_ospf_interface(config_data):
+ command = "interface {name}".format(**config_data)
+ return command
+
+
+def _tmplt_ospf_interface_process(config_data):
+ if "process" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf {id} area {area_id}".format(
+ **config_data["process"]
+ )
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf {id} area {area_id}".format(
+ **config_data["process"]
+ )
+ if "secondaries" in config_data["process"]:
+ command += " secondaries"
+ return command
+
+
+def _tmplt_ip_ospf_authentication(config_data):
+ if "authentication" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf authentication"
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf authentication"
+ if "key_chain" in config_data["authentication"]:
+ command += " key-chain {key_chain}".format(
+ **config_data["authentication"]
+ )
+ elif "message_digest" in config_data["authentication"]:
+ command += " message-digest"
+ elif "null" in config_data["authentication"]:
+ command += " null"
+ return command
+
+
+def _tmplt_ip_ospf_cost(config_data):
+ if "cost" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf cost {interface_cost}".format(
+ **config_data["cost"]
+ )
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf cost"
+ if "interface_cost" in config_data["cost"]:
+ command = "ipv6 ospf cost {interface_cost}".format(
+ **config_data["cost"]
+ )
+ if "dynamic_cost" in config_data["cost"]:
+ if "default" in config_data["cost"]["dynamic_cost"]:
+ command += " dynamic default {default}".format(
+ **config_data["cost"]["dynamic_cost"]
+ )
+ elif "hysteresis" in config_data["cost"]["dynamic_cost"]:
+ command += " dynamic hysteresis"
+ if (
+ "percent"
+ in config_data["cost"]["dynamic_cost"]["hysteresis"]
+ ):
+ command += " percent {percent}".format(
+ **config_data["cost"]["dynamic_cost"]["hysteresis"]
+ )
+ elif (
+ "threshold"
+ in config_data["cost"]["dynamic_cost"]["hysteresis"]
+ ):
+ command += " threshold {threshold}".format(
+ **config_data["cost"]["dynamic_cost"]["hysteresis"]
+ )
+ elif "weight" in config_data["cost"]["dynamic_cost"]:
+ command += " dynamic weight"
+ if (
+ "l2_factor"
+ in config_data["cost"]["dynamic_cost"]["weight"]
+ ):
+ command += " L2-factor {l2_factor}".format(
+ **config_data["cost"]["dynamic_cost"]["weight"]
+ )
+ elif (
+ "latency"
+ in config_data["cost"]["dynamic_cost"]["weight"]
+ ):
+ command += " latency {latency}".format(
+ **config_data["cost"]["dynamic_cost"]["weight"]
+ )
+ elif (
+ "oc" in config_data["cost"]["dynamic_cost"]["weight"]
+ and config_data["cost"]["dynamic_cost"]["weight"]["oc"]
+ ):
+ command += " oc cdr"
+ elif (
+ "resources"
+ in config_data["cost"]["dynamic_cost"]["weight"]
+ ):
+ command += " resources {resources}".format(
+ **config_data["cost"]["dynamic_cost"]["weight"]
+ )
+ elif (
+ "throughput"
+ in config_data["cost"]["dynamic_cost"]["weight"]
+ ):
+ command += " throughput {throughput}".format(
+ **config_data["cost"]["dynamic_cost"]["weight"]
+ )
+ return command
+
+
+def _tmplt_ip_ospf_dead_interval(config_data):
+ if "dead_interval" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf dead-interval"
+ if "time" in config_data["dead_interval"]:
+ command += " {time}".format(**config_data["dead_interval"])
+ elif "minimal" in config_data["dead_interval"]:
+ command += " minimal hello-multiplier {minimal}".format(
+ **config_data["dead_interval"]
+ )
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf dead-interval {time}".format(
+ **config_data["dead_interval"]
+ )
+ return command
+
+
+def _tmplt_ip_ospf_demand_circuit(config_data):
+ if "demand_circuit" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf demand-circuit"
+ if config_data["demand_circuit"]["ignore"]:
+ command += " ignore"
+ elif config_data["demand_circuit"]["enable"]:
+ return command
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf demand-circuit"
+ if config_data["demand_circuit"]["enable"]:
+ return command
+ elif config_data["demand_circuit"]["ignore"]:
+ command += " ignore"
+ elif config_data["demand_circuit"]["disable"]:
+ command += " disable"
+ return command
+
+
+def _tmplt_ip_ospf_manet(config_data):
+ if "manet" in config_data:
+ command = "ipv6 ospf manet peering"
+ if "cost" in config_data["manet"]:
+ command += " cost"
+ if "percent" in config_data["manet"]["cost"]:
+ command += " percent {percent}".format(
+ **config_data["manet"]["cost"]
+ )
+ elif "threshold" in config_data["manet"]["cost"]:
+ command += " threshold {threshold}".format(
+ **config_data["manet"]["cost"]
+ )
+ elif "link_metrics" in config_data["manet"]:
+ command += " link-metrics"
+ if "cost_threshold" in config_data["manet"]["link_metrics"]:
+ command += " {cost_threshold}".format(
+ **config_data["manet"]["link_metrics"]
+ )
+ return command
+
+
+def _tmplt_ip_ospf_multi_area(config_data):
+ if "multi_area" in config_data:
+ command = "ip ospf multi-area {id}".format(**config_data["multi_area"])
+ if "cost" in config_data["multi_area"]:
+ command += " cost {cost}".format(**config_data["multi_area"])
+ return command
+
+
+def _tmplt_ip_ospf_neighbor(config_data):
+ if "neighbor" in config_data:
+ command = "ipv6 ospf neighbor {address}".format(
+ **config_data["neighbor"]
+ )
+ if "cost" in config_data["neighbor"]:
+ command += " cost {cost}".format(**config_data["neighbor"])
+ if (
+ "database_filter" in config_data["neighbor"]
+ and config_data["neighbor"]["database_filter"]
+ ):
+ command += " database-filter all out"
+ if "poll_interval" in config_data["neighbor"]:
+ command += " poll-interval {poll_interval}".format(
+ **config_data["neighbor"]["poll_interval"]
+ )
+ if "priority" in config_data["neighbor"]:
+ command += " priority {priority}".format(
+ **config_data["neighbor"]["priority"]
+ )
+ return command
+
+
+def _tmplt_ip_ospf_network(config_data):
+ if "network" in config_data:
+ if config_data.get("afi") == "ipv4":
+ command = "ip ospf network"
+ elif config_data.get("afi") == "ipv6":
+ command = "ipv6 ospf network"
+ if "broadcast" in config_data["network"]:
+ command += " broadcast"
+ if "manet" in config_data["network"]:
+ command += " manet"
+ if "non_broadcast" in config_data["network"]:
+ command += " non-broadcast"
+ if "point_to_multipoint" in config_data["network"]:
+ command += " point-to-multipoint"
+ if "point_to_point" in config_data["network"]:
+ command += " point-to-point"
+ return command
+
+
+def _tmplt_ip_ospf_ttl_security(config_data):
+ if "ttl_security" in config_data:
+ command = "ip ospf ttl-security"
+ if "hops" in config_data["ttl_security"]:
+ command += " hops {hops}".format(**config_data["ttl_security"])
+ return command
+
+
+class Ospf_InterfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(Ospf_InterfacesTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "name",
+ "getval": re.compile(
+ r"""
+ ^interface
+ \s(?P<name>\S+)$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface {{ name }}",
+ "result": {
+ "{{ name }}": {"name": "{{ name }}", "address_family": {}}
+ },
+ "shared": True,
+ },
+ {
+ "name": "process",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<id>\d+)*
+ \s*(?P<area>area\s\d+)*
+ \s*(?P<secondaries>secondaries)*
+
+ \s*(?P<instance>instance*\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_interface_process,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "process": {
+ "id": "{{ id }}",
+ "area_id": "{{ area.split(' ')[1] }}",
+ "secondaries": "{{ True if secondaries is defined }}",
+ "instance_id": "{{ instance.split(' ')[1]}}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "adjacency",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<adjacency>adjacency*\s*stagger)*
+ \s*(?P<disable>disable)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} adjacency stagger disable",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "adjacency": "{{ True if adjacency is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "authentication",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*authentication*
+ \s*(?P<key_chain>key-chain*\s*\S+)*
+ \s*(?P<message_digest>message-digest)*
+ \s*(?P<null>null)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_authentication,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "authentication": {
+ "key_chain": "{{ key_chain.split(' ')[1] }}",
+ "message_digest": "{{ True if message_digest is defined }}",
+ "null": "{{ True if null is defined }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<bfd>bfd)*
+ \s*(?P<disable>disable)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} bfd",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "bfd": "{{ True if bfd is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "cost_ip",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip)*
+ \s*ospf*
+ \s*(?P<cost>cost*\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_cost,
+ "compval": "cost.interface_cost",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "cost": {
+ "interface_cost": "{{ cost.split(' ')[1] }}"
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "cost_ipv6_dynamic_cost",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ipv6)*
+ \s*ospf*
+ \s*cost*
+ \s*(?P<interface_cost>\d+)*
+ \s*dynamic*
+ \s*(?P<default>default*\s*\d+)*
+ \s*(?P<hysteresis>hysteresis*\s*)*
+ \s*(?P<h_params>(percent|threshold)*\s*\d+)*
+ \s*(?P<weight>weight)*
+ \s*(?P<w_params>(L2-factor|latency|resources|throughput)*\s*\d+)*
+ \s*(?P<weight_oc>oc)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "cost.dynamic_cost",
+ "setval": _tmplt_ip_ospf_cost,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "cost": {
+ "interface_cost": "{{ interface_cost }}",
+ "dynamic_cost": {
+ "default": "{{ default.split(' ')[1] }}",
+ "hysteresis": {
+ "percent": "{{ h_params.split(' ')[1] if h_params is defined and 'percent' in h_params }}",
+ "threshold": "{{ h_params.split(' ')[1] if h_params is defined and 'threshold' in h_params }}",
+ },
+ "weight": {
+ "l2_factor": "{{ w_params.split(' ')[1] if w_params is defined and 'L2-factor' in w_params }}",
+ "latency": "{{ w_params.split(' ')[1] if w_params is defined and 'latency' in w_params }}",
+ "oc": "{{ True if weight_oc is defined}}",
+ "resources": "{{ w_params.split(' ')[1] if w_params is defined and 'resources' in w_params }}",
+ "throughput": "{{ w_params.split(' ')[1] if w_params is defined and 'throughput' in w_params }}",
+ },
+ },
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "database_filter",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<database_filter>database-filter\sall\sout)*
+ \s*(?P<disable>disable)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} database-filter all out",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "database_filter": "{{ True if database_filter is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "dead_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<dead_interval>dead-interval)*
+ \s*(?P<seconds>\d+)*
+ \s*(?P<minimal>minimal\shello-multiplier\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_dead_interval,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "dead_interval": {
+ "time": "{{ seconds }}",
+ "minimal": {
+ "hello_multiplier": "{{ minimal.split(' ')[2] }}"
+ },
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "demand_circuit",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<demand_circuit>demand-circuit)*
+ \s*(?P<ignore>ignore)*
+ \s*(?P<disable>disable)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_demand_circuit,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "demand_circuit": {
+ "enable": "{{ True if demand_circuit is defined and ignore is not defined }}",
+ "ignore": "{{ True if ignore is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "flood_reduction",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<flood_reduction>flood-reduction)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} flood-reduction",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "flood_reduction": "{{ True if flood_reduction is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "hello_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<hello_interval>hello-interval\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} hello-interval {{ hello_interval }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "hello_interval": "{{ hello_interval.split(' ')[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "lls",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip)*
+ \s*ospf*
+ \s*(?P<lls>lls)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} lls",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "lls": "{{ True if lls is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "manet",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ipv6)*
+ \s*ospf*
+ \s*(?P<manet>manet\speering)*
+ \s*(?P<cost>(cost\spercent|cost\sthreshold)\s\d+)*
+ \s*(?P<link_metrics>link-metrics\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_manet,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "manet": {
+ "cost": {
+ "percent": "{{ cost.split(' ')[2] }}",
+ "threshold": "{{ cost.split(' ')[2] }}",
+ },
+ "link_metrics": {
+ "set": "{{ True if link_metrics is not defined and link_metrics is defined }}",
+ "cost_threshold": "{{ link_metrics.split(' ')[1] }}",
+ },
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "mtu_ignore",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<mtu_ignore>mtu-ignore)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} mtu-ignore",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "mtu_ignore": "{{ True if mtu_ignore is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "multi_area",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip)*
+ \s*ospf*
+ \s*(?P<multi_area>multi-area\s\d+)*
+ \s*(?P<cost>cost\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_multi_area,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "multi_area": {
+ "id": "{{ multi_area.split(' ')[1] }}",
+ "cost": "{{ cost.split(' ')[1] }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "neighbor",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ipv6)*
+ \s*ospf*
+ \s*neighbor*
+ \s*(?P<address>(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+)*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<database_filter>database-filter\sall\sout)*
+ \s*(?P<poll_interval>poll-interval\s\d+)*
+ \s*(?P<priority>priority\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_neighbor,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost.split(' ')[1] }}",
+ "database_filter": "{{ True if database_filter is defined }}",
+ "poll_interval": "{{ poll_interval.split(' ')[1] }}",
+ "priority": "{{ priority.split(' ')[1] }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "network",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<network>network)*
+ \s*(?P<broadcast>broadcast)*
+ \s*(?P<manet>manet)*
+ \s*(?P<non_broadcast>non-broadcast)*
+ \s*(?P<point_to_multipoint>point-to-multipoint)*
+ \s*(?P<point_to_point>point-to-point)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_network,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "network": {
+ "broadcast": "{{ True if broadcast is defined }}",
+ "manet": "{{ True if manet is defined }}",
+ "non_broadcast": "{{ True if non_broadcast is defined }}",
+ "point_to_multipoint": "{{ True if point_to_multipoint is defined }}",
+ "point_to_point": "{{ True if point_to_point is defined }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<prefix_suppression>prefix-suppression)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} prefix-suppression",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "prefix_suppression": "{{ True if prefix_suppression is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<priority>priority*\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} priority {{ priority }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "priority": "{{ priority.split(' ')[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "resync_timeout",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip)*
+ \s*ospf*
+ \s*(?P<resync_timeout>resync-timeout*\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ip ospf resync-timeout {{ resync_timeout }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "resync_timeout": "{{ resync_timeout.split(' ')[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "retransmit_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<retransmit_interval>retransmit-interval*\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} retransmit-interval {{ retransmit_interval }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "retransmit_interval": "{{ retransmit_interval.split(' ')[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)*
+ \s*ospf*
+ \s*(?P<shutdown>shutdown)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} shutdown",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "shutdown": "{{ True if shutdown is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "transmit_delay",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ipv6)*
+ \s*ospf*
+ \s*(?P<transmit_delay>transmit-delay*\s*\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ipv6 ospf transmit-delay {{ transmit_delay }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "transmit_delay": "{{ transmit_delay.split(' ')[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip)*
+ \s*ospf*
+ \s*(?P<ttl_security>ttl-security)*
+ \s*(?P<hops>hops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ip_ospf_ttl_security,
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "ttl_security": {
+ "set": "{{ True if hops is not defined and ttl_security is defined }}",
+ "hops": "{{ hops.split(' ')[1] }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ ]
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py
new file mode 100644
index 00000000..9a09e237
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py
@@ -0,0 +1,1947 @@
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import re
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_ospf_vrf_cmd(process):
+ command = "router ospf {process_id}".format(**process)
+ if "vrf" in process:
+ command += " vrf {vrf}".format(**process)
+ return command
+
+
+def _tmplt_ospf_adjacency_cmd(config_data):
+ if "adjacency" in config_data:
+ command = "adjacency stagger "
+ if "none" in config_data["adjacency"]:
+ command += " none"
+ else:
+ command += " {min_adjacency}".format(**config_data["adjacency"])
+ if "max_adjacency" in config_data["adjacency"]:
+ command += " {min_adjacency}".format(**config_data["adjacency"])
+ return command
+
+
+def _tmplt_ospf_address_family_cmd(config_data):
+ if "address_family" in config_data:
+ command = ["address-family ipv4 multicast", "exit-address-family"]
+ if config_data["address_family"].get("topology"):
+ if "base" in config_data["address_family"].get("topology"):
+ command.insert(1, "topology base")
+ elif "name" in config_data["address_family"].get("topology"):
+ cmd = "topology {name}".format(
+ **config_data["address_family"].get("topology")
+ )
+ if "tid" in config_data["address_family"].get("topology"):
+ cmd += " tid {tid}".format(
+ **config_data["address_family"].get("topology")
+ )
+ command.insert(1, cmd)
+ return command
+
+
+def _tmplt_ospf_area_authentication(config_data):
+ if "authentication" in config_data:
+ command = "area {area_id} authentication".format(**config_data)
+ if config_data["authentication"].get("message_digest"):
+ command += " message-digest"
+ return command
+
+
+def _tmplt_ospf_area_filter(config_data):
+ if "filter_list" in config_data:
+ command = []
+ for key, value in iteritems(config_data.get("filter_list")):
+ cmd = "area {area_id}".format(**config_data)
+ if value.get("name") and value.get("direction"):
+ cmd += " filter-list prefix {name} {direction}".format(**value)
+ command.append(cmd)
+ return command
+
+
+def _tmplt_ospf_area_nssa(config_data):
+ if "nssa" in config_data:
+ command = "area {area_id} nssa".format(**config_data)
+ if "default_information_originate" in config_data["nssa"]:
+ command += " default-information-originate"
+ if (
+ "metric"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " metric {metric}".format(
+ **config_data["nssa"]["default_information_originate"]
+ )
+ if (
+ "metric_type"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " metric-type {metric_type}".format(
+ **config_data["nssa"]["default_information_originate"]
+ )
+ if (
+ "nssa_only"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " nssa-only"
+ if config_data["nssa"].get("no_ext_capability"):
+ command += " no-ext-capability"
+ if config_data["nssa"].get("no_redistribution"):
+ command += " no-redistribution"
+ if config_data["nssa"].get("no_summary"):
+ command += " no-summary"
+ return command
+
+
+def _tmplt_ospf_area_nssa_translate(config_data):
+ if "nssa" in config_data:
+ command = "area {area_id} nssa".format(**config_data)
+ if "translate" in config_data["nssa"]:
+ command += " translate type7 {translate}".format(
+ **config_data["nssa"]
+ )
+ return command
+
+
+def _tmplt_ospf_area_ranges(config_data):
+ if "ranges" in config_data:
+ commands = []
+ for k, v in iteritems(config_data["ranges"]):
+ cmd = "area {area_id} range".format(**config_data)
+ temp_cmd = " {address} {netmask}".format(**v)
+ if "advertise" in v:
+ temp_cmd += " advertise"
+ elif "not_advertise" in v:
+ temp_cmd += " not-advertise"
+ if "cost" in v:
+ temp_cmd += " cost {cost}".format(**v)
+ cmd += temp_cmd
+ commands.append(cmd)
+ return commands
+
+
+def _tmplt_ospf_area_sham_link(config_data):
+ if "sham_link" in config_data:
+ command = "area {area_id} sham-link".format(**config_data)
+ if "source" in config_data["sham_link"]:
+ command += " {source} {destination}".format(
+ **config_data["sham_link"]
+ )
+ if "cost" in config_data["sham_link"]:
+ command += " cost {cost}".format(**config_data["sham_link"])
+ if "ttl_security" in config_data["sham_link"]:
+ command += " ttl-security hops {ttl_security}".format(
+ **config_data["sham_link"]
+ )
+ return command
+
+
+def _tmplt_ospf_area_stub_link(config_data):
+ if "stub" in config_data:
+ command = "area {area_id} stub".format(**config_data)
+ if "no_ext_capability" in config_data["stub"]:
+ command += " no-ext-capability"
+ if "no_summary" in config_data["stub"]:
+ command += " no-summary"
+ return command
+
+
+def _tmplt_ospf_auto_cost(config_data):
+ if "auto_cost" in config_data:
+ command = "auto-cost"
+ if "reference_bandwidth" in config_data["auto_cost"]:
+ command += " reference-bandwidth {reference_bandwidth}".format(
+ **config_data["auto_cost"]
+ )
+ return command
+
+
+def _tmplt_ospf_capability(config_data):
+ if "capability" in config_data:
+ if "lls" in config_data["capability"]:
+ command = "capability lls"
+ elif "opaque" in config_data["capability"]:
+ command = "capability opaque"
+ elif "transit" in config_data["capability"]:
+ command = "capability transit"
+ elif "vrf_lite" in config_data["capability"]:
+ command = "capability vrf_lite"
+ return command
+
+
+def _tmplt_ospf_compatible(config_data):
+ if "compatible" in config_data:
+ if "rfc1583" in config_data["compatible"]:
+ command = "compatible rfc1583"
+ elif "rfc1587" in config_data["compatible"]:
+ command = "compatible rfc1587"
+ elif "rfc5243" in config_data["compatible"]:
+ command = "compatible rfc5243"
+ return command
+
+
+def _tmplt_ospf_default_information(config_data):
+ if "default_information" in config_data:
+ command = "default-information"
+ if "originate" in config_data["default_information"]:
+ command += " originate"
+ if "always" in config_data["default_information"]:
+ command += " always"
+ if "metric" in config_data["default_information"]:
+ command += " metric {metric}".format(
+ **config_data["default_information"]
+ )
+ if "metric_type" in config_data["default_information"]:
+ command += " metric-type {metric_type}".format(
+ **config_data["default_information"]
+ )
+ if "metric" in config_data["default_information"]:
+ command += " route-map {route_map}".format(
+ **config_data["default_information"]
+ )
+ return command
+
+
+def _tmplt_ospf_discard_route(config_data):
+ if "discard_route" in config_data:
+ command = "discard-route"
+ if "external" in config_data["discard_route"]:
+ command += " external {external}".format(
+ **config_data["discard_route"]
+ )
+ if "internal" in config_data["discard_route"]:
+ command += " internal {internal}".format(
+ **config_data["discard_route"]
+ )
+ return command
+
+
+def _tmplt_ospf_distance_admin_distance(config_data):
+ if "admin_distance" in config_data["distance"]:
+ command = "distance {distance}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ if "address" in config_data["distance"]["admin_distance"]:
+ command += " {address} {wildcard_bits}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ if "acl" in config_data["distance"]["admin_distance"]:
+ command += " {acl}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ return command
+
+
+def _tmplt_ospf_distance_ospf(config_data):
+ if "ospf" in config_data["distance"]:
+ command = "distance ospf"
+ if "inter_area" in config_data["distance"]["ospf"]:
+ command += " inter-area {inter_area}".format(
+ **config_data["distance"]["ospf"]
+ )
+ if config_data["distance"].get("ospf").get("intra_area"):
+ command += " intra-area {intra_area}".format(
+ **config_data["distance"]["ospf"]
+ )
+ if config_data["distance"].get("ospf").get("external"):
+ command += " external {external}".format(
+ **config_data["distance"]["ospf"]
+ )
+ return command
+
+
+def _tmplt_ospf_distribute_list_acls(config_data):
+ if "acls" in config_data.get("distribute_list"):
+ command = []
+ for k, v in iteritems(config_data["distribute_list"]["acls"]):
+ cmd = "distribute-list {name} {direction}".format(**v)
+ if "interface" in v:
+ cmd += " {interface}".format(**v)
+ if "protocol" in v:
+ cmd += " {protocol}".format(**v)
+ command.append(cmd)
+ return command
+
+
+def _tmplt_ospf_distribute_list_prefix(config_data):
+ if "prefix" in config_data.get("distribute_list"):
+ command = "distribute-list prefix {name}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "gateway_name" in config_data["distribute_list"]["prefix"]:
+ command += " gateway {gateway_name}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "direction" in config_data["distribute_list"]["prefix"]:
+ command += " {direction}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "interface" in config_data["distribute_list"]["prefix"]:
+ command += " {interface}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "protocol" in config_data["distribute_list"]["prefix"]:
+ command += " {protocol}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ return command
+
+
+def _tmplt_ospf_domain_id(config_data):
+ if "domain_id" in config_data:
+ command = "domain-id"
+ if "ip_address" in config_data["domain_id"]:
+ if "address" in config_data["domain_id"]["ip_address"]:
+ command += " {address}".format(
+ **config_data["domain_id"]["ip_address"]
+ )
+ if "secondary" in config_data["domain_id"]["ip_address"]:
+ command += " {secondary}".format(
+ **config_data["domain_id"]["ip_address"]
+ )
+ elif "null" in config_data["domain_id"]:
+ command += " null"
+ return command
+
+
+def _tmplt_ospf_event_log(config_data):
+ if "event_log" in config_data:
+ command = "event-log"
+ if "one_shot" in config_data["event_log"]:
+ command += " one-shot"
+ if "pause" in config_data["event_log"]:
+ command += " pause"
+ if "size" in config_data["event_log"]:
+ command += " size {size}".format(**config_data["event_log"])
+ return command
+
+
+def _tmplt_ospf_limit(config_data):
+ if "limit" in config_data:
+ command = "limit retransmissions"
+ if "dc" in config_data["limit"]:
+ if "number" in config_data["limit"]["dc"]:
+ command += " dc {number}".format(**config_data["limit"]["dc"])
+ if "disable" in config_data["limit"]["dc"]:
+ command += " dc disable"
+ if "non_dc" in config_data["limit"]:
+ if "number" in config_data["limit"]["non_dc"]:
+ command += " non-dc {number}".format(
+ **config_data["limit"]["non_dc"]
+ )
+ if "disable" in config_data["limit"]["dc"]:
+ command += " non-dc disable"
+ return command
+
+
+def _tmplt_ospf_vrf_local_rib_criteria(config_data):
+ if "local_rib_criteria" in config_data:
+ command = "local-rib-criteria"
+ if "forwarding_address" in config_data["local_rib_criteria"]:
+ command += " forwarding-address"
+ if "inter_area_summary" in config_data["local_rib_criteria"]:
+ command += " inter-area-summary"
+ if "nssa_translation" in config_data["local_rib_criteria"]:
+ command += " nssa-translation"
+ return command
+
+
+def _tmplt_ospf_log_adjacency_changes(config_data):
+ if "log_adjacency_changes" in config_data:
+ command = "log-adjacency-changes"
+ if "detail" in config_data["log_adjacency_changes"]:
+ command += " detail"
+ return command
+
+
+def _tmplt_ospf_max_lsa(config_data):
+ if "max_lsa" in config_data:
+ command = "max-lsa {number}".format(**config_data["max_lsa"])
+ if "threshold_value" in config_data["max_lsa"]:
+ command += " {threshold_value}".format(**config_data["max_lsa"])
+ if "ignore_count" in config_data["max_lsa"]:
+ command += " ignore-count {ignore_count}".format(
+ **config_data["max_lsa"]
+ )
+ if "ignore_time" in config_data["max_lsa"]:
+ command += " ignore-time {ignore_time}".format(
+ **config_data["max_lsa"]
+ )
+ if "reset_time" in config_data["max_lsa"]:
+ command += " reset-time {reset_time}".format(
+ **config_data["max_lsa"]
+ )
+ if "warning_only" in config_data["max_lsa"]:
+ command += " warning-only"
+ return command
+
+
+def _tmplt_ospf_max_metric(config_data):
+ if "max_metric" in config_data:
+ command = "max-metric"
+ if "router_lsa" in config_data["max_metric"]:
+ command += " router-lsa"
+ if "external_lsa" in config_data["max_metric"]:
+ command += " external-lsa {external_lsa}".format(
+ **config_data["max_metric"]
+ )
+ if "include_stub" in config_data["max_metric"]:
+ command += " include-stub"
+ if "on_startup" in config_data["max_metric"]:
+ if "time" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup {time}".format(
+ **config_data["max_metric"]["on_startup"]
+ )
+ elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup wait-for-bgp"
+ if "summary_lsa" in config_data["max_metric"]:
+ command += " summary-lsa {summary_lsa}".format(
+ **config_data["max_metric"]
+ )
+ return command
+
+
+def _tmplt_ospf_mpls_ldp(config_data):
+ if "ldp" in config_data["mpls"]:
+ command = "mpls ldp"
+ if "autoconfig" in config_data["mpls"]["ldp"]:
+ command += " autoconfig"
+ if "area" in config_data["mpls"]["ldp"]["autoconfig"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["ldp"]["autoconfig"]
+ )
+ elif "sync" in config_data["mpls"]["ldp"]:
+ command += " sync"
+ return command
+
+
+def _tmplt_ospf_mpls_traffic_eng(config_data):
+ if "traffic_eng" in config_data["mpls"]:
+ command = "mpls traffic-eng"
+ if "area" in config_data["mpls"]["traffic_eng"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ elif "autoroute_exclude" in config_data["mpls"]["traffic_eng"]:
+ command += " autoroute-exclude prefix-list {autoroute_exclude}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ elif "interface" in config_data["mpls"]["traffic_eng"]:
+ command += " interface {int_type}".format(
+ **config_data["mpls"]["traffic_eng"]["interface"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["interface"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]["interface"]
+ )
+ elif "mesh_group" in config_data["mpls"]["traffic_eng"]:
+ command += " mesh-group {id} {interface}".format(
+ **config_data["mpls"]["traffic_eng"]["mesh_group"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]["mesh_group"]
+ )
+ elif "multicast_intact" in config_data["mpls"]["traffic_eng"]:
+ command += " multicast-intact"
+ elif "router_id_interface" in config_data["mpls"]["traffic_eng"]:
+ command += " router-id {router_id_interface}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ return command
+
+
+def _tmplt_ospf_neighbor(config_data):
+ if "neighbor" in config_data:
+ command = "neighbor"
+ if "address" in config_data["neighbor"]:
+ command += " {address}".format(**config_data["neighbor"])
+ if "cost" in config_data["neighbor"]:
+ command += " cost {cost}".format(**config_data["neighbor"])
+ if "database_filter" in config_data["neighbor"]:
+ command += " database-filter all out"
+ if "poll_interval" in config_data["neighbor"]:
+ command += " poll-interval {poll_interval}".format(
+ **config_data["neighbor"]
+ )
+ if "priority" in config_data["neighbor"]:
+ command += " priority {priority}".format(**config_data["neighbor"])
+ return command
+
+
+def _tmplt_ospf_network(config_data):
+ if "network" in config_data:
+ command = []
+ for each in config_data["network"]:
+ cmd = "network"
+ if "address" in each:
+ cmd += " {address} {wildcard_bits}".format(**each)
+ if "area" in each:
+ cmd += " area {area}".format(**each)
+ command.append(cmd)
+ return command
+
+
+def _tmplt_ospf_nsf_cisco(config_data):
+ if "cisco" in config_data["nsf"]:
+ command = "nsf cisco helper"
+ if "disable" in config_data["nsf"]["cisco"]:
+ command += " disable"
+ return command
+
+
+def _tmplt_ospf_nsf_ietf(config_data):
+ if "ietf" in config_data["nsf"]:
+ command = "nsf ietf helper"
+ if "disable" in config_data["nsf"]["ietf"]:
+ command += " disable"
+ elif "strict_lsa_checking" in config_data["nsf"]["ietf"]:
+ command += " strict-lsa-checking"
+ return command
+
+
+def _tmplt_ospf_queue_depth_hello(config_data):
+ if "hello" in config_data["queue_depth"]:
+ command = "queue-depth hello"
+ if "max_packets" in config_data["queue_depth"]["hello"]:
+ command += " {max_packets}".format(
+ **config_data["queue_depth"]["hello"]
+ )
+ elif "unlimited" in config_data["queue_depth"]["hello"]:
+ command += " unlimited"
+ return command
+
+
+def _tmplt_ospf_queue_depth_update(config_data):
+ if "update" in config_data["queue_depth"]:
+ command = "queue-depth update"
+ if "max_packets" in config_data["queue_depth"]["update"]:
+ command += " {max_packets}".format(
+ **config_data["queue_depth"]["update"]
+ )
+ elif "unlimited" in config_data["queue_depth"]["update"]:
+ command += " unlimited"
+ return command
+
+
+def _tmplt_ospf_summary_address(config_data):
+ if "summary_address" in config_data:
+ command = "summary-address {address} {mask}".format(
+ **config_data["summary_address"]
+ )
+ if "not_advertise" in config_data["summary_address"]:
+ command += " not-advertise"
+ elif "nssa_only" in config_data["summary_address"]:
+ command += " nssa-only"
+ if "tag" in config_data["summary_address"]:
+ command += " tag {tag}".format(
+ **config_data["summary_address"]
+ )
+ return command
+
+
+def _tmplt_ospf_timers_pacing(config_data):
+ if "pacing" in config_data["timers"]:
+ command = "timers pacing"
+ if "flood" in config_data["timers"]["pacing"]:
+ command += " flood {flood}".format(
+ **config_data["timers"]["pacing"]
+ )
+ elif "lsa_group" in config_data["timers"]["pacing"]:
+ command += " lsa-group {lsa_group}".format(
+ **config_data["timers"]["pacing"]
+ )
+ elif "retransmission" in config_data["timers"]["pacing"]:
+ command += " retransmission {retransmission}".format(
+ **config_data["timers"]["pacing"]
+ )
+ return command
+
+
+def _tmplt_ospf_ttl_security(config_data):
+ if "ttl_security" in config_data:
+ command = "ttl-security all-interfaces"
+ if "hops" in config_data["ttl_security"]:
+ command += " hops {hops}".format(**config_data["ttl_security"])
+ return command
+
+
+class Ospfv2Template(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(Ospfv2Template, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "pid",
+ "getval": re.compile(
+ r"""
+ ^router\s
+ ospf*
+ \s(?P<pid>\S+)
+ \svrf
+ \s(?P<vrf>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "process_id": "{{ pid|int }}",
+ "vrf": "{{ vrf }}",
+ }
+ }
+ },
+ "shared": True,
+ },
+ {
+ "name": "pid",
+ "getval": re.compile(
+ r"""
+ ^router\s
+ ospf*
+ \s(?P<pid>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_cmd,
+ "result": {
+ "processes": {"{{ pid }}": {"process_id": "{{ pid|int }}"}}
+ },
+ "shared": True,
+ },
+ {
+ "name": "adjacency",
+ "getval": re.compile(
+ r"""\s+adjacency
+ \sstagger*
+ \s*((?P<min>\d+)|(?P<none_adj>none))*
+ \s*(?P<max>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "address_family",
+ "getval": re.compile(
+ r"""\s+topology
+ \s(?P<base>base)*
+ \s*(?P<name>\S+)*
+ \s*(?P<tid>tid\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "address_family": {
+ "topology": {
+ "base": "{{ True if base is defined }}",
+ "name": "{{ name }}",
+ "tid": "{{ tid.split(" ")[1] }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \sdefault-cost*
+ \s*(?P<default_cost>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} default-cost {{ default_cost }}",
+ "compval": "default_cost",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.filter_list",
+ "getval": re.compile(
+ r"""\s+area
+ \s*(?P<area_id>\S+)*
+ \s*filter-list\sprefix*
+ \s*(?P<name>\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ }
+ ],
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.nssa",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \s(?P<nssa>nssa)*
+ \s*(?P<no_redis>no-redistribution)*
+ \s*(?P<def_origin>default-information-originate)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<no_summary>no-summary)*
+ \s*(?P<no_ext>no-ext-capability)*$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and def_origin is undefined and "
+ "no_ext is undefined and no_redis is undefined and nssa_only is undefined }}",
+ "default_information_originate": {
+ "set": "{{ True if def_origin is defined and metric is undefined and "
+ "metric_type is undefined and nssa_only is undefined }}",
+ "metric": "{{ metric.split("
+ ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.nssa.translate",
+ "getval": re.compile(
+ r"""\s+area*
+ \s*(?P<area_id>\S+)*
+ \s*(?P<nssa>nssa)*
+ \stranslate\stype7*
+ \s(?P<translate_always>always)*
+ \s* (?P<translate_supress>suppress-fa)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa.translate",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}"
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.ranges",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \srange
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<netmask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*((?P<advertise>advertise)|(?P<not_advertise>not-advertise))*
+ \s*(?P<cost>cost\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ }
+ ],
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.sham_link",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \ssham-link
+ \s(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<destination>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<ttl_security>ttl-security\shops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.stub",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \s(?P<stub>stub)*
+ \s*(?P<no_ext>no-ext-capability)*
+ \s*(?P<no_sum>no-summary)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"bfd": "{{ True if bfd is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "capability": {
+ "lls": "{{ True if lls is defined }}",
+ "opaque": "{{ True if opaque is defined }}",
+ "transit": "{{ True if transit is defined }}",
+ "vrf_lite": "{{ True if vrf_lite is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "default_information",
+ "getval": re.compile(
+ r"""\s+default-information*
+ \s*(?P<originate>originate)*
+ \s*(?P<always>always)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<route_map>route-map\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "default_information": {
+ "originate": "{{ True if originate is defined }}",
+ "always": "{{ True if always is defined }}",
+ "metric": "{{ metric.split(" ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "route_map": "{{ route_map.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"default_metric": "{{ default_metric| int}}"}
+ }
+ },
+ },
+ {
+ "name": "discard_route",
+ "getval": re.compile(
+ r"""\s+(?P<discard_route>discard-route)*
+ \s*(?P<external>external\s\d+)*
+ \s*(?P<internal>internal\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "discard_route": {
+ "set": "{{ True if discard_route is defined and external is undefined and internal is undefined }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ "internal": "{{ internal.split(" ")[1]|int }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distance.admin_distance",
+ "getval": re.compile(
+ r"""\s+distance
+ \s(?P<admin_dist>\S+)*
+ \s*(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<acl>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distance.ospf",
+ "getval": re.compile(
+ r"""\s+distance
+ \sospf*
+ \s*(?P<intra>intra-area\s\d+)*
+ \s*(?P<inter>inter-area\s\d+)*
+ \s*(?P<external>external\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.acls",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<name>\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ ]
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.prefix",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<prefix>prefix\s\S+)*
+ \s*(?P<gateway>gateway\s\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split("
+ ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "distribute-list route-map {{ distribute_list.route_map.name }} in",
+ "compval": "distribute_list.route_map",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "route_map": {
+ "name": "{{ route_map.split(" ")[1] }}"
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "domain_id",
+ "getval": re.compile(
+ r"""\s+domain-id
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<secondary>secondary)*
+ \s*(?P<null>null)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "result": {
+ "processes": {"{{ pid }}": {"domain_tag": "{{ tag|int }}"}}
+ },
+ },
+ {
+ "name": "event_log",
+ "getval": re.compile(
+ r"""\s+(?P<event_log>event-log)*
+ \s*(?P<one_shot>one-shot)*
+ \s*(?P<pause>pause)*
+ \s*(?P<size>size\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "event_log": {
+ "enable": "{{ True if event_log is defined and one_shot is undefined and pause is undefined and size is undefined }}",
+ "one_shot": "{{ True if one_shot is defined }}",
+ "pause": "{{ True if pause is defined }}",
+ "size": "{{ size.split(" ")[1]|int }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"help": "{{ True if help is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "ignore",
+ "getval": re.compile(
+ r"""\s+(?P<ignore>ignore)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ignore lsa mospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"ignore": "{{ True if ignore is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "interface_id": "{{ True if interface_id is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "ispf",
+ "getval": re.compile(
+ r"""\s+(?P<ispf>ispf)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ispf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"ispf": "{{ True if ispf is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "limit",
+ "getval": re.compile(
+ r"""\s+limit\sretransmissions
+ \s((?P<dc_num>dc\s\d+)|(?P<dc_disable>dc\sdisable))*
+ \s*((?P<non_dc_num>non-dc\s\d+)|(?P<non_dc_disable>non-dc\sdisable))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "local_rib_criteria",
+ "getval": re.compile(
+ r"""\s+(?P<local>local-rib-criteria)*
+ \s*(?P<forward>forwarding-address)*
+ \s*(?P<inter>inter-area-summary)*
+ \s*(?P<nssa>nssa-translation)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "max_lsa",
+ "getval": re.compile(
+ r"""\s+max-lsa
+ \s(?P<number>\d+)*
+ \s*(?P<threshold>\d+)*
+ \s*(?P<ignore_count>ignore-count\s\d+)*
+ \s*(?P<ignore_time>ignore-time\s\d+)*
+ \s*(?P<reset_time>reset-time\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_lsa": {
+ "number": "{{ number }}",
+ "threshold_value": "{{ threshold }}",
+ "ignore_count": "{{ ignore_count.split(" ")[1] }}",
+ "ignore_time": "{{ ignore_time.split(" ")[1] }}",
+ "reset_time": "{{ reset_time.split(" ")[1] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "max_metric",
+ "getval": re.compile(
+ r"""\s+max-metric*
+ \s*(?P<router_lsa>router-lsa)*
+ \s*(?P<include_stub>include-stub)*
+ \s*(?P<external_lsa>external-lsa\s\d+)*
+ \s*(?P<startup_time>on-startup\s\d+)*
+ \s*(?P<startup_wait>on-startup\s\S+)*
+ \s*(?P<summary_lsa>summary-lsa\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "result": {
+ "processes": {"{{ pid }}": {"maximum_paths": "{{ paths }}"}}
+ },
+ },
+ {
+ "name": "mpls.ldp",
+ "getval": re.compile(
+ r"""\s+mpls
+ \sldp*
+ \s*(?P<autoconfig>autoconfig*\s*(?P<area>area\s\S+))*
+ \s*(?P<sync>sync)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_ldp,
+ "compval": "ldp",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "ldp": {
+ "autoconfig": {
+ "set": "{{ True if autoconfig is defined and area is undefined }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ "sync": "{{ True if sync is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "mpls.traffic_eng",
+ "getval": re.compile(
+ r"""\s+mpls
+ \straffic-eng*
+ \s*(?P<area>area\s\S+)*
+ \s*(?P<autoroute>autoroute-exclude\s\S+\s\S+)*
+ \s*(?P<interface>interface\s(?P<int_type>\S+\s\S+)\s(?P<int_area>area\s\S+))*
+ \s*(?P<mesh>mesh-group\s\d+\s(?P<mesh_int>\S+\s\S+)\s(?P<mesh_area>area\s\d+))*
+ \s*(?P<multicast>multicast-intact)*
+ \s*(?P<router>router-id\s(?P<router_int>\S+\s\S+))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_traffic_eng,
+ "compval": "traffic_eng",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "traffic_eng": {
+ "area": "{{ area.split(" ")[1] }}",
+ "autoroute_exclude": "{{ autoroute.split("
+ ")[2] }}",
+ "interface": {
+ "interface_type": "{{ int_type }}",
+ "area": "{{ int_area.split(" ")[1] }}",
+ },
+ "mesh_group": {
+ "id": "{{ mesh.split(" ")[1] }}",
+ "interface": "{{ mest_int }}",
+ "area": "{{ mesh_area.split(" ")[1] }}",
+ },
+ "multicast_intact": "{{ True if multicast is defined }}",
+ "router_id_interface": "{{ router_int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "neighbor",
+ "getval": re.compile(
+ r"""\s+neighbor
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<db_filter>database-filter\sall\sout)*
+ \s*(?P<poll>poll-interval\s\d+)*
+ \s*(?P<priority>priority\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_neighbor,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost.split(" ")[1] }}",
+ "database_filter": "{{ True if db_filter is defined }}",
+ "poll_interval": "{{ poll.split(" ")[1] }}",
+ "priority": "{{ priority.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "network",
+ "getval": re.compile(
+ r"""\s+network
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<area>area\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_network,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "network": [
+ {
+ "address": "{{ address }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "area": "{{ area.split(" ")[1] }}",
+ }
+ ]
+ }
+ }
+ },
+ },
+ {
+ "name": "nsf.cisco",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<cisco>cisco)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_cisco,
+ "compval": "cisco",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "cisco": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "nsf.ietf",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<ietf>ietf)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<strict>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_ietf,
+ "compval": "ietf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "ietf": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "strict_lsa_checking": "{{ True if strict is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"passive_interface": "{{ interface }}"}
+ }
+ },
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "prefix_suppression": "{{ True if prefix_sup is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""\s+priority
+ \s(?P<priority>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "priority {{ priority }}",
+ "result": {
+ "processes": {"{{ pid }}": {"priority": "{{ priority }}"}}
+ },
+ },
+ {
+ "name": "queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "router_id",
+ "getval": re.compile(
+ r"""\s+router-id
+ \s(?P<id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "result": {"processes": {"{{ pid }}": {"router_id": "{{ id }}"}}},
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "shutdown": "{{ True if shutdown is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "summary_address",
+ "getval": re.compile(
+ r"""\s+summary-address
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<mask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<not_adv>not-advertise)*
+ \s*(?P<nssa>nssa-only)*
+ \s*(?P<tag>tag\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_summary_address,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "summary_address": {
+ "address": "{{ address }}",
+ "mask": "{{ mask }}",
+ "not_advertise": "{{ True if not_adv is defined }}",
+ "nssa_only": "{{ True if nssa is defined }}",
+ "tag": "{{ tag.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \slsa
+ \sarrival
+ \s(?P<lsa>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers lsa arrival {{ timers.lsa }}",
+ "compval": "lsa",
+ "result": {
+ "processes": {"{{ pid }}": {"timers": {"lsa": "{{ lsa }}"}}}
+ },
+ },
+ {
+ "name": "timers.pacing",
+ "getval": re.compile(
+ r"""\s+timers
+ \spacing
+ \s(?P<flood>flood\s\d+)*
+ \s*(?P<lsa_group>lsa-group\s\d+)*
+ \s*(?P<retransmission>retransmission\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split("
+ ")[1] }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.throttle.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<lsa>lsa)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.throttle.spf",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<spf>spf)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "traffic_share",
+ "getval": re.compile(
+ r"""\s+(?P<traffic>traffic-share\smin\sacross-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "traffic-share min across-interfaces",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "traffic_share": "{{ True if traffic is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""\s+ttl-security
+ \s(?P<interfaces>all-interfaces)*
+ \s*(?P<hops>hops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_ttl_security,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "ttl_security": {
+ "set": "{{ True if interfaces is defined and hops is undefined }}",
+ "hops": "{{ hops.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ ]
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py
new file mode 100644
index 00000000..08830a61
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py
@@ -0,0 +1,3132 @@
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import re
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_ospfv3_cmd(process):
+
+ command = "router ospfv3 {process_id}".format(**process)
+ if "vrf" in process:
+ command += " vrf {vrf}".format(**process)
+ return command
+
+
+def _tmplt_ospf_adjacency_cmd(config_data):
+ if "adjacency" in config_data:
+ command = "adjacency stagger"
+ if "none" in config_data["adjacency"]:
+ command += " none"
+ else:
+ command += " {min_adjacency}".format(**config_data["adjacency"])
+ if "max_adjacency" in config_data["adjacency"]:
+ command += " {min_adjacency}".format(**config_data["adjacency"])
+ return command
+
+
+def _tmplt_ospf_address_family_cmd(config_data):
+ if "address_family" in config_data:
+ command = []
+ # for config_data in config_data["address_family"]:
+ cmd = "address-family {afi}".format(**config_data["address_family"])
+ if config_data["address_family"].get("unicast"):
+ cmd += " unicast"
+ if config_data["address_family"].get("vrf"):
+ cmd += " vrf {vrf}".format(**config_data["address_family"])
+ command.append(cmd)
+ if command:
+ command.insert(len(command), "exit-address-family")
+ return command
+
+
+def _tmplt_address_family_graceful_restart(config_data):
+ if "graceful_restart" in config_data:
+ command = "graceful_restart {enable}".format(
+ **config_data["graceful_restart"]
+ )
+ if "disable" in config_data["graceful_restart"]:
+ command += " disable"
+ elif "strict_lsa_checking" in config_data["graceful_restart"]:
+ command += " strict-lsa-checking"
+ return command
+
+
+def _tmplt_ospf_area_authentication(config_data):
+ if "authentication" in config_data:
+ command = "area {area_id} authentication".format(**config_data)
+ if config_data["authentication"].get("message_digest"):
+ command += " message-digest"
+ return command
+
+
+def _tmplt_ospf_area_filter(config_data):
+ if "filter_list" in config_data:
+ command = []
+ for key, value in iteritems(config_data.get("filter_list")):
+ cmd = "area {area_id}".format(**config_data)
+ if value.get("name") and value.get("direction"):
+ cmd += " filter-list prefix {name} {direction}".format(**value)
+ command.append(cmd)
+ return command
+
+
+def _tmplt_ospf_area_nssa(config_data):
+ if "nssa" in config_data:
+ command = "area {area_id} nssa".format(**config_data)
+ if "default_information_originate" in config_data["nssa"]:
+ command += " default-information-originate"
+ if (
+ "metric"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " metric {metric}".format(
+ **config_data["nssa"]["default_information_originate"]
+ )
+ if (
+ "metric_type"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " metric-type {metric_type}".format(
+ **config_data["nssa"]["default_information_originate"]
+ )
+ if (
+ "nssa_only"
+ in config_data["nssa"]["default_information_originate"]
+ ):
+ command += " nssa-only"
+ if config_data["nssa"].get("no_ext_capability"):
+ command += " no-ext-capability"
+ if config_data["nssa"].get("no_redistribution"):
+ command += " no-redistribution"
+ if config_data["nssa"].get("no_summary"):
+ command += " no-summary"
+ return command
+
+
+def _tmplt_ospf_area_nssa_translate(config_data):
+ if "nssa" in config_data and "translate" in config_data["nssa"]:
+ command = "area {area_id} nssa".format(**config_data)
+ if "translate" in config_data["nssa"]:
+ command += " translate type7 {translate}".format(
+ **config_data["nssa"]
+ )
+ return command
+
+
+def _tmplt_ospf_area_ranges(config_data):
+ if "ranges" in config_data:
+ commands = []
+ for k, v in iteritems(config_data["ranges"]):
+ cmd = "area {area_id} range".format(**config_data)
+ temp_cmd = " {address} {netmask}".format(**v)
+ if "advertise" in v:
+ temp_cmd += " advertise"
+ elif "not_advertise" in v:
+ temp_cmd += " not-advertise"
+ if "cost" in v:
+ temp_cmd += " cost {cost}".format(**v)
+ cmd += temp_cmd
+ commands.append(cmd)
+ return commands
+
+
+def _tmplt_ospf_area_sham_link(config_data):
+ if "sham_link" in config_data:
+ command = "area {area_id} sham-link".format(**config_data)
+ if "source" in config_data["sham_link"]:
+ command += " {source} {destination}".format(
+ **config_data["sham_link"]
+ )
+ if "cost" in config_data["sham_link"]:
+ command += " cost {cost}".format(**config_data["sham_link"])
+ if "ttl_security" in config_data["sham_link"]:
+ command += " ttl-security hops {ttl_security}".format(
+ **config_data["sham_link"]
+ )
+ return command
+
+
+def _tmplt_ospf_area_stub_link(config_data):
+ if "stub" in config_data:
+ command = "area {area_id} stub".format(**config_data)
+ if "no_ext_capability" in config_data["stub"]:
+ command += " no-ext-capability"
+ if "no_summary" in config_data["stub"]:
+ command += " no-summary"
+ return command
+
+
+def _tmplt_ospf_auto_cost(config_data):
+ if "auto_cost" in config_data:
+ command = "auto-cost"
+ if "reference_bandwidth" in config_data["auto_cost"]:
+ command += " reference-bandwidth {reference_bandwidth}".format(
+ **config_data["auto_cost"]
+ )
+ return command
+
+
+def _tmplt_ospf_capability(config_data):
+ if "capability" in config_data:
+ if "lls" in config_data["capability"]:
+ command = "capability lls"
+ elif "opaque" in config_data["capability"]:
+ command = "capability opaque"
+ elif "transit" in config_data["capability"]:
+ command = "capability transit"
+ elif "vrf_lite" in config_data["capability"]:
+ command = "capability vrf_lite"
+ return command
+
+
+def _tmplt_ospf_compatible(config_data):
+ if "compatible" in config_data:
+ if "rfc1583" in config_data["compatible"]:
+ command = "compatible rfc1583"
+ elif "rfc1587" in config_data["compatible"]:
+ command = "compatible rfc1587"
+ elif "rfc5243" in config_data["compatible"]:
+ command = "compatible rfc5243"
+ return command
+
+
+def _tmplt_ospf_default_information(config_data):
+ if "default_information" in config_data:
+ command = "default-information"
+ if "originate" in config_data["default_information"]:
+ command += " originate"
+ if "always" in config_data["default_information"]:
+ command += " always"
+ if "metric" in config_data["default_information"]:
+ command += " metric {metric}".format(
+ **config_data["default_information"]
+ )
+ if "metric_type" in config_data["default_information"]:
+ command += " metric-type {metric_type}".format(
+ **config_data["default_information"]
+ )
+ if "metric" in config_data["default_information"]:
+ command += " route-map {route_map}".format(
+ **config_data["default_information"]
+ )
+ return command
+
+
+def _tmplt_ospf_discard_route(config_data):
+ if "discard_route" in config_data:
+ command = "discard-route"
+ if "external" in config_data["discard_route"]:
+ command += " external {external}".format(
+ **config_data["discard_route"]
+ )
+ if "internal" in config_data["discard_route"]:
+ command += " internal {internal}".format(
+ **config_data["discard_route"]
+ )
+ return command
+
+
+def _tmplt_ospf_distance_admin_distance(config_data):
+ if "admin_distance" in config_data["distance"]:
+ command = "distance {distance}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ if "address" in config_data["distance"]["admin_distance"]:
+ command += " {address} {wildcard_bits}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ if "acl" in config_data["distance"]["admin_distance"]:
+ command += " {acl}".format(
+ **config_data["distance"]["admin_distance"]
+ )
+ return command
+
+
+def _tmplt_ospf_distance_ospf(config_data):
+ if "ospf" in config_data["distance"]:
+ command = "distance ospf"
+ if "inter_area" in config_data["distance"]["ospf"]:
+ command += " inter-area {inter_area}".format(
+ **config_data["distance"]["ospf"]
+ )
+ if config_data["distance"].get("ospf").get("intra_area"):
+ command += " intra-area {intra_area}".format(
+ **config_data["distance"]["ospf"]
+ )
+ if config_data["distance"].get("ospf").get("external"):
+ command += " external {external}".format(
+ **config_data["distance"]["ospf"]
+ )
+ return command
+
+
+def _tmplt_ospf_distribute_list_acls(config_data):
+ if "acls" in config_data.get("distribute_list"):
+ command = []
+ for k, v in iteritems(config_data["distribute_list"]["acls"]):
+ cmd = "distribute-list {name} {direction}".format(**v)
+ if "interface" in v:
+ cmd += " {interface}".format(**v)
+ if "protocol" in v:
+ cmd += " {protocol}".format(**v)
+ command.append(cmd)
+ return command
+
+
+def _tmplt_ospf_distribute_list_prefix(config_data):
+ if "prefix" in config_data.get("distribute_list"):
+ command = "distribute-list prefix {name}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "gateway_name" in config_data["distribute_list"]["prefix"]:
+ command += " gateway {gateway_name}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "direction" in config_data["distribute_list"]["prefix"]:
+ command += " {direction}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "interface" in config_data["distribute_list"]["prefix"]:
+ command += " {interface}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ if "protocol" in config_data["distribute_list"]["prefix"]:
+ command += " {protocol}".format(
+ **config_data["distribute_list"]["prefix"]
+ )
+ return command
+
+
+def _tmplt_ospf_domain_id(config_data):
+ if "domain_id" in config_data:
+ command = "domain-id"
+ if "ip_address" in config_data["domain_id"]:
+ if "address" in config_data["domain_id"]["ip_address"]:
+ command += " {address}".format(
+ **config_data["domain_id"]["ip_address"]
+ )
+ if "secondary" in config_data["domain_id"]["ip_address"]:
+ command += " {secondary}".format(
+ **config_data["domain_id"]["ip_address"]
+ )
+ elif "null" in config_data["domain_id"]:
+ command += " null"
+ return command
+
+
+def _tmplt_ospf_event_log(config_data):
+ if "event_log" in config_data:
+ command = "event-log"
+ if "one_shot" in config_data["event_log"]:
+ command += " one-shot"
+ if "pause" in config_data["event_log"]:
+ command += " pause"
+ if "size" in config_data["event_log"]:
+ command += " size {size}".format(**config_data["event_log"])
+ return command
+
+
+def _tmplt_ospf_manet(config_data):
+ if "manet" in config_data:
+ command = []
+ if "cache" in config_data["manet"]:
+ cmd = "manet cache"
+ if "acknowledgement" in config_data["manet"]["cache"]:
+ cmd += " acknowledgement {acknowledgement}".format(
+ **config_data["manet"]["cache"]
+ )
+ elif "redundancy" in config_data["manet"]["cache"]:
+ cmd += " redundancy {redundancy}".format(
+ **config_data["manet"]["cache"]
+ )
+ command.append(cmd)
+ if "hello" in config_data["manet"] and config_data["manet"]["hello"]:
+ command.append("manet hello")
+ if "peering" in config_data["manet"]:
+ cmd = "manet peering selective"
+ if "per_interface" in config_data["manet"]["peering"]:
+ cmd += " per-interface"
+ if "redundancy" in config_data["manet"]["peering"]:
+ cmd += " redundancy {redundancy}".format(
+ **config_data["manet"]["peering"]
+ )
+ command.append(cmd)
+ if "willingness" in config_data["manet"]:
+ command.append(
+ "manet willingness".format(
+ **config_data["manet"]["willingness"]
+ )
+ )
+ return command
+
+
+def _tmplt_ospf_limit(config_data):
+ if "limit" in config_data:
+ command = "limit retransmissions"
+ if "dc" in config_data["limit"]:
+ if "number" in config_data["limit"]["dc"]:
+ command += " dc {number}".format(**config_data["limit"]["dc"])
+ if "disable" in config_data["limit"]["dc"]:
+ command += " dc disable"
+ if "non_dc" in config_data["limit"]:
+ if "number" in config_data["limit"]["non_dc"]:
+ command += " non-dc {number}".format(
+ **config_data["limit"]["non_dc"]
+ )
+ if "disable" in config_data["limit"]["dc"]:
+ command += " non-dc disable"
+ return command
+
+
+def _tmplt_ospf_vrf_local_rib_criteria(config_data):
+ if "local_rib_criteria" in config_data:
+ command = "local-rib-criteria"
+ if "forwarding_address" in config_data["local_rib_criteria"]:
+ command += " forwarding-address"
+ if "inter_area_summary" in config_data["local_rib_criteria"]:
+ command += " inter-area-summary"
+ if "nssa_translation" in config_data["local_rib_criteria"]:
+ command += " nssa-translation"
+ return command
+
+
+def _tmplt_ospf_log_adjacency_changes(config_data):
+ if "log_adjacency_changes" in config_data:
+ command = "log-adjacency-changes"
+ if "detail" in config_data["log_adjacency_changes"]:
+ command += " detail"
+ return command
+
+
+def _tmplt_ospf_max_lsa(config_data):
+ if "max_lsa" in config_data:
+ command = "max-lsa {number}".format(**config_data["max_lsa"])
+ if "threshold_value" in config_data["max_lsa"]:
+ command += " {threshold_value}".format(**config_data["max_lsa"])
+ if "ignore_count" in config_data["max_lsa"]:
+ command += " ignore-count {ignore_count}".format(
+ **config_data["max_lsa"]
+ )
+ if "ignore_time" in config_data["max_lsa"]:
+ command += " ignore-time {ignore_time}".format(
+ **config_data["max_lsa"]
+ )
+ if "reset_time" in config_data["max_lsa"]:
+ command += " reset-time {reset_time}".format(
+ **config_data["max_lsa"]
+ )
+ if "warning_only" in config_data["max_lsa"]:
+ command += " warning-only"
+ return command
+
+
+def _tmplt_ospf_max_metric(config_data):
+ if "max_metric" in config_data:
+ command = "max-metric"
+ if "router_lsa" in config_data["max_metric"]:
+ command += " router-lsa"
+ if "external_lsa" in config_data["max_metric"]:
+ command += " external-lsa {external_lsa}".format(
+ **config_data["max_metric"]
+ )
+ if "include_stub" in config_data["max_metric"]:
+ command += " include-stub"
+ if "on_startup" in config_data["max_metric"]:
+ if "time" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup {time}".format(
+ **config_data["max_metric"]["on_startup"]
+ )
+ elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup wait-for-bgp"
+ if "summary_lsa" in config_data["max_metric"]:
+ command += " summary-lsa {summary_lsa}".format(
+ **config_data["max_metric"]
+ )
+ return command
+
+
+def _tmplt_ospf_mpls_ldp(config_data):
+ if "ldp" in config_data["mpls"]:
+ command = "mpls ldp"
+ if "autoconfig" in config_data["mpls"]["ldp"]:
+ command += " autoconfig"
+ if "area" in config_data["mpls"]["ldp"]["autoconfig"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["ldp"]["autoconfig"]
+ )
+ elif "sync" in config_data["mpls"]["ldp"]:
+ command += " sync"
+ return command
+
+
+def _tmplt_ospf_mpls_traffic_eng(config_data):
+ if "traffic_eng" in config_data["mpls"]:
+ command = "mpls traffic-eng"
+ if "area" in config_data["mpls"]["traffic_eng"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ elif "autoroute_exclude" in config_data["mpls"]["traffic_eng"]:
+ command += " autoroute-exclude prefix-list {autoroute_exclude}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ elif "interface" in config_data["mpls"]["traffic_eng"]:
+ command += " interface {int_type}".format(
+ **config_data["mpls"]["traffic_eng"]["interface"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["interface"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]["interface"]
+ )
+ elif "mesh_group" in config_data["mpls"]["traffic_eng"]:
+ command += " mesh-group {id} {interface}".format(
+ **config_data["mpls"]["traffic_eng"]["mesh_group"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]:
+ command += " area {area}".format(
+ **config_data["mpls"]["traffic_eng"]["mesh_group"]
+ )
+ elif "multicast_intact" in config_data["mpls"]["traffic_eng"]:
+ command += " multicast-intact"
+ elif "router_id_interface" in config_data["mpls"]["traffic_eng"]:
+ command += " router-id {router_id_interface}".format(
+ **config_data["mpls"]["traffic_eng"]
+ )
+ return command
+
+
+def _tmplt_ospf_neighbor(config_data):
+ if "neighbor" in config_data:
+ command = "neighbor"
+ if "address" in config_data["neighbor"]:
+ command += " {address}".format(**config_data["neighbor"])
+ if "cost" in config_data["neighbor"]:
+ command += " cost {cost}".format(**config_data["neighbor"])
+ if "database_filter" in config_data["neighbor"]:
+ command += " database-filter all out"
+ if "poll_interval" in config_data["neighbor"]:
+ command += " poll-interval {poll_interval}".format(
+ **config_data["neighbor"]
+ )
+ if "priority" in config_data["neighbor"]:
+ command += " priority {priority}".format(**config_data["neighbor"])
+ return command
+
+
+def _tmplt_ospf_network(config_data):
+ if "network" in config_data:
+ command = "network"
+ if "address" in config_data["network"]:
+ command += " {address} {wildcard_bits}".format(
+ **config_data["network"]
+ )
+ if "area" in config_data["network"]:
+ command += " area {area}".format(**config_data["network"])
+ return command
+
+
+def _tmplt_ospf_nsf_cisco(config_data):
+ if "cisco" in config_data["nsf"]:
+ command = "nsf cisco helper"
+ if "disable" in config_data["nsf"]["cisco"]:
+ command += " disable"
+ return command
+
+
+def _tmplt_ospf_nsf_ietf(config_data):
+ if "ietf" in config_data["nsf"]:
+ command = "nsf ietf helper"
+ if "disable" in config_data["nsf"]["ietf"]:
+ command += " disable"
+ elif "strict_lsa_checking" in config_data["nsf"]["ietf"]:
+ command += " strict-lsa-checking"
+ return command
+
+
+def _tmplt_ospf_queue_depth_hello(config_data):
+ if "hello" in config_data["queue_depth"]:
+ command = "queue-depth hello"
+ if "max_packets" in config_data["queue_depth"]["hello"]:
+ command += " {max_packets}".format(
+ **config_data["queue_depth"]["hello"]
+ )
+ elif "unlimited" in config_data["queue_depth"]["hello"]:
+ command += " unlimited"
+ return command
+
+
+def _tmplt_ospf_queue_depth_update(config_data):
+ if "update" in config_data["queue_depth"]:
+ command = "queue-depth update"
+ if "max_packets" in config_data["queue_depth"]["update"]:
+ command += " {max_packets}".format(
+ **config_data["queue_depth"]["update"]
+ )
+ elif "unlimited" in config_data["queue_depth"]["update"]:
+ command += " unlimited"
+ return command
+
+
+def _tmplt_ospf_summary_prefix(config_data):
+ if "summary_prefix" in config_data:
+ command = "summary-prefix {address} {mask}".format(
+ **config_data["summary_prefix"]
+ )
+ if "not_advertise" in config_data["summary_prefix"]:
+ command += " not-advertise"
+ elif "nssa_only" in config_data["summary_prefix"]:
+ command += " nssa-only"
+ if "tag" in config_data["summary_prefix"]:
+ command += " tag {tag}".format(**config_data["summary_prefix"])
+ return command
+
+
+def _tmplt_ospf_timers_pacing(config_data):
+ if "pacing" in config_data["timers"]:
+ command = "timers pacing"
+ if "flood" in config_data["timers"]["pacing"]:
+ command += " flood {flood}".format(
+ **config_data["timers"]["pacing"]
+ )
+ elif "lsa_group" in config_data["timers"]["pacing"]:
+ command += " lsa-group {lsa_group}".format(
+ **config_data["timers"]["pacing"]
+ )
+ elif "retransmission" in config_data["timers"]["pacing"]:
+ command += " retransmission {retransmission}".format(
+ **config_data["timers"]["pacing"]
+ )
+ return command
+
+
+def _tmplt_ospf_ttl_security(config_data):
+ if "ttl_security" in config_data:
+ command = "ttl-security all-interfaces"
+ if "hops" in config_data["ttl_security"]:
+ command += " hops {hops}".format(**config_data["ttl_security"])
+ return command
+
+
+class Ospfv3Template(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(Ospfv3Template, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "pid",
+ "getval": re.compile(
+ r"""
+ ^router\s
+ ospfv3*
+ \s(?P<pid>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospfv3_cmd,
+ "result": {
+ "processes": {"{{ pid }}": {"process_id": "{{ pid|int }}"}}
+ },
+ "shared": True,
+ },
+ {
+ "name": "adjacency",
+ "getval": re.compile(
+ r"""\s+adjacency
+ \sstagger*
+ \s*((?P<min>\d+)|(?P<none_adj>none))*
+ \s*(?P<max>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \sdefault-cost*
+ \s*(?P<default_cost>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} default-cost {{ default_cost }}",
+ "compval": "default_cost",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.filter_list",
+ "getval": re.compile(
+ r"""\s+area
+ \s*(?P<area_id>\S+)*
+ \s*filter-list\sprefix*
+ \s*(?P<name>\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ }
+ ],
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.nssa",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \s(?P<nssa>nssa)*
+ \s*(?P<no_redis>no-redistribution)*
+ \s*(?P<def_origin>default-information-originate)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<no_summary>no-summary)*
+ \s*(?P<no_ext>no-ext-capability)*$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and def_origin is undefined and "
+ "no_ext is undefined and no_redis is undefined and nssa_only is undefined }}",
+ "default_information_originate": {
+ "set": "{{ True if def_origin is defined and metric is undefined and "
+ "metric_type is undefined and nssa_only is undefined }}",
+ "metric": "{{ metric.split("
+ ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.nssa.translate",
+ "getval": re.compile(
+ r"""\s+area*
+ \s*(?P<area_id>\S+)*
+ \s*(?P<nssa>nssa)*
+ \stranslate\stype7*
+ \s(?P<translate_always>always)*
+ \s* (?P<translate_supress>suppress-fa)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa.translate",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}"
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.ranges",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \srange
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<netmask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*((?P<advertise>advertise)|(?P<not_advertise>not-advertise))*
+ \s*(?P<cost>cost\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ }
+ ],
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.sham_link",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \ssham-link
+ \s(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<destination>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<ttl_security>ttl-security\shops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "area.stub",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \s(?P<stub>stub)*
+ \s*(?P<no_ext>no-ext-capability)*
+ \s*(?P<no_sum>no-summary)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"bfd": "{{ True if bfd is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "capability": {
+ "lls": "{{ True if lls is defined }}",
+ "opaque": "{{ True if opaque is defined }}",
+ "transit": "{{ True if transit is defined }}",
+ "vrf_lite": "{{ True if vrf_lite is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "default_information",
+ "getval": re.compile(
+ r"""\s+default-information*
+ \s*(?P<originate>originate)*
+ \s*(?P<always>always)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<route_map>route-map\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "default_information": {
+ "originate": "{{ True if originate is defined }}",
+ "always": "{{ True if always is defined }}",
+ "metric": "{{ metric.split(" ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "route_map": "{{ route_map.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"default_metric": "{{ default_metric| int}}"}
+ }
+ },
+ },
+ {
+ "name": "discard_route",
+ "getval": re.compile(
+ r"""\s+(?P<discard_route>discard-route)*
+ \s*(?P<external>external\s\d+)*
+ \s*(?P<internal>internal\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "discard_route": {
+ "set": "{{ True if discard_route is defined and external is undefined and internal is undefined }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ "internal": "{{ internal.split(" ")[1]|int }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distance.admin_distance",
+ "getval": re.compile(
+ r"""\s+distance
+ \s(?P<admin_dist>\S+)*
+ \s*(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<acl>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distance.ospf",
+ "getval": re.compile(
+ r"""\s+distance
+ \sospf*
+ \s*(?P<intra>intra-area\s\d+)*
+ \s*(?P<inter>inter-area\s\d+)*
+ \s*(?P<external>external\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.acls",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<name>\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ ]
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.prefix",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<prefix>prefix\s\S+)*
+ \s*(?P<gateway>gateway\s\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split("
+ ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "distribute-list route-map {{ distribute_list.route_map.name }} in",
+ "compval": "distribute_list.route_map",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "route_map": {
+ "name": "{{ route_map.split(" ")[1] }}"
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "domain_id",
+ "getval": re.compile(
+ r"""\s+domain-id
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<secondary>secondary)*
+ \s*(?P<null>null)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "result": {
+ "processes": {"{{ pid }}": {"domain_tag": "{{ tag|int }}"}}
+ },
+ },
+ {
+ "name": "event_log",
+ "getval": re.compile(
+ r"""\s+(?P<event_log>event-log)*
+ \s*(?P<one_shot>one-shot)*
+ \s*(?P<pause>pause)*
+ \s*(?P<size>size\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "event_log": {
+ "enable": "{{ True if event_log is defined and one_shot is undefined and pause is undefined and size is undefined }}",
+ "one_shot": "{{ True if one_shot is defined }}",
+ "pause": "{{ True if pause is defined }}",
+ "size": "{{ size.split(" ")[1]|int }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"help": "{{ True if help is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "ignore",
+ "getval": re.compile(
+ r"""\s+(?P<ignore>ignore)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ignore lsa mospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"ignore": "{{ True if ignore is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "interface_id": "{{ True if interface_id is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "ispf",
+ "getval": re.compile(
+ r"""\s+(?P<ispf>ispf)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ispf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"ispf": "{{ True if ispf is defined }}"}
+ }
+ },
+ },
+ {
+ "name": "limit",
+ "getval": re.compile(
+ r"""\s+limit\sretransmissions
+ \s((?P<dc_num>dc\s\d+)|(?P<dc_disable>dc\sdisable))*
+ \s*((?P<non_dc_num>non-dc\s\d+)|(?P<non_dc_disable>non-dc\sdisable))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "local_rib_criteria",
+ "getval": re.compile(
+ r"""\s+(?P<local>local-rib-criteria)*
+ \s*(?P<forward>forwarding-address)*
+ \s*(?P<inter>inter-area-summary)*
+ \s*(?P<nssa>nssa-translation)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "manet",
+ "getval": re.compile(
+ r"""\s+manet*
+ \s*(?P<cache>cache)*
+ \s*(?P<acknowledgement>acknowledgement\s\d+)*
+ \s*(?P<update>update\s\d+)*
+ \s*(?P<hello>hello)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<multicast>multicast)*
+ \s*(?P<peering>peering\sselective)*
+ \s*(?P<disable>disable)*
+ \s*(?P<per_interface>per-interface)*
+ \s*(?P<redundancy>redundancy\s\d+)*
+ \s*(?P<willingness>willingness\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_manet,
+ "compval": "manet",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "manet": {
+ "cache": {
+ "acknowledgement": "{{ acknowledgement.split("
+ ")[1] }}",
+ "update": "{{ update.split(" ")[1] }}",
+ },
+ "hello": {
+ "unicast": "{{ True if unicast is defined }}",
+ "multicast": "{{ True if multicast is defined }}",
+ },
+ "peering": {
+ "set": "{{ True if peering is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "per_interface": "{{ True if per_interface is defined }}",
+ "redundancy": "{{ redundancy.split(" ")[1] }}",
+ },
+ "willingness": "{{ willingness.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "max_lsa",
+ "getval": re.compile(
+ r"""\s+max-lsa
+ \s(?P<number>\d+)*
+ \s*(?P<threshold>\d+)*
+ \s*(?P<ignore_count>ignore-count\s\d+)*
+ \s*(?P<ignore_time>ignore-time\s\d+)*
+ \s*(?P<reset_time>reset-time\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_lsa": {
+ "number": "{{ number }}",
+ "threshold_value": "{{ threshold }}",
+ "ignore_count": "{{ ignore_count.split(" ")[1] }}",
+ "ignore_time": "{{ ignore_time.split(" ")[1] }}",
+ "reset_time": "{{ reset_time.split(" ")[1] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "max_metric",
+ "getval": re.compile(
+ r"""\s+max-metric*
+ \s*(?P<router_lsa>router-lsa)*
+ \s*(?P<include_stub>include-stub)*
+ \s*(?P<external_lsa>external-lsa\s\d+)*
+ \s*(?P<startup_time>on-startup\s\d+)*
+ \s*(?P<startup_wait>on-startup\s\S+)*
+ \s*(?P<summary_lsa>summary-lsa\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "result": {
+ "processes": {"{{ pid }}": {"maximum_paths": "{{ paths }}"}}
+ },
+ },
+ {
+ "name": "mpls.ldp",
+ "getval": re.compile(
+ r"""\s+mpls
+ \sldp*
+ \s*(?P<autoconfig>autoconfig*\s*(?P<area>area\s\S+))*
+ \s*(?P<sync>sync)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_ldp,
+ "compval": "ldp",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "ldp": {
+ "autoconfig": {
+ "set": "{{ True if autoconfig is defined and area is undefined }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ "sync": "{{ True if sync is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "mpls.traffic_eng",
+ "getval": re.compile(
+ r"""\s+mpls
+ \straffic-eng*
+ \s*(?P<area>area\s\S+)*
+ \s*(?P<autoroute>autoroute-exclude\s\S+\s\S+)*
+ \s*(?P<interface>interface\s(?P<int_type>\S+\s\S+)\s(?P<int_area>area\s\S+))*
+ \s*(?P<mesh>mesh-group\s\d+\s(?P<mesh_int>\S+\s\S+)\s(?P<mesh_area>area\s\d+))*
+ \s*(?P<multicast>multicast-intact)*
+ \s*(?P<router>router-id\s(?P<router_int>\S+\s\S+))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_traffic_eng,
+ "compval": "traffic_eng",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "traffic_eng": {
+ "area": "{{ area.split(" ")[1] }}",
+ "autoroute_exclude": "{{ autoroute.split("
+ ")[2] }}",
+ "interface": {
+ "interface_type": "{{ int_type }}",
+ "area": "{{ int_area.split(" ")[1] }}",
+ },
+ "mesh_group": {
+ "id": "{{ mesh.split(" ")[1] }}",
+ "interface": "{{ mest_int }}",
+ "area": "{{ mesh_area.split(" ")[1] }}",
+ },
+ "multicast_intact": "{{ True if multicast is defined }}",
+ "router_id_interface": "{{ router_int }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "neighbor",
+ "getval": re.compile(
+ r"""\s+neighbor
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<db_filter>database-filter\sall\sout)*
+ \s*(?P<poll>poll-interval\s\d+)*
+ \s*(?P<priority>priority\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_neighbor,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost.split(" ")[1] }}",
+ "database_filter": "{{ True if db_filter is defined }}",
+ "poll_interval": "{{ poll.split(" ")[1] }}",
+ "priority": "{{ priority.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "network",
+ "getval": re.compile(
+ r"""\s+network
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<area>area\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_network,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "network": {
+ "address": "{{ address }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "area": "{{ area.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "nsf.cisco",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<cisco>cisco)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_cisco,
+ "compval": "cisco",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "cisco": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "nsf.ietf",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<ietf>ietf)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<strict>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_ietf,
+ "compval": "ietf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "ietf": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "strict_lsa_checking": "{{ True if strict is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"passive_interface": "{{ interface }}"}
+ }
+ },
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "prefix_suppression": "{{ True if prefix_sup is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""\s+priority
+ \s(?P<priority>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "priority {{ priority }}",
+ "result": {
+ "processes": {"{{ pid }}": {"priority": "{{ priority }}"}}
+ },
+ },
+ {
+ "name": "queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "router_id",
+ "getval": re.compile(
+ r"""\s+router-id
+ \s(?P<id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "result": {"processes": {"{{ pid }}": {"router_id": "{{ id }}"}}},
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "shutdown": "{{ True if shutdown is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \slsa
+ \sarrival
+ \s(?P<lsa>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers lsa arrival {{ timers.lsa }}",
+ "compval": "lsa",
+ "result": {
+ "processes": {"{{ pid }}": {"timers": {"lsa": "{{ lsa }}"}}}
+ },
+ },
+ {
+ "name": "timers.pacing",
+ "getval": re.compile(
+ r"""\s+timers
+ \spacing
+ \s(?P<flood>flood\s\d+)*
+ \s*(?P<lsa_group>lsa-group\s\d+)*
+ \s*(?P<retransmission>retransmission\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split("
+ ")[1] }}",
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.throttle.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<lsa>lsa)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "timers.throttle.spf",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<spf>spf)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "traffic_share",
+ "getval": re.compile(
+ r"""\s+(?P<traffic>traffic-share\smin\sacross-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "traffic-share min across-interfaces",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "traffic_share": "{{ True if traffic is defined }}"
+ }
+ }
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""\s+ttl-security
+ \s(?P<interfaces>all-interfaces)*
+ \s*(?P<hops>hops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_ttl_security,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "ttl_security": {
+ "set": "{{ True if interfaces is defined and hops is undefined }}",
+ "hops": "{{ hops.split(" ")[1] }}",
+ }
+ }
+ }
+ },
+ },
+ {
+ "name": "address_family",
+ "getval": re.compile(
+ r"""\s+address-family*
+ \s*(?P<afi>\S+)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<vrf>vrf\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ # "compval": "afi",
+ "result": {
+ "address_family": [
+ {
+ "afi": "{{ afi }}",
+ "unicast": "{{ True if unicast is defined }}",
+ "vrf": "{{ vrf.split(" ")[1] }}",
+ }
+ ]
+ },
+ "shared": True,
+ },
+ {
+ "name": "address_family.exit",
+ "getval": re.compile(
+ r"""\s+exit-address-family
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ "result": {
+ "address_family": [
+ {
+ "exit": {
+ "pid": "{{ id }}",
+ "afi": "{{ afi }}",
+ "unicast": "{{ True if unicast is defined }}",
+ "vrf": "{{ vrf.split(" ")[1] }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.adjacency",
+ "getval": re.compile(
+ r"""\s+adjacency
+ \sstagger*
+ \s*((?P<min>\d+)|(?P<none_adj>none))*
+ \s*(?P<max>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "compval": "adjacency",
+ "result": {
+ "address_family": [
+ {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \sdefault-cost*
+ \s*(?P<default_cost>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} default-cost {{ default_cost }}",
+ "compval": "default_cost",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.filter_list",
+ "getval": re.compile(
+ r"""\s+area
+ \s*(?P<area_id>\S+)*
+ \s*filter-list\sprefix*
+ \s*(?P<name>\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ }
+ ],
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.nssa",
+ "getval": re.compile(
+ r"""\s+area*
+ \s*(?P<area_id>\S+)*
+ \s*(?P<nssa>nssa)*
+ \s*(?P<no_redis>no-redistribution)*
+ \s*(?P<def_origin>default-information-originate)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<nssa_only>nssa-only)*
+ \s*(?P<no_summary>no-summary)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and def_origin is undefined and "
+ "no_ext is undefined and no_redis is undefined and nssa_only is undefined }}",
+ "default_information_originate": {
+ "set": "{{ True if def_origin is defined and metric is undefined and "
+ "metric_type is undefined and nssa_only is undefined }}",
+ "metric": "{{ metric.split("
+ ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.nssa.translate",
+ "getval": re.compile(
+ r"""\s+area*
+ \s*(?P<area_id>\S+)*
+ \s*(?P<nssa>nssa)*
+ \stranslate\stype7*
+ \s(?P<translate_always>always)*
+ \s* (?P<translate_supress>suppress-fa)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa.translate",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}"
+ },
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.ranges",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \srange
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<netmask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*((?P<advertise>advertise)|(?P<not_advertise>not-advertise))*
+ \s*(?P<cost>cost\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ }
+ ],
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.sham_link",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \ssham-link
+ \s(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ \s(?P<destination>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<cost>cost\s\d+)*
+ \s*(?P<ttl_security>ttl-security\shops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.area.stub",
+ "getval": re.compile(
+ r"""\s+area\s(?P<area_id>\S+)
+ \s(?P<stub>stub)*
+ \s*(?P<no_ext>no-ext-capability)*
+ \s*(?P<no_sum>no-summary)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "compval": "auto_cost",
+ "result": {
+ "address_family": [
+ {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "compval": "bfd",
+ "result": {
+ "address_family": [{"bfd": "{{ True if bfd is defined }}"}]
+ },
+ },
+ {
+ "name": "address_family.capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "compval": "capability",
+ "result": {
+ "address_family": [
+ {
+ "capability": {
+ "lls": "{{ True if lls is defined }}",
+ "opaque": "{{ True if opaque is defined }}",
+ "transit": "{{ True if transit is defined }}",
+ "vrf_lite": "{{ True if vrf_lite is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "compval": "compatible",
+ "result": {
+ "address_family": [
+ {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.default_information",
+ "getval": re.compile(
+ r"""\s+default-information*
+ \s*(?P<originate>originate)*
+ \s*(?P<always>always)*
+ \s*(?P<metric>metric\s\d+)*
+ \s*(?P<metric_type>metric-type\s\d+)*
+ \s*(?P<route_map>route-map\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "compval": "default_information",
+ "result": {
+ "address_family": [
+ {
+ "default_information": {
+ "originate": "{{ True if originate is defined }}",
+ "always": "{{ True if always is defined }}",
+ "metric": "{{ metric.split(" ")[1]|int }}",
+ "metric_type": "{{ metric_type.split("
+ ")[1]|int }}",
+ "route_map": "{{ route_map.split(" ")[1] }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "compval": "default_metric",
+ "result": {
+ "address_family": [
+ {"default_metric": "{{ default_metric| int}}"}
+ ]
+ },
+ },
+ {
+ "name": "address_family.discard_route",
+ "getval": re.compile(
+ r"""\s+(?P<discard_route>discard-route)*
+ \s*(?P<external>external\s\d+)*
+ \s*(?P<internal>internal\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "compval": "discard_route",
+ "result": {
+ "address_family": [
+ {
+ "discard_route": {
+ "set": "{{ True if discard_route is defined and external is undefined and internal is undefined }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ "internal": "{{ internal.split(" ")[1]|int }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.distance.admin_distance",
+ "getval": re.compile(
+ r"""\s+distance
+ \s(?P<admin_dist>\S+)*
+ \s*(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<acl>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "address_family": [
+ {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.distance.ospf",
+ "getval": re.compile(
+ r"""\s+distance
+ \sospf*
+ \s*(?P<intra>intra-area\s\d+)*
+ \s*(?P<inter>inter-area\s\d+)*
+ \s*(?P<external>external\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "address_family": [
+ {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.distribute_list.acls",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<name>\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "address_family": [
+ {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ ]
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.distribute_list.prefix",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<prefix>prefix\s\S+)*
+ \s*(?P<gateway>gateway\s\S+)*
+ \s*(?P<dir>\S+)*
+ \s*(?P<int_pro>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "address_family": [
+ {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split("
+ ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "distribute-list route-map {{ distribute_list.route_map.name }} in",
+ "compval": "distribute_list.route_map",
+ "result": {
+ "address_family": [
+ {
+ "distribute_list": {
+ "route_map": {
+ "name": "{{ route_map.split(" ")[1] }}"
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.domain_id",
+ "getval": re.compile(
+ r"""\s+domain-id
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<secondary>secondary)*
+ \s*(?P<null>null)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "compval": "domain_id",
+ "result": {
+ "address_family": [
+ {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "compval": "domain_tag",
+ "result": {"address_family": [{"domain_tag": "{{ tag|int }}"}]},
+ },
+ {
+ "name": "address_family.graceful_restart",
+ "getval": re.compile(
+ r"""\s+graceful-restart*
+ \s*(?P<enable>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<lsa>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_address_family_graceful_restart,
+ "compval": "graceful_restart",
+ "result": {
+ "address_family": [
+ {
+ "event_log": {
+ "enable": "{{ True if is enable defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "strict_lsa_checking": "{{ True if lsa is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.event_log",
+ "getval": re.compile(
+ r"""\s+(?P<event_log>event-log)*
+ \s*(?P<one_shot>one-shot)*
+ \s*(?P<pause>pause)*
+ \s*(?P<size>size\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "compval": "event_log",
+ "result": {
+ "address_family": [
+ {
+ "event_log": {
+ "enable": "{{ True if event_log is defined and one_shot is undefined and pause is undefined and size is undefined }}",
+ "one_shot": "{{ True if one_shot is defined }}",
+ "pause": "{{ True if pause is defined }}",
+ "size": "{{ size.split(" ")[1]|int }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "compval": "help",
+ "result": {
+ "address_family": [{"help": "{{ True if help is defined }}"}]
+ },
+ },
+ {
+ "name": "address_family.interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "compval": "interface_id",
+ "result": {
+ "address_family": [
+ {"interface_id": "{{ True if interface_id is defined }}"}
+ ]
+ },
+ },
+ {
+ "name": "address_family.limit",
+ "getval": re.compile(
+ r"""\s+limit\sretransmissions
+ \s((?P<dc_num>dc\s\d+)|(?P<dc_disable>dc\sdisable))*
+ \s*((?P<non_dc_num>non-dc\s\d+)|(?P<non_dc_disable>non-dc\sdisable))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "compval": "limit",
+ "result": {
+ "address_family": [
+ {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.local_rib_criteria",
+ "getval": re.compile(
+ r"""\s+(?P<local>local-rib-criteria)*
+ \s*(?P<forward>forwarding-address)*
+ \s*(?P<inter>inter-area-summary)*
+ \s*(?P<nssa>nssa-translation)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "compval": "local_rib_criteria",
+ "result": {
+ "address_family": [
+ {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "compval": "log_adjacency_changes",
+ "result": {
+ "address_family": [
+ {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.manet",
+ "getval": re.compile(
+ r"""\s+manet*
+ \s*(?P<cache>cache)*
+ \s*(?P<acknowledgement>acknowledgement\s\d+)*
+ \s*(?P<update>update\s\d+)*
+ \s*(?P<hello>hello)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<multicast>multicast)*
+ \s*(?P<peering>peering\sselective)*
+ \s*(?P<disable>disable)*
+ \s*(?P<per_interface>per-interface)*
+ \s*(?P<redundancy>redundancy\s\d+)*
+ \s*(?P<willingness>willingness\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "compval": "manet",
+ "result": {
+ "address_family": [
+ {
+ "manet": {
+ "cache": {
+ "acknowledgement": "{{ acknowledgement.split("
+ ")[1] }}",
+ "update": "{{ update.split(" ")[1] }}",
+ },
+ "hello": {
+ "unicast": "{{ True if unicast is defined }}",
+ "multicast": "{{ True if multicast is defined }}",
+ },
+ "peering": {
+ "set": "{{ True if peering is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "per_interface": "{{ True if per_interface is defined }}",
+ "redundancy": "{{ redundancy.split(" ")[1] }}",
+ },
+ "willingness": "{{ willingness.split(" ")[1] }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.max_lsa",
+ "getval": re.compile(
+ r"""\s+max-lsa
+ \s(?P<number>\d+)*
+ \s*(?P<threshold>\d+)*
+ \s*(?P<ignore_count>ignore-count\s\d+)*
+ \s*(?P<ignore_time>ignore-time\s\d+)*
+ \s*(?P<reset_time>reset-time\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "compval": "max_lsa",
+ "result": {
+ "address_family": [
+ {
+ "max_lsa": {
+ "number": "{{ number }}",
+ "threshold_value": "{{ threshold }}",
+ "ignore_count": "{{ ignore_count.split(" ")[1] }}",
+ "ignore_time": "{{ ignore_time.split(" ")[1] }}",
+ "reset_time": "{{ reset_time.split(" ")[1] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.max_metric",
+ "getval": re.compile(
+ r"""\s+max-metric*
+ \s*(?P<router_lsa>router-lsa)*
+ \s*(?P<include_stub>include-stub)*
+ \s*(?P<external_lsa>external-lsa\s\d+)*
+ \s*(?P<startup_time>on-startup\s\d+)*
+ \s*(?P<startup_wait>on-startup\s\S+)*
+ \s*(?P<summary_lsa>summary-lsa\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "compval": "max_metric",
+ "result": {
+ "address_family": [
+ {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "compval": "maximum_paths",
+ "result": {"address_family": [{"maximum_paths": "{{ paths }}"}]},
+ },
+ {
+ "name": "address_family.passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "compval": "passive_interface",
+ "result": {
+ "address_family": [{"passive_interface": "{{ interface }}"}]
+ },
+ },
+ {
+ "name": "address_family.prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "compval": "prefix_suppression",
+ "result": {
+ "address_family": [
+ {
+ "prefix_suppression": "{{ True if prefix_sup is defined }}"
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "address_family": [
+ {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "address_family": [
+ {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.router_id",
+ "getval": re.compile(
+ r"""\s+router-id
+ \s(?P<id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "compval": "router_id",
+ "result": {"address_family": [{"router_id": "{{ id }}"}]},
+ },
+ {
+ "name": "address_family.summary_prefix",
+ "getval": re.compile(
+ r"""\s+summary-address
+ \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<mask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*
+ \s*(?P<not_adv>not-advertise)*
+ \s*(?P<nssa>nssa-only)*
+ \s*(?P<tag>tag\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_summary_prefix,
+ "compval": "summary_prefix",
+ "result": {
+ "address_family": [
+ {
+ "summary_prefix": {
+ "address": "{{ address }}",
+ "mask": "{{ mask }}",
+ "not_advertise": "{{ True if not_adv is defined }}",
+ "nssa_only": "{{ True if nssa is defined }}",
+ "tag": "{{ tag.split(" ")[1] }}",
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "compval": "shutdown",
+ "result": {
+ "address_family": [
+ {"shutdown": "{{ True if shutdown is defined }}"}
+ ]
+ },
+ },
+ {
+ "name": "address_family.timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \slsa
+ \sarrival
+ \s(?P<lsa>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers lsa arrival {{ timers.lsa }}",
+ "compval": "lsa",
+ "result": {"address_family": [{"timers": {"lsa": "{{ lsa }}"}}]},
+ },
+ {
+ "name": "address_family.timers.pacing",
+ "getval": re.compile(
+ r"""\s+timers
+ \spacing
+ \s(?P<flood>flood\s\d+)*
+ \s*(?P<lsa_group>lsa-group\s\d+)*
+ \s*(?P<retransmission>retransmission\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split("
+ ")[1] }}",
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.timers.throttle.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<lsa>lsa)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ ]
+ },
+ },
+ {
+ "name": "address_family.timers.throttle.spf",
+ "getval": re.compile(
+ r"""\s+timers
+ \sthrottle
+ \s*(?P<spf>spf)*
+ \s*(?P<first_delay>\d+)*
+ \s*(?P<min_delay>\d+)*
+ \s*(?P<max_delay>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ }
+ }
+ }
+ }
+ ]
+ },
+ },
+ ]
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py
new file mode 100644
index 00000000..61da2db6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py
@@ -0,0 +1,385 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.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 reverify_diff_py35(want, have):
+ """ Function to re-verify the set diff for py35 as it doesn't maintains dict order which results
+ into unexpected set diff
+ :param config: want and have set config
+ :returns: True/False post checking if there's any actual diff b/w want and have sets
+ """
+ if not have:
+ return True
+ for each_want in want:
+ diff = True
+ for each_have in have:
+ if each_have == sorted(each_want) or sorted(each_have) == sorted(
+ each_want
+ ):
+ diff = False
+ if diff:
+ return True
+ return False
+
+
+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:
+ if have.get(k):
+ 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:
+ if have.get(k) and key in have.get(k):
+ dict_val = have.get(k)[0].get(key)
+ test_key_dict.update({key: dict_val})
+ elif have.get(k):
+ if (
+ 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):
+ # convert netmask to cidr and returns the cidr notation
+ return str(sum([bin(int(x)).count("1") for x in netmask.split(".")]))
+
+
+def is_valid_ip(ip_str):
+ valid = True
+ try:
+ if "::" in ip_str:
+ socket.inet_pton(socket.AF_INET6, ip_str) # for IPv6
+ else:
+ socket.inet_pton(socket.AF_INET, ip_str) # for IPv4
+ except socket.error:
+ valid = False
+ return valid
+
+
+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"
+ elif name.lower().startswith("virtual-te"):
+ if_type = "Virtual-Template"
+ elif name.lower().startswith("tu"):
+ if_type = "Tunnel"
+ 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"
+ elif interface.upper().startswith("VIRTUAL-TE"):
+ return "Virtual-Template"
+ elif interface.upper().startswith("TU"):
+ return "Tunnel"
+ else:
+ return "unknown"
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py
new file mode 100644
index 00000000..75094a92
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py
@@ -0,0 +1,598 @@
+#!/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/>.
+#
+"""
+The module file for ios_acl_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_acl_interfaces
+short_description: ACL interfaces resource module
+description: This module configures and manages the access-control (ACL) attributes
+ of interfaces on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL
+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
+ - 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
+ - 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+
+# 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+
+# File: parsed.cfg
+# ----------------
+#
+# 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
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_acl_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ 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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import (
+ Acl_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py
new file mode 100644
index 00000000..1f1b2831
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_acls.py
@@ -0,0 +1,1415 @@
+#!/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/>.
+#
+"""
+The module file for ios_acls
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_acls
+short_description: ACLs resource module
+description: This module configures and manages the named or numbered ACLs on IOS
+ platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL
+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
+ evaluate:
+ description: Evaluate an access list
+ type: str
+ 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:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh access-list).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ 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
+"""
+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
+ cisco.ios.ios_acls:
+ 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:
+ - sequence: 10
+ protocol_options:
+ icmp:
+ traceroute: true
+ - 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
+ cisco.ios.ios_acls:
+ 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
+ cisco.ios.ios_acls:
+ 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 ACLs (Note: This won't delete the all configured ACLs)"
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: test
+ acl_type: extended
+ - name: 110
+ - afi: ipv6
+ acls:
+ - name: R1_TRAFFIC
+ state: deleted
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list extended test
+# - no ip access-list extended 110
+# - 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
+# 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
+
+# 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 ACLs based on AFI (Note: This won't delete the all configured ACLs)"
+ cisco.ios.ios_acls:
+ 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 ACLs)"
+
+# 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 ALL of configured ACLs (Note: This WILL delete the all configured
+ ACLs)'
+ cisco.ios.ios_acls:
+ 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 with provided configurations
+ cisco.ios.ios_acls:
+ 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
+ cisco.ios.ios_acls:
+ 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
+
+# File: parsed.cfg
+# ----------------
+#
+# ipv6 access-list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_acls:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ 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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py
new file mode 100644
index 00000000..4370857b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_banner.py
@@ -0,0 +1,188 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_banner
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.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
+ type: str
+ 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).
+ type: str
+ state:
+ description:
+ - Specifies whether or not the configuration is present in the current devices
+ active running configuration.
+ default: present
+ type: str
+ choices:
+ - present
+ - absent
+"""
+EXAMPLES = """
+- name: configure the login banner
+ cisco.ios.ios_banner:
+ banner: login
+ text: |
+ this is my login banner
+ that contains a multiline
+ string
+ state: present
+
+- name: remove the motd banner
+ cisco.ios.ios_banner:
+ banner: motd
+ state: absent
+
+- name: Configure banner from file
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py
new file mode 100644
index 00000000..bc189436
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py
@@ -0,0 +1,509 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_bgp
+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
+version_added: 1.0.0
+notes:
+- Tested against Cisco IOS Version 15.6(3)M2
+options:
+ config:
+ description:
+ - Specifies the BGP related configuration.
+ type: dict
+ 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.
+ type: str
+ default:
+ log_neighbor_changes:
+ description:
+ - Enable/disable logging neighbor up/down and reset reason.
+ type: bool
+ neighbors:
+ description:
+ - Specifies BGP neighbor related configurations.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor:
+ description:
+ - Neighbor router address.
+ required: true
+ type: str
+ remote_as:
+ description:
+ - Remote AS of the BGP neighbor to configure.
+ type: int
+ required: true
+ update_source:
+ description:
+ - Source of the routing updates.
+ type: str
+ password:
+ description:
+ - Password to authenticate the BGP peer connection.
+ type: str
+ enabled:
+ description:
+ - Administratively shutdown or enable a neighbor.
+ type: bool
+ description:
+ description:
+ - Neighbor specific description.
+ type: str
+ 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.
+ type: str
+ timers:
+ description:
+ - Specifies BGP neighbor timer related configurations.
+ type: dict
+ 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.
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description:
+ - Network ID to announce via BGP.
+ required: true
+ type: str
+ masklen:
+ description:
+ - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
+ type: int
+ route_map:
+ description:
+ - Route map to modify the attributes.
+ type: str
+ address_family:
+ description:
+ - Specifies BGP address family related configurations.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Type of address family to configure.
+ choices:
+ - ipv4
+ - ipv6
+ required: true
+ type: str
+ safi:
+ description:
+ - Specifies the type of cast for the address family.
+ choices:
+ - flowspec
+ - unicast
+ - multicast
+ - labeled-unicast
+ default: unicast
+ type: str
+ 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.
+ type: list
+ elements: dict
+ suboptions:
+ protocol:
+ description:
+ - Specifies the protocol for configuring redistribute information.
+ choices:
+ - ospf
+ - ospfv3
+ - eigrp
+ - isis
+ - static
+ - connected
+ - odr
+ - lisp
+ - mobile
+ - rip
+ required: true
+ type: str
+ id:
+ description:
+ - Identifier for the routing protocol for configuring redistribute
+ information.
+ - Valid for protocols 'ospf', 'ospfv3' and 'eigrp'.
+ type: str
+ metric:
+ description:
+ - Specifies the metric for redistributed routes.
+ type: int
+ route_map:
+ description:
+ - Specifies the route map reference.
+ type: str
+ networks:
+ description:
+ - Specify Networks to announce via BGP.
+ - For operation replace, this option is mutually exclusive with root level
+ networks option.
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description:
+ - Network ID to announce via BGP.
+ required: true
+ type: str
+ masklen:
+ description:
+ - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
+ type: int
+ route_map:
+ description:
+ - Route map to modify the attributes.
+ type: str
+ neighbors:
+ description:
+ - Specifies BGP neighbor related configurations in Address Family configuration
+ mode.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor:
+ description:
+ - Neighbor router address.
+ required: true
+ type: str
+ 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.
+ type: str
+ prefix_list_out:
+ description:
+ - Name of ip prefix-list to apply to outgoing prefixes.
+ type: str
+ 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
+ type: str
+ choices:
+ - merge
+ - replace
+ - override
+ - delete
+"""
+EXAMPLES = """
+- name: configure global bgp as 64496
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.providers.module import (
+ NetworkModule,
+)
+from ansible_collections.cisco.ios.plugins.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"),
+ "next_hop_unchanged": 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py
new file mode 100644
index 00000000..8e401986
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py
@@ -0,0 +1,2139 @@
+#!/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/>.
+#
+"""
+The module file for ios_bgp_global
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_bgp_global
+short_description: Global BGP resource module
+description: This module configures and manages the attributes of global bgp on Cisco IOS.
+version_added: 1.3.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL
+options:
+ config:
+ description: A list of configurations for global bgp.
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number.
+ type: str
+ required: true
+ aggregate_address:
+ description: Configure BGP aggregate entries
+ type: dict
+ suboptions:
+ address:
+ description: Aggregate address
+ type: str
+ netmask:
+ description: Aggregate mask
+ type: str
+ advertise_map:
+ description: Set condition to advertise attribute
+ type: str
+ as_confed_set:
+ description: Generate AS confed set path information
+ type: bool
+ as_set:
+ description: Generate AS set path information
+ type: bool
+ attribute_map:
+ description: Set attributes of aggregate
+ type: str
+ summary_only:
+ description: Filter more specific routes from updates
+ type: bool
+ suppress_map:
+ description: Conditionally filter more specific routes from updates
+ type: str
+ auto_summary:
+ description: Enable automatic network number summarization
+ type: bool
+ bgp:
+ description: Enable address family and enter its config mode
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Additional paths in the BGP table
+ type: dict
+ suboptions:
+ install:
+ description: Additional paths to install into RIB
+ type: bool
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ select:
+ description: Selection criteria to pick the paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ best_external:
+ description: Select best-external path
+ type: bool
+ group_best:
+ description: Select group-best path
+ type: bool
+ send:
+ description: Send additional paths to neighbors
+ type: bool
+ advertise_best_external:
+ description: Advertise best external path to internal peers
+ type: bool
+ aggregate_timer:
+ description:
+ - Configure Aggregation Timer
+ - Please refer vendor documentation for valid values
+ type: int
+ always_compare_med:
+ description: Allow comparing MED from different neighbors
+ type: bool
+ asnotation:
+ description:
+ - Change the default asplain notation
+ - asdot notation
+ type: bool
+ bestpath:
+ description: Change the default bestpath selection
+ type: list
+ elements: dict
+ suboptions:
+ aigp:
+ description:
+ - if both paths doesn't have aigp ignore on bestpath comparision
+ - ignore
+ type: bool
+ compare_routerid:
+ description: Compare router-id for identical EBGP paths
+ type: bool
+ cost_community:
+ description: cost community
+ type: bool
+ igp_metric:
+ description:
+ - igp metric
+ - Ignore igp metric in bestpath selection
+ type: bool
+ med:
+ description: MED attribute
+ type: dict
+ suboptions:
+ confed:
+ description: Compare MED among confederation paths
+ type: bool
+ missing_as_worst:
+ description: Treat missing MED as the least preferred one
+ type: bool
+ client_to_client:
+ description: Configure client to client route reflection
+ type: dict
+ suboptions:
+ set:
+ description: set reflection of routes allowed
+ type: bool
+ all:
+ description: inter-cluster and intra-cluster (default)
+ type: bool
+ intra_cluster:
+ description:
+ - intra cluster reflection
+ - intra-cluster reflection for cluster-id
+ type: str
+ cluster_id:
+ description:
+ - Configure Route-Reflector Cluster-id (peers may reset)
+ - A.B.C.D/Please refer vendor documentation for valid Route-Reflector Cluster-id
+ type: bool
+ confederation:
+ description: AS confederation parameters
+ type: dict
+ suboptions:
+ identifier:
+ description:
+ - Set routing domain confederation AS
+ - AS number
+ type: str
+ peers:
+ description:
+ - Peer ASs in BGP confederation
+ - AS number
+ type: str
+ consistency_checker:
+ description: Consistency-checker
+ type: dict
+ suboptions:
+ auto_repair:
+ description: Auto-Repair
+ type: dict
+ suboptions:
+ set:
+ description: Enable Auto-Repair
+ type: bool
+ interval:
+ description:
+ - Set the bgp consistency checker
+ - Please refer vendor documentation for valid values
+ type: int
+ error_message:
+ description: Log Error-Msg
+ type: dict
+ suboptions:
+ set:
+ description: Enable Error-Msg
+ type: bool
+ interval:
+ description:
+ - Set the bgp consistency checker
+ - Please refer vendor documentation for valid values
+ type: int
+ dampening:
+ description: Enable route-flap dampening
+ type: dict
+ suboptions:
+ penalty_half_time:
+ description:
+ - Half-life time for the penalty
+ - Please refer vendor documentation for valid values
+ type: int
+ reuse_route_val:
+ description:
+ - Value to start reusing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ suppress_route_val:
+ description:
+ - Value to start suppressing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ max_suppress:
+ description:
+ - Maximum duration to suppress a stable route
+ - Please refer vendor documentation for valid values
+ type: int
+ route_map:
+ description: Route-map to specify criteria for dampening
+ type: str
+ deterministic_med:
+ description: Pick the best-MED path among paths advertised from the neighboring AS
+ type: bool
+ dmzlink_bw:
+ description: Use DMZ Link Bandwidth as weight for BGP multipaths
+ type: bool
+ enforce_first_as:
+ description: Enforce the first AS for EBGP routes(default)
+ type: bool
+ enhanced_error:
+ description: Enabled BGP Enhanced error handling
+ type: bool
+ fast_external_fallover:
+ description: Immediately reset session if a link to a directly connected external peer goes down
+ type: bool
+ graceful_restart:
+ description: Graceful restart capability parameters
+ type: dict
+ suboptions:
+ set:
+ description: Set Graceful-Restart
+ type: bool
+ extended:
+ description: Enable Graceful-Restart Extension
+ type: bool
+ restart_time:
+ description:
+ - Set the max time needed to restart and come back up
+ - Please refer vendor documentation for valid values
+ type: int
+ stalepath_time:
+ description:
+ - Set the max time to hold onto restarting peer's stale paths
+ - Please refer vendor documentation for valid values
+ type: int
+ graceful_shutdown:
+ description: Graceful shutdown capability parameters
+ type: dict
+ suboptions:
+ neighbors:
+ description: Gracefully shut down all neigbors
+ type: dict
+ suboptions:
+ time:
+ description:
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ activate:
+ description: Activate graceful shutdown of all neigbors
+ type: bool
+ vrfs:
+ description: Gracefully shut down all vrf neigbors
+ type: dict
+ suboptions:
+ time:
+ description:
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ activate:
+ description: Activate graceful shutdown of all neigbors
+ type: bool
+ community:
+ description:
+ - Set Community for Gshut routes
+ - community number/community number in aa:nn format
+ type: str
+ local_preference:
+ description:
+ - Set Local Preference for Gshut routes
+ - Please refer vendor documentation for valid values
+ type: int
+ inject_map:
+ description: Routemap which specifies prefixes to inject
+ type: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ exist_map_name:
+ description: route-map name
+ type: str
+ copy_attributes:
+ description: Copy attributes from aggregate
+ type: bool
+ listen:
+ description: Neighbor subnet range listener
+ type: dict
+ suboptions:
+ limit:
+ description:
+ - Set the max limit for the dynamic subnet range neighbors
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: Subnet network range
+ type: dict
+ suboptions:
+ ipv4_with_subnet:
+ description: IPv4 subnet range(A.B.C.D/nn)
+ type: str
+ ipv6_with_subnet:
+ description: IPv6 subnet range(X:X:X:X::X/<0-128>)
+ type: str
+ peer_group:
+ description: Member of the peer-group
+ type: str
+ log_neighbor_changes:
+ description: Log neighbor up/down and reset reason
+ type: bool
+ maxas_limit:
+ description:
+ - Allow AS-PATH attribute from any neighbor imposing a limit on number of ASes
+ - Please refer vendor documentation for valid values
+ type: int
+ maxcommunity_limit:
+ description:
+ - Allow COMMUNITY attribute from any neighbor imposing a limit on number of communities
+ - Please refer vendor documentation for valid values
+ type: int
+ maxextcommunity_limit:
+ description:
+ - Allow EXTENDED COMMUNITY attribute from any neighbor imposing a limit on number of extended communities
+ - Please refer vendor documentation for valid values
+ type: int
+ nexthop:
+ description: Nexthop tracking commands
+ type: dict
+ suboptions:
+ route_map:
+ description: Route map for valid nexthops
+ type: str
+ trigger:
+ description: nexthop trackings
+ type: dict
+ suboptions:
+ delay:
+ description:
+ - Set the delay to tigger nexthop tracking
+ - Please refer vendor documentation for valid values
+ type: int
+ enable:
+ description: Enable nexthop tracking
+ type: bool
+ nopeerup_delay:
+ description: Set how long BGP will wait for the first peer to come up before beginning the update delay or
+ graceful restart timers (in seconds)
+ type: list
+ elements: dict
+ suboptions:
+ cold_boot:
+ description:
+ - How long to wait for the first peer to come up upon a cold boot
+ - Please refer vendor documentation for valid values
+ type: int
+ nsf_switchover:
+ description:
+ - How long to wait for the first peer, post NSF switchover
+ - Please refer vendor documentation for valid values
+ type: int
+ post_boot:
+ description:
+ - How long to wait for the first peer to come up once the system is already
+ booted and all peers go down
+ - Please refer vendor documentation for valid values
+ type: int
+ user_initiated:
+ description:
+ - How long to wait for the first peer, post a manual clear of BGP peers by the admin user
+ - Please refer vendor documentation for valid values
+ type: int
+ recursion:
+ description:
+ - recursion rule for the nexthops
+ - recursion via host for the nexthops
+ type: bool
+ redistribute_internal:
+ description: Allow redistribution of iBGP into IGPs (dangerous)
+ type: bool
+ refresh:
+ description: refresh
+ type: dict
+ suboptions:
+ max_eor_time:
+ description:
+ - Configure refresh max-eor time
+ - Please refer vendor documentation for valid values
+ type: int
+ stalepath_time:
+ description:
+ - Configure refresh stale-path time
+ - Please refer vendor documentation for valid values
+ type: int
+ regexp:
+ description:
+ - Select regular expression engine
+ - Enable bounded-execution-time regular expression engine
+ type: bool
+ route_map:
+ description:
+ - route-map control commands
+ - Have route-map set commands take priority over BGP commands such as next-hop unchanged
+ type: bool
+ router_id:
+ description: Override configured router identifier (peers will reset)
+ type: dict
+ suboptions:
+ address:
+ description: Manually configured router identifier(A.B.C.D)
+ type: str
+ interface:
+ description: Use IPv4 address on interface
+ type: str
+ vrf:
+ description:
+ - vrf-specific router id configuration
+ - Automatically assign per-vrf bgp router id
+ type: bool
+ scan_time:
+ description:
+ - Configure background scanner interval
+ - Please refer vendor documentation for valid values
+ type: int
+ slow_peer:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ detection:
+ description: Slow-peer detection
+ type: dict
+ suboptions:
+ set:
+ description: Slow-peer detection
+ type: bool
+ threshold:
+ description:
+ - Set the slow-peer detection threshold
+ - Please refer vendor documentation for valid values
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: int
+ snmp:
+ description:
+ - BGP SNMP options
+ - BGP SNMP trap options
+ - Use cbgpPeer2Type as part of index for traps
+ type: bool
+ sso:
+ description:
+ - Stateful Switchover
+ - Enable SSO only for Route-Refresh capable peers
+ type: bool
+ soft_reconfig_backup:
+ description: Use soft-reconfiguration inbound only when route-refresh is not negotiated
+ type: bool
+ suppress_inactive:
+ description: Suppress routes that are not in the routing table
+ type: bool
+ transport:
+ description:
+ - Global enable/disable transport session parameters
+ - Transport path MTU discovery
+ type: bool
+ update_delay:
+ description:
+ - Set the max initial delay for sending update
+ - Please refer vendor documentation for valid values
+ type: int
+ update_group:
+ description:
+ - Manage peers in bgp update groups
+ - Split update groups based on Policy
+ - Keep peers with as-override in different update groups
+ type: bool
+ upgrade_cli:
+ description: Upgrade to hierarchical AFI mode
+ type: dict
+ suboptions:
+ set:
+ description: enable upgrade to hierarchical AFI mode
+ type: bool
+ af_mode:
+ description: Upgrade to AFI mode
+ type: bool
+ bmp:
+ description: BGP Monitoring Protocol)
+ type: dict
+ suboptions:
+ buffer_size:
+ description:
+ - BMP Buffer Size
+ - Please refer vendor documentation for valid values
+ type: int
+ initial_refresh:
+ description: Initial Refresh options
+ type: dict
+ suboptions:
+ delay:
+ description: Delay before Initial Refresh
+ type: int
+ skip:
+ description: skip all refreshes
+ type: bool
+ server:
+ description:
+ - Server Information
+ - Please refer vendor documentation for valid values
+ type: int
+ default_information:
+ description:
+ - Control distribution of default information
+ - Distribute a default route
+ type: bool
+ default_metric:
+ description:
+ - Set metric of redistributed routes
+ - Please refer vendor documentation for valid values
+ type: int
+ distance:
+ description: Define an administrative distance
+ type: dict
+ suboptions:
+ admin:
+ description: Administrative distance
+ type: dict
+ suboptions:
+ distance:
+ description:
+ - Administrative distance
+ - Please refer vendor documentation for valid values
+ type: int
+ address:
+ description: IP Source address (A.B.C.D)
+ type: str
+ wildcard_bit:
+ description: Wildcard bits (A.B.C.D)
+ type: str
+ acl:
+ description:
+ - IP Standard access list number
+ - IP Standard expanded access list number
+ - Standard access-list name
+ type: str
+ bgp:
+ description: BGP distance
+ type: dict
+ suboptions:
+ routes_external:
+ description:
+ - Distance for routes external to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_internal:
+ description:
+ - Distance for routes internal to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_local:
+ description:
+ - Distance for local routes
+ - Please refer vendor documentation for valid values
+ type: int
+ mbgp:
+ description: MBGP distance
+ type: dict
+ suboptions:
+ routes_external:
+ description:
+ - Distance for routes external to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_internal:
+ description:
+ - Distance for routes internal to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_local:
+ description:
+ - Distance for local routes
+ - Please refer vendor documentation for valid values
+ type: int
+ distribute_list:
+ description: Filter networks in routing updates
+ type: dict
+ suboptions:
+ acl:
+ description: IP access list number/name
+ type: str
+ in:
+ description: Filter incoming routing updates
+ type: bool
+ out:
+ description: Filter outgoing routing updates
+ type: bool
+ interface:
+ description: interface details
+ type: str
+ maximum_paths:
+ description: Forward packets over multiple paths
+ type: dict
+ suboptions:
+ paths:
+ description: Number of paths
+ type: int
+ eibgp:
+ description: Both eBGP and iBGP paths as multipath
+ type: int
+ ibgp:
+ description: iBGP-multipath
+ type: int
+ maximum_secondary_paths:
+ description: Maximum secondary paths
+ type: dict
+ suboptions:
+ paths:
+ description: Number of secondary paths
+ type: int
+ eibgp:
+ description: Both eBGP and iBGP paths as secondary multipath
+ type: int
+ ibgp:
+ description: iBGP-secondary-multipath
+ type: int
+ neighbor:
+ description: Specify a neighbor router
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Neighbor address (A.B.C.D)
+ type: str
+ tag:
+ description: Neighbor tag
+ type: str
+ ipv6_adddress:
+ description: Neighbor ipv6 address (X:X:X:X::X)
+ type: str
+ activate:
+ description: Enable the Address Family for this Neighbor
+ type: bool
+ additional_paths:
+ description: Negotiate additional paths capabilities with this neighbor
+ type: dict
+ suboptions:
+ disable:
+ description: Disable additional paths for this neighbor
+ type: bool
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ send:
+ description: Send additional paths to neighbors
+ type: bool
+ advertise:
+ description: Advertise to this neighbor
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ group_best:
+ description: Select group-best path
+ type: bool
+ best_external:
+ description: Advertise best-external (at RRs best-internal) path
+ type: bool
+ diverse_path:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ backup:
+ description: Diverse path can be backup path
+ type: bool
+ mpath:
+ description: Diverse path can be multipath
+ type: bool
+ advertise_map:
+ description: specify route-map for conditional advertisement
+ type: dict
+ suboptions:
+ name:
+ description: advertise route-map name
+ type: str
+ exist_map:
+ description:
+ - advertise prefix only if prefix is in the condition exists
+ - condition route-map name
+ type: str
+ non_exist_map:
+ description:
+ - advertise prefix only if prefix in the condition does not exist
+ - condition route-map name
+ type: str
+ advertisement_interval:
+ description: Minimum interval between sending BGP routing updates
+ type: int
+ aigp:
+ description: AIGP on neighbor
+ type: dict
+ suboptions:
+ enable:
+ description: Enable AIGP
+ type: bool
+ send:
+ description: Cost community or MED carrying AIGP VALUE
+ type: dict
+ suboptions:
+ cost_community:
+ description: Cost extended community carrying AIGP Value
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Community ID
+ - Please refer vendor documentation for valid values
+ type: int
+ poi:
+ description: Point of Insertion
+ type: dict
+ suboptions:
+ igp_cost:
+ description: Point of Insertion After IGP
+ type: bool
+ pre_bestpath:
+ description: Point of Insertion At Beginning
+ type: bool
+ transitive:
+ description: Cost community is Transitive
+ type: bool
+ med:
+ description: Med carrying AIGP Value
+ type: bool
+ allow_policy:
+ description: Enable the policy support for this IBGP Neighbor
+ type: bool
+ allowas_in:
+ description: Accept as-path with my AS present in it
+ type: int
+ as_override:
+ description:
+ - Override matching AS-number while sending update
+ - Maintain Split Horizon while sending update
+ type: bool
+ bmp_activate:
+ description: Activate the BMP monitoring for a BGP peer
+ type: dict
+ suboptions:
+ all:
+ description: Activate BMP monitoring for all servers
+ type: bool
+ server:
+ description:
+ - Activate BMP for server
+ - BMP Server Number
+ - Please refer vendor documentation for valid values
+ type: int
+ capability:
+ description:
+ - Advertise capability to the peer
+ - Advertise ORF capability to the peer
+ - Advertise prefixlist ORF capability to this neighbor
+ type: dict
+ suboptions:
+ both:
+ description: Capability to SEND and RECEIVE the ORF to/from this neighbor
+ type: bool
+ receive:
+ description: Capability to RECEIVE the ORF from this neighbor
+ type: bool
+ send:
+ description: Capability to SEND the ORF to this neighbor
+ type: bool
+ cluster_id:
+ description:
+ - Configure Route-Reflector Cluster-id (peers may reset)
+ - Route-Reflector Cluster-id as 32 bit quantity, or
+ Route-Reflector Cluster-id in IP address format (A.B.C.D)
+ type: str
+ default_originate:
+ description: Originate default route to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Originate default route to this neighbor
+ type: bool
+ route_map:
+ description: Route-map to specify criteria to originate default
+ type: str
+ description:
+ description: Neighbor specific description
+ type: str
+ disable_connected_check:
+ description: one-hop away EBGP peer using loopback address
+ type: bool
+ distribute_list:
+ description: Filter updates to/from this neighbor
+ type: dict
+ suboptions:
+ acl:
+ description: IP access list number/name
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ dmzlink_bw:
+ description: Propagate the DMZ link bandwidth
+ type: bool
+ ebgp_multihop:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: dict
+ suboptions:
+ enable:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: bool
+ hop_count:
+ description:
+ - Maximum hop count
+ - Please refer vendor documentation for valid values
+ type: int
+ fall_over:
+ description: Session fall on peer route lost
+ type: dict
+ suboptions:
+ bfd:
+ description: Use BFD to detect failure
+ type: dict
+ suboptions:
+ set:
+ description: set bfd
+ type: bool
+ multi_hop:
+ description: Force BFD multi-hop to detect failure
+ type: bool
+ single_hop:
+ description: Force BFD single-hop to detect failure
+ type: bool
+ route_map:
+ description: Route map for peer route
+ type: str
+ filter_list:
+ description: Establish BGP filters
+ type: dict
+ suboptions:
+ path_acl:
+ description: AS path access list
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ ha_mode:
+ description: high availability mode
+ type: dict
+ suboptions:
+ set:
+ description: set ha-mode and graceful-restart for this peer
+ type: bool
+ disable:
+ description: disable graceful-restart
+ type: bool
+ inherit:
+ description:
+ - Inherit a template
+ - Inherit a peer-session template and Template name
+ type: str
+ local_as:
+ description: Specify a local-as number
+ type: dict
+ suboptions:
+ set:
+ description: set local-as number
+ type: bool
+ number:
+ description:
+ - AS number used as local AS
+ - Please refer vendor documentation for valid values
+ type: int
+ dual_as:
+ description: Accept either real AS or local AS from the ebgp peer
+ type: bool
+ no_prepend:
+ description: Do not prepend local-as to updates from ebgp peers
+ type: dict
+ suboptions:
+ set:
+ description: Set prepend
+ type: bool
+ replace_as:
+ description: Replace real AS with local AS in the EBGP updates
+ type: bool
+ log_neighbor_changes:
+ description: Log neighbor up/down and reset reason
+ type: dict
+ suboptions:
+ set:
+ description: set Log neighbor up/down and reset
+ type: bool
+ disable:
+ description: disable Log neighbor up/down and reset
+ type: bool
+ maximum_prefix:
+ description: Maximum number of prefixes accepted from this peer
+ type: dict
+ suboptions:
+ max_no:
+ description: maximum no. of prefix limit
+ type: int
+ threshold_val:
+ description: Threshold value (%) at which to generate a warning msg
+ type: int
+ restart:
+ description: Restart bgp connection after limit is exceeded
+ type: int
+ warning_only:
+ description: Only give warning message when limit is exceeded
+ type: bool
+ next_hop_self:
+ description: Disable the next hop calculation for this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Enable next-hop-self
+ type: bool
+ all:
+ description: Enable next-hop-self for both eBGP and iBGP received paths
+ type: bool
+ next_hop_unchanged:
+ description:
+ - Propagate next hop unchanged for iBGP paths to this neighbor
+ - Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Enable next-hop-unchanged
+ type: bool
+ allpaths:
+ description: Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: bool
+ password:
+ description: Set a password
+ type: str
+ path_attribute:
+ description: BGP optional attribute filtering
+ type: dict
+ suboptions:
+ discard:
+ description: Discard matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ treat_as_withdraw:
+ description: Treat-as-withdraw matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ peer_group:
+ description: Member of the peer-group
+ type: str
+ remote_as:
+ description:
+ - Specify a BGP neighbor
+ - AS of remote neighbor
+ type: int
+ remove_private_as:
+ description: Remove private AS number from outbound updates
+ type: dict
+ suboptions:
+ set:
+ description: Remove private AS number
+ type: bool
+ all:
+ description: Remove all private AS numbers
+ type: bool
+ replace_as:
+ description: Replace all private AS numbers with local AS
+ type: bool
+ route_map:
+ description: Apply route map to neighbor
+ type: dict
+ suboptions:
+ name:
+ description: Replace all private AS numbers with local AS
+ type: str
+ in:
+ description: Apply map to incoming routes
+ type: bool
+ out:
+ description: Apply map to outbound routes
+ type: bool
+ route_reflector_client:
+ description: Configure a neighbor as Route Reflector client
+ type: bool
+ route_server_client:
+ description: Configure a neighbor as Route Server client
+ type: dict
+ suboptions:
+ set:
+ description: Set Route Server client
+ type: bool
+ context:
+ description:
+ - Specify Route Server context for neighbor
+ - Route Server context name
+ type: str
+ send_community:
+ description: Send Community attribute to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Set send Community attribute to this neighbor
+ type: bool
+ both:
+ description: Send Standard and Extended Community attributes
+ type: bool
+ extended:
+ description: Send Extended Community attribute
+ type: bool
+ standard:
+ description: Send Standard Community attribute
+ type: bool
+ send_label:
+ description: Send NLRI + MPLS Label to this peer
+ type: dict
+ suboptions:
+ set:
+ description: Set send NLRI + MPLS Label to this peer
+ type: bool
+ explicit_null:
+ description: Advertise Explicit Null label in place of Implicit Null
+ type: bool
+ shutdown:
+ description: Administratively shut down this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: shut down
+ type: bool
+ graceful:
+ description:
+ - Gracefully shut down this neighbor
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ slow_peer:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ detection:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ threshold:
+ description: Set the slow-peer detection threshold
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: bool
+ static:
+ description: Static slow-peer
+ type: bool
+ soft_reconfiguration:
+ description:
+ - Per neighbor soft reconfiguration
+ - Allow inbound soft reconfiguration for this neighbor
+ type: bool
+ timers:
+ description: BGP per neighbor timers
+ type: dict
+ suboptions:
+ interval:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Holdtime
+ type: int
+ min_holdtime:
+ description: Minimum hold time from neighbor
+ type: int
+ translate_update:
+ description: Translate Update to MBGP format
+ type: dict
+ suboptions:
+ set:
+ description: Set Translate Update
+ type: bool
+ nlri:
+ description: Specify type of nlri to translate to
+ type: dict
+ suboptions:
+ multicast:
+ description: Translate Update to multicast nlri
+ type: bool
+ unicast:
+ description: Process Update as unicast nlri
+ type: bool
+ transport:
+ description: Transport options
+ type: dict
+ suboptions:
+ connection_mode:
+ description: Specify passive or active connection
+ type: dict
+ suboptions:
+ active:
+ description: Actively establish the TCP session
+ type: bool
+ passive:
+ description: Passively establish the TCP session
+ type: bool
+ multi_session:
+ description: Use Multi-session for transport
+ type: bool
+ path_mtu_discovery:
+ description: Use transport path MTU discovery
+ type: dict
+ suboptions:
+ set:
+ description: Use path MTU discovery
+ type: bool
+ disable:
+ description: disable
+ type: bool
+ ttl_security:
+ description:
+ - BGP ttl security check
+ - maximum number of hops
+ - Please refer vendor documentation for valid values
+ type: int
+ unsuppress_map:
+ description:
+ - Route-map to selectively unsuppress suppressed routes
+ - Name of route map
+ type: str
+ version:
+ description:
+ - Set the BGP version to match a neighbor
+ - Neighbor's BGP version
+ - Please refer vendor documentation for valid values
+ type: int
+ weight:
+ description: Set default weight for routes from this neighbor
+ type: int
+ redistribute:
+ description: Redistribute information from another routing protocol
+ type: list
+ elements: dict
+ suboptions:
+ application:
+ description: Application
+ type: dict
+ suboptions:
+ name:
+ description: Application name
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ bgp:
+ description: Border Gateway Protocol (BGP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ connected:
+ description: Connected
+ type: dict
+ suboptions:
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ eigrp:
+ description: Enhanced Interior Gateway Routing Protocol (EIGRP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ isis:
+ description: ISO IS-IS
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ clns:
+ description: Redistribution of OSI dynamic routes
+ type: bool
+ ip:
+ description: Redistribution of IP dynamic routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ iso_igrp:
+ description: IGRP for OSI networks
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ route_map:
+ description: Route map reference
+ type: str
+ lisp:
+ description: Locator ID Separation Protocol (LISP)
+ type: dict
+ suboptions:
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ mobile:
+ description: Mobile routes
+ type: dict
+ suboptions:
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ odr:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ ospf:
+ description: Open Shortest Path First (OSPF)
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ match:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ external:
+ description: Redistribute OSPF external routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description: Redistribute OSPF NSSA external routes
+ type: bool
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: VPN Routing/Forwarding Instance
+ type: str
+ ospfv3:
+ description: OSPFv3
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ match:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ external:
+ description: Redistribute OSPF external routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description: Redistribute OSPF NSSA external routes
+ type: bool
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ rip:
+ description: Routing Information Protocol (RIP)
+ type: dict
+ suboptions:
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ static:
+ description: Static routes
+ type: dict
+ suboptions:
+ clns:
+ description: Redistribution of OSI static routes
+ type: bool
+ ip:
+ description: Redistribution of IP static routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: Specify a source VRF
+ type: dict
+ suboptions:
+ name:
+ description: Source VRF name
+ type: str
+ global:
+ description: global VRF
+ type: bool
+ route_server_context:
+ description: Enter route server context command mode
+ type: dict
+ suboptions:
+ name:
+ description: Name of route server context
+ type: str
+ address_family:
+ description: Enter address family command mode
+ type: dict
+ suboptions:
+ afi:
+ description: Address family
+ type: str
+ choices: ['ipv4', 'ipv6']
+ modifier:
+ description: Address Family modifier
+ type: str
+ choices: ['multicast', 'unicast']
+ import_map:
+ description:
+ - Import matching routes using a route map
+ - Name of route map
+ type: str
+ description:
+ description: Textual description of the router server context
+ type: str
+ scope:
+ description: Enter scope command mode
+ type: dict
+ suboptions:
+ global:
+ description: Global scope
+ type: bool
+ vrf:
+ description:
+ - VRF scope
+ - VPN Routing/Forwarding instance name
+ type: str
+ synchronization:
+ description: Perform IGP synchronization
+ type: bool
+ table_map:
+ description: Map external entry attributes into routing table
+ type: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ filter:
+ description: Selective route download
+ type: bool
+ template:
+ description: Enter template command mode
+ type: dict
+ suboptions:
+ peer_policy:
+ description: Template configuration for policy parameters
+ type: str
+ peer_session:
+ description: Template configuration for session parameters
+ type: str
+ timers:
+ description:
+ - Adjust routing timers
+ - BGP timers
+ type: dict
+ suboptions:
+ keepalive:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Holdtime
+ type: int
+ min_holdtime:
+ description: Minimum hold time from neighbor
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^router bgp).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - purged
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ 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
+"""
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ bgp:
+ advertise_best_external: true
+ bestpath:
+ - compare_routerid: true
+ nopeerup_delay:
+ - post_boot: 10
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ graceful_shutdown:
+ neighbors:
+ time: 50
+ community: 100
+ local_preference: 100
+ neighbor:
+ - address: 198.51.100.1
+ description: merge neighbor
+ remote_as: 100
+ aigp:
+ send:
+ cost_community:
+ id: 100
+ poi:
+ igp_cost: true
+ transitive: true
+ route_map:
+ name: test-route
+ out: true
+ state: merged
+
+# Commands fired:
+# ---------------
+#
+# "commands": [
+# "router bgp 65000",
+# "bgp dampening 1 1 1 1",
+# "bgp graceful-shutdown all neighbors 50 community 100 local-preference 100",
+# "bgp advertise-best-external",
+# "bgp nopeerup-delay post-boot 10",
+# "bgp bestpath compare-routerid",
+# "neighbor 198.51.100.1 remote-as 100",
+# "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive",
+# "neighbor 198.51.100.1 description merge neighbor",
+# "neighbor 198.51.100.1 route-map test-route out"
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+
+- name: Replaces device configuration of listed global BGP with provided configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ bgp:
+ advertise_best_external: true
+ bestpath:
+ - med:
+ confed: true
+ log_neighbor_changes: true
+ nopeerup_delay:
+ - post_boot: 10
+ cold_boot: 20
+ neighbor:
+ - address: 192.0.2.1
+ description: replace neighbor
+ remote_as: 100
+ slow_peer:
+ detection:
+ disable: true
+ state: replaced
+
+# Commands fired:
+# ---------------
+#
+# "commands": [
+# "router bgp 65000"
+# "no bgp dampening 1 1 1 1"
+# "no timers bgp 100 200 150"
+# "no bgp bestpath compare-routerid"
+# "bgp bestpath med confed"
+# "bgp nopeerup-delay cold-boot 20"
+# "no neighbor 198.51.100.1 remote-as 100"
+# "neighbor 192.0.2.1 remote-as 100"
+# "no bgp graceful-shutdown all neighbors 50 local-preference 100 community 100"
+# "no neighbor 198.51.100.1 route-map test-route out"
+# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive"
+# "no neighbor 198.51.100.1 description merge neighbor"
+# "neighbor 192.0.2.1 slow-peer detection disable"
+# "neighbor 192.0.2.1 description replace neighbor"
+# ]
+
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay cold-boot 20
+# bgp nopeerup-delay post-boot 10
+# bgp bestpath med confed
+# bgp advertise-best-external
+# redistribute connected metric 10
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description replace neighbor
+# neighbor 192.0.2.1 slow-peer detection disable
+
+# Using Deleted
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+- name: "Delete global BGP (Note: This won't delete the configured global BGP)"
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ state: deleted
+
+# Commands fired:
+# ---------------
+# "commands": [
+# "router bgp 65000",
+# "no bgp dampening 1 1 1 1",
+# "no bgp graceful-shutdown all neighbors 50 community 100 local-preference 100",
+# "no bgp advertise-best-external",
+# "no bgp bestpath compare-routerid",
+# "no bgp nopeerup-delay post-boot 10",
+# "no neighbor 198.51.100.1 remote-as 100",
+# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive",
+# "no neighbor 198.51.100.1 description merge neighbor",
+# "no neighbor 198.51.100.1 route-map test-route out"
+# ]
+
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+
+
+# Using Deleted without any config passed
+#"(NOTE: This will delete all of configured global BGP)"
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+
+- name: "Delete global BGP without config"
+ cisco.ios.ios_bgp_global:
+ state: deleted
+
+# Commands fired:
+# ---------------
+# "commands": [
+# "router bgp 65000",
+# "no bgp dampening 1 1 1 1",
+# "no bgp graceful-shutdown all neighbors 50 community 100 local-preference 100",
+# "no bgp advertise-best-external",
+# "no bgp bestpath compare-routerid",
+# "no bgp nopeerup-delay post-boot 10",
+# "no neighbor 198.51.100.1 remote-as 100",
+# "no neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive",
+# "no neighbor 198.51.100.1 description merge neighbor",
+# "no neighbor 198.51.100.1 route-map test-route out"
+# ]
+
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+
+# Using Purged
+#"(NOTE: This WILL delete the configured global BGP)"
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+
+- name: 'Delete the configured global BGP (Note: This WILL delete the the configured
+ global BGP)'
+ cisco.ios.ios_bgp_global:
+ state: purged
+
+# Commands fired:
+# ---------------
+# "commands": [
+# "no router bgp 65000",
+# ]
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+
+- name: Gather listed global BGP with provided configurations
+ cisco.ios.ios_bgp_global:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "as_number": "65000",
+# "bgp": {
+# "advertise_best_external": true,
+# "bestpath": [
+# {
+# "compare_routerid": true
+# }
+# ],
+# "dampening": {
+# "max_suppress": 1,
+# "penalty_half_time": 1,
+# "reuse_route_val": 1,
+# "suppress_route_val": 1
+# },
+# "graceful_shutdown": {
+# "community": "100",
+# "local_preference": 100,
+# "neighbors": {
+# "time": 50
+# }
+# },
+# "nopeerup_delay": [
+# {
+# "post_boot": 10
+# }
+# ]
+# },
+# "neighbor": [
+# {
+# "address": "198.51.100.1",
+# "aigp": {
+# "send": {
+# "cost_community": {
+# "id": 100,
+# "poi": {
+# "igp_cost": true,
+# "transitive": true
+# }
+# }
+# }
+# },
+# "description": "merge neighbor",
+# "remote_as": 100,
+# "route_map": {
+# "name": "test-route",
+# "out": true
+# }
+# }
+# ]
+# }
+
+# Using Rendered
+
+- name: Rendered the provided configuration with the exisiting running configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ bgp:
+ advertise_best_external: true
+ bestpath:
+ - compare_routerid: true
+ nopeerup_delay:
+ - post_boot: 10
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ graceful_shutdown:
+ neighbors:
+ time: 50
+ community: 100
+ local_preference: 100
+ neighbor:
+ - address: 198.51.100.1
+ description: merge neighbor
+ remote_as: 100
+ aigp:
+ send:
+ cost_community:
+ id: 100
+ poi:
+ igp_cost: true
+ transitive: true
+ route_map:
+ name: test-route
+ out: true
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "router bgp 65000",
+# "bgp dampening 1 1 1 1",
+# "bgp graceful-shutdown all neighbors 50 community 100 local-preference 100",
+# "bgp advertise-best-external",
+# "bgp nopeerup-delay post-boot 10",
+# "bgp bestpath compare-routerid",
+# "neighbor 198.51.100.1 remote-as 100",
+# "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive",
+# "neighbor 198.51.100.1 description merge neighbor",
+# "neighbor 198.51.100.1 route-map test-route out"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 198.51.100.1 remote-as 100
+# neighbor 198.51.100.1 description merge neighbor
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 route-map test-route out
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_bgp_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "as_number": "65000",
+# "bgp": {
+# "advertise_best_external": true,
+# "bestpath": [
+# {
+# "compare_routerid": true
+# }
+# ],
+# "dampening": {
+# "max_suppress": 1,
+# "penalty_half_time": 1,
+# "reuse_route_val": 1,
+# "suppress_route_val": 1
+# },
+# "graceful_shutdown": {
+# "community": "100",
+# "local_preference": 100,
+# "neighbors": {
+# "time": 50
+# }
+# },
+# "nopeerup_delay": [
+# {
+# "post_boot": 10
+# }
+# ]
+# },
+# "neighbor": [
+# {
+# "address": "198.51.100.1",
+# "aigp": {
+# "send": {
+# "cost_community": {
+# "id": 100,
+# "poi": {
+# "igp_cost": true,
+# "transitive": true
+# }
+# }
+# }
+# },
+# "description": "merge neighbor",
+# "remote_as": 100,
+# "route_map": {
+# "name": "test-route",
+# "out": true
+# }
+# }
+# ]
+# }
+
+"""
+
+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: ["router bgp 65000", "bgp nopeerup-delay post-boot 10", "bgp advertise-best-external"]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.bgp_global.bgp_global import (
+ Bgp_global,
+)
+
+
+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=Bgp_globalArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Bgp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py
new file mode 100644
index 00000000..7c502974
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_command.py
@@ -0,0 +1,215 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_command
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.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
+ type: list
+ elements: raw
+ 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
+ type: list
+ elements: str
+ 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
+ type: str
+ choices:
+ - any
+ - all
+ 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
+ type: int
+ 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
+ type: int
+"""
+EXAMPLES = """
+- name: run show version on remote devices
+ cisco.ios.ios_command:
+ commands: show version
+
+- name: run show version and check to see if output contains IOS
+ cisco.ios.ios_command:
+ commands: show version
+ wait_for: result[0] contains IOS
+
+- name: run multiple commands on remote nodes
+ cisco.ios.ios_command:
+ commands:
+ - show version
+ - show interfaces
+
+- name: run multiple commands and evaluate the output
+ cisco.ios.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
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import (
+ Conditional,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ transform_commands,
+ to_lines,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ run_commands,
+)
+from ansible_collections.cisco.ios.plugins.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", elements="raw", required=True),
+ wait_for=dict(type="list", elements="str", 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py
new file mode 100644
index 00000000..260b74b0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_config.py
@@ -0,0 +1,593 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_config
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.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).
+- To ensure idempotency and correct diff the configuration lines in the relevant module options should be similar to how they
+ appear if present in the running configuration on device including the indentation.
+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 to ensure
+ idempotency and correct diff. Be sure to note the configuration command syntax as
+ some commands are automatically modified by the device config parser.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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). The configuration lines in the
+ source file should be similar to how it will appear if present in the running-configuration
+ of the device including the indentation to ensure idempotency and correct diff.
+ type: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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
+ type: str
+ 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
+ type: str
+ 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: '@'
+ type: str
+ 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
+ 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.
+ The configuration lines for this option should be similar to how it will appear if present
+ in the running-configuration of the device including the indentation to ensure idempotency
+ and correct diff.
+ type: str
+ aliases:
+ - config
+ 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
+ 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
+ type: str
+ 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.
+ type: str
+ choices:
+ - running
+ - startup
+ - intended
+ 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.
+ type: list
+ elements: str
+ 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). The configuration lines for this value should be similar to how it
+ will appear if present in the running-configuration of the device including the indentation
+ to ensure correct diff.
+ type: str
+ 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>
+ type: str
+ 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
+"""
+EXAMPLES = """
+- name: configure top level configuration
+ cisco.ios.ios_config:
+ lines: hostname {{ inventory_hostname }}
+
+- name: configure interface settings
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.ios_config:
+ lines:
+ - conform-action transmit
+ - exceed-action drop
+ parents:
+ - policy-map Foo
+ - class Scavenger
+ - police cir 64000
+
+- name: load new acl into device
+ cisco.ios.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
+ cisco.ios.ios_config:
+ diff_against: intended
+ intended_config: "{{ lookup('file', 'master.cfg') }}"
+
+- name: check the startup-config against the running-config
+ cisco.ios.ios_config:
+ diff_against: startup
+ diff_ignore_lines:
+ - ntp clock .*
+
+- name: save running to startup when modified
+ cisco.ios.ios_config:
+ save_when: modified
+
+- name: for idempotency, use full-form commands
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.ios_config:
+ backup: yes
+ src: ios_template.j2
+
+- name: configurable backup path
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ run_commands,
+ get_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_defaults_flag,
+ get_connection,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.ansible.netcommon.plugins.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="str"),
+ lines=dict(aliases=["commands"], type="list", elements="str"),
+ parents=dict(type="list", elements="str"),
+ before=dict(type="list", elements="str"),
+ after=dict(type="list", elements="str"),
+ 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", elements="str"),
+ )
+ 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"])):
+ msg = (
+ "To ensure idempotency and correct diff the input configuration lines should be"
+ " similar to how they appear if present in the running configuration on device"
+ )
+ if module.params["src"]:
+ msg += " including the indentation"
+ warnings.append(msg)
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py
new file mode 100644
index 00000000..e66d9048
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_facts.py
@@ -0,0 +1,236 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_facts
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.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'
+ type: list
+ elements: str
+ 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'.
+ type: list
+ elements: str
+"""
+EXAMPLES = """
+- name: Gather all legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: all
+
+- name: Gather only the config and default facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - config
+
+- name: Do not gather hardware facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - '!hardware'
+
+- name: Gather legacy and resource facts
+ cisco.ios.ios_facts:
+ gather_subset: all
+ gather_network_resources: all
+
+- name: Gather only the interfaces resource facts and no legacy facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - '!all'
+ - '!min'
+ gather_network_resources:
+ - interfaces
+
+- name: Gather interfaces resource and minimal legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: min
+ gather_network_resources: interfaces
+
+- name: Gather L2 interfaces resource and minimal legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: min
+ gather_network_resources: l2_interfaces
+
+- name: Gather L3 interfaces resource and minimal legacy facts
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.facts.facts import (
+ FactsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ Facts,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py
new file mode 100644
index 00000000..a1e540bc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interface.py
@@ -0,0 +1,597 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_interface
+author: Ganesh Nalawade (@ganeshrn)
+short_description: (deprecated, removed after 2022-06-01) Manage Interface on Cisco
+ IOS network devices
+description:
+- This module provides declarative management of Interfaces on Cisco IOS network devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_interfaces
+ why: Newer and updated modules released with more functionality in Ansible 2.9
+ removed_at_date: '2022-06-01'
+notes:
+- Tested against IOS 15.6
+options:
+ name:
+ description:
+ - Name of the Interface.
+ type: str
+ description:
+ description:
+ - Description of Interface.
+ type: str
+ enabled:
+ description:
+ - Interface link status.
+ default: True
+ type: bool
+ speed:
+ description:
+ - Interface link speed.
+ type: str
+ mtu:
+ description:
+ - Maximum size of transmit packet.
+ type: str
+ duplex:
+ description:
+ - Interface link status
+ type: str
+ 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)
+ type: str
+ 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)
+ type: str
+ neighbors:
+ description:
+ - Check the operational state of given interface C(name) for CDP/LLDP neighbor.
+ - The following suboptions are available.
+ type: list
+ elements: dict
+ suboptions:
+ host:
+ description:
+ - CDP/LLDP neighbor host for given interface C(name).
+ type: str
+ port:
+ description:
+ - CDP/LLDP neighbor port to which given interface C(name) is connected.
+ type: str
+ aggregate:
+ description: List of Interfaces definitions.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the Interface.
+ required: true
+ type: str
+ description:
+ description:
+ - Description of Interface.
+ type: str
+ enabled:
+ description:
+ - Interface link status.
+ type: bool
+ speed:
+ description:
+ - Interface link speed.
+ type: str
+ mtu:
+ description:
+ - Maximum size of transmit packet.
+ type: str
+ duplex:
+ description:
+ - Interface link status
+ choices:
+ - full
+ - half
+ - auto
+ type: str
+ 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)
+ type: str
+ 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)
+ type: str
+ neighbors:
+ description:
+ - Check the operational state of given interface C(name) for CDP/LLDP neighbor.
+ - The following suboptions are available.
+ type: list
+ elements: dict
+ suboptions:
+ host:
+ description:
+ - CDP/LLDP neighbor host for given interface C(name).
+ type: str
+ port:
+ description:
+ - CDP/LLDP neighbor port to which given interface C(name) is connected.
+ type: str
+ 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).
+ type: int
+ state:
+ description:
+ - State of the Interface configuration, C(up) means present and operationally
+ up and C(down) means present and operationally C(down)
+ choices:
+ - present
+ - absent
+ - up
+ - down
+ type: str
+ 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
+ type: int
+ 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
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+
+
+"""
+EXAMPLES = """
+- name: configure interface
+ cisco.ios.ios_interface:
+ name: GigabitEthernet0/2
+ description: test-interface
+ speed: 100
+ duplex: half
+ mtu: 512
+
+- name: remove interface
+ cisco.ios.ios_interface:
+ name: Loopback9
+ state: absent
+
+- name: make interface up
+ cisco.ios.ios_interface:
+ name: GigabitEthernet0/2
+ enabled: true
+
+- name: make interface down
+ cisco.ios.ios_interface:
+ name: GigabitEthernet0/2
+ enabled: false
+
+- name: Check intent arguments
+ cisco.ios.ios_interface:
+ name: GigabitEthernet0/2
+ state: up
+ tx_rate: ge(0)
+ rx_rate: le(0)
+
+- name: Check neighbors intent arguments
+ cisco.ios.ios_interface:
+ name: Gi0/0
+ neighbors:
+ - port: eth0
+ host: netdev
+
+- name: Config + intent
+ cisco.ios.ios_interface:
+ name: GigabitEthernet0/2
+ enabled: false
+ state: down
+
+- name: Add interface using aggregate
+ cisco.ios.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
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.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("^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("%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("^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("%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("%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("%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: (.*?)
+.*?Interface: (.*?), Port ID .outgoing port.: (.*?)
+""",
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py
new file mode 100644
index 00000000..aeb1561d
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py
@@ -0,0 +1,568 @@
+#!/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/>.
+#
+"""
+The module file for ios_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_interfaces
+short_description: Interfaces resource module
+description: This module manages the interface attributes of Cisco IOS network devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL
+options:
+ config:
+ description: A dictionary of interface options
+ type: list
+ elements: dict
+ 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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ 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
+"""
+
+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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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)"
+ cisco.ios.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)"
+ cisco.ios.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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# description this is interface1
+# mtu 65
+# duplex auto
+# speed 10
+# interface GigabitEthernet0/2
+# description this is interface2
+# mtu 110
+# shutdown
+# duplex auto
+# speed 100
+
+- name: Gather listed interfaces with provided configurations
+ cisco.ios.ios_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "description": "this is interface1",
+# "duplex": "auto",
+# "enabled": true,
+# "mtu": 65,
+# "name": "GigabitEthernet0/1",
+# "speed": "10"
+# },
+# {
+# "description": "this is interface2",
+# "duplex": "auto",
+# "enabled": false,
+# "mtu": 110,
+# "name": "GigabitEthernet0/2",
+# "speed": "100"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# description this is interface1
+# mtu 65
+# duplex auto
+# speed 10
+# interface GigabitEthernet0/2
+# description this is interface2
+# mtu 110
+# shutdown
+# duplex auto
+# speed 100
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ description: Configured by Ansible-Network
+ mtu: 110
+ enabled: true
+ duplex: half
+ - name: GigabitEthernet0/2
+ description: Configured by Ansible-Network
+ mtu: 2800
+ enabled: false
+ speed: 100
+ duplex: full
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "description Configured by Ansible-Network",
+# "mtu 110",
+# "duplex half",
+# "no shutdown",
+# "interface GigabitEthernet0/2",
+# "description Configured by Ansible-Network",
+# "mtu 2800",
+# "speed 100",
+# "duplex full",
+# "shutdown"
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# description interfaces 0/1
+# mtu 110
+# duplex half
+# no shutdown
+# interface GigabitEthernet0/2
+# description interfaces 0/2
+# mtu 2800
+# speed 100
+# duplex full
+# shutdown
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "description": "interfaces 0/1",
+# "duplex": "half",
+# "enabled": true,
+# "mtu": 110,
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "description": "interfaces 0/2",
+# "duplex": "full",
+# "enabled": true,
+# "mtu": 2800,
+# "name": "GigabitEthernet0/2",
+# "speed": "100"
+# }
+# ]
+
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.interfaces.interfaces import (
+ InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py
new file mode 100644
index 00000000..dfe8ca63
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interface.py
@@ -0,0 +1,581 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_l2_interface
+extends_documentation_fragment:
+- cisco.ios.ios
+short_description: (deprecated, removed after 2022-06-01) Manage Layer-2 interface
+ on Cisco IOS devices.
+description:
+- This module provides declarative management of Layer-2 interfaces on Cisco IOS devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_l2_interfaces
+ why: Newer and updated modules released with more functionality in Ansible 2.9
+ removed_at_date: '2022-06-01'
+author:
+- Nathaniel Case (@Qalthos)
+options:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
+ aliases:
+ - interface
+ type: str
+ mode:
+ description:
+ - Mode in which interface needs to be configured.
+ choices:
+ - access
+ - trunk
+ type: str
+ access_vlan:
+ description:
+ - Configure given VLAN in access port. If C(mode=access), used as the access VLAN
+ ID.
+ type: str
+ 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.
+ type: str
+ native_vlan:
+ description:
+ - Native VLAN to be configured in trunk port. If C(mode=trunk), used as the trunk
+ native VLAN ID.
+ type: str
+ 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".
+ type: str
+ aggregate:
+ description:
+ - List of Layer-2 interface definitions.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
+ aliases:
+ - interface
+ type: str
+ mode:
+ description:
+ - Mode in which interface needs to be configured.
+ choices:
+ - access
+ - trunk
+ type: str
+ access_vlan:
+ description:
+ - Configure given VLAN in access port. If C(mode=access), used as the access VLAN
+ ID.
+ type: str
+ 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.
+ type: str
+ native_vlan:
+ description:
+ - Native VLAN to be configured in trunk port. If C(mode=trunk), used as the trunk
+ native VLAN ID.
+ type: str
+ 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".
+ type: str
+ state:
+ description:
+ - Manage the state of the Layer-2 Interface configuration.
+ choices:
+ - present
+ - absent
+ - unconfigured
+ type: str
+ state:
+ description:
+ - Manage the state of the Layer-2 Interface configuration.
+ default: present
+ choices:
+ - present
+ - absent
+ - unconfigured
+ type: str
+
+"""
+EXAMPLES = """
+- name: Ensure GigabitEthernet0/5 is in its default l2 interface state
+ ios.ios_l2_interface:
+ name: GigabitEthernet0/5
+ state: unconfigured
+- name: Ensure GigabitEthernet0/5 is configured for access vlan 20
+ ios.ios_l2_interface:
+ name: GigabitEthernet0/5
+ mode: access
+ access_vlan: 20
+- name: Ensure GigabitEthernet0/5 only has vlans 5-10 as trunk vlans
+ ios.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.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.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ load_config,
+ run_commands,
+)
+from ansible_collections.cisco.ios.plugins.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("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("Administrative Mode: (?:.* )?(\\w+)$", config, re.M)
+ access = re.search("Access Mode VLAN: (\\d+)", config)
+ native = re.search("Trunking Native Mode VLAN: (\\d+)", config)
+ trunk = re.search("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
+port first before using this module. You can use
+the ios_interface module for this."""
+ )
+ if interface_is_portchannel(name, module):
+ module.fail_json(
+ msg="""Cannot change L2 config on physical
+port because it is in a portchannel.
+You 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
+does 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
+does 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py
new file mode 100644
index 00000000..08b208d4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py
@@ -0,0 +1,560 @@
+#!/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/>.
+#
+"""
+The module file for ios_l2_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_l2_interfaces
+short_description: L2 interfaces resource module
+description: This module provides declarative management of Layer-2 interface on Cisco
+ IOS devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ elements: str
+ 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
+ elements: str
+ mode:
+ description:
+ - Mode in which interface needs to be configured.
+ - An interface whose trunk encapsulation is "Auto" can not be configured to
+ "trunk" mode.
+ type: str
+ choices:
+ - access
+ - trunk
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ 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
+
+"""
+
+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
+ cisco.ios.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 voice 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# switchport access vlan 10
+# interface GigabitEthernet0/2
+# switchport trunk allowed vlan 10-20,40
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10,20
+# switchport mode trunk
+
+- name: Gather listed l2 interfaces with provided configurations
+ cisco.ios.ios_l2_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "GigabitEthernet0/0"
+# },
+# {
+# "access": {
+# "vlan": 10
+# },
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "mode": "trunk",
+# "name": "GigabitEthernet0/2",
+# "trunk": {
+# "allowed_vlans": [
+# "10-20",
+# "40"
+# ],
+# "encapsulation": "dot1q",
+# "native_vlan": 10,
+# "pruning_vlans": [
+# "10",
+# "20"
+# ]
+# }
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# switchport access vlan 10
+# interface GigabitEthernet0/2
+# switchport trunk allowed vlan 10-20,40
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10,20
+# switchport mode trunk
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access:
+ vlan: 30
+ - name: GigabitEthernet0/2
+ trunk:
+ allowed_vlans: 10-20,40
+ native_vlan: 20
+ pruning_vlans: 10,20
+ encapsulation: dot1q
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "switchport access vlan 30",
+# "interface GigabitEthernet0/2",
+# "switchport trunk encapsulation dot1q",
+# "switchport trunk native vlan 20",
+# "switchport trunk allowed vlan 10-20,40",
+# "switchport trunk pruning vlan 10,20"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# switchport mode access
+# switchport access vlan 30
+# interface GigabitEthernet0/2
+# switchport trunk allowed vlan 15-20,40
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 20
+# switchport trunk pruning vlan 10,20
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_l2_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "access": {
+# "vlan": 30
+# },
+# "mode": "access",
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "trunk": {
+# "allowed_vlans": [
+# "15-20",
+# "40"
+# ],
+# "encapsulation": "dot1q",
+# "native_vlan": 20,
+# "pruning_vlans": [
+# "10",
+# "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', 'switchport access vlan 20']
+"""
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import (
+ L2_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=L2_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = L2_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py
new file mode 100644
index 00000000..2a2b10a5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interface.py
@@ -0,0 +1,382 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_l3_interface
+author: Ganesh Nalawade (@ganeshrn)
+short_description: (deprecated, removed after 2022-06-01) Manage Layer-3 interfaces
+ on Cisco IOS network devices.
+description:
+- This module provides declarative management of Layer-3 interfaces on IOS network
+ devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_l3_interfaces
+ why: Newer and updated modules released with more functionality in Ansible 2.9
+ removed_at_date: '2022-06-01'
+notes:
+- Tested against IOS 15.2
+options:
+ name:
+ description:
+ - Name of the Layer-3 interface to be configured eg. GigabitEthernet0/2
+ type: str
+ 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: 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: str
+ 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.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the Layer-3 interface to be configured eg. GigabitEthernet0/2
+ 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: 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: str
+ state:
+ description:
+ - State of the Layer-3 interface configuration. It indicates if the configuration
+ should be present or absent on remote device.
+ type: str
+ choices:
+ - present
+ - absent
+ 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
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+
+
+"""
+EXAMPLES = """
+- name: Remove GigabitEthernet0/3 IPv4 and IPv6 address
+ cisco.ios.ios_l3_interface:
+ name: GigabitEthernet0/3
+ state: absent
+- name: Set GigabitEthernet0/3 IPv4 address
+ cisco.ios.ios_l3_interface:
+ name: GigabitEthernet0/3
+ ipv4: 192.168.0.1/24
+- name: Set GigabitEthernet0/3 IPv6 address
+ cisco.ios.ios_l3_interface:
+ name: GigabitEthernet0/3
+ ipv6: fd5d:12c9:2201:1::1/64
+- name: Set GigabitEthernet0/3 in dhcp
+ cisco.ios.ios_l3_interface:
+ name: GigabitEthernet0/3
+ ipv4: dhcp
+ ipv6: dhcp
+- name: Set interface Vlan1 (SVI) IPv4 address
+ cisco.ios.ios_l3_interface:
+ name: Vlan1
+ ipv4: 192.168.0.5/24
+- name: Set IP addresses on aggregate
+ cisco.ios.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
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+from ansible_collections.ansible.netcommon.plugins.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
+ )
+ elif 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("%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("^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:
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py
new file mode 100644
index 00000000..0ea1bb3a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py
@@ -0,0 +1,605 @@
+#!/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/>.
+#
+"""
+The module file for ios_l3_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_l3_interfaces
+short_description: L3 interfaces resource module
+description:
+- This module provides declarative management of Layer-3 interface on Cisco IOS devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ 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 | section ^interface) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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 sitself)"
+ cisco.ios.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)"
+ cisco.ios.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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# ip address 203.0.113.27 255.255.255.0
+# interface GigabitEthernet0/2
+# ip address 192.0.2.1 255.255.255.0 secondary
+# ip address 192.0.2.2 255.255.255.0
+# ipv6 address 2001:DB8:0:3::/64
+
+- name: Gather listed l3 interfaces with provided configurations
+ cisco.ios.ios_l3_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "ipv4": [
+# {
+# "address": "203.0.113.27 255.255.255.0"
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "192.0.2.1 255.255.255.0",
+# "secondary": true
+# },
+# {
+# "address": "192.0.2.2 255.255.255.0"
+# }
+# ],
+# "ipv6": [
+# {
+# "address": "2001:db8:0:3::/64"
+# }
+# ],
+# "name": "GigabitEthernet0/2"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# ip address 203.0.113.27 255.255.255.0
+# interface GigabitEthernet0/2
+# ip address 192.0.2.1 255.255.255.0 secondary
+# ip address 192.0.2.2 255.255.255.0
+# ipv6 address 2001:DB8:0:3::/64
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ ipv4:
+ - address: dhcp
+ dhcp_client: 0
+ dhcp_hostname: test.com
+ - name: GigabitEthernet0/2
+ ipv4:
+ - address: 198.51.100.1/24
+ secondary: true
+ - address: 198.51.100.2/24
+ ipv6:
+ - address: 2001:db8:0:3::/64
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "ip address dhcp client-id GigabitEthernet 0/0 hostname test.com",
+# "interface GigabitEthernet0/2",
+# "ip address 198.51.100.1 255.255.255.0 secondary",
+# "ip address 198.51.100.2 255.255.255.0",
+# "ipv6 address 2001:db8:0:3::/64"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# ip address dhcp client-id
+# GigabitEthernet 0/0 hostname test.com
+# interface GigabitEthernet0/2
+# ip address 198.51.100.1 255.255.255.0
+# secondary ip address 198.51.100.2 255.255.255.0
+# ipv6 address 2001:db8:0:3::/64
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_l3_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "ipv4": [
+# {
+# "address": "dhcp",
+# "dhcp_client": 0,
+# "dhcp_hostname": "test.com"
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "198.51.100.1 255.255.255.0",
+# "secondary": true
+# },
+# {
+# "address": "198.51.100.2 255.255.255.0"
+# }
+# ],
+# "ipv6": [
+# {
+# "address": "2001:db8:0:3::/64"
+# }
+# ],
+# "name": "GigabitEthernet0/2"
+# }
+# ]
+
+"""
+
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import (
+ L3_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=L3_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = L3_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py
new file mode 100644
index 00000000..71884ab0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py
@@ -0,0 +1,273 @@
+#!/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/>.
+#
+"""
+The module file for ios_lacp
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lacp
+short_description: LACP resource module
+description: This module provides declarative management of Global LACP on Cisco IOS
+ network devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show lacp sys-id).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - deleted
+ - rendered
+ - parsed
+ - gathered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 32768, 5e00.0000.8000
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.ios_lacp:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#show lacp sys-id
+# 32768, 5e00.0000.8000
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+- name: Gather listed LACP with provided configurations
+ cisco.ios.ios_lacp:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "system": {
+# "priority": 500
+# }
+# }
+
+# After state:
+# ------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lacp:
+ config:
+ system:
+ priority: 123
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "lacp system-priority 10"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# lacp system-priority 123
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lacp:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "system": {
+# "priority": 123
+# }
+# }
+
+"""
+
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp.lacp import (
+ LacpArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=LacpArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lacp(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py
new file mode 100644
index 00000000..7bf4092a
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py
@@ -0,0 +1,508 @@
+#!/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/>.
+#
+"""
+The module file for ios_lacp_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lacp_interfaces
+short_description: LACP interfaces resource module
+description: This module provides declarative management of LACP on Cisco IOS network
+ devices lacp_interfaces.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - rendered
+ - gathered
+ - parsed
+ 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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)"
+ cisco.ios.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)"
+ cisco.ios.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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 2
+# interface Port-channel40
+# lacp max-bundle 5
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# lacp port-priority 30
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+
+- name: Gather listed LACP interfaces with provided configurations
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "fast_switchover": true,
+# "max_bundle": 2,
+# "name": "Port-channel10"
+# },
+# {
+# "max_bundle": 5,
+# "name": "Port-channel40"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "port_priority": 30
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "port_priority": 20
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 2
+# interface Port-channel40
+# lacp max-bundle 5
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# lacp port-priority 30
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ port_priority: 10
+ - name: GigabitEthernet0/2
+ port_priority: 20
+ - name: Port-channel10
+ fast_switchover: true
+ max_bundle: 2
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "lacp port-priority 10",
+# "interface GigabitEthernet0/2",
+# "lacp port-priority 20",
+# "interface Port-channel10",
+# "lacp max-bundle 2",
+# "lacp fast-switchover"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+# interface Port-channel10
+# lacp max-bundle 2 fast-switchover
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "name": "GigabitEthernet0/1",
+# "port_priority": 10
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "port_priority": 20
+# },
+# {
+# "fast_switchover": true,
+# "max_bundle": 2,
+# "name": "Port-channel10"
+# }
+# ]
+
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import (
+ Lacp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lacp_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lacp_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py
new file mode 100644
index 00000000..679925ea
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py
@@ -0,0 +1,534 @@
+#!/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/>.
+#
+"""
+The module file for ios_l3_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_lag_interfaces
+short_description: LAG interfaces resource module
+description: This module manages properties of Link Aggregation Group on Cisco IOS
+ devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ elements: dict
+ suboptions:
+ member:
+ description:
+ - Interface member of the link aggregation group.
+ type: str
+ mode:
+ description:
+ - Etherchannel Mode of the interface for link aggregation.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ type: str
+ required: true
+ 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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - rendered
+ - parsed
+ - gathered
+ 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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)"
+ cisco.ios.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)"
+ cisco.ios.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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel11
+# interface Port-channel22
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 11 mode active
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 22 mode active
+
+- name: Gather listed LAG interfaces with provided configurations
+ cisco.ios.ios_lag_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/1",
+# "mode": "active"
+# }
+# ],
+# "name": "Port-channel11"
+# },
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/2",
+# "mode": "active"
+# }
+# ],
+# "name": "Port-channel22"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel11
+# interface Port-channel22
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 11 mode active
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 22 mode active
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel11
+ members:
+ - member: GigabitEthernet0/1
+ mode: active
+ - name: Port-channel22
+ members:
+ - member: GigabitEthernet0/2
+ mode: passive
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "channel-group 11 mode active",
+# "interface GigabitEthernet0/2",
+# "channel-group 22 mode passive",
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# channel-group 11 mode active
+# interface GigabitEthernet0/2
+# channel-group 22 mode passive
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lag_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/1",
+# "mode": "active"
+# }
+# ],
+# "name": "Port-channel11"
+# },
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/2",
+# "mode": "passive"
+# }
+# ],
+# "name": "Port-channel22"
+# }
+# ]
+
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import (
+ Lag_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lag_interfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lag_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py
new file mode 100644
index 00000000..ebf934d8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py
@@ -0,0 +1,363 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = r"""
+module: ios_linkagg
+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.
+version_added: 1.0.0
+notes:
+- Tested against IOS 15.2
+options:
+ group:
+ description:
+ - Channel-group number for the port-channel Link aggregation group. Range 1-255.
+ type: int
+ mode:
+ description:
+ - Mode of the link aggregation group.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - active
+ - 'on'
+ - passive
+ - auto
+ - desirable
+ type: str
+ members:
+ description:
+ - List of members of the link aggregation group.
+ type: list
+ elements: str
+ aggregate:
+ description: List of link aggregation definitions.
+ type: list
+ elements: dict
+ suboptions:
+ group:
+ description:
+ - Channel-group number for the port-channel Link aggregation group. Range 1-255.
+ type: str
+ required: true
+ mode:
+ description:
+ - Mode of the link aggregation group.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - active
+ - 'on'
+ - passive
+ - auto
+ - desirable
+ type: str
+ members:
+ description:
+ - List of members of the link aggregation group.
+ type: list
+ elements: str
+ state:
+ description:
+ - State of the link aggregation group.
+ choices:
+ - present
+ - absent
+ type: str
+ state:
+ description:
+ - State of the link aggregation group.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+ purge:
+ description:
+ - Purge links not defined in the I(aggregate) parameter.
+ default: false
+ type: bool
+extends_documentation_fragment:
+- cisco.ios.ios
+"""
+EXAMPLES = """
+- name: create link aggregation group
+ cisco.ios.ios_linkagg:
+ group: 10
+ state: present
+
+- name: delete link aggregation group
+ cisco.ios.ios_linkagg:
+ group: 10
+ state: absent
+
+- name: set link aggregation group to members
+ cisco.ios.ios_linkagg:
+ group: 200
+ mode: active
+ members:
+ - GigabitEthernet0/0
+ - GigabitEthernet0/1
+
+- name: remove link aggregation group from GigabitEthernet0/0
+ cisco.ios.ios_linkagg:
+ group: 200
+ mode: active
+ members:
+ - GigabitEthernet0/1
+
+- name: Create aggregate of linkagg definitions
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ CustomNetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.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)
+ )
+ elif 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("interface {0}\\n".format(member), body, re.M)
+ if match_int:
+ match = re.search(
+ "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(
+ "channel-group {0} mode".format(group), l, re.M
+ )
+ if match_group:
+ match = re.search("interface (\\S+)", l, re.M)
+ if match:
+ members.append(match.group(1))
+ return members
+
+
+def get_channel(module, config, group):
+ match = re.findall("^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("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", elements="str"),
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py
new file mode 100644
index 00000000..7b6d48e6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py
@@ -0,0 +1,113 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_lldp
+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.
+version_added: 1.0.0
+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
+ - enabled
+ - disabled
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+"""
+EXAMPLES = """
+- name: Enable LLDP service
+ cisco.ios.ios_lldp:
+ state: present
+
+- name: Disable LLDP service
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ load_config,
+ run_commands,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py
new file mode 100644
index 00000000..77f65a05
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py
@@ -0,0 +1,356 @@
+#!/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/>.
+#
+"""
+The module file for ios_lldp_global
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_lldp_global
+short_description: LLDP resource module
+description: This module configures and manages the Link Layer Discovery Protocol(LLDP)
+ attributes on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^lldp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+
+
+"""
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+# vios#sh running-config | section ^lldp
+# vios1#
+
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.ios_lldp_global:
+ state: deleted
+
+# After state:
+# -------------
+# vios#sh running-config | section ^lldp
+# vios1#
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Gather listed interfaces with provided configurations
+ cisco.ios.ios_lldp_global:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "enabled": true,
+# "holdtime": 10,
+# "reinit": 3,
+# "timer": 10
+# }
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+# Using Rendered
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lldp_global:
+ config:
+ holdtime: 10
+ enabled: true
+ reinit: 3
+ timer: 10
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "lldp holdtime 10",
+# "lldp run",
+# "lldp timer 10",
+# "lldp reinit 3"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lldp_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "enabled": true,
+# "holdtime": 10,
+# "reinit": 3,
+# "timer": 10
+# }
+
+"""
+
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_global.lldp_global import (
+ Lldp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lldp_globalArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lldp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py
new file mode 100644
index 00000000..32629d09
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py
@@ -0,0 +1,666 @@
+#!/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/>.
+#
+"""
+The module file for ios_lldp_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lldp_interfaces
+short_description: LLDP interfaces resource module
+description: This module manages link layer discovery protocol (LLDP) attributes of
+ interfaces on Cisco IOS devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(sh lldp interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - rendered
+ - gathered
+ - parsed
+ 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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)"
+ cisco.ios.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)"
+ cisco.ios.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
+
+# Using Gathered
+
+# 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: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+- name: Gather listed LLDP interfaces with provided configurations
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "GigabitEthernet0/0",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "receive": true,
+# "transmit": true
+# }
+# ]
+
+# 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: WAIT FOR FRAME
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/0
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/1
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/2
+ receive: true
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/0",
+# "lldp receive",
+# "lldp transmit",
+# "interface GigabitEthernet0/1",
+# "lldp receive",
+# "lldp transmit",
+# "interface GigabitEthernet0/2",
+# "lldp receive"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# 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
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "name": "GigabitEthernet0/0",
+# "receive": false,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "receive": true,
+# "transmit": false
+# }
+# ]
+
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import (
+ Lldp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lldp_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lldp_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py
new file mode 100644
index 00000000..0d1046a1
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_logging.py
@@ -0,0 +1,511 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_logging
+author: Trishna Guha (@trishnaguha)
+short_description: Manage logging on network devices
+description:
+- This module provides declarative management of logging on Cisco Ios devices.
+version_added: 1.0.0
+notes:
+- Tested against IOS 15.6
+options:
+ dest:
+ description:
+ - Destination of the logs.
+ - On dest has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - 'on'
+ - host
+ - console
+ - monitor
+ - buffered
+ - trap
+ type: str
+ name:
+ description:
+ - The hostname or IP address of the destination.
+ - Required when I(dest=host).
+ type: str
+ size:
+ description:
+ - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes.
+ type: int
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ default: debugging
+ choices:
+ - emergencies
+ - alerts
+ - critical
+ - errors
+ - warnings
+ - notifications
+ - informational
+ - debugging
+ type: str
+ aggregate:
+ description: List of logging definitions.
+ type: list
+ elements: dict
+ suboptions:
+ dest:
+ description:
+ - Destination of the logs.
+ - On dest has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - 'on'
+ - host
+ - console
+ - monitor
+ - buffered
+ - trap
+ type: str
+ name:
+ description:
+ - The hostname or IP address of the destination.
+ - Required when I(dest=host).
+ type: str
+ size:
+ description:
+ - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes.
+ type: int
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ type: str
+ choices:
+ - emergencies
+ - alerts
+ - critical
+ - errors
+ - warnings
+ - notifications
+ - informational
+ - debugging
+ state:
+ description:
+ - State of the logging configuration.
+ choices:
+ - present
+ - absent
+ type: str
+ state:
+ description:
+ - State of the logging configuration.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+"""
+EXAMPLES = """
+- name: configure host logging
+ cisco.ios.ios_logging:
+ dest: host
+ name: 172.16.0.1
+ state: present
+
+- name: remove host logging configuration
+ cisco.ios.ios_logging:
+ dest: host
+ name: 172.16.0.1
+ state: absent
+
+- name: configure console logging level and facility
+ cisco.ios.ios_logging:
+ dest: console
+ facility: local7
+ level: debugging
+ state: present
+
+- name: enable logging to all
+ cisco.ios.ios_logging:
+ dest: on
+
+- name: configure buffer size
+ cisco.ios.ios_logging:
+ dest: buffered
+ size: 5000
+
+- name: Configure logging using aggregate
+ cisco.ios.ios_logging:
+ aggregate:
+ - {dest: console, level: notifications}
+ - {dest: buffered, size: 9000}
+
+- name: remove logging using aggregate
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+ validate_ip_address,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_capabilities,
+)
+from ansible_collections.cisco.ios.plugins.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))
+ elif 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("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(
+ "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("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(
+ "logging buffered(?: \\d+)?(?: ([a-z]+))?", line, re.M
+ )
+ else:
+ match = re.search("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("^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(
+ "\\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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py
new file mode 100644
index 00000000..8f8e0da4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py
@@ -0,0 +1,326 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_ntp
+extends_documentation_fragment:
+- cisco.ios.ios
+short_description: Manages core NTP configuration.
+description:
+- Manages core NTP configuration.
+version_added: 1.0.0
+author:
+- Federico Olivieri (@Federico87)
+options:
+ server:
+ description:
+ - Network address of NTP server.
+ type: str
+ source_int:
+ description:
+ - Source interface for NTP packets.
+ type: str
+ acl:
+ description:
+ - ACL for peer/server access restricition.
+ type: str
+ 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.
+ type: str
+ key_id:
+ description:
+ - auth_key id. Data type string
+ type: str
+ state:
+ description:
+ - Manage the state of the resource.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+"""
+EXAMPLES = """
+# Set new NTP server and source interface
+- cisco.ios.ios_ntp:
+ server: 10.0.255.10
+ source_int: Loopback0
+ logging: false
+ state: present
+
+# Remove NTP ACL and logging
+- cisco.ios.ios_ntp:
+ acl: NTP_ACL
+ logging: true
+ state: absent
+
+# Set NTP authentication
+- cisco.ios.ios_ntp:
+ key_id: 10
+ auth_key: 15435A030726242723273C21181319000A
+ auth: true
+ state: present
+
+# Set new NTP configuration
+- cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+
+
+def parse_server(line, dest):
+ if dest == "server":
+ match = re.search(
+ "(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("(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(
+ "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(
+ "(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("(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("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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py
new file mode 100644
index 00000000..b5bdc775
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py
@@ -0,0 +1,1101 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospf_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_ospf_interfaces
+short_description: OSPF_Interfaces resource module
+description: This module configures and manages the Open Shortest Path First (OSPF)
+ version 2 on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+options:
+ config:
+ description: A dictionary of OSPF 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
+ address_family:
+ description:
+ - OSPF interfaces settings on the interfaces in address-family
+ context.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Address Family Identifier (AFI) for OSPF interfaces settings
+ on the interfaces.
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ required: true
+ process:
+ description: OSPF interfaces process config
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Address Family Identifier (AFI) for OSPF interfaces settings
+ on the interfaces. Please refer vendor documentation of Valid
+ values.
+ type: int
+ area_id:
+ description:
+ - OSPF interfaces area ID as a decimal value. Please
+ refer vendor documentation of Valid values.
+ - OSPF interfaces area ID in IP address format(e.g.
+ A.B.C.D)
+ type: str
+ secondaries:
+ description:
+ - Include or exclude secondary IP addresses.
+ - Valid only with IPv4 config
+ type: bool
+ instance_id:
+ description:
+ - Set the OSPF instance based on ID
+ - Valid only with IPv6 OSPF config
+ type: int
+ adjacency:
+ description: Adjacency staggering
+ type: bool
+ authentication:
+ description: Enable authentication
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic
+ authentication keys
+ type: str
+ message_digest:
+ description: Use message-digest authentication
+ type: bool
+ 'null':
+ description: Use no authentication
+ type: bool
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable/Disable BFD on this interface
+ type: bool
+ cost:
+ description: Interface cost
+ type: dict
+ suboptions:
+ interface_cost:
+ description: Interface cost or Route cost of this interface
+ type: int
+ dynamic_cost:
+ description:
+ - Specify dynamic cost options
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ default:
+ description: Specify default link metric value
+ type: int
+ hysteresis:
+ description: Specify hysteresis value for LSA dampening
+ type: dict
+ suboptions:
+ percent:
+ description: Specify hysteresis percent changed.
+ Please refer vendor documentation of Valid values.
+ type: int
+ threshold:
+ description: Specify hysteresis threshold value.
+ Please refer vendor documentation of Valid values.
+ type: int
+ weight:
+ description: Specify weight to be placed on individual
+ metrics
+ type: dict
+ suboptions:
+ l2_factor:
+ description:
+ - Specify weight to be given to L2-factor metric
+ - Percentage weight of L2-factor metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ latency:
+ description:
+ - Specify weight to be given to latency metric.
+ - Percentage weight of latency metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ oc:
+ description:
+ - Specify weight to be given to cdr/mdr for oc
+ - Give 100 percent weightage for current data rate(0
+ for maxdatarate)
+ type: bool
+ resources:
+ description:
+ - Specify weight to be given to resources metric
+ - Percentage weight of resources metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ throughput:
+ description:
+ - Specify weight to be given to throughput metric
+ - Percentage weight of throughput metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ database_filter:
+ description: Filter OSPF LSA during synchronization and flooding
+ type: bool
+ dead_interval:
+ description: Interval after which a neighbor is declared dead
+ type: dict
+ suboptions:
+ time:
+ description: time in seconds
+ type: int
+ minimal:
+ description:
+ - Set to 1 second and set multiplier for Hellos
+ - Number of Hellos sent within 1 second. Please refer
+ vendor documentation of Valid values.
+ - Valid only with IP OSPF config
+ type: int
+ demand_circuit:
+ description: OSPF Demand Circuit, enable or disable
+ the demand circuit'
+ type: dict
+ suboptions:
+ enable:
+ description: Enable Demand Circuit
+ type: bool
+ ignore:
+ description: Ignore demand circuit auto-negotiation requests
+ type: bool
+ disable:
+ description:
+ - Disable demand circuit on this interface
+ - Valid only with IPv6 OSPF config
+ type: bool
+ flood_reduction:
+ description: OSPF Flood Reduction
+ type: bool
+ hello_interval:
+ description:
+ - Time between HELLO packets
+ - Please refer vendor documentation of Valid values.
+ type: int
+ lls:
+ description:
+ - Link-local Signaling (LLS) support
+ - Valid only with IP OSPF config
+ type: bool
+ manet:
+ description:
+ - Mobile Adhoc Networking options
+ - MANET Peering options
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ cost:
+ description: Redundant path cost improvement required to peer
+ type: dict
+ suboptions:
+ percent:
+ description: Relative incremental path cost.
+ Please refer vendor documentation of Valid values.
+ type: int
+ threshold:
+ description: Absolute incremental path cost.
+ Please refer vendor documentation of Valid values.
+ type: int
+ link_metrics:
+ description: Redundant path cost improvement required to peer
+ type: dict
+ suboptions:
+ set:
+ description: Enable link-metrics
+ type: bool
+ cost_threshold:
+ description: Minimum link cost threshold.
+ Please refer vendor documentation of Valid values.
+ type: int
+ mtu_ignore:
+ description: Ignores the MTU in DBD packets
+ type: bool
+ multi_area:
+ description:
+ - Set the OSPF multi-area ID
+ - Valid only with IP OSPF config
+ type: dict
+ suboptions:
+ id:
+ description:
+ - OSPF multi-area ID as a decimal value. Please refer vendor
+ documentation of Valid values.
+ - OSPF multi-area ID in IP address format(e.g. A.B.C.D)
+ type: int
+ cost:
+ description: Interface cost
+ type: int
+ neighbor:
+ description:
+ - OSPF neighbor link-local IPv6 address (X:X:X:X::X)
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ address:
+ description: Neighbor link-local IPv6 address
+ type: str
+ cost:
+ description: OSPF cost for point-to-multipoint neighbor
+ type: int
+ database_filter:
+ description: Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor
+ type: bool
+ poll_interval:
+ description: OSPF dead-router polling interval
+ type: int
+ priority:
+ description: OSPF priority of non-broadcast neighbor
+ type: int
+ network:
+ description: Network type
+ type: dict
+ suboptions:
+ broadcast:
+ description: Specify OSPF broadcast multi-access network
+ type: bool
+ manet:
+ description:
+ - Specify MANET OSPF interface type
+ - Valid only with IPv6 OSPF config
+ type: bool
+ non_broadcast:
+ description: Specify OSPF NBMA network
+ type: bool
+ point_to_multipoint:
+ description: Specify OSPF point-to-multipoint network
+ type: bool
+ point_to_point:
+ description: Specify OSPF point-to-point network
+ type: bool
+ prefix_suppression:
+ description: Enable/Disable OSPF prefix suppression
+ type: bool
+ priority:
+ description: Router priority. Please refer vendor documentation
+ of Valid values.
+ type: int
+ resync_timeout:
+ description: Interval after which adjacency is reset if oob-resync
+ is not started. Please refer vendor documentation of Valid values.
+ type: int
+ retransmit_interval:
+ description: Time between retransmitting lost link state
+ advertisements. Please refer vendor documentation of Valid values.
+ type: int
+ shutdown:
+ description: Set OSPF protocol's state to disable under
+ current interface
+ type: bool
+ transmit_delay:
+ description: Link state transmit delay.
+ Please refer vendor documentation of Valid values.
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - Valid only with IPV4 OSPF config
+ type: dict
+ suboptions:
+ set:
+ description: Enable TTL Security on all interfaces
+ type: bool
+ hops:
+ description:
+ - Maximum number of IP hops allowed
+ - Please refer vendor documentation of Valid values.
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section
+ ^interface).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ 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 deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+- name: Delete provided OSPF Interface config
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/1",
+# "no ipv6 ospf 55 area 105",
+# "no ipv6 ospf adjacency stagger disable",
+# "no ipv6 ospf priority 20",
+# "no ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+# Using deleted without any config passed (NOTE: This will delete all OSPF Interfaces configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+- name: Delete all OSPF config from interfaces
+ cisco.ios.ios_ospf_interfaces:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "no ip ospf 10 area 20",
+# "no ip ospf adjacency stagger disable",
+# "no ip ospf cost 30",
+# "no ip ospf priority 40",
+# "no ip ospf ttl-security hops 50",
+# "interface GigabitEthernet0/1",
+# "no ipv6 ospf 55 area 105",
+# "no ipv6 ospf adjacency stagger disable",
+# "no ipv6 ospf priority 20",
+# "no ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# router-ios#
+
+- name: Merge provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 30
+ adjacency: true
+ bfd: true
+ cost:
+ interface_cost: 5
+ dead_interval:
+ time: 5
+ demand_circuit:
+ ignore: true
+ network:
+ broadcast: true
+ priority: 25
+ resync_timeout: 10
+ shutdown: true
+ ttl_security:
+ hops: 50
+ - afi: ipv6
+ process:
+ id: 35
+ area_id: 45
+ adjacency: true
+ database_filter: true
+ manet:
+ link_metrics:
+ cost_threshold: 10
+ priority: 55
+ transmit_delay: 45
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/1",
+# "ip ospf 10 area 30",
+# "ip ospf adjacency stagger disable",
+# "ip ospf bfd",
+# "ip ospf cost 5",
+# "ip ospf dead-interval 5",
+# "ip ospf demand-circuit ignore",
+# "ip ospf network broadcast",
+# "ip ospf priority 25",
+# "ip ospf resync-timeout 10",
+# "ip ospf shutdown",
+# "ip ospf ttl-security hops 50",
+# "ipv6 ospf 35 area 45",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf database-filter all out",
+# "ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 55",
+# "ipv6 ospf transmit-delay 45"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Override provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv6
+ process:
+ id: 55
+ area_id: 105
+ adjacency: true
+ priority: 20
+ transmit_delay: 30
+ - name: GigabitEthernet0/2
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 20
+ adjacency: true
+ cost:
+ interface_cost: 30
+ priority: 40
+ ttl_security:
+ hops: 50
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "ip ospf 10 area 20",
+# "ip ospf adjacency stagger disable",
+# "ip ospf cost 30",
+# "ip ospf priority 40",
+# "ip ospf ttl-security hops 50",
+# "interface GigabitEthernet0/1",
+# "ipv6 ospf 55 area 105",
+# "no ipv6 ospf database-filter all out",
+# "no ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 20",
+# "ipv6 ospf transmit-delay 30",
+# "no ip ospf 10 area 30",
+# "no ip ospf adjacency stagger disable",
+# "no ip ospf bfd",
+# "no ip ospf cost 5",
+# "no ip ospf dead-interval 5",
+# "no ip ospf demand-circuit ignore",
+# "no ip ospf network broadcast",
+# "no ip ospf priority 25",
+# "no ip ospf resync-timeout 10",
+# "no ip ospf shutdown",
+# "no ip ospf ttl-security hops 50"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Replaced provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ address_family:
+ - afi: ipv6
+ process:
+ id: 55
+ area_id: 105
+ adjacency: true
+ priority: 20
+ transmit_delay: 30
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "ipv6 ospf 55 area 105",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf priority 20",
+# "ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Gather OSPF Interfaces provided configurations
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "GigabitEthernet0/2"
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": true,
+# "afi": "ipv4",
+# "bfd": true,
+# "cost": {
+# "interface_cost": 5
+# },
+# "dead_interval": {
+# "time": 5
+# },
+# "demand_circuit": {
+# "ignore": true
+# },
+# "network": {
+# "broadcast": true
+# },
+# "priority": 25,
+# "process": {
+# "area_id": "30",
+# "id": 10
+# },
+# "resync_timeout": 10,
+# "shutdown": true,
+# "ttl_security": {
+# "hops": 50
+# }
+# },
+# {
+# "adjacency": true,
+# "afi": "ipv6",
+# "database_filter": true,
+# "manet": {
+# "link_metrics": {
+# "cost_threshold": 10
+# }
+# },
+# "priority": 55,
+# "process": {
+# "area_id": "45",
+# "id": 35
+# },
+# "transmit_delay": 45
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 30
+ adjacency: true
+ bfd: true
+ cost:
+ interface_cost: 5
+ dead_interval:
+ time: 5
+ demand_circuit:
+ ignore: true
+ network:
+ broadcast: true
+ priority: 25
+ resync_timeout: 10
+ shutdown: true
+ ttl_security:
+ hops: 50
+ - afi: ipv6
+ process:
+ id: 35
+ area_id: 45
+ adjacency: true
+ database_filter: true
+ manet:
+ link_metrics:
+ cost_threshold: 10
+ priority: 55
+ transmit_delay: 45
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "ip ospf 10 area 30",
+# "ip ospf adjacency stagger disable",
+# "ip ospf bfd",
+# "ip ospf cost 5",
+# "ip ospf dead-interval 5",
+# "ip ospf demand-circuit ignore",
+# "ip ospf network broadcast",
+# "ip ospf priority 25",
+# "ip ospf resync-timeout 10",
+# "ip ospf shutdown",
+# "ip ospf ttl-security hops 50",
+# "ipv6 ospf 35 area 45",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf database-filter all out",
+# "ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 55",
+# "ipv6 ospf transmit-delay 45"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/2
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/0
+
+- name: Parse the provided configuration with the exisiting running configuration
+ cisco.ios.ios_ospf_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# },
+# {
+# "name": "GigabitEthernet0/2"
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": true,
+# "afi": "ipv4",
+# "bfd": true,
+# "cost": {
+# "interface_cost": 5
+# },
+# "dead_interval": {
+# "time": 5
+# },
+# "demand_circuit": {
+# "ignore": true
+# },
+# "network": {
+# "broadcast": true
+# },
+# "priority": 25,
+# "process": {
+# "area_id": "30",
+# "id": 10
+# },
+# "resync_timeout": 10,
+# "shutdown": true,
+# "ttl_security": {
+# "hops": 50
+# }
+# },
+# {
+# "adjacency": true,
+# "afi": "ipv6",
+# "database_filter": true,
+# "manet": {
+# "link_metrics": {
+# "cost_threshold": 10
+# }
+# },
+# "priority": 55,
+# "process": {
+# "area_id": "45",
+# "id": 35
+# },
+# "transmit_delay": 45
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# }
+# ]
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['interface GigabitEthernet0/1', 'ip ospf 10 area 30', 'ip ospf cost 5', 'ip ospf priority 25']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospf_interfaces.ospf_interfaces import (
+ Ospf_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospf_interfaces.ospf_interfaces import (
+ Ospf_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=Ospf_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ result = Ospf_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py
new file mode 100644
index 00000000..6a435b43
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py
@@ -0,0 +1,1691 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospfv2
+"""
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_ospfv2
+short_description: OSPFv2 resource module
+description: This module configures and manages the Open Shortest Path First (OSPF)
+ version 2 on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+options:
+ config:
+ description: A dictionary of OSPF options.
+ type: dict
+ suboptions:
+ processes:
+ description:
+ - List of OSPF instance configurations.
+ type: list
+ elements: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ required: true
+ type: int
+ vrf:
+ description: Specify parameters for a VPN Routing/Forwarding instance
+ type: str
+ address_family:
+ description: Router Address Family configuration mode
+ type: dict
+ suboptions:
+ default:
+ description: Set a command to its defaults
+ type: bool
+ snmp_context:
+ description:
+ - Modify snmp parameters
+ - Configure SNMP context name
+ type: str
+ topology:
+ description: Associate the routing protocol to a topology instance
+ type: dict
+ suboptions:
+ name:
+ description: Routing topology instance name
+ type: str
+ base:
+ description: Entering router topology sub mode
+ type: bool
+ tid:
+ description:
+ - Configuring the routing protocol topology tid
+ - Note, please refer vendor documentation for valid values
+ type: bool
+ adjacency:
+ description: To configure control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Area authentication
+ type: dict
+ suboptions:
+ enable:
+ description: Enable area authentication
+ type: bool
+ message_digest:
+ description: Use IPsec authentication
+ type: bool
+ capability:
+ description:
+ - Enable area specific capability
+ - Enable exclusion of links from base topology
+ type: bool
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ filter_list:
+ description: Filter networks between OSPF areas
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ direction:
+ description: The direction to apply on the filter networks sent to and from this area.
+ type: str
+ choices: ['in', 'out']
+ required: true
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_ext_capability:
+ description: Do not send domain specific capabilities into NSSA
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ['always', 'suppress-fa']
+ ranges:
+ description: Summarize routes matching address/mask (border routers only)
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: IP address to match
+ type: str
+ netmask:
+ description: IP mask for address
+ type: str
+ advertise:
+ description:
+ - Advertise this range (default)
+ - Since, advertise when enabled is not shown in running-config
+ idempotency won't be maintained for the play in the second or
+ next run of the play.
+ type: bool
+ cost:
+ description: User specified metric for this range
+ type: int
+ not_advertise:
+ description: DoNotAdvertise this range
+ type: bool
+ sham_link:
+ description: Define a sham link and its parameters
+ type: dict
+ suboptions:
+ source:
+ description: IP addr associated with sham-link source (A.B.C.D)
+ type: str
+ destination:
+ description: IP addr associated with sham-link destination (A.B.C.D)
+ type: str
+ cost:
+ description:
+ - Associate a cost with the sham-link
+ - Cost of the sham-link
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - Maximum number of IP hops allowed
+ type: int
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_ext_capability:
+ description: Do not send domain specific capabilities into stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable BFD on all interfaces
+ type: bool
+ capability:
+ description: Enable specific OSPF feature
+ type: dict
+ suboptions:
+ lls:
+ description: Link-local Signaling (LLS) support
+ type: bool
+ opaque:
+ description: Opaque LSA
+ type: bool
+ transit:
+ description: Transit Area
+ type: bool
+ vrf_lite:
+ description: Do not perform PE specific checks
+ type: bool
+ compatible:
+ description: OSPF router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ default_information:
+ description: Control distribution of default information
+ type: dict
+ suboptions:
+ originate:
+ description: Distribute a default route
+ type: bool
+ always:
+ description: Always advertise default route
+ type: bool
+ metric:
+ description:
+ - OSPF default metric
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ route_map:
+ description: Route-map reference name
+ type: str
+ default_metric:
+ description: Set metric of redistributed routes
+ type: int
+ discard_route:
+ description: Enable or disable discard-route installation
+ type: dict
+ suboptions:
+ set:
+ description: Enable discard-route installation
+ type: bool
+ external:
+ description:
+ - Discard route for redistributed summarised routes
+ - Administrative distance for redistributed summarised routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ internal:
+ description:
+ - Discard route for summarised internal routes
+ - Administrative distance for summarised internal routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ distance:
+ description: Define an administrative distance
+ type: dict
+ suboptions:
+ admin_distance:
+ description: OSPF Administrative distance
+ type: dict
+ suboptions:
+ distance:
+ description: Administrative distance
+ type: int
+ address:
+ description: IP Source address
+ type: str
+ wildcard_bits:
+ description: Wildcard bits
+ type: str
+ acl:
+ description: Access-list name/number
+ type: str
+ ospf:
+ description: OSPF distance
+ type: dict
+ suboptions:
+ external:
+ description: External type 5 and type 7 routes
+ type: int
+ inter_area:
+ description: Inter-area routes
+ type: int
+ intra_area:
+ description: Intra-area routes
+ type: int
+ distribute_list:
+ description: Filter networks in routing updates
+ type: dict
+ suboptions:
+ acls:
+ description: IP access list
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: IP access list name/number
+ type: str
+ required: true
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ['in', 'out']
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ prefix:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ required: true
+ gateway_name:
+ description: Gateway name for filtering incoming updates based on gateway
+ type: str
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ['in', 'out']
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ route_map:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Route-map name
+ type: str
+ required: true
+ domain_id:
+ description: OSPF domain-id
+ type: dict
+ suboptions:
+ ip_address:
+ description: IP address
+ type: dict
+ suboptions:
+ address:
+ description: OSPF domain ID in IP address format
+ type: str
+ secondary:
+ description: Secondary Domain-ID
+ type: bool
+ 'null':
+ description: Null Domain-ID
+ type: bool
+ domain_tag:
+ description:
+ - OSPF domain-tag which is OSPF domain tag - 32-bit value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ help:
+ description: Description of the interactive help system
+ type: bool
+ ignore:
+ description:
+ - Do not complain about specific event
+ - Do not complain upon receiving LSA of the specified type, MOSPF Type 6 LSA
+ type: bool
+ interface_id:
+ description:
+ - Source of the interface ID
+ - SNMP MIB ifIndex
+ type: bool
+ ispf:
+ description: Enable incremental SPF computation
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description: Set maximum metric
+ type: dict
+ suboptions:
+ router_lsa:
+ description: Maximum metric in self-originated router-LSAs
+ type: bool
+ required: true
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ include_stub:
+ description: Set maximum metric for stub links in router-LSAs
+ type: bool
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ summary_lsa:
+ description:
+ - Override summary-lsa metric with max-metric value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ maximum_paths:
+ description:
+ - Forward packets over multiple paths
+ - Number of paths
+ type: int
+ mpls:
+ description: Configure MPLS routing protocol parameters
+ type: dict
+ suboptions:
+ ldp:
+ description: routing protocol commands for MPLS LDP
+ type: dict
+ suboptions:
+ autoconfig:
+ description: routing protocol commands for MPLS LDP
+ type: dict
+ suboptions:
+ set:
+ description: Configure LDP automatic configuration and set the config
+ type: bool
+ area:
+ description: Configure an OSPF area to run MPLS LDP
+ type: str
+ sync:
+ description: Configure LDP-IGP Synchronization
+ type: bool
+ traffic_eng:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: dict
+ suboptions:
+ area:
+ description:
+ - Configure an ospf area to run MPLS Traffic Engineering
+ - OSPF area ID as a decimal value or in IP address format
+ type: str
+ autoroute_exclude:
+ description:
+ - MPLS TE autoroute exclude
+ - Filter prefixes based on name of an IP prefix-list
+ type: str
+ interface:
+ description: MPLS TE interface configuration for this OSPF process
+ type: dict
+ suboptions:
+ interface_type:
+ description: TE Interface configuration (GigabitEthernet A/B)
+ type: str
+ area:
+ description:
+ - Advertise MPLS TE information for this interface into area
+ - OSPF area ID as a decimal value
+ type: int
+ mesh_group:
+ description: Traffic Engineering Mesh-Group advertisement
+ type: dict
+ suboptions:
+ id:
+ description: Mesh Group Id
+ type: int
+ interface:
+ description: Interface configuration (GigabitEthernet A/B)
+ type: str
+ area:
+ description: configure flooding scope as area
+ type: str
+ multicast_intact:
+ description: MPLS TE and PIM interaction
+ type: bool
+ router_id_interface:
+ description: Router Interface configuration (GigabitEthernet A/B)
+ type: str
+ neighbor:
+ description: Specify a neighbor router
+ type: dict
+ suboptions:
+ address:
+ description: Neighbor address (A.B.C.D)
+ type: str
+ cost:
+ description:
+ - OSPF cost for point-to-multipoint neighbor metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ database_filter:
+ description:
+ - Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor
+ - Filter all outgoing LSA
+ type: bool
+ poll_interval:
+ description: OSPF dead-router polling interval of non-broadcast neighbor in Seconds
+ type: int
+ priority:
+ description: OSPF priority of non-broadcast neighbor priority
+ type: int
+ network:
+ description: Enable routing on an IP network
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Network number
+ type: str
+ wildcard_bits:
+ description: OSPF wild card bits
+ type: str
+ area:
+ description: Set the OSPF area ID
+ type: str
+ nsf:
+ description: Non-stop forwarding
+ type: dict
+ suboptions:
+ cisco:
+ description: Cisco Non-stop forwarding
+ type: dict
+ suboptions:
+ helper:
+ description: helper support
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ ietf:
+ description: IETF graceful restart
+ type: dict
+ suboptions:
+ helper:
+ description: helper support
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ passive_interface:
+ description:
+ - Suppress routing updates on an interface (GigabitEthernet A/B)
+ - Interface name with respective interface number
+ type: str
+ prefix_suppression:
+ description: Enable prefix suppression
+ type: bool
+ priority:
+ description:
+ - OSPF topology priority
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ update:
+ description: OSPF Router process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: bool
+ summary_address:
+ description: Configure IP address summaries
+ type: dict
+ suboptions:
+ address:
+ description: IP summary address
+ type: str
+ mask:
+ description: IP Summary mask
+ type: str
+ not_advertise:
+ description: Do not advertise or translate
+ type: bool
+ nssa_only:
+ description: Limit summary to NSSA areas
+ type: bool
+ tag:
+ description: Set tag
+ type: int
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ traffic_share:
+ description:
+ - How to compute traffic share over alternate paths
+ - All traffic shared among min metric paths
+ - Use different interfaces for equal-cost paths
+ type: bool
+ ttl_security:
+ description: TTL security check
+ type: dict
+ suboptions:
+ set:
+ description: Enable TTL Security on all interfaces
+ type: bool
+ hops:
+ description:
+ - Maximum number of IP hops allowed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^router ospf).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ 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
+ - parsed
+ - rendered
+ default: merged
+
+"""
+EXAMPLES = """
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Delete provided OSPF V2 processes
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ - process_id: 200
+ vrf: blue
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+
+# Using deleted without any config passed (NOTE: This will delete all OSPFV2 configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Delete all OSPF processes
+ cisco.ios.ios_ospfv2:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 200 vrf blue",
+# "no router ospf 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router-ios#
+
+- name: Merge provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ areas:
+ - area_id: '5'
+ capability: true
+ authentication:
+ enable: true
+ - area_id: '10'
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ default_cost: 10
+ filter_list:
+ - name: test_prefix_in
+ direction: in
+ - name: test_prefix_out
+ direction: out
+ network:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ area: 5
+ default_information:
+ originate: true
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.3.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ areas:
+ - area_id: '10'
+ capability: true
+ distribute_list:
+ acls:
+ - name: 10
+ direction: out
+ - name: 123
+ direction: in
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "router ospf 200 vrf blue",
+# "auto-cost reference-bandwidth 4",
+# "distribute-list 10 out",
+# "distribute-list 123 in",
+# "domain-id 192.0.3.1",
+# "max-metric router-lsa on-startup 100",
+# "area 10 capability default-exclusion",
+# "router ospf 1",
+# "default-information originate",
+# "max-metric router-lsa on-startup 110",
+# "network 198.51.100.0 0.0.0.255 area 5",
+# "area 10 authentication message-digest",
+# "area 10 default-cost 10",
+# "area 10 nssa translate type7 suppress-fa",
+# "area 10 nssa default-information-originate metric 10",
+# "area 10 filter-list prefix test_prefix_out out",
+# "area 10 filter-list prefix test_prefix_in in",
+# "area 5 authentication",
+# "area 5 capability default-exclusion"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Override provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.4.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ maximum_paths: 15
+ ttl_security:
+ hops: 7
+ areas:
+ - area_id: '10'
+ default_cost: 10
+ authentication:
+ message_digest: true
+ - process_id: 100
+ vrf: ospf_vrf
+ domain_id:
+ ip_address:
+ address: 192.0.5.1
+ auto_cost:
+ reference_bandwidth: 5
+ areas:
+ - area_id: '5'
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 1",
+# "router ospf 100 vrf ospf_vrf",
+# "auto-cost reference-bandwidth 5",
+# "domain-id 192.0.5.1",
+# "area 5 authentication message-digest",
+# "area 5 nssa translate type7 suppress-fa",
+# "area 5 nssa default-information-originate metric 10",
+# "router ospf 200 vrf blue",
+# "no auto-cost reference-bandwidth 4",
+# "no distribute-list 10 out",
+# "no distribute-list 123 in",
+# "domain-id 192.0.4.1",
+# "max-metric router-lsa on-startup 200",
+# "maximum-paths 15",
+# "ttl-security all-interfaces hops 7",
+# "area 10 authentication message-digest",
+# "no area 10 capability default-exclusion",
+# "area 10 default-cost 10"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.4.1
+# max-metric router-lsa on-startup 200
+# ttl-security all-interfaces hops 7
+# area 10 authentication message-digest
+# area 10 default-cost 10
+# maximum-paths 15
+# router ospf 100 vrf ospf_vrf
+# domain-id 192.0.5.1
+# auto-cost reference-bandwidth 5
+# area 5 authentication message-digest
+# area 5 nssa default-information-originate metric 10
+# area 5 nssa translate type7 suppress-fa
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Replaced provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.4.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ maximum_paths: 15
+ ttl_security:
+ hops: 7
+ areas:
+ - area_id: '10'
+ default_cost: 10
+ authentication:
+ message_digest: true
+ - process_id: 100
+ vrf: ospf_vrf
+ domain_id:
+ ip_address:
+ address: 192.0.5.1
+ auto_cost:
+ reference_bandwidth: 5
+ areas:
+ - area_id: '5'
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "router ospf 100 vrf ospf_vrf",
+# "auto-cost reference-bandwidth 5",
+# "domain-id 192.0.5.1",
+# "area 5 authentication message-digest",
+# "area 5 nssa translate type7 suppress-fa",
+# "area 5 nssa default-information-originate metric 10",
+# "router ospf 200 vrf blue",
+# "no auto-cost reference-bandwidth 4",
+# "no distribute-list 10 out",
+# "no distribute-list 123 in",
+# "domain-id 192.0.4.1",
+# "max-metric router-lsa on-startup 200",
+# "maximum-paths 15",
+# "ttl-security all-interfaces hops 7",
+# "area 10 authentication message-digest",
+# "no area 10 capability default-exclusion",
+# "area 10 default-cost 10"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.4.1
+# max-metric router-lsa on-startup 200
+# ttl-security all-interfaces hops 7
+# area 10 authentication message-digest
+# area 10 default-cost 10
+# maximum-paths 15
+# router ospf 100 vrf ospf_vrf
+# domain-id 192.0.5.1
+# auto-cost reference-bandwidth 5
+# area 5 authentication message-digest
+# area 5 nssa default-information-originate metric 10
+# area 5 nssa translate type7 suppress-fa
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 5 capability default-exclusion
+# area 5 authentication
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_in in
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Gather OSPFV2 provided configurations
+ cisco.ios.ios_ospfv2:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "processes": [
+# {
+# "areas": [
+# {
+# "area_id": "5",
+# "authentication": {
+# "enable": true
+# },
+# "capability": true
+# },
+# {
+# "area_id": "10",
+# "authentication": {
+# "message_digest": true
+# },
+# "default_cost": 10,
+# "filter_list": [
+# {
+# "direction": "in",
+# "name": "test_prefix_in"
+# },
+# {
+# "direction": "out",
+# "name": "test_prefix_out"
+# }
+# ],
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# },
+# "translate": "suppress-fa"
+# }
+# }
+# ],
+# "default_information": {
+# "originate": true
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "network": {
+# "address": "198.51.100.0",
+# "area": "5",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "process_id": 1
+# },
+# {
+# "areas": [
+# {
+# "area_id": "10",
+# "capability": true
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 4
+# },
+# "distribute_list": {
+# "acls": [
+# {
+# "direction": "out",
+# "name": "10"
+# },
+# {
+# "direction": "in",
+# "name": "123"
+# }
+# ]
+# },
+# "domain_id": {
+# "ip_address": {
+# "address": "192.0.3.1"
+# }
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 100
+# },
+# "router_lsa": true
+# },
+# "process_id": 200,
+# "vrf": "blue"
+# }
+# ]
+# }
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ areas:
+ - area_id: '5'
+ capability: true
+ authentication:
+ enable: true
+ - area_id: '10'
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ default_cost: 10
+ filter_list:
+ - name: test_prefix_in
+ direction: in
+ - name: test_prefix_out
+ direction: out
+ network:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ area: 5
+ default_information:
+ originate: true
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.3.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ areas:
+ - area_id: '10'
+ capability: true
+ distribute_list:
+ acls:
+ - name: 10
+ direction: out
+ - name: 123
+ direction: in
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "router ospf 200 vrf blue",
+# "auto-cost reference-bandwidth 4",
+# "distribute-list 10 out",
+# "distribute-list 123 in",
+# "domain-id 192.0.3.1",
+# "max-metric router-lsa on-startup 100",
+# "area 10 capability default-exclusion",
+# "router ospf 1",
+# "default-information originate",
+# "max-metric router-lsa on-startup 110",
+# "network 198.51.100.0 0.0.0.255 area 5",
+# "area 10 authentication message-digest",
+# "area 10 default-cost 10",
+# "area 10 nssa translate type7 suppress-fa",
+# "area 10 nssa default-information-originate metric 10",
+# "area 10 filter-list prefix test_prefix_out out",
+# "area 10 filter-list prefix test_prefix_in in",
+# "area 5 authentication",
+# "area 5 capability default-exclusion"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router ospf 100
+# auto-cost reference-bandwidth 5
+# domain-id 192.0.5.1
+# area 5 authentication message-digest
+# area 5 nssa translate type7 suppress-fa
+# area 5 nssa default-information-originate metric 10
+
+- name: Parse the provided configuration with the exisiting running configuration
+ cisco.ios.ios_ospfv2:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "processes": [
+# {
+# "areas": [
+# {
+# "area_id": "5",
+# "authentication": {
+# "message_digest": true
+# },
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# },
+# "translate": "suppress-fa"
+# }
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 5
+# },
+# "domain_id": {
+# "ip_address": {
+# "address": "192.0.5.1"
+# }
+# },
+# "process_id": 100
+# }
+# ]
+# }
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['router ospf 200 vrf blue', 'auto-cost reference-bandwidth 5', 'domain-id 192.0.4.1']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv2.ospfv2 import (
+ Ospfv2,
+)
+
+
+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=Ospfv2Args.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ result = Ospfv2(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py
new file mode 100644
index 00000000..f566a2e2
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py
@@ -0,0 +1,1974 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospfv3
+"""
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_ospfv3
+short_description: OSPFv3 resource module
+description: This module configures and manages the Open Shortest Path First (OSPF)
+ version 3 on IOS platforms.
+version_added: 1.1.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+options:
+ config:
+ description: A list of configurations for ospfv3.
+ type: dict
+ suboptions:
+ processes:
+ description: List of OSPF instance configurations.
+ type: list
+ elements: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ required: true
+ type: int
+ address_family:
+ description: Enter Address Family command mode
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description: Enter Address Family command mode
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ unicast:
+ description: Address Family modifier
+ type: bool
+ vrf:
+ description: Specify parameters for a VPN Routing/Forwarding instance
+ type: str
+ adjacency:
+ description: Control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ disable:
+ description: Disable adjacency staggering
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ 'null':
+ description: Use no authentication
+ type: bool
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ filter_list:
+ description: Filter networks between OSPFv3 areas
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ direction:
+ description: The direction to apply on the filter networks sent to and from this area.
+ type: str
+ choices: ['in', 'out']
+ required: True
+ normal:
+ description: Specify a normal area type
+ type: bool
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ['always', 'suppress-fa']
+ ranges:
+ description: Summarize routes matching address/mask (border routers only)
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: IP address to match
+ type: str
+ netmask:
+ description: IP mask for address
+ type: str
+ advertise:
+ description:
+ - Advertise this range (default)
+ - Since, advertise when enabled is not shown in running-config
+ idempotency won't be maintained for the play in the second or
+ next run of the play.
+ type: bool
+ cost:
+ description: User specified metric for this range
+ type: int
+ not_advertise:
+ description: DoNotAdvertise this range
+ type: bool
+ sham_link:
+ description: Define a sham link and its parameters
+ type: dict
+ suboptions:
+ source:
+ description: IPv6 address associated with sham-link source (X:X:X:X::X)
+ type: str
+ destination:
+ description: IPv6 address associated with sham-link destination (X:X:X:X::X)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ 'null':
+ description: Use no authentication
+ type: bool
+ cost:
+ description:
+ - Associate a cost with the sham-link
+ - Cost of the sham-link
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - maximum number of hops allowed
+ type: int
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ authentication:
+ description:
+ - Authentication parameters
+ - Authentication operation mode
+ type: dict
+ suboptions:
+ deployment:
+ description: Deployment mode of operation
+ type: bool
+ normal:
+ description: Normal mode of operation
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description: BFD configuration commands
+ type: dict
+ suboptions:
+ all_interfaces:
+ description: Enable BFD on all interfaces
+ type: bool
+ disable:
+ description: Disable BFD on all interfaces
+ type: bool
+ capability:
+ description:
+ - Enable a specific feature
+ - Do not perform PE specific checks
+ type: bool
+ compatible:
+ description: OSPFv3 router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ default_information:
+ description: Control distribution of default information
+ type: dict
+ suboptions:
+ originate:
+ description: Distribute a default route
+ type: bool
+ always:
+ description: Always advertise default route
+ type: bool
+ metric:
+ description:
+ - OSPF default metric
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ route_map:
+ description: Route-map reference name
+ type: str
+ default_metric:
+ description: Set metric of redistributed routes
+ type: int
+ discard_route:
+ description: Enable or disable discard-route installation
+ type: dict
+ suboptions:
+ sham_link:
+ description: Discard route for sham-link routes
+ type: bool
+ external:
+ description: Discard route for summarised redistributed routes
+ type: bool
+ internal:
+ description: Discard route for summarised inter-area routes
+ type: bool
+ distance:
+ description:
+ - Define an administrative distance
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ distribute_list:
+ description: Filter networks in routing updates
+ type: dict
+ suboptions:
+ acls:
+ description: IP access list
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: IP access list name/number
+ type: str
+ required: true
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ['in', 'out']
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ prefix:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ required: true
+ gateway_name:
+ description: Gateway name for filtering incoming updates based on gateway
+ type: str
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ['in', 'out']
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ route_map:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Route-map name
+ type: str
+ required: true
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ graceful_restart:
+ description:
+ - Graceful-restart options
+ - helper support
+ type: dict
+ suboptions:
+ enable:
+ description: helper support enabled
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ interface_id:
+ description: Source of the interface ID
+ type: dict
+ suboptions:
+ ios_if_index:
+ description: IOS interface number
+ type: bool
+ snmp_if_index:
+ description: SNMP MIB ifIndex
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ manet:
+ description: Specify MANET OSPF parameters
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description:
+ - Specify MANET acknowledgement cache size
+ - Maximum number of acknowledgements in cache
+ type: int
+ update:
+ description:
+ - Specify MANET LSA cache size
+ - Maximum number of LSAs in cache
+ type: int
+ hello:
+ description: Unicast Hellos rather than multicast
+ type: dict
+ suboptions:
+ multicast:
+ description: Multicast Hello requests and responses rather than unicast
+ type: bool
+ unicast:
+ description: Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ disable:
+ description: Disable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description:
+ - Set maximum metric
+ - Maximum metric in self-originated router-LSAs
+ type: dict
+ suboptions:
+ disable:
+ description: disable maximum metric in self-originated router-LSAs
+ type: bool
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ inter_area_lsas:
+ description:
+ - Override inter-area-lsas metric with max-metric value
+ - Overriding metric in inter-area-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ stub_prefix_lsa:
+ description: Set maximum metric for stub links in prefix LSAs
+ type: bool
+ maximum_paths:
+ description:
+ - Forward packets over multiple paths
+ - Number of paths
+ type: int
+ passive_interface:
+ description: Suppress routing updates on an interface
+ type: str
+ prefix_suppression:
+ description: Prefix suppression
+ type: dict
+ suboptions:
+ enable:
+ description: Enable prefix suppression
+ type: bool
+ disable:
+ description: Disable prefix suppression
+ type: bool
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ update:
+ description: OSPF Router process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: dict
+ suboptions:
+ enable:
+ description: Shutdown the router process
+ type: bool
+ disable:
+ description: Disable Shutdown
+ type: bool
+ summary_prefix:
+ description: Configure IP address summaries
+ type: dict
+ suboptions:
+ address:
+ description:
+ - IP summary address (A.B.C.D)
+ - IP prefix <network>/<length> (A.B.C.D/nn)
+ type: str
+ mask:
+ description: IP Summary mask
+ type: str
+ not_advertise:
+ description: Do not advertise or translate
+ type: bool
+ nssa_only:
+ description: Limit summary to NSSA areas
+ type: bool
+ tag:
+ description: Set tag
+ type: int
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ manet:
+ description: OSPF MANET timers
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ adjacency:
+ description: Control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ ipsec:
+ description: Use IPsec authentication
+ type: dict
+ suboptions:
+ spi:
+ description: Set the SPI (Security Parameters Index)
+ type: int
+ md5:
+ description: Use MD5 authentication
+ type: int
+ sha1:
+ description: Use SHA-1 authentication
+ type: int
+ hex_string:
+ description: SHA-1 key (40 chars)
+ type: str
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ['always', 'suppress-fa']
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ authentication:
+ description:
+ - Authentication parameter mode
+ - Deployment mode of operation
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable BFD on all interfaces
+ type: bool
+ compatible:
+ description: OSPFv3 router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ graceful_restart:
+ description: Graceful-restart options for helper support
+ type: dict
+ suboptions:
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ help:
+ description: Description of the interactive help system
+ type: bool
+ interface_id:
+ description:
+ - Source of the interface ID
+ - SNMP MIB ifIndex
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ manet:
+ description: Specify MANET OSPF parameters
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description: Set maximum metric
+ type: dict
+ suboptions:
+ router_lsa:
+ description: Maximum metric in self-originated router-LSAs
+ type: bool
+ required: true
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ include_stub:
+ description: Set maximum metric for stub links in router-LSAs
+ type: bool
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ summary_lsa:
+ description:
+ - Override summary-lsa metric with max-metric value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ passive_interface:
+ description: Suppress routing updates on an interface
+ type: str
+ prefix_suppression:
+ description: Enable prefix suppression
+ type: bool
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: bool
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ manet:
+ description: OSPF MANET timers
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(sh running-config | section ^router ospfv3).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - parsed
+ - rendered
+ default: merged
+
+"""
+EXAMPLES = """
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Delete provided OSPF V3 processes
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using deleted without any config passed (NOTE: This will delete all OSPFV3 configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Delete all OSPF processes
+ cisco.ios.ios_ospfv3:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 200",
+# "no router ospfv3 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router-ios#
+
+- name: Merge provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ address_family:
+ - afi: ipv4
+ unicast: true
+ vrf: blue
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 25
+ nssa:
+ default_information_originate:
+ metric: 25
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ timers:
+ throttle:
+ lsa:
+ first_delay: 12
+ min_delay: 14
+ max_delay: 16
+ - process_id: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 200
+ max_adjacency: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "router ospfv3 1",
+# "max-metric router-lsa on-startup 110",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast vrf blue",
+# "adjacency stagger 50 50",
+# "area 25 nssa default-information-originate metric 25 nssa-only",
+# "exit-address-family",
+# "router ospfv3 200",
+# "auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 100",
+# "address-family ipv4 unicast",
+# "adjacency stagger 200 200",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Override provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 200
+ nssa:
+ default_information_originate:
+ metric: 200
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 1",
+# "router ospfv3 200",
+# "no auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 200",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast",
+# "adjacency stagger 50 50",
+# "area 200 nssa default-information-originate metric 200 nssa-only",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 200
+# max-metric router-lsa on-startup 200
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast
+# adjacency stagger 50 50
+# area 200 nssa default-information-originate metric 200 nssa-only
+# exit-address-family
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Replaced provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 200
+ nssa:
+ default_information_originate:
+ metric: 200
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "router ospfv3 200",
+# "no auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 200",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast",
+# "adjacency stagger 50 50",
+# "area 200 nssa default-information-originate metric 200 nssa-only",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 200
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast
+# adjacency stagger 50 50
+# area 200 nssa default-information-originate metric 200 nssa-only
+# exit-address-family
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Gather OSPFV3 provided configurations
+ cisco.ios.ios_ospfv3:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "processes": [
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 50,
+# "min_adjacency": 50
+# },
+# "afi": "ipv4",
+# "areas": [
+# {
+# "area_id": "25",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 25,
+# "nssa_only": true
+# }
+# }
+# }
+# ],
+# "unicast": true,
+# "vrf": "blue"
+# }
+# ],
+# "areas": [
+# {
+# "area_id": "10",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# }
+# }
+# }
+# ],
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "process_id": 1
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 200,
+# "min_adjacency": 200
+# },
+# "afi": "ipv4",
+# "unicast": true
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 4
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 100
+# },
+# "router_lsa": true
+# },
+# "process_id": 200
+# }
+# ]
+# }
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ address_family:
+ - afi: ipv4
+ unicast: true
+ vrf: blue
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 25
+ nssa:
+ default_information_originate:
+ metric: 25
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ timers:
+ throttle:
+ lsa:
+ first_delay: 12
+ min_delay: 14
+ max_delay: 16
+ - process_id: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 200
+ max_adjacency: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "router ospfv3 1",
+# "max-metric router-lsa on-startup 110",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast vrf blue",
+# "adjacency stagger 50 50",
+# "area 25 nssa default-information-originate metric 25 nssa-only",
+# "exit-address-family",
+# "router ospfv3 200",
+# "auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 100",
+# "address-family ipv4 unicast",
+# "adjacency stagger 200 200",
+# "exit-address-family"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Parse the provided configuration with the exisiting running configuration
+ cisco.ios.ios_ospfv3:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "processes": [
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 50,
+# "min_adjacency": 50
+# },
+# "afi": "ipv4",
+# "areas": [
+# {
+# "area_id": "25",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 25,
+# "nssa_only": true
+# }
+# }
+# }
+# ],
+# "unicast": true,
+# "vrf": "blue"
+# }
+# ],
+# "areas": [
+# {
+# "area_id": "10",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# }
+# }
+# }
+# ],
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "process_id": 1
+# }
+# ]
+# }
+
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['router ospfv3 1', 'address-family ipv4 unicast vrf blue', 'adjacency stagger 50 50']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv3.ospfv3 import (
+ Ospfv3,
+)
+
+
+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=Ospfv3Args.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ result = Ospfv3(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py
new file mode 100644
index 00000000..b67edc57
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_ping.py
@@ -0,0 +1,242 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+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.
+version_added: 1.0.0
+author:
+- Jacob McGill (@jmcgill298)
+extends_documentation_fragment:
+- cisco.ios.ios
+options:
+ count:
+ description:
+ - Number of packets to send.
+ type: int
+ dest:
+ description:
+ - The IP Address or hostname (resolvable by switch) of the remote node.
+ required: true
+ type: str
+ df_bit:
+ description:
+ - Set the DF bit.
+ default: false
+ type: bool
+ size:
+ description:
+ - Size of packets to send.
+ type: int
+ source:
+ description:
+ - The source IP Address.
+ type: str
+ state:
+ description:
+ - Determines if the expected result is success or fail.
+ choices:
+ - absent
+ - present
+ default: present
+ type: str
+ vrf:
+ description:
+ - The VRF to use for forwarding.
+ type: str
+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 = """
+- name: Test reachability to 10.10.10.10 using default vrf
+ cisco.ios.ios_ping:
+ dest: 10.10.10.10
+
+- name: Test reachability to 10.20.20.20 using prod vrf
+ cisco.ios.ios_ping:
+ dest: 10.20.20.20
+ vrf: prod
+
+- name: Test unreachability to 10.30.30.30 using default vrf
+ cisco.ios.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
+ cisco.ios.ios_ping:
+ dest: 10.40.40.40
+ source: loopback0
+ vrf: prod
+ count: 20
+
+- name: Test reachability to 10.50.50.50 using df-bit and size
+ cisco.ios.ios_ping:
+ dest: 10.50.50.50
+ df_bit: true
+ size: 1400
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ run_commands,
+)
+from ansible_collections.cisco.ios.plugins.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),
+ df_bit=dict(type="bool", default=False),
+ size=dict(type="int"),
+ 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"]
+ df_bit = module.params["df_bit"]
+ size = module.params["size"]
+ source = module.params["source"]
+ vrf = module.params["vrf"]
+ warnings = list()
+ results = {}
+ if warnings:
+ results["warnings"] = warnings
+ results["commands"] = [build_ping(dest, count, source, vrf, size, df_bit)]
+ 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, size=None, df_bit=False
+):
+ """
+ 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 size is not None:
+ cmd += " size {0}".format(size)
+ if df_bit:
+ cmd += " df-bit"
+ 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(
+ "^\\w+\\s+\\w+\\s+\\w+\\s+(?P<pct>\\d+)\\s+\\w+\\s+\\((?P<rx>\\d+)/(?P<tx>\\d+)\\)"
+ )
+ rtt_re = re.compile(
+ ".*,\\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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py
new file mode 100644
index 00000000..a3b5a957
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_route.py
@@ -0,0 +1,372 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_static_route
+author: Ricardo Carrillo Cruz (@rcarrillocruz)
+short_description: (deprecated, removed after 2022-06-01) Manage static IP routes
+ on Cisco IOS network devices
+description:
+- This module provides declarative management of static IP routes on Cisco IOS network
+ devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_static_routes
+ why: Newer and updated modules released with more functionality.
+ removed_at_date: '2022-06-01'
+notes:
+- Tested against IOS 15.6
+options:
+ prefix:
+ description:
+ - Network prefix of the static route.
+ type: str
+ mask:
+ description:
+ - Network prefix mask of the static route.
+ type: str
+ next_hop:
+ description:
+ - Next hop IP of the static route.
+ type: str
+ vrf:
+ description:
+ - VRF of the static route.
+ type: str
+ interface:
+ description:
+ - Interface of the static route.
+ type: str
+ name:
+ description:
+ - Name of the static route
+ type: str
+ aliases:
+ - description
+ admin_distance:
+ description:
+ - Admin distance of the static route.
+ type: str
+ tag:
+ description:
+ - Set tag of the static route.
+ type: str
+ track:
+ description:
+ - Tracked item to depend on for the static route.
+ type: str
+ aggregate:
+ description: List of static route definitions.
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description:
+ - Network prefix of the static route.
+ type: str
+ required: true
+ mask:
+ description:
+ - Network prefix mask of the static route.
+ type: str
+ next_hop:
+ description:
+ - Next hop IP of the static route.
+ type: str
+ vrf:
+ description:
+ - VRF of the static route.
+ type: str
+ interface:
+ description:
+ - Interface of the static route.
+ type: str
+ name:
+ description:
+ - Name of the static route
+ aliases:
+ - description
+ type: str
+ admin_distance:
+ description:
+ - Admin distance of the static route.
+ type: str
+ tag:
+ description:
+ - Set tag of the static route.
+ type: str
+ track:
+ description:
+ - Tracked item to depend on for the static route.
+ type: str
+ state:
+ description:
+ - State of the static route configuration.
+ choices:
+ - present
+ - absent
+ type: str
+ state:
+ description:
+ - State of the static route configuration.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+"""
+EXAMPLES = """
+- name: configure static route
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.ios_static_route:
+ prefix: 192.168.2.0
+ mask: 255.255.255.0
+ interface: GigabitEthernet1
+ name: hello world
+ tag: 100
+
+- name: remove configuration
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+ validate_ip_address,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.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:
+ # Try to match an existing config with the desired config
+ 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
+ # Try to match an existing config with the desired config
+ if (
+ 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)))
+ 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():
+ # Split by whitespace but do not split quotes, needed for name parameter
+ splitted_line = findall('[^"\\s]\\S*|".+?"', line)
+ 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('"')
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py
new file mode 100644
index 00000000..f8115095
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py
@@ -0,0 +1,692 @@
+#!/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/>.
+#
+"""
+The module file for ios_static_routes
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_static_routes
+short_description: Static routes resource module
+description: This module configures and manages the static routes on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSv Version 15.2 on VIRL.
+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:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(show running-config | include ip route|ipv6 route).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ 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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.static_routes.static_routes import (
+ Static_RoutesArgs,
+)
+from ansible_collections.cisco.ios.plugins.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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py
new file mode 100644
index 00000000..208270bc
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_system.py
@@ -0,0 +1,382 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_system
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.ios
+notes:
+- Tested against IOS 15.6
+options:
+ hostname:
+ description:
+ - Configure the device hostname parameter. This option takes an ASCII string value.
+ type: str
+ 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.
+ type: list
+ elements: raw
+ 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.
+ type: list
+ elements: raw
+ 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.
+ type: str
+ 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.
+ type: list
+ elements: raw
+ 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
+ type: str
+"""
+EXAMPLES = """
+- name: configure hostname and domain name
+ cisco.ios.ios_system:
+ hostname: ios01
+ domain_name: test.example.com
+ domain_search:
+ - ansible.com
+ - redhat.com
+ - cisco.com
+
+- name: remove configuration
+ cisco.ios.ios_system:
+ state: absent
+
+- name: configure DNS lookup sources
+ cisco.ios.ios_system:
+ lookup_source: MgmtEth0/0/CPU0/0
+ lookup_enabled: yes
+
+- name: configure name servers
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+from ansible_collections.ansible.netcommon.plugins.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("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("^hostname (\\S+)", config, re.M)
+ return match.group(1)
+
+
+def parse_domain_name(config):
+ match = re.findall(
+ "^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(
+ "^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("^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(
+ "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", elements="raw"),
+ domain_search=dict(type="list", elements="raw"),
+ name_servers=dict(type="list", elements="raw"),
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py
new file mode 100644
index 00000000..8c94ef96
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_user.py
@@ -0,0 +1,616 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_user
+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.
+version_added: 1.0.0
+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
+ type: list
+ elements: dict
+ suboptions:
+ 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).
+ type: str
+ required: true
+ 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).
+ type: str
+ 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.
+ choices:
+ - on_create
+ - always
+ type: str
+ password_type:
+ description:
+ - This argument determines whether a 'password' or 'secret' will be configured.
+ choices:
+ - secret
+ - password
+ type: str
+ hashed_password:
+ description:
+ - This option allows configuring hashed passwords on Cisco IOS devices.
+ type: dict
+ 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
+ type: str
+ 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.
+ type: int
+ 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
+ type: str
+ sshkey:
+ description:
+ - Specifies one or more SSH public key(s) to configure for the given username.
+ - This argument accepts a valid SSH key value.
+ type: list
+ elements: str
+ 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
+ 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
+ choices:
+ - present
+ - absent
+ type: str
+ 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).
+ type: str
+ 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).
+ type: str
+ 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
+ type: str
+ password_type:
+ description:
+ - This argument determines whether a 'password' or 'secret' will be configured.
+ default: secret
+ choices:
+ - secret
+ - password
+ type: str
+ hashed_password:
+ description:
+ - This option allows configuring hashed passwords on Cisco IOS devices.
+ type: dict
+ 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
+ type: str
+ 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.
+ type: int
+ 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
+ type: str
+ sshkey:
+ description:
+ - Specifies one or more SSH public key(s) to configure for the given username.
+ - This argument accepts a valid SSH key value.
+ type: list
+ elements: str
+ 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
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+"""
+EXAMPLES = """
+- name: create a new user
+ cisco.ios.ios_user:
+ name: ansible
+ nopassword: true
+ sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
+ state: present
+
+- name: create a new user with multiple keys
+ cisco.ios.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
+ cisco.ios.ios_user:
+ purge: yes
+
+- name: remove all users except admin and these listed users
+ cisco.ios.ios_user:
+ aggregate:
+ - name: testuser1
+ - name: testuser2
+ - name: testuser3
+ purge: yes
+
+- name: set multiple users to privilege level 15
+ cisco.ios.ios_user:
+ aggregate:
+ - name: netop
+ - name: netend
+ privilege: 15
+ state: present
+
+- name: set user view/role
+ cisco.ios.ios_user:
+ name: netop
+ view: network-operator
+ state: present
+
+- name: Change Password for User netop
+ cisco.ios.ios_user:
+ name: netop
+ configured_password: '{{ new_password }}'
+ update_password: always
+ state: present
+
+- name: Aggregate of users
+ cisco.ios.ios_user:
+ aggregate:
+ - name: ansibletest2
+ - name: ansibletest3
+ view: network-admin
+
+- name: Add a user specifying password type
+ cisco.ios.ios_user:
+ name: ansibletest4
+ configured_password: '{{ new_password }}'
+ password_type: password
+
+- name: Add a user with MD5 hashed password
+ cisco.ios.ios_user:
+ name: ansibletest5
+ hashed_password:
+ type: 5
+ value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/
+
+- name: Delete users with aggregate
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+from ansible_collections.cisco.ios.plugins.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("view (\\S+)", data, re.M)
+ if match:
+ return match.group(1)
+
+
+def parse_sshkey(data, user):
+ sshregex = "username %s(\\n\\s+key-hash .+$)+" % user
+ sshcfg = re.search(sshregex, data, re.M)
+ key_list = []
+ if sshcfg:
+ match = re.findall(
+ "key-hash (\\S+ \\S+(?: .+)?)$", sshcfg.group(), re.M
+ )
+ if match:
+ key_list = match
+ return key_list
+
+
+def parse_privilege(data):
+ match = re.search("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("(?:^(?:u|\\s{2}u))sername (\\S+)", data, re.M)
+ if not match:
+ return list()
+ instances = list()
+ for user in set(match):
+ regex = "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", elements="str"),
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py
new file mode 100644
index 00000000..f18f3027
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlan.py
@@ -0,0 +1,416 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_vlan
+author: Trishna Guha (@trishnaguha)
+short_description: (deprecated, removed after 2022-06-01) Manage VLANs on IOS network
+ devices
+description:
+- This module provides declarative management of VLANs on Cisco IOS network devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_vlans
+ why: Newer and updated modules released with more functionality in Ansible 2.9
+ removed_at_date: '2022-06-01'
+notes:
+- Tested against IOS 15.2
+options:
+ name:
+ description:
+ - Name of the VLAN.
+ type: str
+ vlan_id:
+ description:
+ - ID of the VLAN. Range 1-4094.
+ type: int
+ interfaces:
+ description:
+ - List of interfaces that should be associated to the VLAN.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ delay:
+ description:
+ - Delay the play should wait to check for declarative intent params values.
+ default: 10
+ type: int
+ aggregate:
+ description: List of VLANs definitions.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the VLAN.
+ type: str
+ vlan_id:
+ description:
+ - ID of the VLAN. Range 1-4094.
+ required: true
+ type: str
+ interfaces:
+ description:
+ - List of interfaces that should be associated to the VLAN.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ delay:
+ description:
+ - Delay the play should wait to check for declarative intent params values.
+ type: int
+ state:
+ description:
+ - State of the VLAN configuration.
+ type: str
+ choices:
+ - present
+ - absent
+ - active
+ - suspend
+ purge:
+ description:
+ - Purge VLANs not defined in the I(aggregate) parameter.
+ default: false
+ type: bool
+ state:
+ description:
+ - State of the VLAN configuration.
+ default: present
+ choices:
+ - present
+ - absent
+ - active
+ - suspend
+ type: str
+extends_documentation_fragment:
+- cisco.ios.ios
+
+
+"""
+EXAMPLES = """
+- name: Create vlan
+ cisco.ios.ios_vlan:
+ vlan_id: 100
+ name: test-vlan
+ state: present
+
+- name: Add interfaces to VLAN
+ cisco.ios.ios_vlan:
+ vlan_id: 100
+ interfaces:
+ - GigabitEthernet0/0
+ - GigabitEthernet0/1
+
+- name: Check if interfaces is assigned to VLAN
+ cisco.ios.ios_vlan:
+ vlan_id: 100
+ associated_interfaces:
+ - GigabitEthernet0/0
+ - GigabitEthernet0/1
+
+- name: Delete vlan
+ cisco.ios.ios_vlan:
+ vlan_id: 100
+ state: absent
+
+- name: Add vlan using aggregate
+ cisco.ios.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
+ cisco.ios.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ load_config,
+ run_commands,
+ normalize_interface,
+)
+from ansible_collections.cisco.ios.plugins.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)
+ 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(
+ "(?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", elements="str"),
+ associated_interfaces=dict(type="list", elements="str"),
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py
new file mode 100644
index 00000000..d215a62e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py
@@ -0,0 +1,748 @@
+#!/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/>.
+#
+"""
+The module file for ios_vlans
+"""
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_vlans
+short_description: VLANs resource module
+description: This module provides declarative management of VLANs on Cisco IOS network
+ devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+- Tested against Cisco IOSl2 device with Version 15.2 on VIRL.
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show vlan).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ 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
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios_l2#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
+ cisco.ios.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_l2#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_l2#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
+ cisco.ios.ios_vlans:
+ config:
+ - name: Vlan_10
+ vlan_id: 10
+ mtu: 1000
+ state: overridden
+
+# After state:
+# ------------
+#
+# vios_l2#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_l2#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
+ cisco.ios.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_l2#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_l2#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
+ cisco.ios.ios_vlans:
+ config:
+ - vlan_id: 10
+ - vlan_id: 20
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios_l2#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_l2#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
+ cisco.ios.ios_vlans:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios_l2#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
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios_l2#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: Gather listed vlans with provided configurations
+ cisco.ios.ios_vlans:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "mtu": 1500,
+# "name": "default",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0010",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0020",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0030",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 30
+# },
+# {
+# "mtu": 1500,
+# "name": "fddi-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1002
+# },
+# {
+# "mtu": 1500,
+# "name": "token-ring-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1003
+# },
+# {
+# "mtu": 1500,
+# "name": "fddinet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1004
+# },
+# {
+# "mtu": 1500,
+# "name": "trnet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1005
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios_l2#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 Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.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: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "vlan 10",
+# "name Vlan_10",
+# "state active",
+# "remote-span",
+# "no shutdown",
+# "vlan 20",
+# "name Vlan_20",
+# "state active",
+# "mtu 610",
+# "shutdown",
+# "vlan 30",
+# "name Vlan_30",
+# "state suspend",
+# "shutdown"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# 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 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
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_vlans:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "mtu": 1500,
+# "name": "default",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_10",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_20",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_30",
+# "shutdown": "enabled",
+# "state": "suspend",
+# "vlan_id": 30
+# },
+# {
+# "mtu": 1500,
+# "name": "fddi-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1002
+# },
+# {
+# "mtu": 1500,
+# "name": "token-ring-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1003
+# },
+# {
+# "mtu": 1500,
+# "name": "fddinet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1004
+# },
+# {
+# "mtu": 1500,
+# "name": "trnet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1005
+# }
+# ]
+
+"""
+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_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vlans.vlans import (
+ VlansArgs,
+)
+from ansible_collections.cisco.ios.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=VlansArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Vlans(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py
new file mode 100644
index 00000000..b86df5a0
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py
@@ -0,0 +1,750 @@
+#!/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/>.
+#
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_vrf
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- cisco.ios.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.
+ type: list
+ elements: raw
+ 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
+ type: str
+ 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.
+ type: str
+ 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.
+ type: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ delay:
+ description:
+ - Time in seconds to wait before checking for the operational state on remote
+ device.
+ default: 10
+ type: int
+ 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
+ type: str
+ route_both:
+ description:
+ - Adds an export and import list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_export:
+ description:
+ - Adds an export list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_import:
+ description:
+ - Adds an import list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_both_ipv4:
+ description:
+ - Adds an export and import list of extended route target communities in address-family
+ configuration submode to the VRF.
+ type: list
+ elements: str
+ route_export_ipv4:
+ description:
+ - Adds an export list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_import_ipv4:
+ description:
+ - Adds an import list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_both_ipv6:
+ description:
+ - Adds an export and import list of extended route target communities in address-family
+ configuration submode to the VRF.
+ type: list
+ elements: str
+ route_export_ipv6:
+ description:
+ - Adds an export list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_import_ipv6:
+ description:
+ - Adds an import list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+"""
+EXAMPLES = """
+- name: configure a vrf named management
+ cisco.ios.ios_vrf:
+ name: management
+ description: oob mgmt vrf
+ interfaces:
+ - Management1
+
+- name: remove a vrf named test
+ cisco.ios.ios_vrf:
+ name: test
+ state: absent
+
+- name: configure set of VRFs and purge any others
+ cisco.ios.ios_vrf:
+ vrfs:
+ - red
+ - blue
+ - green
+ purge: yes
+
+- name: Creates a list of import RTs for the VRF with the same parameters
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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
+ cisco.ios.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_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ load_config,
+ get_config,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ ios_argument_spec,
+)
+from ansible_collections.ansible.netcommon.plugins.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:
+ for intf in set(have.get("interfaces", [])).difference(
+ want["interfaces"]
+ ):
+ commands.extend(
+ [
+ "interface %s" % intf,
+ "no vrf forwarding %s" % want["name"],
+ ]
+ )
+ 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("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("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("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("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("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("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("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("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("^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()
+ 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", elements="raw"),
+ name=dict(),
+ description=dict(),
+ rd=dict(),
+ route_export=dict(type="list", elements="str"),
+ route_import=dict(type="list", elements="str"),
+ route_both=dict(type="list", elements="str"),
+ route_export_ipv4=dict(type="list", elements="str"),
+ route_import_ipv4=dict(type="list", elements="str"),
+ route_both_ipv4=dict(type="list", elements="str"),
+ route_export_ipv6=dict(type="list", elements="str"),
+ route_import_ipv6=dict(type="list", elements="str"),
+ route_both_ipv6=dict(type="list", elements="str"),
+ interfaces=dict(type="list", elements="str"),
+ associated_interfaces=dict(type="list", elements="str"),
+ 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/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/__init__.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/ios.py b/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/ios.py
new file mode 100644
index 00000000..f519952c
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/ios/plugins/terminal/ios.py
@@ -0,0 +1,116 @@
+#
+# (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"),
+ re.compile(br"Command Rejected: ?[\s]+", re.I),
+ ]
+
+ 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")