summaryrefslogtreecommitdiffstats
path: root/ansible_collections/cisco/asa/plugins/module_utils
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/cisco/asa/plugins/module_utils
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/cisco/asa/plugins/module_utils')
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py293
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py29
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py261
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py156
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py237
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py694
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py107
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py70
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py185
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py98
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py71
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py126
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py249
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py538
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py0
-rw-r--r--ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py320
30 files changed, 3434 insertions, 0 deletions
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py
new file mode 100644
index 000000000..f27708e8a
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py
@@ -0,0 +1,293 @@
+# -*- 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 asa_acls module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class AclsArgs(object):
+ """The arg spec for the asa_acls module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "acls": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "acl_type": {
+ "choices": ["extended", "standard"],
+ "type": "str",
+ },
+ "rename": {"type": "str"},
+ "aces": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "grant": {
+ "choices": ["permit", "deny"],
+ "type": "str",
+ },
+ "line": {"type": "int"},
+ "remark": {"type": "str"},
+ "source": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "any": {"type": "bool"},
+ "any4": {"type": "bool"},
+ "any6": {"type": "bool"},
+ "host": {"type": "str"},
+ "interface": {"type": "str"},
+ "object_group": {"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",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "any": {"type": "bool"},
+ "any4": {"type": "bool"},
+ "any6": {"type": "bool"},
+ "host": {"type": "str"},
+ "interface": {"type": "str"},
+ "object_group": {"type": "str"},
+ "service_object_group": {
+ "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"},
+ "icmp": {
+ "type": "dict",
+ "options": {
+ "alternate_address": {
+ "type": "bool",
+ },
+ "conversion_error": {
+ "type": "bool",
+ },
+ "echo": {"type": "bool"},
+ "echo_reply": {"type": "bool"},
+ "information_reply": {
+ "type": "bool",
+ },
+ "information_request": {
+ "type": "bool",
+ },
+ "mask_reply": {"type": "bool"},
+ "mask_request": {
+ "type": "bool",
+ },
+ "mobile_redirect": {
+ "type": "bool",
+ },
+ "parameter_problem": {
+ "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"},
+ "unreachable": {
+ "type": "bool",
+ },
+ },
+ },
+ "icmp6": {
+ "type": "dict",
+ "options": {
+ "echo": {"type": "bool"},
+ "echo_reply": {"type": "bool"},
+ "membership_query": {
+ "type": "bool",
+ },
+ "membership_reduction": {
+ "type": "bool",
+ },
+ "membership_report": {
+ "type": "bool",
+ },
+ "neighbor_advertisement": {
+ "type": "bool",
+ },
+ "neighbor_redirect": {
+ "type": "bool",
+ },
+ "neighbor_solicitation": {
+ "type": "bool",
+ },
+ "packet_too_big": {
+ "type": "bool",
+ },
+ "parameter_problem": {
+ "type": "bool",
+ },
+ "router_advertisement": {
+ "type": "bool",
+ },
+ "router_renumbering": {
+ "type": "bool",
+ },
+ "router_solicitation": {
+ "type": "bool",
+ },
+ "time_exceeded": {
+ "type": "bool",
+ },
+ "unreachable": {
+ "type": "bool",
+ },
+ },
+ },
+ "igmp": {"type": "bool"},
+ "igrp": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "ipinip": {"type": "bool"},
+ "ipsec": {"type": "bool"},
+ "nos": {"type": "bool"},
+ "ospf": {"type": "bool"},
+ "pcp": {"type": "bool"},
+ "pim": {"type": "bool"},
+ "pptp": {"type": "bool"},
+ "sctp": {"type": "bool"},
+ "snp": {"type": "bool"},
+ "tcp": {"type": "bool"},
+ "udp": {"type": "bool"},
+ },
+ },
+ "inactive": {"type": "bool"},
+ "log": {
+ "type": "str",
+ "choices": [
+ "default",
+ "alerts",
+ "critical",
+ "debugging",
+ "disable",
+ "emergencies",
+ "errors",
+ "informational",
+ "interval",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "time_range": {"type": "str"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py
new file mode 100644
index 000000000..af6d008dd
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py
@@ -0,0 +1,29 @@
+#
+# -*- 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 asa facts module.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class FactsArgs(object):
+ """The arg spec for the asa 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/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py
new file mode 100644
index 000000000..65c9daccb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py
@@ -0,0 +1,261 @@
+# -*- 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 asa_ogs module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class OGsArgs(object):
+ """The arg spec for the asa_ogs module"""
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "object_type": {
+ "type": "str",
+ "required": True,
+ "choices": [
+ "icmp-type",
+ "network",
+ "protocol",
+ "security",
+ "service",
+ "user",
+ ],
+ },
+ "object_groups": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "description": {"type": "str"},
+ "icmp_type": {
+ "type": "dict",
+ "options": {
+ "icmp_object": {
+ "type": "list",
+ "elements": "str",
+ "choices": [
+ "alternate-address",
+ "conversion-error",
+ "echo",
+ "echo-reply",
+ "information-reply",
+ "information-request",
+ "mask-reply",
+ "mask-request",
+ "mobile-redirect",
+ "parameter-problem",
+ "redirect",
+ "router-advertisement",
+ "router-solicitation",
+ "source-quench",
+ "time-exceeded",
+ "timestamp-reply",
+ "timestamp-request",
+ "traceroute",
+ "unreachable",
+ ],
+ },
+ },
+ },
+ "network_object": {
+ "type": "dict",
+ "options": {
+ "host": {"type": "list", "elements": "str"},
+ "address": {"type": "list", "elements": "str"},
+ "ipv6_address": {
+ "type": "list",
+ "elements": "str",
+ },
+ "object": {"type": "list", "elements": "str"},
+ },
+ },
+ "protocol_object": {
+ "type": "dict",
+ "options": {
+ "protocol": {"type": "list", "elements": "str"},
+ },
+ },
+ "security_group": {
+ "type": "dict",
+ "options": {
+ "sec_name": {
+ "type": "list",
+ "elements": "str",
+ },
+ "tag": {"type": "list", "elements": "str"},
+ },
+ },
+ "services_object": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "protocol": {"type": "str"},
+ "object": {"type": "str"},
+ "source_port": {
+ "type": "dict",
+ "options": {
+ "eq": {"type": "str"},
+ "gt": {"type": "str"},
+ "lt": {"type": "str"},
+ "neq": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "str"},
+ "end": {"type": "str"},
+ },
+ },
+ },
+ },
+ "destination_port": {
+ "type": "dict",
+ "options": {
+ "eq": {"type": "str"},
+ "gt": {"type": "str"},
+ "lt": {"type": "str"},
+ "neq": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "str"},
+ "end": {"type": "str"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "protocol": {
+ "type": "str",
+ "choices": ["tcp", "tcp-udp", "udp"],
+ },
+ "port_object": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "eq": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "str"},
+ "end": {"type": "str"},
+ },
+ },
+ },
+ },
+ "service_object": {
+ "type": "dict",
+ "options": {
+ "protocol": {
+ "type": "list",
+ "elements": "str",
+ "choices": [
+ "ah",
+ "eigrp",
+ "esp",
+ "gre",
+ "icmp",
+ "icmp6",
+ "igmp",
+ "igrp",
+ "ip",
+ "ipinip",
+ "ipsec",
+ "nos",
+ "ospf",
+ "pcp",
+ "pim",
+ "pptp",
+ "sctp",
+ "snp",
+ "tcp",
+ "tcp-udp",
+ "udp",
+ ],
+ },
+ "object": {"type": "str"},
+ },
+ },
+ "user_object": {
+ "type": "dict",
+ "options": {
+ "user": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {
+ "required": True,
+ "type": "str",
+ },
+ "domain": {
+ "required": True,
+ "type": "str",
+ },
+ },
+ },
+ "user_group": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {
+ "required": True,
+ "type": "str",
+ },
+ "domain": {
+ "required": True,
+ "type": "str",
+ },
+ },
+ },
+ },
+ },
+ "group_object": {"type": "list", "elements": "str"},
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py
new file mode 100644
index 000000000..7a19c7d30
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py
@@ -0,0 +1,156 @@
+# 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.connection import Connection, ConnectionError, exec_command
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ EntityCollection,
+)
+
+
+_DEVICE_CONFIGS = {}
+_CONNECTION = None
+
+command_spec = {"command": dict(key=True), "prompt": dict(), "answer": dict()}
+
+asa_argument_spec = {
+ "context": dict(type="str"),
+ "passwords": dict(type="bool"),
+}
+
+
+def check_args(module):
+ pass
+
+
+def get_connection(module):
+ if hasattr(module, "_asa_connection"):
+ return module._asa_connection
+
+ # Not all modules include the 'context' key.
+ context = module.params.get("context")
+ connection_proxy = Connection(module._socket_path)
+ cap = json.loads(connection_proxy.get_capabilities())
+ if cap["network_api"] == "cliconf":
+ module._asa_connection = Connection(module._socket_path)
+
+ if context:
+ if context == "system":
+ command = "changeto system"
+ else:
+ command = "changeto context %s" % context
+ module._asa_connection.get(command)
+
+ return module._asa_connection
+
+
+def get_capabilities(module):
+ if hasattr(module, "_asa_capabilities"):
+ return module._asa_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._asa_capabilities = json.loads(capabilities)
+
+ return module._asa_capabilities
+
+
+def to_commands(module, commands):
+ if not isinstance(commands, list):
+ raise AssertionError("argument must be of type <list>")
+
+ transform = EntityCollection(module, command_spec)
+ commands = transform(commands)
+
+ for index, item in enumerate(commands):
+ if module.check_mode and not item["command"].startswith("show"):
+ module.warn(
+ "only show commands are supported when using check "
+ "mode, not executing `%s`" % item["command"],
+ )
+
+ return commands
+
+
+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 get_config(module, flags=None):
+ flags = [] if flags is None else flags
+
+ # Not all modules include the 'passwords' key.
+ passwords = module.params.get("passwords", False)
+ if passwords:
+ cmd = "more system:running-config"
+ else:
+ cmd = "show running-config "
+ cmd += " ".join(flags)
+ cmd = cmd.strip()
+
+ try:
+ return _DEVICE_CONFIGS[cmd]
+ except KeyError:
+ conn = get_connection(module)
+ out = conn.get(cmd)
+ cfg = to_text(out, errors="surrogate_then_replace").strip()
+ _DEVICE_CONFIGS[cmd] = cfg
+ return cfg
+
+
+def load_config(module, config):
+ try:
+ conn = get_connection(module)
+ conn.edit_config(config)
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc))
+
+
+def get_defaults_flag(module):
+ rc, out, err = exec_command(module, "show running-config ?")
+ out = to_text(out, errors="surrogate_then_replace")
+
+ commands = set()
+ for line in out.splitlines():
+ if line:
+ commands.add(line.strip().split()[0])
+
+ if "all" in commands:
+ return "all"
+ else:
+ return "full"
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py
new file mode 100644
index 000000000..67c6ee9aa
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py
@@ -0,0 +1,237 @@
+#
+# -*- 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 asa_acls class
+It is in this file where the current configuration (as dict)
+is compared to the provided configuration (as dict) and the command set
+necessary to bring the current configuration to it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import copy
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import (
+ ResourceModule,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.facts import Facts
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.rm_templates.acls import (
+ AclsTemplate,
+)
+
+
+class Acls(ResourceModule):
+ """
+ The asa_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 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:
+ temp = {}
+ for entry in self.want["acls"]:
+ temp.update({(entry["name"]): entry})
+ wantd = temp
+ else:
+ wantd = {}
+ if self.have:
+ temp = {}
+ for entry in self.have["acls"]:
+ temp.update({(entry["name"]): entry})
+ haved = temp
+ else:
+ haved = {}
+
+ for k, want in iteritems(wantd):
+ h_want = haved.get(k, {})
+ if want.get("aces"):
+ for each in want["aces"]:
+ if h_want.get("aces"):
+ for e_have in h_want.get("aces"):
+ if e_have.get("source") == each.get("source") and e_have.get(
+ "destination",
+ ) == each.get(
+ "destination",
+ ):
+ if (
+ "protocol" in e_have
+ and "protocol" not in each
+ and each.get("protocol_options")
+ == e_have.get("protocol_options")
+ ):
+ del e_have["protocol"]
+ break
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ # to append line number from have to want
+ # if want ace config mateches have ace config
+ temp_have = copy.deepcopy(haved)
+ for k, v in iteritems(wantd):
+ h_item = temp_have.pop(k, {})
+ if not h_item:
+ continue
+ if v.get("aces"):
+ for each in v["aces"]:
+ if "line" in each:
+ continue
+ else:
+ for each_have in h_item["aces"]:
+ have_line = each_have.pop("line")
+ if each == each_have:
+ each.update({"line": have_line})
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted":
+ temp = {}
+ for k, v in iteritems(haved):
+ if k in wantd or not wantd:
+ temp.update({k: v})
+ haved = temp
+ 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)
+
+ temp = []
+ for k, want in iteritems(wantd):
+ if want.get("rename") and want.get("rename") not in temp:
+ self.commands.extend(
+ ["access-list {name} rename {rename}".format(**want)],
+ )
+ elif k in haved:
+ temp.append(k)
+ self._compare(want=want, have=haved.pop(k, {}))
+ if self.state in ["replaced", "overridden", "deleted"]:
+ config_cmd = [cmd for cmd in self.commands if "no" in cmd][::-1]
+ config_cmd.extend(
+ [cmd for cmd in self.commands if "no" not in cmd],
+ )
+ self.commands = config_cmd
+
+ 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"):
+ for each in want["aces"]:
+ set_want = True
+ if have.get("aces"):
+ temp = 0
+ for e_have in have.get("aces"):
+ if e_have.get("source") == each.get("source") and e_have.get(
+ "destination",
+ ) == each.get(
+ "destination",
+ ):
+ set_want = False
+ if each.get("protocol") == e_have.get("protocol"):
+ if not each.get(
+ "protocol_options",
+ ) and e_have.get("protocol_options"):
+ del e_have["protocol_options"]
+ if each == e_have:
+ del have.get("aces")[temp]
+ break
+ each.update(
+ {
+ "name": want.get("name"),
+ "acl_type": want.get("acl_type"),
+ },
+ )
+ e_have.update(
+ {
+ "name": have.get("name"),
+ "acl_type": have.get("acl_type"),
+ },
+ )
+ self.compare(
+ parsers=parsers,
+ want={"aces": each},
+ have={"aces": e_have},
+ )
+ break
+ temp += 1
+ else:
+ each.update(
+ {
+ "name": want.get("name"),
+ "acl_type": want.get("acl_type"),
+ },
+ )
+ self.compare(
+ parsers=parsers,
+ want={"aces": each},
+ have=dict(),
+ )
+ set_want = False
+ if set_want:
+ each.update(
+ {
+ "name": want.get("name"),
+ "acl_type": want.get("acl_type"),
+ },
+ )
+ self.compare(
+ parsers=parsers,
+ want={"aces": each},
+ have=dict(),
+ )
+ if self.state in ["overridden", "deleted", "replaced"]:
+ if have.get("aces"):
+ for each in have["aces"]:
+ each.update(
+ {
+ "name": have.get("name"),
+ "acl_type": have.get("acl_type"),
+ },
+ )
+ self.compare(
+ parsers=parsers,
+ want=dict(),
+ have={"aces": each},
+ )
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py
new file mode 100644
index 000000000..b414aee08
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py
@@ -0,0 +1,694 @@
+#
+# -*- 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 asa_ogs 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.rm_base.resource_module import (
+ ResourceModule,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.facts import Facts
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.rm_templates.ogs import (
+ OGsTemplate,
+)
+
+
+class OGs(ResourceModule):
+ """
+ The asa_ogs class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ogs"]
+
+ def __init__(self, module):
+ super(OGs, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ogs",
+ tmplt=OGsTemplate(),
+ )
+
+ 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:
+ temp = {}
+ for entry in self.want:
+ temp.update({(entry["object_type"]): entry})
+ wantd = temp
+ else:
+ wantd = {}
+ if self.have:
+ temp = {}
+ for entry in self.have:
+ temp.update({(entry["object_type"]): entry})
+ haved = temp
+ else:
+ haved = {}
+
+ obj_gp = {}
+ for k, v in wantd.items():
+ temp = {}
+ for each in v.get("object_groups"):
+ temp[each.get("name")] = each
+ temp["object_type"] = k
+ obj_gp[k] = temp
+ if obj_gp:
+ wantd = obj_gp
+ obj_gp = {}
+ for k, v in haved.items():
+ temp = {}
+ for each in v.get("object_groups"):
+ temp[each.get("name")] = each
+ temp["object_type"] = k
+ obj_gp[k] = temp
+ if obj_gp:
+ haved = obj_gp
+
+ # if state is merged, merge want onto have
+ 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":
+ temp = {}
+ for k, v in iteritems(haved):
+ temp_have = {}
+ if k in wantd or not wantd:
+ for key, val in iteritems(v):
+ if not wantd or key in wantd[k]:
+ temp_have.update({key: val})
+ temp.update({k: temp_have})
+ haved = temp
+ 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:
+ for each_key, each_val in iteritems(have):
+ if each_key != "object_type":
+ each_val.update(
+ {"object_type": have.get("object_type")},
+ )
+ self.addcmd(each_val, "og_name", True)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ if want != have:
+ for k, v in iteritems(want):
+ if k != "object_type":
+ v.update({"object_type": want.get("object_type")})
+ if have:
+ for k, v in iteritems(have):
+ if k != "object_type":
+ v.update({"object_type": want.get("object_type")})
+
+ object_type = want.get("object_type")
+ if object_type == "icmp-type":
+ self._icmp_object_compare(want, have)
+ if object_type == "network":
+ self._network_object_compare(want, have)
+ elif object_type == "protocol":
+ self._protocol_object_compare(want, have)
+ elif object_type == "security":
+ self._security_object_compare(want, have)
+ elif object_type == "service":
+ self._service_object_compare(want, have)
+ elif object_type == "user":
+ self._user_object_compare(want, have)
+
+ def get_list_diff(self, want, have, object, param):
+ diff = [item for item in want[object][param] if item not in have[object][param]]
+ return diff
+
+ def check_for_have_and_overidden(self, have):
+ if have and self.state == "overridden":
+ for name, entry in iteritems(have):
+ if name != "object_type":
+ self.addcmd(entry, "og_name", True)
+
+ def _icmp_object_compare(self, want, have):
+ icmp_obj = "icmp_type"
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type" and entry[icmp_obj].get("icmp_object"):
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ icmp_obj,
+ ["icmp_type"],
+ )
+ else:
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if self.state in ("overridden", "replaced") and h_item:
+ self.compare(["icmp_type"], {}, h_item)
+ if h_item and h_item[icmp_obj].get("icmp_object"):
+ li_diff = self.get_list_diff(
+ entry,
+ h_item,
+ icmp_obj,
+ "icmp_object",
+ )
+ else:
+ li_diff = entry[icmp_obj].get("icmp_object")
+ entry[icmp_obj]["icmp_object"] = li_diff
+ self.addcmd(entry, "icmp_type", False)
+ self.check_for_have_and_overidden(have)
+
+ def _network_object_compare(self, want, have):
+ network_obj = "network_object"
+ parsers = [
+ "network_object.host",
+ "network_object.address",
+ "network_object.ipv6_address",
+ "network_object.object",
+ ]
+ add_obj_cmd = False
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type":
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ network_obj,
+ ["address", "host", "ipv6_address", "object"],
+ )
+ else:
+ add_obj_cmd = True
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if entry[network_obj].get("address"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ network_obj,
+ "address",
+ parsers,
+ "network_object.address",
+ )
+ elif h_item and h_item.get(network_obj) and h_item[network_obj].get("address"):
+ h_item[network_obj] = {
+ "address": h_item[network_obj].get("address"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ if entry[network_obj].get("host"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ network_obj,
+ "host",
+ parsers,
+ "network_object.host",
+ )
+ elif h_item and h_item[network_obj].get("host"):
+ h_item[network_obj] = {
+ "host": h_item[network_obj].get("host"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ if entry[network_obj].get("ipv6_address"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ network_obj,
+ "ipv6_address",
+ parsers,
+ "network_object.ipv6_address",
+ )
+ elif h_item and h_item.get(network_obj) and h_item[network_obj].get("ipv6_address"):
+ h_item[network_obj] = {
+ "ipv6_address": h_item[network_obj].get("ipv6_address"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ if entry[network_obj].get("object"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ network_obj,
+ "object",
+ parsers,
+ "network_object.object",
+ )
+ elif h_item and h_item.get(network_obj) and h_item[network_obj].get("object"):
+ h_item[network_obj] = {
+ "object": h_item[network_obj].get("object"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ self.check_for_have_and_overidden(have)
+
+ def _protocol_object_compare(self, want, have):
+ protocol_obj = "protocol_object"
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type":
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ protocol_obj,
+ ["protocol"],
+ )
+ else:
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if entry[protocol_obj].get("protocol"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ protocol_obj,
+ "protocol",
+ [protocol_obj],
+ protocol_obj,
+ )
+ self.check_for_have_and_overidden(have)
+
+ def _security_object_compare(self, want, have):
+ security_obj = "security_group"
+ parsers = ["security_group.sec_name", "security_group.tag"]
+ add_obj_cmd = False
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type":
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ security_obj,
+ ["sec_name", "tag"],
+ )
+ else:
+ add_obj_cmd = True
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if entry[security_obj].get("sec_name"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ security_obj,
+ "sec_name",
+ parsers,
+ "security_group.sec_name",
+ )
+ elif h_item and h_item[security_obj].get("sec_name"):
+ h_item[security_obj] = {
+ "sec_name": h_item[security_obj].get("sec_name"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ if entry[security_obj].get("tag"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ security_obj,
+ "tag",
+ parsers,
+ "security_group.tag",
+ )
+ elif h_item and h_item[security_obj].get("tag"):
+ h_item[security_obj] = {
+ "tag": h_item[security_obj].get("tag"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ self.check_for_have_and_overidden(have)
+
+ def _service_object_compare(self, want, have):
+ service_obj = "service_object"
+ services_obj = "services_object"
+ port_obj = "port_object"
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type":
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ service_obj,
+ ["protocol"],
+ )
+ else:
+ protocol = entry.get("protocol")
+ if protocol:
+ entry["name"] = "{0} {1}".format(name, protocol)
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if entry.get(service_obj):
+ if entry[service_obj].get("protocol"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ service_obj,
+ "protocol",
+ ["service_object"],
+ service_obj,
+ )
+ elif entry.get(services_obj):
+ if h_item:
+ h_item = self.convert_list_to_dict(
+ val=h_item,
+ source="source_port",
+ destination="destination_port",
+ )
+ entry = self.convert_list_to_dict(
+ val=entry,
+ source="source_port",
+ destination="destination_port",
+ )
+ command_len = len(self.commands)
+ for k, v in iteritems(entry):
+ if h_item:
+ h_service_item = h_item.pop(k, {})
+ if h_service_item != v:
+ self.compare(
+ [services_obj],
+ want={services_obj: v},
+ have={services_obj: h_service_item},
+ )
+ else:
+ temp_want = {"name": name, services_obj: v}
+ self.addcmd(temp_want, "og_name", True)
+
+ self.compare(
+ [services_obj],
+ want=temp_want,
+ have={},
+ )
+ if h_item and self.state in ["overridden", "replaced"]:
+ for k, v in iteritems(h_item):
+ temp_have = {"name": name, services_obj: v}
+ self.compare(
+ [services_obj],
+ want={},
+ have=temp_have,
+ )
+ if command_len < len(self.commands):
+ cmd = "object-group service {0}".format(name)
+ if cmd not in self.commands:
+ self.commands.insert(command_len, cmd)
+ elif entry.get(port_obj):
+ protocol = entry.get("protocol")
+ if h_item:
+ h_item = self.convert_list_to_dict(
+ val=h_item,
+ source="source_port",
+ destination="destination_port",
+ )
+ entry = self.convert_list_to_dict(
+ val=entry,
+ source="source_port",
+ destination="destination_port",
+ )
+ command_len = len(self.commands)
+ for k, v in iteritems(entry):
+ h_port_item = h_item.pop(k, {})
+ if "http" in k and "_" in k:
+ # This condition is to TC of device behaviour, where if user tries to
+ # configure http it gets converted to www.
+ temp = k.split("_")[0]
+ h_port_item = {temp: "http"}
+ if h_port_item != v:
+ self.compare(
+ [port_obj],
+ want={port_obj: v},
+ have={port_obj: h_port_item},
+ )
+ elif not h_port_item:
+ temp_want = {"name": name, port_obj: v}
+ self.compare([port_obj], want=temp_want, have={})
+ if h_item and self.state in ["overridden", "replaced"]:
+ for k, v in iteritems(h_item):
+ temp_have = {"name": name, port_obj: v}
+ self.compare([port_obj], want={}, have=temp_have)
+ self.check_for_have_and_overidden(have)
+
+ def convert_list_to_dict(self, *args, **kwargs):
+ temp = {}
+ if kwargs["val"].get("services_object"):
+ for every in kwargs["val"]["services_object"]:
+ temp_key = every["protocol"]
+ if "source_port" in every:
+ if "range" in every["source_port"]:
+ temp_key = (
+ "range"
+ + "_"
+ + str(every["source_port"]["range"]["start"])
+ + "_"
+ + str(every["source_port"]["range"]["end"])
+ )
+ else:
+ source_key = list(every["source_port"])[0]
+ temp_key = (
+ temp_key + "_" + source_key + "_" + every["source_port"][source_key]
+ )
+ if "destination_port" in every:
+ if "range" in every["destination_port"]:
+ temp_key = (
+ "range"
+ + "_"
+ + str(every["destination_port"]["range"]["start"])
+ + "_"
+ + str(every["destination_port"]["range"]["end"])
+ )
+ else:
+ destination_key = list(every["destination_port"])[0]
+ temp_key = (
+ temp_key
+ + "_"
+ + destination_key
+ + "_"
+ + every["destination_port"][destination_key]
+ )
+ temp.update({temp_key: every})
+ return temp
+ elif kwargs["val"].get("port_object"):
+ for every in kwargs["val"]["port_object"]:
+ if "range" in every:
+ temp_key = (
+ "start"
+ + "_"
+ + every["range"]["start"]
+ + "_"
+ + "end"
+ + "_"
+ + every["range"]["end"]
+ )
+ else:
+ every_key = list(every)[0]
+ temp_key = every_key + "_" + every[every_key]
+ temp.update({temp_key: every})
+ return temp
+
+ def _user_object_compare(self, want, have):
+ user_obj = "user_object"
+ parsers = ["user_object.user", "user_object.user_gp"]
+ add_obj_cmd = False
+ for name, entry in iteritems(want):
+ h_item = have.pop(name, {})
+ if entry != h_item and name != "object_type":
+ if h_item and entry.get("group_object"):
+ self.addcmd(entry, "og_name", False)
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if h_item:
+ self._add_object_cmd(
+ entry,
+ h_item,
+ user_obj,
+ ["user", "user_group"],
+ )
+ else:
+ add_obj_cmd = True
+ self.addcmd(entry, "og_name", False)
+ self.compare(["description"], entry, h_item)
+ if entry.get("group_object"):
+ self._add_group_object_cmd(entry, h_item)
+ continue
+ if entry[user_obj].get("user"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ user_obj,
+ "user",
+ ["user_object.user"],
+ "user_object.user",
+ )
+ elif h_item and h_item[user_obj].get("user"):
+ h_item[user_obj] = {"user": h_item[user_obj].get("user")}
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ if entry[user_obj].get("user_group"):
+ self._compare_object_diff(
+ entry,
+ h_item,
+ user_obj,
+ "user_group",
+ ["user_object.user_group"],
+ "user_object.user_gp",
+ )
+ elif h_item and h_item[user_obj].get("user_group"):
+ h_item[user_obj] = {
+ "user_group": h_item[user_obj].get("user_group"),
+ }
+ if not add_obj_cmd:
+ self.addcmd(entry, "og_name", False)
+ self.compare(parsers, {}, h_item)
+ self.check_for_have_and_overidden(have)
+
+ def _add_object_cmd(self, want, have, object, object_elements):
+ obj_cmd_added = False
+ for each in object_elements:
+ want_element = want[object].get(each) if want.get(object) else want
+ have_element = have[object].get(each) if have.get(object) else have
+ if (
+ want_element
+ and isinstance(want_element, list)
+ and isinstance(want_element[0], dict)
+ ):
+ if want_element and have_element and want_element != have_element:
+ if not obj_cmd_added:
+ self.addcmd(want, "og_name", False)
+ self.compare(["description"], want, have)
+ obj_cmd_added = True
+ else:
+ if want_element and have_element and set(want_element) != set(have_element):
+ if not obj_cmd_added:
+ self.addcmd(want, "og_name", False)
+ self.compare(["description"], want, have)
+ obj_cmd_added = True
+
+ def _add_group_object_cmd(self, want, have):
+ if have and have.get("group_object"):
+ want["group_object"] = list(
+ set(want.get("group_object")) - set(have.get("group_object")),
+ )
+ have["group_object"] = list(
+ set(have.get("group_object")) - set(want.get("group_object")),
+ )
+ for each in want["group_object"]:
+ self.compare(["group_object"], {"group_object": each}, dict())
+ if (
+ (self.state == "replaced" or self.state == "overridden")
+ and have
+ and have.get("group_object")
+ ):
+ for each in have["group_object"]:
+ self.compare(["group_object"], dict(), {"group_object": each})
+
+ def _compare_object_diff(
+ self,
+ want,
+ have,
+ object,
+ object_type,
+ parsers,
+ val,
+ ):
+ temp_have = copy.copy(have)
+ temp_want = copy.copy(want)
+ if temp_have and temp_have.get(object) and temp_have[object].get(object_type):
+ want_diff = self.get_list_diff(
+ temp_want,
+ temp_have,
+ object,
+ object_type,
+ )
+ have_diff = [
+ each
+ for each in temp_have[object][object_type]
+ if each not in temp_want[object][object_type]
+ ]
+ if have_diff:
+ temp_have[object].pop(object_type)
+ else:
+ have_diff = []
+ want_diff = temp_want[object].get(object_type)
+ temp_want[object][object_type] = want_diff
+ if have_diff or temp_have.get(object) and self.state in ("overridden", "replaced"):
+ if have_diff:
+ temp_have[object] = {object_type: have_diff}
+ self.compare(parsers, {}, temp_have)
+ self.addcmd(temp_want, val, False)
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py
new file mode 100644
index 000000000..b624a055b
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py
@@ -0,0 +1,107 @@
+#
+# -*- 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 asa_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.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.rm_templates.acls import (
+ AclsTemplate,
+)
+
+
+class AclsFacts(object):
+ """The asa_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_acls_config(self, connection):
+ 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_acls_config(connection)
+
+ rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=AclsTemplate())
+ current = rmmod.parse()
+ acls = list()
+ if current.get("acls"):
+ for key, val in iteritems(current.get("acls")):
+ if val.get("name") == "cached":
+ continue
+ for each in val.get("aces"):
+ if "protocol_number" in each:
+ each["protocol_options"] = {
+ "protocol_number": each["protocol_number"],
+ }
+ del each["protocol_number"]
+ if "icmp_icmp6_protocol" in each and each.get("protocol"):
+ each["protocol_options"] = {
+ each.get("protocol"): {
+ each["icmp_icmp6_protocol"].replace(
+ "-",
+ "_",
+ ): True,
+ },
+ }
+ del each["icmp_icmp6_protocol"]
+ elif (
+ each.get("protocol")
+ and each.get("protocol") != "icmp"
+ and each.get("protocol") != "icmp6"
+ ):
+ each["protocol_options"] = {each.get("protocol"): True}
+ acls.append(val)
+ facts = {}
+ params = {}
+ if acls:
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": {"acls": acls}},
+ )
+ params = utils.remove_empties(params)
+ facts["acls"] = params["config"]
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py
new file mode 100644
index 000000000..59533d327
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py
@@ -0,0 +1,70 @@
+# -*- 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 asa
+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.asa.plugins.module_utils.network.asa.facts.acls.acls import AclsFacts
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.legacy.base import (
+ Config,
+ Default,
+ Hardware,
+)
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.ogs.ogs import OGsFacts
+
+
+FACT_LEGACY_SUBSETS = dict(default=Default, hardware=Hardware, config=Config)
+
+FACT_RESOURCE_SUBSETS = dict(acls=AclsFacts, ogs=OGsFacts)
+
+
+class Facts(FactsBase):
+ """The fact class for asa"""
+
+ 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 asa
+ :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/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py
new file mode 100644
index 000000000..d256229bc
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py
@@ -0,0 +1,185 @@
+# -*- 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 asa 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.asa.plugins.module_utils.network.asa.asa import (
+ get_capabilities,
+ run_commands,
+)
+
+
+class FactsBase(object):
+ COMMANDS = list()
+
+ def __init__(self, module):
+ self.module = module
+ self.facts = dict()
+ self.warnings = list()
+ self.responses = None
+
+ def populate(self):
+ self.responses = run_commands(
+ self.module,
+ commands=self.COMMANDS,
+ check_rc=False,
+ )
+
+ def run(self, cmd):
+ return run_commands(self.module, commands=cmd, check_rc=False)
+
+
+class Default(FactsBase):
+ COMMANDS = ["show version"]
+
+ def populate(self):
+ super(Default, self).populate()
+ self.facts.update(self.platform_facts())
+ data = self.responses[0]
+ if data:
+ self.facts["asatype"] = self.parse_asatype(data)
+ self.facts["serialnum"] = self.parse_serialnum(data)
+ self.parse_stacks(data)
+
+ def parse_asatype(self, data):
+ match = re.search(r"Hardware:(\s+)ASA", data)
+ if match:
+ return "ASA"
+
+ def parse_serialnum(self, data):
+ match = re.search(r"Serial Number: (\S+)", data)
+ if match:
+ return match.group(1)
+
+ def parse_stacks(self, data):
+ match = re.findall(r"^Model [Nn]umber\s+: (\S+)", data, re.M)
+ if match:
+ self.facts["stacked_models"] = match
+
+ match = re.findall(
+ r"^System [Ss]erial [Nn]umber\s+: (\S+)",
+ data,
+ re.M,
+ )
+ if match:
+ self.facts["stacked_serialnums"] = match
+
+ def platform_facts(self):
+ platform_facts = {}
+
+ resp = get_capabilities(self.module)
+ device_info = resp["device_info"]
+ platform_facts["system"] = device_info["network_os"]
+
+ for item in (
+ "model",
+ "image",
+ "version",
+ "platform",
+ "hostname",
+ "firepower_version",
+ "device_mgr_version",
+ ):
+ 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"]
+
+ 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:
+ mem_list = [l for l in data.splitlines() if "memory" in l]
+ for each in mem_list:
+ if "Free memory" in each:
+ match = re.search(
+ r"Free memory.+ (\d+) .+(\d\d)",
+ each,
+ )
+ if match:
+ self.facts["memfree_mb"] = int(match.group(1)) // 1024
+ elif "Used memory" in each:
+ match = re.search(
+ r"Used memory.+ (\d+) .+(\d\d)",
+ each,
+ )
+ if match:
+ self.facts["memused_mb"] = int(match.group(1)) // 1024
+ elif "Total memory" in each:
+ match = re.search(
+ r"Total memory.+ (\d+) .+(\d\d)",
+ each,
+ )
+ if match:
+ self.facts["memtotal_mb"] = int(match.group(1)) // 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\/(\d+)% 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
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py
new file mode 100644
index 000000000..41821d4c1
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py
@@ -0,0 +1,98 @@
+# -*- 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 asa_og 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 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.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.argspec.ogs.ogs import OGsArgs
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.rm_templates.ogs import (
+ OGsTemplate,
+)
+
+
+class OGsFacts(object):
+ """The asa_ogs fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = OGsArgs.argument_spec
+
+ def get_og_data(self, connection):
+ return connection.get("sh running-config object-group")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for OGs
+ :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_og_data(connection)
+ rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=OGsTemplate())
+ current = rmmod.parse()
+ ogs = []
+ object_groups = {
+ "icmp-type": "icmp_type",
+ "network": "network_object",
+ "protocol": "protocol_object",
+ "security": "security_group",
+ "service": "service_object",
+ "user": "user_object",
+ }
+ if current.get("ogs"):
+ for k, v in iteritems(current.get("ogs")):
+ obj_gp = {}
+ config_dict = {}
+ config_dict["object_type"] = k
+ config_dict["object_groups"] = []
+ for each in iteritems(v):
+ obj_gp["name"] = each[1].pop("name")
+ each[1].pop("object_type")
+ if each[1].get("description"):
+ obj_gp["description"] = each[1].pop("description")
+ if each[1].get("group_object"):
+ obj_gp["group_object"] = each[1].pop("group_object")
+ if k == "service":
+ if "services_object" in each[1]:
+ obj_gp["services_object"] = each[1]["services_object"]
+ elif "port_object" in each[1]:
+ obj_gp["port_object"] = each[1]["port_object"]
+ obj_gp["protocol"] = each[1]["protocol"]
+ else:
+ obj_gp[object_groups.get(k)] = each[1]
+ config_dict["object_groups"].append(obj_gp)
+ obj_gp = {}
+ config_dict["object_groups"] = sorted(
+ config_dict["object_groups"],
+ key=lambda k, sk="name": str(k[sk]),
+ )
+ ogs.append(config_dict)
+ # sort the object group list of dict by object_type
+ ogs = sorted(ogs, key=lambda i: i["object_type"])
+ facts = {}
+ params = utils.remove_empties(
+ utils.validate_config(self.argument_spec, {"config": ogs}),
+ )
+ facts["ogs"] = params.get("config")
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py
new file mode 100644
index 000000000..ca76966f5
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py
@@ -0,0 +1,71 @@
+#
+# (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._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import Connection
+
+from ansible_collections.cisco.asa.plugins.module_utils.network.asa.providers import providers
+
+
+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/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py
new file mode 100644
index 000000000..ad956ea64
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py
@@ -0,0 +1,126 @@
+#
+# (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.config import (
+ NetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+
+_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/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py
new file mode 100644
index 000000000..b97151027
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py
@@ -0,0 +1,249 @@
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import re
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_access_list_name(config_data):
+ command = "access-list {acls_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, cmd, type):
+ if config_data["aces"][type].get("any"):
+ cmd += " any"
+ elif config_data["aces"][type].get("any4"):
+ cmd += " any4"
+ elif config_data["aces"][type].get("any6"):
+ cmd += " any6"
+ elif config_data["aces"][type].get("address"):
+ cmd += " {address}".format(**config_data["aces"][type])
+ if config_data["aces"][type].get("netmask"):
+ cmd += " {netmask}".format(**config_data["aces"][type])
+ elif config_data["aces"][type].get("host"):
+ cmd += " host {host}".format(**config_data["aces"][type])
+ elif config_data["aces"][type].get("interface"):
+ cmd += " interface {interface}".format(**config_data["aces"][type])
+ elif config_data["aces"][type].get("object_group"):
+ cmd += " object-group {object_group}".format(**config_data["aces"][type])
+ if type == "destination" and config_data["aces"][type].get(
+ "service_object_group",
+ ):
+ cmd += " object-group {service_object_group}".format(**config_data["aces"][type])
+ if config_data["aces"].get("protocol_options"):
+ protocol_option_key = list(
+ config_data["aces"]["protocol_options"],
+ )[0]
+ if (
+ isinstance(
+ config_data["aces"]["protocol_options"][protocol_option_key],
+ dict,
+ )
+ and type == "destination"
+ ):
+ val = list(
+ config_data["aces"]["protocol_options"][protocol_option_key],
+ )[0]
+ cmd += " {0}".format(val.replace("_", "-"))
+ if config_data["aces"][type].get("port_protocol"):
+ if config_data["aces"][type].get("port_protocol").get("range"):
+ start = config_data["aces"][type].get("port_protocol")["range"]["start"]
+ end = config_data["aces"][type].get("port_protocol")["range"]["end"]
+ cmd += " range {0} {1}".format(start, end)
+ else:
+ port_protocol = list(
+ config_data["aces"][type]["port_protocol"],
+ )[0]
+ cmd += (
+ " "
+ + port_protocol
+ + " "
+ + config_data["aces"][type]["port_protocol"][port_protocol]
+ )
+ return cmd
+
+ cmd = ""
+ if config_data["aces"].get("remark"):
+ command.append(
+ "access-list {name} line {line} remark {remark}".format(**config_data["aces"]),
+ )
+ if len(config_data["aces"]) > 4:
+ try:
+ cmd = "access-list {name} line {line}".format(**config_data["aces"])
+ except KeyError:
+ cmd = "access-list {name}".format(**config_data["aces"])
+ if (
+ config_data["aces"].get("acl_type")
+ and config_data["aces"].get("acl_type") != "standard"
+ ):
+ cmd += " {acl_type}".format(**config_data["aces"])
+ if config_data["aces"].get("grant"):
+ cmd += " {grant}".format(**config_data["aces"])
+ if config_data["aces"].get("protocol_options"):
+ if "protocol_number" in config_data["aces"]["protocol_options"]:
+ cmd += " {protocol_number}".format(**config_data["aces"]["protocol_options"])
+ else:
+ cmd += " {0}".format(
+ list(config_data["aces"]["protocol_options"])[0],
+ )
+ elif config_data["aces"].get("protocol"):
+ cmd += " {protocol}".format(**config_data["aces"])
+ if config_data["aces"].get("source"):
+ cmd = source_destination_common_config(
+ config_data,
+ cmd,
+ "source",
+ )
+ if config_data["aces"].get("destination"):
+ cmd = source_destination_common_config(
+ config_data,
+ cmd,
+ "destination",
+ )
+ if config_data["aces"].get("log"):
+ cmd += " log {log}".format(**config_data["aces"])
+ if config_data["aces"].get("inactive"):
+ cmd += " inactive"
+ if config_data["aces"].get("time_range"):
+ cmd += " time-range {time_range}".format(**config_data["aces"])
+ if cmd:
+ command.append(cmd)
+ 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"""^access-list*
+ \s*(?P<acl_name>\S+);
+ \s*\S+\s*elements;
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_access_list_name,
+ "compval": "name",
+ "result": {"acls": {"{{ acl_name }}": {"name": "{{ acl_name }}"}}},
+ "shared": True,
+ },
+ {
+ "name": "aces",
+ "getval": re.compile(
+ r"""^access-list*
+ \s*(?P<acl_name>\S+)*
+ \s*(?P<line>line\s\d+)*
+ \s*(?P<remark>remark\s\S.*)*
+ \s*(?P<ethertype>ethertype)*
+ \s*(?P<webtype>webtype)*
+ \s*(?P<acl_type>extended|standard)*
+ \s*(?P<grant>deny|permit)*
+ \s*(?P<ethertype_params>(dsap\s\S+)|bpdu|eii-ipx|ipx|mpls-unicast|mpls-multicast|isis|any\s)*
+ \s*(?P<std_dest>(host\s\S+)|any4|(?:[0-9]{1,3}\.){3}[0-9]{1,3}\s(?:[0-9]{1,3}\.){3}[0-9]{1,3})*
+ \s*(?P<protocol>ah|eigrp|esp|gre|icmp|icmp6|igmp|igrp|ip|ipinip|ipsec|nos|ospf|pcp|pim|pptp|sctp|snp|tcp|udp)*
+ \s*(?P<protocol_num>\d+\s)*
+ \s*(?P<source>any4|any6|any|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-f0-9:]+:+)+[a-f0-9]+\S+|host\s(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-f0-9:]+:+)+[a-f0-9]+)\S+)|interface\s\S+|object-group\s\S+))*
+ \s*(?P<source_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+)|range\s\S+\s\S+)*
+ \s*(?P<destination>any4|any6|any|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-f0-9:]+:+)+[a-f0-9]+\S+|host\s(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-f0-9:]+:+)+[a-f0-9]+)\S+)|interface\s\S+|object-group\s\S+))*
+ \s*(?P<dest_svc_object_group>object-group\s\S+)*
+ \s*(?P<dest_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+)|range\s\S+\s\S+)*
+ \s*(?P<icmp_icmp6_protocol>alternate-address|conversion-error|echo|echo-reply|information-reply|information-request|mask-reply|mask-request|membership-query|membership-reduction|membership-report|mobile-redirect|neighbor-advertisement|neighbor-redirect|neighbor-solicitation|parameter-problem|packet-too-big|redirect|router-advertisement|router-renumbering|router-solicitation|source-quench|source-route-failed|time-exceeded|timestamp-reply|timestamp-request|traceroute|unreachable)*
+ \s*(?P<log>log\s\S+)*
+ \s*(?P<time_range>time-range\s\S+)*
+ \s*(?P<inactive>inactive)*
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_access_list_entries,
+ "result": {
+ "acls": {
+ "{{ acl_name }}": {
+ "name": "{{ acl_name }}",
+ "acl_type": "{{ acl_type if acl_type is defined }}",
+ "aces": [
+ {
+ "grant": "{{ grant }}",
+ "line": "{{ line.split(' ')[1] if line is defined }}",
+ "remark": "{{ remark.split('remark ')[1] if remark is defined }}",
+ "protocol": "{{ protocol if protocol is defined else None }}",
+ "protocol_number": "{{ protocol_num if protocol_num is defined }}",
+ "icmp_icmp6_protocol": "{{ icmp_icmp6_protocol if icmp_icmp6_protocol is defined else None }}",
+ "source": {
+ "address": "{% if source is defined and '.' in source and 'host'\
+ not in source and 'object-group' not in source %}{{ source.split(' ')[0] }}{% elif source is defined and\
+ '::' in source and 'host' not in source %}{{ source }}{% endif %}",
+ "netmask": "{{ source.split(' ')[1] if source\
+ is defined and '.' in source and 'host' not in source else None and 'object-group' not in source }}",
+ "any4": "{{ True if source is defined and source == 'any4' else None }}",
+ "any6": "{{ True if source is defined and source == 'any6' else None }}",
+ "any": "{{ True if source is defined and source == 'any' else None }}",
+ "host": "{{ source.split(' ')[1] if source is defined and 'host' in source else None }}",
+ "interface": "{{ source.split(' ')[1] if source is defined and 'interface' in source else None }}",
+ "object_group": "{{ source.split(' ')[1] if source is defined and 'object-group' in source else None }}",
+ "port_protocol": {
+ "{{ source_port_protocol.split(' ')[0] if source_port_protocol\
+ is defined and 'range' not in source_port_protocol else None }}": "{{ source_port_protocol.split(' ')[1]\
+ if source_port_protocol is defined and 'range' not in source_port_protocol else None }}",
+ "{{ 'range' }}": {
+ "start": "{{ source_port_protocol.split(' ')[1] if source_port_protocol is defined and\
+ 'range' in source_port_protocol else None }}",
+ "end": "{{ source_port_protocol.split(' ')[2] if source_port_protocol is defined and\
+ 'range' in source_port_protocol else None }}",
+ },
+ },
+ },
+ "destination": {
+ "address": "{% if destination is defined and 'host' not in destination and\
+ '.' in destination and\
+ 'object-group' 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 %}",
+ "netmask": "{% if destination is defined and 'host' not in destination and\
+ '.' in destination and\
+ 'object-group' 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 %}",
+ "any4": "{% if destination is defined and\
+ destination == 'any4' %}{{ True }}{% elif std_dest is defined and std_dest == 'any4' %}{{ True }}{% endif %}",
+ "any6": "{{ True if destination is defined and destination == 'any6' else None }}",
+ "any": "{{ True if destination is defined and destination == 'any' else None }}",
+ "host": "{% if destination is defined and\
+ 'host' in destination %}{{ destination.split(' ')[1] }}{% elif std_dest is defined and\
+ 'host' in std_dest %}{{ std_dest.split(' ')[1] }}{% endif %}",
+ "interface": "{{ destination.split(' ')[1] if destination is defined and 'interface' in destination else None }}",
+ "object_group": "{{ destination.split(' ')[1] if destination is defined and 'object-group' in destination else None }}",
+ "service_object_group": "{{ dest_svc_object_group.split('object-group ')[1] if dest_svc_object_group is defined }}",
+ "port_protocol": {
+ "{{ dest_port_protocol.split(' ')[0] if dest_port_protocol\
+ is defined and 'range' not in dest_port_protocol else None }}": "{{ dest_port_protocol.split(' ')[1]\
+ if dest_port_protocol is defined and 'range' not in dest_port_protocol else None }}",
+ "{{ 'range' }}": {
+ "start": "{{ dest_port_protocol.split(' ')[1] if dest_port_protocol is defined and\
+ 'range' in dest_port_protocol }}",
+ "end": "{{ dest_port_protocol.split(' ')[2] if dest_port_protocol is defined and\
+ 'range' in dest_port_protocol }}",
+ },
+ },
+ },
+ "inactive": "{{ True if inactive is defined }}",
+ "log": "{{ log.split('log ')[1] if log is defined }}",
+ "time_range": "{{ time_range if time_range is defined }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ ]
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py
new file mode 100644
index 000000000..26a032478
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py
@@ -0,0 +1,538 @@
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import re
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_object_group(config_data):
+ command = "object-group {object_type} {name}".format(**config_data)
+ return command
+
+
+def _tmplt_icmp_object(config_data):
+ commands = []
+ if config_data.get("icmp_type").get("icmp_object"):
+ for each in config_data.get("icmp_type").get("icmp_object"):
+ commands.append("icmp-object {0}".format(each))
+ return commands
+
+
+def _tmplt_network_object(config_data):
+ commands = []
+ if config_data.get("network_object").get("host"):
+ for each in config_data.get("network_object").get("host"):
+ commands.append("network-object host {0}".format(each))
+ return commands
+
+
+def _tmplt_network_object_address(config_data):
+ commands = []
+ if config_data.get("network_object").get("address"):
+ for each in config_data.get("network_object").get("address"):
+ commands.append("network-object {0}".format(each))
+ return commands
+
+
+def _tmplt_network_object_ipv6(config_data):
+ commands = []
+ if config_data.get("network_object").get("ipv6_address"):
+ for each in config_data.get("network_object").get("ipv6_address"):
+ commands.append("network-object {0}".format(each))
+ return commands
+
+
+def _tmplt_network_object_object(config_data):
+ commands = []
+ if config_data.get("network_object").get("object"):
+ for each in config_data.get("network_object").get("object"):
+ commands.append("network-object object {0}".format(each))
+ return commands
+
+
+def _tmplt_protocol_object(config_data):
+ commands = []
+ if config_data.get("protocol_object").get("protocol"):
+ for each in config_data.get("protocol_object").get("protocol"):
+ commands.append("protocol {0}".format(each))
+ return commands
+
+
+def _tmplt_sec_group_name(config_data):
+ commands = []
+ if config_data.get("security_group").get("sec_name"):
+ for each in config_data.get("security_group").get("sec_name"):
+ commands.append("security-group name {0}".format(each))
+ return commands
+
+
+def _tmplt_sec_group_tag(config_data):
+ commands = []
+ if config_data.get("security_group").get("tag"):
+ for each in config_data.get("security_group").get("tag"):
+ commands.append("security-group tag {0}".format(each))
+ return commands
+
+
+def _tmplt_service_object(config_data):
+ if config_data.get("service_object").get("protocol"):
+ commands = []
+ for each in config_data.get("service_object").get("protocol"):
+ commands.append("service-object {0}".format(each))
+ return commands
+
+
+def _tmplt_services_object(config_data):
+ if config_data.get("services_object"):
+ cmd = "service-object {protocol}".format(**config_data["services_object"])
+ if config_data["services_object"].get("source_port"):
+ if config_data["services_object"]["source_port"].get("range"):
+ cmd += " source range {start} {end}".format(
+ **config_data["services_object"]["source_port"]["range"]
+ )
+ else:
+ key = list(config_data["services_object"]["source_port"])[0]
+ cmd += " source {0} {1}".format(
+ key,
+ config_data["services_object"]["source_port"][key],
+ )
+ if config_data["services_object"].get("destination_port"):
+ if config_data["services_object"]["destination_port"].get("range"):
+ cmd += " destination range {start} {end}".format(
+ **config_data["services_object"]["destination_port"]["range"]
+ )
+ else:
+ key = list(config_data["services_object"]["destination_port"])[0]
+ cmd += " destination {0} {1}".format(
+ key,
+ config_data["services_object"]["destination_port"][key],
+ )
+ return cmd
+
+
+def _tmplt_port_object(config_data):
+ if config_data.get("port_object"):
+ cmd = "port-object"
+ if config_data["port_object"].get("range"):
+ cmd += " range {start} {end}".format(**config_data["port_object"]["range"])
+ else:
+ key = list(config_data["port_object"])[0]
+ cmd += " {0} {1}".format(key, config_data["port_object"][key])
+ return cmd
+
+
+def _tmplt_user_object_user(config_data):
+ commands = []
+ if config_data.get("user_object").get("user"):
+ for each in config_data.get("user_object").get("user"):
+ commands.append("user {domain}\\{name}".format(**each))
+ return commands
+
+
+def _tmplt_user_object_user_gp(config_data):
+ commands = []
+ if config_data.get("user_object").get("user_group"):
+ for each in config_data.get("user_object").get("user_group"):
+ commands.append(r"user-group {domain}\\{name}".format(**each))
+ return commands
+
+
+def _tmplt_group_object(config_data):
+ command = "group-object {group_object}".format(**config_data)
+ return command
+
+
+class OGsTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(OGsTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "og_name",
+ "getval": re.compile(
+ r"""
+ ^object-group*
+ \s*(?P<obj_type>\S+)*
+ \s*(?P<obj_name>\S+)*
+ \s*(?P<protocol>\S+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_object_group,
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {
+ "object_type": "{{ obj_type }}",
+ "name": "{{ obj_name }}",
+ "protocol": "{{ protocol }}",
+ },
+ },
+ },
+ },
+ "shared": True,
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""\s+description:*
+ \s*(?P<description>.+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "description {{ description }}",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"description": "{{ description }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "icmp_type",
+ "getval": re.compile(
+ r"""\s+icmp-object*
+ \s*(?P<object>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_icmp_object,
+ "compval": "icmp_type",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"icmp_object": ["{{ object }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "network_object.address",
+ "getval": re.compile(
+ r"""\s+network-object*
+ \s*(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_network_object_address,
+ "compval": "network_object.address",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"address": ["{{ address }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "network_object.ipv6_address",
+ "getval": re.compile(
+ r"""\s+network-object*
+ \s*(?P<ipv6>\S+::/\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_network_object_ipv6,
+ "compval": "network_object.ipv6_address",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"ipv6_address": ["{{ ipv6 }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "network_object.host",
+ "getval": re.compile(
+ r"""\s+network-object*
+ \s*(?P<host_obj>host)*
+ \s*(?P<host_address>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_network_object,
+ "compval": "network_object.host",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"host": ["{{ host_address }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "network_object.object",
+ "getval": re.compile(
+ r"""\s+network-object\s
+ object*
+ \s*(?P<object>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_network_object_object,
+ "compval": "network_object.object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"object": ["{{ object }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "protocol_object",
+ "getval": re.compile(
+ r"""\s+protocol-object*
+ \s*(?P<protocol>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_protocol_object,
+ "compval": "protocol_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"protocol": ["{{ protocol }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "security_group.sec_name",
+ "getval": re.compile(
+ r"""\s+security-group\s
+ name*
+ \s*(?P<name>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_sec_group_name,
+ "compval": "security_group.sec_name",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"sec_name": ["{{ name }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "security_group.tag",
+ "getval": re.compile(
+ r"""\s+security-group\s
+ tag*
+ \s*(?P<tag>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_sec_group_tag,
+ "compval": "security_group.tag",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"tag": ["{{ tag }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "port_object",
+ "getval": re.compile(
+ r"""\s+port-object*
+ \s*(?P<eq>eq\s\S+)*
+ \s*(?P<range>range\s(\S+|\d+)\s(\S+|\d+))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_port_object,
+ "compval": "port_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {
+ "port_object": [
+ {
+ "eq": "{{ eq.split(' ')[1] if eq is defined }}",
+ "range": {
+ "start": "{{ range.split('range ')[1].split(' ')[0] if range is defined else None }}",
+ "end": "{{ range.split('range ')[1].split(' ')[1] if range is defined else None }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "services_object",
+ "getval": re.compile(
+ r"""\s+service-object*
+ \s*(?P<protocol>\S+)*
+ \s*(?P<source_port>source\s((eq|gts|lt|neq)\s(\S+|\d+)|(range\s(\S+|\S+)\s(\S+|\S+))))*
+ \s*(?P<destination_port>destination\s((eq|gt|lt|neq)\s(\S+|\d+)|(range\s(\S+|\S+)\s(\S+|\S+))))
+ *""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_services_object,
+ "compval": "services_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {
+ "services_object": [
+ {
+ "protocol": "{{ protocol }}",
+ "source_port": {
+ "eq": "{{ source_port.split(' ')[2] if source_port is defined and\
+ 'eq' in source_port and 'range' not in source_port }}",
+ "gt": "{{ source_port.split(' ')[2] if source_port is defined and\
+ 'gt' in source_port and 'range' not in source_port }}",
+ "lt": "{{ source_port.split(' ')[2] if source_port is defined and\
+ 'lt' in source_port and 'range' not in source_port }}",
+ "neq": "{{ source_port.split(' ')[2] if source_port is defined and\
+ 'neq' in source_port and 'range' not in source_port }}",
+ "range": {
+ "start": "{{ source_port.split('range ')[1].split(' ')[0] if source_port is defined and\
+ 'range' in source_port else None }}",
+ "end": "{{ source_port.split('range ')[1].split(' ')[1] if source_port is defined and\
+ 'range' in source_port else None }}",
+ },
+ },
+ "destination_port": {
+ "eq": "{{ destination_port.split(' ')[2] if destination_port is defined and\
+ 'eq' in destination_port and 'range' not in destination_port }}",
+ "gt": "{{ destination_port.split(' ')[2] if destination_port is defined and\
+ 'gt' in destination_port and 'range' not in destination_port }}",
+ "lt": "{{ destination_port.split(' ')[2] if destination_port is defined and\
+ 'lt' in destination_port and 'range' not in destination_port }}",
+ "neq": "{{ destination_port.split(' ')[2] if destination_port is defined and\
+ 'neq' in destination_port and 'range' not in destination_port }}",
+ "range": {
+ "start": "{{ destination_port.split('range ')[1].split(' ')[0] if destination_port is defined and\
+ 'range' in destination_port else None }}",
+ "end": "{{ destination_port.split('range ')[1].split(' ')[1] if destination_port is defined and\
+ 'range' in destination_port else None }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "service_object.object",
+ "getval": re.compile(
+ r"""\s+service-object\s
+ object*
+ \s*(?P<object>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "service-object object {{ object }}",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"object": "{{ object }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "service_object",
+ "getval": re.compile(
+ r"""\s+service-object*
+ \s*(?P<protocol>\S+)*\s
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_service_object,
+ "compval": "service_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"protocol": ["{{ protocol }}"]},
+ },
+ },
+ },
+ },
+ {
+ "name": "user_object.user",
+ "getval": re.compile(
+ r"""\s+user*
+ \s*(?P<domain>\S+)\\
+ (?P<user_name>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_user_object_user,
+ "compval": "user_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {
+ "user": [
+ {
+ "name": "{{ user_name }}",
+ "domain": "{{ domain }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "user_object.user_gp",
+ "getval": re.compile(
+ r"""\s+user-group*
+ \s*(?P<domain>\S+\\)
+ (?P<user_gp>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_user_object_user_gp,
+ "compval": "user_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {
+ "user_group": [
+ {
+ "name": "{{ user_gp }}",
+ "domain": r"{{ domain.split('\\')[0] }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "group_object",
+ "getval": re.compile(
+ r"""\s+group-object*
+ \s*(?P<gp_obj>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_group_object,
+ "compval": "group_object",
+ "result": {
+ "ogs": {
+ "{{ obj_type }}": {
+ "{{ obj_name }}": {"group_object": ["{{ gp_obj }}"]},
+ },
+ },
+ },
+ },
+ ]
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py
diff --git a/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py
new file mode 100644
index 000000000..c5399db00
--- /dev/null
+++ b/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py
@@ -0,0 +1,320 @@
+#
+# -*- 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.common.network import is_masklen, to_netmask
+from ansible.module_utils.six import iteritems
+
+
+def remove_duplicate_cmd(cmd, commands):
+ # Remove duplicate interface from commands
+ set_cmd = []
+ for each in commands:
+ if cmd in each:
+ if each not in set_cmd:
+ set_cmd.append(each)
+ else:
+ set_cmd.append(each)
+
+ return set_cmd
+
+
+def remove_command_from_config_list(interface, cmd, commands):
+ # To delete the passed config
+ if interface not in commands:
+ commands.insert(0, interface)
+ commands.append("no %s" % cmd)
+ return commands
+
+
+def add_command_to_config_list(interface, cmd, commands):
+ # To set the passed config
+ if interface not in commands:
+ commands.insert(0, interface)
+ commands.append(cmd)
+
+
+def check_n_return_valid_ipv6_addr(module, input_list, filtered_ipv6_list):
+ # To verify the valid ipv6 address
+ try:
+ for each in input_list:
+ if "::" in each:
+ if "/" in each:
+ each = each.split("/")[0]
+ if socket.inet_pton(socket.AF_INET6, each):
+ filtered_ipv6_list.append(each)
+ return filtered_ipv6_list
+ except socket.error:
+ module.fail_json(msg="Incorrect IPV6 address!")
+
+
+def new_dict_to_set(input_dict, temp_list, test_set, count=0):
+ # recursive function to convert input dict to set for comparision
+ test_dict = dict()
+ if isinstance(input_dict, dict):
+ input_dict_len = len(input_dict)
+ for k, v in sorted(iteritems(input_dict)):
+ count += 1
+ if isinstance(v, list):
+ temp_list.append(k)
+ for each in v:
+ if isinstance(each, dict):
+ if [True for i in each.values() if type(i) == list]:
+ new_dict_to_set(each, temp_list, test_set, count)
+ else:
+ new_dict_to_set(each, temp_list, test_set, 0)
+ else:
+ if v is not None:
+ test_dict.update({k: v})
+ try:
+ if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len:
+ test_set.add(tuple(iteritems(test_dict)))
+ count = 0
+ except TypeError:
+ temp_dict = {}
+
+ def expand_dict(dict_to_expand):
+ temp = dict()
+ for k, v in iteritems(dict_to_expand):
+ if isinstance(v, dict):
+ expand_dict(v)
+ else:
+ if v is not None:
+ temp.update({k: v})
+ temp_dict.update(tuple(iteritems(temp)))
+
+ new_dict = {k: v}
+ expand_dict(new_dict)
+ if tuple(iteritems(temp_dict)) not in test_set:
+ test_set.add(tuple(iteritems(temp_dict)))
+
+
+def dict_to_set(sample_dict):
+ # Generate a set with passed dictionary for comparison
+ test_dict = dict()
+ if isinstance(sample_dict, dict):
+ for k, v in iteritems(sample_dict):
+ if v is not None:
+ if isinstance(v, list):
+ if isinstance(v[0], dict):
+ li = []
+ for each in v:
+ for key, value in iteritems(each):
+ if isinstance(value, list):
+ each[key] = tuple(value)
+ li.append(tuple(iteritems(each)))
+ v = tuple(li)
+ else:
+ v = tuple(v)
+ elif isinstance(v, dict):
+ li = []
+ for key, value in iteritems(v):
+ if isinstance(value, list):
+ v[key] = tuple(value)
+ li.extend(tuple(iteritems(v)))
+ v = tuple(li)
+ test_dict.update({k: v})
+ return_set = set(tuple(iteritems(test_dict)))
+ else:
+ return_set = set(sample_dict)
+ return return_set
+
+
+def filter_dict_having_none_value(want, have):
+ # Generate dict with have dict value which is None in want dict
+ test_dict = dict()
+ test_key_dict = dict()
+ name = want.get("name")
+ if name:
+ test_dict["name"] = name
+ diff_ip = False
+ want_ip = ""
+ for k, v in iteritems(want):
+ if isinstance(v, dict):
+ for key, value in iteritems(v):
+ if value is None:
+ dict_val = have.get(k).get(key)
+ test_key_dict.update({key: dict_val})
+ test_dict.update({k: test_key_dict})
+ if isinstance(v, list):
+ for key, value in iteritems(v[0]):
+ if value is None:
+ dict_val = have.get(k).get(key)
+ test_key_dict.update({key: dict_val})
+ test_dict.update({k: test_key_dict})
+ # below conditions checks are added to check if
+ # secondary IP is configured, if yes then delete
+ # the already configured IP if want and have IP
+ # is different else if it's same no need to delete
+ for each in v:
+ if each.get("secondary"):
+ want_ip = each.get("address").split("/")
+ have_ip = have.get("ipv4")
+ 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 normalize_interface(name):
+ """Return the normalized interface name"""
+ if not name:
+ return
+
+ def _get_number(name):
+ digits = ""
+ for char in name:
+ if char.isdigit() or char in "/.":
+ digits += char
+ return digits
+
+ if name.lower().startswith("gi"):
+ if_type = "GigabitEthernet"
+ elif name.lower().startswith("te"):
+ if_type = "TenGigabitEthernet"
+ elif name.lower().startswith("fa"):
+ if_type = "FastEthernet"
+ elif name.lower().startswith("fo"):
+ if_type = "FortyGigabitEthernet"
+ elif name.lower().startswith("long"):
+ if_type = "LongReachEthernet"
+ elif name.lower().startswith("et"):
+ if_type = "Ethernet"
+ elif name.lower().startswith("vl"):
+ if_type = "Vlan"
+ elif name.lower().startswith("lo"):
+ if_type = "loopback"
+ elif name.lower().startswith("po"):
+ if_type = "Port-channel"
+ elif name.lower().startswith("nv"):
+ if_type = "nve"
+ elif name.lower().startswith("twe"):
+ if_type = "TwentyFiveGigE"
+ elif name.lower().startswith("hu"):
+ if_type = "HundredGigE"
+ else:
+ if_type = None
+
+ number_list = name.split(" ")
+ if len(number_list) == 2:
+ number = number_list[-1].strip()
+ else:
+ number = _get_number(name)
+
+ if if_type:
+ proper_interface = if_type + number
+ else:
+ proper_interface = name
+
+ return proper_interface
+
+
+def get_interface_type(interface):
+ """Gets the type of interface"""
+
+ if interface.upper().startswith("GI"):
+ return "GigabitEthernet"
+ elif interface.upper().startswith("TE"):
+ return "TenGigabitEthernet"
+ elif interface.upper().startswith("FA"):
+ return "FastEthernet"
+ elif interface.upper().startswith("FO"):
+ return "FortyGigabitEthernet"
+ elif interface.upper().startswith("LON"):
+ return "LongReachEthernet"
+ elif interface.upper().startswith("ET"):
+ return "Ethernet"
+ elif interface.upper().startswith("VL"):
+ return "Vlan"
+ elif interface.upper().startswith("LO"):
+ return "loopback"
+ elif interface.upper().startswith("PO"):
+ return "Port-channel"
+ elif interface.upper().startswith("NV"):
+ return "nve"
+ elif interface.upper().startswith("TWE"):
+ return "TwentyFiveGigE"
+ elif interface.upper().startswith("HU"):
+ return "HundredGigE"
+ else:
+ return "unknown"