diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
commit | a453ac31f3428614cceb99027f8efbdb9258a40b (patch) | |
tree | f61f87408f32a8511cbd91799f9cececb53e0374 /collections-debian-merged/ansible_collections/cisco/asa/plugins | |
parent | Initial commit. (diff) | |
download | ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.tar.xz ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.zip |
Adding upstream version 2.10.7+merged+base+2.10.8+dfsg.upstream/2.10.7+merged+base+2.10.8+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/asa/plugins')
46 files changed, 7640 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/asa.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/asa.py new file mode 100644 index 00000000..0fa543c4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/action/asa.py @@ -0,0 +1,96 @@ +# +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import sys +import copy + +from ansible import constants as C +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + asa_provider_spec, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + load_provider, +) +from ansible.utils.display import Display + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = ( + True if module_name in ["asa_config", "config"] else False + ) + + if self._play_context.connection == "local": + provider = load_provider(asa_provider_spec, self._task.args) + pc = copy.deepcopy(self._play_context) + pc.connection = "network_cli" + pc.network_os = "asa" + pc.remote_addr = provider["host"] or self._play_context.remote_addr + pc.port = int(provider["port"] or self._play_context.port or 22) + pc.remote_user = ( + provider["username"] or self._play_context.connection_user + ) + pc.password = provider["password"] or self._play_context.password + pc.private_key_file = ( + provider["ssh_keyfile"] or self._play_context.private_key_file + ) + command_timeout = int( + provider["timeout"] or C.PERSISTENT_COMMAND_TIMEOUT + ) + pc.become = provider["authorize"] or False + pc.become_pass = provider["auth_pass"] + pc.become_method = "enable" + + display.vvv( + "using connection plugin %s (was local)" % pc.connection, + pc.remote_addr, + ) + connection = self._shared_loader_obj.connection_loader.get( + "persistent", pc, sys.stdin, task_uuid=self._task._uuid + ) + connection.set_options( + direct={"persistent_command_timeout": command_timeout} + ) + + socket_path = connection.run() + + display.vvvv("socket_path: %s" % socket_path, pc.remote_addr) + if not socket_path: + return { + "failed": True, + "msg": "unable to open shell. Please see: " + + "https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell", + } + + task_vars["ansible_socket"] = socket_path + + result = super(ActionModule, self).run(task_vars=task_vars) + + return result diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/asa.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/asa.py new file mode 100644 index 00000000..d5126356 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/cliconf/asa.py @@ -0,0 +1,145 @@ +# +# (c) 2017 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +--- +author: Ansible Security Team +cliconf: asa +short_description: Use asa cliconf to run command on Cisco ASA platform +description: +- This asa plugin provides low level abstraction apis for sending and receiving CLI + commands from Cisco ASA network devices. +version_added: 1.0.0 +""" + +import re +import json + +from itertools import chain +from ansible.errors import AnsibleConnectionFailure +from ansible.module_utils._text import to_text +from ansible.module_utils.common._collections_compat import Mapping +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + to_list, +) +from ansible.plugins.cliconf import CliconfBase, enable_mode + + +class Cliconf(CliconfBase): + def get_device_info(self): + device_info = {} + + device_info["network_os"] = "asa" + reply = self.get("show version") + data = to_text(reply, errors="surrogate_or_strict").strip() + + match = re.search(r"Version (\S+)", data) + if match: + device_info["network_os_version"] = match.group(1) + + match = re.search(r"Firepower .+ Version (\S+)", data) + if match: + device_info["network_os_firepower_version"] = match.group(1) + + match = re.search(r"Device .+ Version (\S+)", data) + if match: + device_info["network_os_device_mgr_version"] = match.group(1) + + match = re.search(r"^Model Id:\s+(.+) \(revision", data, re.M) + if match: + device_info["network_os_model"] = match.group(1) + + match = re.search(r"^(.+) up", data, re.M) + if match: + device_info["network_os_hostname"] = match.group(1) + + match = re.search(r'image file is "(.+)"', data) + if match: + device_info["network_os_image"] = match.group(1) + + return device_info + + @enable_mode + def get_config(self, source="running", format="text", flags=None): + if source not in ("running", "startup"): + return self.invalid_params( + "fetching configuration from %s is not supported" % source + ) + if source == "running": + cmd = "show running-config all" + else: + cmd = "show startup-config" + return self.send_command(cmd) + + @enable_mode + def edit_config(self, command): + for cmd in chain(["configure terminal"], to_list(command), ["end"]): + self.send_command(cmd) + + def get( + self, + command, + prompt=None, + answer=None, + sendonly=False, + newline=True, + check_all=False, + ): + return self.send_command( + command=command, + prompt=prompt, + answer=answer, + sendonly=sendonly, + newline=newline, + check_all=check_all, + ) + + def get_capabilities(self): + result = super(Cliconf, self).get_capabilities() + return json.dumps(result) + + def run_commands(self, commands=None, check_rc=True): + if commands is None: + raise ValueError("'commands' value is required") + + responses = list() + for cmd in to_list(commands): + if not isinstance(cmd, Mapping): + cmd = {"command": cmd} + + output = cmd.pop("output", None) + if output: + raise ValueError( + "'output' value %s is not supported for run_commands" + % output + ) + + try: + out = self.send_command(**cmd) + except AnsibleConnectionFailure as e: + if check_rc: + raise + out = getattr(e, "err", to_text(e)) + + responses.append(out) + + return responses diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/asa.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/asa.py new file mode 100644 index 00000000..3ce7f396 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/doc_fragments/asa.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +# Copyright: (c) 2016, Peter Sprygada <psprygada@ansible.com> +# Copyright: (c) 2016, Patrick Ogenstad <@ogenstad> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +class ModuleDocFragment(object): + + # Standard files documentation fragment + DOCUMENTATION = r"""options: + authorize: + description: + - B(Deprecated) + - 'Starting with Ansible 2.5 we recommend using C(connection: network_cli) and + C(become: yes).' + - For more information please see the L(Network Guide, ../network/getting_started/network_differences.html#multiple-communication-protocols). + - HORIZONTALLINE + - Instructs the module to enter privileged mode on the remote device before sending + any commands. If not specified, the device will attempt to execute all commands + in non-privileged mode. If the value is not specified in the task, the value + of environment variable C(ANSIBLE_NET_AUTHORIZE) will be used instead. + type: bool + default: false + context: + description: + - Specifies which context to target if you are running in the ASA in multiple + context mode. Defaults to the current context you login to. + type: str + passwords: + description: + - Specifies which context to target if you are running in the ASA in multiple + context mode. Defaults to the current context you login to. + type: bool + provider: + description: + - B(Deprecated) + - 'Starting with Ansible 2.5 we recommend using C(connection: network_cli).' + - For more information please see the L(Network Guide, ../network/getting_started/network_differences.html#multiple-communication-protocols). + - HORIZONTALLINE + - A dict object containing connection details. + type: dict + suboptions: + host: + description: + - Specifies the DNS host name or address for connecting to the remote device + over the specified transport. The value of host is used as the destination + address for the transport. + type: str + port: + description: + - Specifies the port to use when building the connection to the remote device. + type: int + username: + description: + - Configures the username to use to authenticate the connection to the remote + device. This value is used to authenticate the SSH session. If the value + is not specified in the task, the value of environment variable C(ANSIBLE_NET_USERNAME) + will be used instead. + type: str + password: + description: + - Specifies the password to use to authenticate the connection to the remote + device. This value is used to authenticate the SSH session. If the value + is not specified in the task, the value of environment variable C(ANSIBLE_NET_PASSWORD) + will be used instead. + type: str + ssh_keyfile: + description: + - Specifies the SSH key to use to authenticate the connection to the remote + device. This value is the path to the key used to authenticate the SSH + session. If the value is not specified in the task, the value of environment + variable C(ANSIBLE_NET_SSH_KEYFILE) will be used instead. + type: path + authorize: + description: + - Instructs the module to enter privileged mode on the remote device before + sending any commands. If not specified, the device will attempt to execute + all commands in non-privileged mode. If the value is not specified in the + task, the value of environment variable C(ANSIBLE_NET_AUTHORIZE) will be + used instead. + type: bool + default: false + auth_pass: + description: + - Specifies the password to use if required to enter privileged mode on the + remote device. If I(authorize) is false, then this argument does nothing. + If the value is not specified in the task, the value of environment variable + C(ANSIBLE_NET_AUTH_PASS) will be used instead. + type: str + timeout: + description: + - Specifies idle timeout in seconds for the connection, in seconds. Useful + if the console freezes before continuing. For example when saving configurations. + type: int +notes: +- For more information on using Ansible to manage network devices see the :ref:`Ansible + Network Guide <network_guide>` +""" diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py new file mode 100644 index 00000000..3a8b2e52 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/acls/acls.py @@ -0,0 +1,290 @@ +# -*- 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"}, + "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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py new file mode 100644 index 00000000..e1f0b526 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/facts/facts.py @@ -0,0 +1,27 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The arg spec for the 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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py new file mode 100644 index 00000000..d236993a --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/argspec/ogs/ogs.py @@ -0,0 +1,229 @@ +# -*- 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 + """ + + def __init__(self, **kwargs): + pass + + 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", + }, + }, + }, + "protocol_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", + "udp", + ], + } + }, + }, + "security_group": { + "type": "dict", + "options": { + "sec_name": { + "type": "list", + "elements": "str", + }, + "tag": {"type": "list", "elements": "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", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py new file mode 100644 index 00000000..f2a3ba2f --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/asa.py @@ -0,0 +1,194 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# (c) 2016 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type +import json + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import env_fallback +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + EntityCollection, +) +from ansible.module_utils.connection import exec_command +from ansible.module_utils.connection import Connection, ConnectionError + +_DEVICE_CONFIGS = {} +_CONNECTION = None + +asa_provider_spec = { + "host": dict(), + "port": dict(type="int"), + "username": dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])), + "password": dict( + fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True + ), + "ssh_keyfile": dict( + fallback=(env_fallback, ["ANSIBLE_NET_SSH_KEYFILE"]), type="path" + ), + "authorize": dict( + fallback=(env_fallback, ["ANSIBLE_NET_AUTHORIZE"]), type="bool" + ), + "auth_pass": dict( + fallback=(env_fallback, ["ANSIBLE_NET_AUTH_PASS"]), no_log=True + ), + "timeout": dict(type="int"), +} + +asa_argument_spec = { + "provider": dict( + type="dict", + options=asa_provider_spec, + removed_at_date="2022-06-01", + removed_from_collection="cisco.asa", + ) +} + +asa_top_spec = { + "authorize": dict( + fallback=(env_fallback, ["ANSIBLE_NET_AUTHORIZE"]), type="bool" + ), + "context": dict(type="str"), + "passwords": dict(type="bool"), +} +asa_argument_spec.update(asa_top_spec) + +command_spec = {"command": dict(key=True), "prompt": dict(), "answer": dict()} + + +def get_provider_argspec(): + return asa_provider_spec + + +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") + capabilities = get_capabilities(module) + network_api = capabilities.get("network_api") + if network_api == "cliconf": + module._asa_connection = Connection(module._socket_path) + else: + module.fail_json(msg="Invalid connection type %s" % network_api) + + 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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py new file mode 100644 index 00000000..548453bd --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/acls/acls.py @@ -0,0 +1,199 @@ +# +# -*- 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 + + +from ansible.module_utils.six import iteritems +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.facts import ( + Facts, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.rm_templates.acls import ( + AclsTemplate, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import ( + ResourceModule, +) + + +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: + wantd = {(entry["name"]): entry for entry in self.want["acls"]} + else: + wantd = {} + if self.have: + haved = {(entry["name"]): entry for entry in self.have["acls"]} + 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": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = { + k: v for k, v in iteritems(haved) if k in wantd or not wantd + } + wantd = {} + + # remove superfluous config for overridden and deleted + if self.state in ["overridden", "deleted"]: + for k, have in iteritems(haved): + if k not in wantd: + self._compare(want={}, have=have) + + 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 + 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}, + ) + del have.get("aces")[temp] + 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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py new file mode 100644 index 00000000..857b43ff --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/config/ogs/ogs.py @@ -0,0 +1,459 @@ +# +# -*- 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.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, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.resource_module import ( + ResourceModule, +) + + +class 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: + wantd = {(entry["object_type"]): entry for entry in self.want} + else: + wantd = {} + if self.have: + haved = {(entry["object_type"]): entry for entry in self.have} + 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: + 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 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", + ] + 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: + self._add_object_cmd( + entry, + h_item, + network_obj, + ["address", "host", "ipv6_address"], + ) + else: + add_obj_cmd = True + self.addcmd(entry, "og_name", False) + self.compare(["description"], entry, h_item) + 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[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[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) + 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: + 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[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: + 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[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" + for name, entry in iteritems(want): + h_item = have.pop(name, {}) + if entry != h_item and name != "object_type": + if h_item: + self._add_object_cmd( + entry, h_item, service_obj, ["protocol"] + ) + else: + self.addcmd(entry, "og_name", False) + self.compare(["description"], entry, h_item) + if entry[service_obj].get("protocol"): + self._compare_object_diff( + entry, + h_item, + service_obj, + "protocol", + ["service_object"], + service_obj, + ) + self.check_for_have_and_overidden(have) + + 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: + 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[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) + have_element = have[object].get(each) + if want_element 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 _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[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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py new file mode 100644 index 00000000..5c3f7b97 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/acls/acls.py @@ -0,0 +1,106 @@ +# +# -*- 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.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, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import ( + NetworkTemplate, +) + + +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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py new file mode 100644 index 00000000..b874c3f0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/facts.py @@ -0,0 +1,67 @@ +# -*- 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.ogs.ogs import ( + OGsFacts, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.legacy.base import ( + Default, + Hardware, + Config, +) + + +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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py new file mode 100644 index 00000000..3ad46007 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/legacy/base.py @@ -0,0 +1,186 @@ +# -*- 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 ( + run_commands, + get_capabilities, +) + + +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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py new file mode 100644 index 00000000..cf1c4335 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/facts/ogs/ogs.py @@ -0,0 +1,108 @@ +# -*- 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 copy import deepcopy +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.cisco.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, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network_template import ( + NetworkTemplate, +) + + +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 + 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_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") + 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": 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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py new file mode 100644 index 00000000..1a847275 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/module.py @@ -0,0 +1,73 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.providers import ( + providers, +) +from ansible.module_utils._text import to_text + + +class NetworkModule(AnsibleModule): + + fail_on_missing_provider = True + + def __init__(self, connection=None, *args, **kwargs): + super(NetworkModule, self).__init__(*args, **kwargs) + + if connection is None: + connection = Connection(self._socket_path) + + self.connection = connection + + @property + def provider(self): + if not hasattr(self, "_provider"): + capabilities = self.from_json(self.connection.get_capabilities()) + + network_os = capabilities["device_info"]["network_os"] + network_api = capabilities["network_api"] + + if network_api == "cliconf": + connection_type = "network_cli" + + cls = providers.get( + network_os, self._name.split(".")[-1], connection_type + ) + + if not cls: + msg = ( + "unable to find suitable provider for network os %s" + % network_os + ) + if self.fail_on_missing_provider: + self.fail_json(msg=msg) + else: + self.warn(msg) + + obj = cls(self.params, self.connection, self.check_mode) + + setattr(self, "_provider", obj) + + return getattr(self, "_provider") + + def get_facts(self, subset=None): + try: + self.provider.get_facts(subset) + except Exception as exc: + self.fail_json(msg=to_text(exc)) + + def edit_config(self, config_filter=None): + current_config = self.connection.get_config(flags=config_filter) + try: + commands = self.provider.edit_config(current_config) + changed = bool(commands) + return {"commands": commands, "changed": changed} + except Exception as exc: + self.fail_json(msg=to_text(exc)) diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py new file mode 100644 index 00000000..fdf99cb3 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/providers/providers.py @@ -0,0 +1,129 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import json + +from threading import RLock + +from ansible.module_utils.six import itervalues +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + to_list, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, +) + + +_registered_providers = {} +_provider_lock = RLock() + + +def register_provider(network_os, module_name): + def wrapper(cls): + _provider_lock.acquire() + try: + if network_os not in _registered_providers: + _registered_providers[network_os] = {} + for ct in cls.supported_connections: + if ct not in _registered_providers[network_os]: + _registered_providers[network_os][ct] = {} + for item in to_list(module_name): + for entry in itervalues(_registered_providers[network_os]): + entry[item] = cls + finally: + _provider_lock.release() + return cls + + return wrapper + + +def get(network_os, module_name, connection_type): + network_os_providers = _registered_providers.get(network_os) + if network_os_providers is None: + raise ValueError("unable to find a suitable provider for this module") + if connection_type not in network_os_providers: + raise ValueError("provider does not support this connection type") + elif module_name not in network_os_providers[connection_type]: + raise ValueError("could not find a suitable provider for this module") + return network_os_providers[connection_type][module_name] + + +class ProviderBase(object): + + supported_connections = () + + def __init__(self, params, connection=None, check_mode=False): + self.params = params + self.connection = connection + self.check_mode = check_mode + + @property + def capabilities(self): + if not hasattr(self, "_capabilities"): + resp = self.from_json(self.connection.get_capabilities()) + setattr(self, "_capabilities", resp) + return getattr(self, "_capabilities") + + def get_value(self, path): + params = self.params.copy() + for key in path.split("."): + params = params[key] + return params + + def get_facts(self, subset=None): + raise NotImplementedError(self.__class__.__name__) + + def edit_config(self): + raise NotImplementedError(self.__class__.__name__) + + +class CliProvider(ProviderBase): + + supported_connections = ("network_cli",) + + @property + def capabilities(self): + if not hasattr(self, "_capabilities"): + resp = self.from_json(self.connection.get_capabilities()) + setattr(self, "_capabilities", resp) + return getattr(self, "_capabilities") + + def get_config_context(self, config, path, indent=1): + if config is not None: + netcfg = NetworkConfig(indent=indent, contents=config) + try: + config = netcfg.get_block_config(to_list(path)) + except ValueError: + config = None + return config + + def render(self, config=None): + raise NotImplementedError(self.__class__.__name__) + + def cli(self, command): + try: + if not hasattr(self, "_command_output"): + setattr(self, "_command_output", {}) + return self._command_output[command] + except KeyError: + out = self.connection.get(command) + try: + out = json.loads(out) + except ValueError: + pass + self._command_output[command] = out + return out + + def get_facts(self, subset=None): + return self.populate() + + def edit_config(self, config=None): + commands = self.render(config) + if commands and self.check_mode is False: + self.connection.edit_config(commands) + return commands diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py new file mode 100644 index 00000000..c57c5ffd --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/acls.py @@ -0,0 +1,231 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import re +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.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 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"): + 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: + cmd = "access-list {name} line {line}".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}\.){3}[0-9]{1,3}\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|interface\s\S+|object-group\s\S+)* + \s*(?P<source_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+))* + \s*(?P<destination>any4|any6|any|(?:[0-9]{1,3}\.){3}[0-9]{1,3}\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+|host\s(?:[0-9]{1,3}\.){3}[0-9]{1,3}|interface\s\S+|object-group\s\S+)* + \s*(?P<dest_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+))* + \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 %}{{ source.split(' ')[0] }}{% elif source is defined and\ + '::' in source %}{{ source }}{% endif %}", + "netmask": "{{ source.split(' ')[1] if source is defined and '.' in source and 'host' not in source else None }}", + "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 else None }}": "{{ source_port_protocol.split(' ')[1]\ + if source_port_protocol is defined else None }}" + }, + }, + "destination": { + "address": "{% if destination is defined and\ + '.' 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\ + '.' 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 %}{{ source_host.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 }}", + "port_protocol": { + "{{ dest_port_protocol.split(' ')[0] if dest_port_protocol\ + is defined else None }}": "{{ dest_port_protocol.split(' ')[1]\ + if dest_port_protocol is defined else None }}" + }, + }, + "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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py new file mode 100644 index 00000000..ed196fdf --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/rm_templates/ogs.py @@ -0,0 +1,400 @@ +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import re +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.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_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_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("user-group {domain}\\{name} {0}".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+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_object_group, + "result": { + "ogs": { + "{{ obj_type }}": { + "{{ obj_name }}": { + "object_type": "{{ obj_type }}", + "name": "{{ obj_name }}", + } + } + } + }, + "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.host", + "getval": re.compile( + r"""\s+network-object* + \s*(?P<host_obj>host)* + \s*(?P<host_address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_network_object, + "compval": "network_object.host", + "result": { + "ogs": { + "{{ obj_type }}": { + "{{ obj_name }}": {"host": ["{{ host_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.object", + "getval": re.compile( + r"""\s+network-object\s + object* + \s*(?P<object>\S+) + *$""", + re.VERBOSE, + ), + "setval": "network-object 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": "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": "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": "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": "{{ domain }}", + } + ] + } + } + } + }, + }, + { + "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/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py new file mode 100644 index 00000000..5dd85312 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/module_utils/network/asa/utils/utils.py @@ -0,0 +1,330 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# utils + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import socket +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + is_masklen, + to_netmask, +) + + +def remove_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" diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acl.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acl.py new file mode 100644 index 00000000..a73bcc4a --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acl.py @@ -0,0 +1,235 @@ +#!/usr/bin/python +# +# Copyright: Ansible Project +# 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 + + +DOCUMENTATION = """ +module: asa_acl +author: Patrick Ogenstad (@ogenstad) +short_description: (deprecated, removed after 2022-06-01) Manage access-lists on a + Cisco ASA +description: +- This module allows you to work with access-lists on a Cisco ASA device. +version_added: 1.0.0 +deprecated: + alternative: asa_acl + why: Newer and updated modules released with more functionality in Ansible 2.10 + removed_at_date: '2022-06-01' +extends_documentation_fragment: +- cisco.asa.asa +options: + lines: + description: + - The ordered set of commands that should be configured in the section. The commands + must be the exact same commands as found in the device running-config. Be sure + to note the configuration command syntax as some commands are automatically + modified by the device config parser. + required: true + aliases: + - commands + type: list + elements: str + before: + description: + - The ordered set of commands to push on to the command stack if a change needs + to be made. This allows the playbook designer the opportunity to perform configuration + commands prior to pushing any changes without affecting how the set of commands + are matched against the system. + type: list + elements: str + after: + description: + - The ordered set of commands to append to the end of the command stack if a changed + needs to be made. Just like with I(before) this allows the playbook designer + to append a set of commands to be executed after the command set. + type: list + elements: str + match: + description: + - Instructs the module on the way to perform the matching of the set of commands + against the current device config. If match is set to I(line), commands are + matched line by line. If match is set to I(strict), command lines are matched + with respect to position. Finally if match is set to I(exact), command lines + must be an equal match. + default: line + choices: + - line + - strict + - exact + type: str + replace: + description: + - Instructs the module on the way to perform the configuration on the device. If + the replace argument is set to I(line) then the modified lines are pushed to + the device in configuration mode. If the replace argument is set to I(block) + then the entire command block is pushed to the device in configuration mode + if any line is not correct. + default: line + choices: + - line + - block + type: str + force: + description: + - The force argument instructs the module to not consider the current devices + running-config. When set to true, this will cause the module to push the contents + of I(src) into the device without first checking if already configured. + type: bool + default: no + config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. There + are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. + type: str +""" + +EXAMPLES = """ +- cisco.asa.asa_acl: + lines: + - access-list ACL-ANSIBLE extended permit tcp any any eq 82 + - access-list ACL-ANSIBLE extended permit tcp any any eq www + - access-list ACL-ANSIBLE extended permit tcp any any eq 97 + - access-list ACL-ANSIBLE extended permit tcp any any eq 98 + - access-list ACL-ANSIBLE extended permit tcp any any eq 99 + before: clear configure access-list ACL-ANSIBLE + match: strict + replace: block + provider: '{{ cli }}' + +- cisco.asa.asa_acl: + lines: + - access-list ACL-OUTSIDE extended permit tcp any any eq www + - access-list ACL-OUTSIDE extended permit tcp any any eq https + context: customer_a + provider: '{{ cli }}' +""" + +RETURN = """ +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['access-list ACL-OUTSIDE extended permit tcp any any eq www'] +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + asa_argument_spec, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + get_config, + load_config, +) + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) + + +def get_acl_config(module, acl_name): + contents = module.params["config"] + if not contents: + contents = get_config(module) + + filtered_config = list() + for item in contents.split("\n"): + if item.startswith("access-list %s " % acl_name): + filtered_config.append(item) + + return NetworkConfig(indent=1, contents="\n".join(filtered_config)) + + +def parse_acl_name(module): + first_line = True + for line in module.params["lines"]: + ace = line.split() + if ace[0] != "access-list": + module.fail_json( + msg='All lines/commands must begin with "access-list" %s is not permitted' + % ace[0] + ) + if len(ace) <= 1: + module.fail_json( + msg="All lines/commands must contain the name of the access-list" + ) + if first_line: + acl_name = ace[1] + else: + if acl_name != ace[1]: + module.fail_json( + msg="All lines/commands must use the same access-list %s is not %s" + % (ace[1], acl_name) + ) + first_line = False + + return acl_name + + +def main(): + + argument_spec = dict( + lines=dict( + aliases=["commands"], required=True, type="list", elements="str" + ), + before=dict(type="list", elements="str"), + after=dict(type="list", elements="str"), + match=dict( + default="line", choices=["line", "strict", "exact"], type="str" + ), + replace=dict(default="line", choices=["line", "block"], type="str"), + force=dict(default=False, type="bool"), + config=dict(type="str"), + ) + + argument_spec.update(asa_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + + lines = module.params["lines"] + + result = {"changed": False} + if len(lines) > 0: + candidate = NetworkConfig(indent=1) + candidate.add(lines) + + acl_name = parse_acl_name(module) + + if not module.params["force"]: + contents = get_acl_config(module, acl_name) + config = NetworkConfig(indent=1, contents=contents) + + commands = candidate.difference(config) + commands = dumps(commands, "commands").split("\n") + commands = [str(c) for c in commands if c] + else: + commands = str(candidate).split("\n") + + if commands: + if module.params["before"]: + commands[:0] = module.params["before"] + + if module.params["after"]: + commands.extend(module.params["after"]) + + if not module.check_mode: + load_config(module, commands) + + result["changed"] = True + + result["updates"] = commands + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acls.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acls.py new file mode 100644 index 00000000..dfcaf159 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_acls.py @@ -0,0 +1,1258 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for asa_acls +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: asa_acls +short_description: Access-Lists resource module +description: This module configures and manages the named or numbered ACLs on ASA + platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco ASA Version 9.10(1)11 +- This module works with connection C(network_cli). See L(ASA Platform Options,../network/user_guide/platform_asa.html). +options: + config: + description: A dictionary of ACL options. + type: dict + suboptions: + acls: + description: + - A list of Access Control Lists (ACL). + type: list + elements: dict + suboptions: + name: + description: The name or the number of the ACL. + required: true + type: str + acl_type: + description: + - ACL type + type: str + choices: + - extended + - standard + rename: + description: + - Rename an existing access-list. + - If input to rename param is given, it'll take preference over other + parameters and only rename config will be matched and computed against. + type: str + aces: + description: The entries within the ACL. + elements: dict + type: list + suboptions: + grant: + description: Specify the action. + type: str + choices: + - permit + - deny + line: + description: + - Use this to specify line number at which ACE should be entered. + - Existing ACE can be updated based on the input line number. + - It's not a required param in case of configuring the acl, but in + case of Delete operation it's required, else Delete operation won't + work as expected. + - Refer to vendor documentation for valid values. + type: int + remark: + description: + - Specify a comment (remark) for the access-list after this keyword + type: str + protocol: + description: + - Specify the protocol to match. + - Refer to vendor documentation for valid values. + type: str + protocol_options: + description: protocol type. + type: dict + suboptions: + protocol_number: + description: An IP protocol number + type: int + ahp: + description: Authentication Header Protocol. + type: bool + eigrp: + description: Cisco's EIGRP routing protocol. + type: bool + esp: + description: Encapsulation Security Payload. + type: bool + gre: + description: Cisco's GRE tunneling. + type: bool + icmp: + description: Internet Control Message Protocol. + type: dict + suboptions: + alternate_address: + description: Alternate address + type: bool + conversion_error: + description: Datagram conversion + type: bool + echo: + description: Echo (ping) + type: bool + echo_reply: + description: Echo reply + type: bool + information_reply: + description: Information replies + type: bool + information_request: + description: Information requests + type: bool + mask_reply: + description: Mask replies + type: bool + mask_request: + description: mask_request + type: bool + mobile_redirect: + description: Mobile host redirect + type: bool + parameter_problem: + description: All parameter problems + type: bool + redirect: + description: All redirects + type: bool + router_advertisement: + description: Router discovery advertisements + type: bool + router_solicitation: + description: Router discovery solicitations + type: bool + source_quench: + description: Source quenches + type: bool + source_route_failed: + description: Source route + type: bool + time_exceeded: + description: All time exceededs + type: bool + timestamp_reply: + description: Timestamp replies + type: bool + timestamp_request: + description: Timestamp requests + type: bool + traceroute: + description: Traceroute + type: bool + unreachable: + description: All unreachables + type: bool + icmp6: + description: Internet Control Message Protocol. + type: dict + suboptions: + echo: + description: Echo (ping) + type: bool + echo_reply: + description: Echo reply + type: bool + membership_query: + description: Membership query + type: bool + membership_reduction: + description: Membership reduction + type: bool + membership_report: + description: Membership report + type: bool + neighbor_advertisement: + description: Neighbor advertisement + type: bool + neighbor_redirect: + description: Neighbor redirect + type: bool + neighbor_solicitation: + description: Neighbor_solicitation + type: bool + packet_too_big: + description: Packet too big + type: bool + parameter_problem: + description: Parameter problem + type: bool + router_advertisement: + description: Router discovery advertisements + type: bool + router_renumbering: + description: Router renumbering + type: bool + router_solicitation: + description: Router solicitation + type: bool + time_exceeded: + description: Time exceeded + type: bool + unreachable: + description: All unreachables + type: bool + igmp: + description: Internet Gateway Message Protocol. + type: bool + igrp: + description: Internet Gateway Routing Protocol. + type: bool + ip: + description: Any Internet Protocol. + type: bool + ipinip: + description: IP in IP tunneling. + type: bool + ipsec: + description: IP Security. + type: bool + nos: + description: KA9Q NOS compatible IP over IP tunneling. + type: bool + ospf: + description: OSPF routing protocol. + type: bool + pcp: + description: Payload Compression Protocol. + type: bool + pim: + description: Protocol Independent Multicast. + type: bool + pptp: + description: Point-to-Point Tunneling Protocol. + type: bool + sctp: + description: Stream Control Transmission Protocol. + type: bool + snp: + description: Simple Network Protocol. + type: bool + udp: + description: User Datagram Protocol. + type: bool + tcp: + description: Match TCP packet flags + type: bool + source: + description: Specify the packet source. + type: dict + suboptions: + address: + description: Source network address. + type: str + netmask: + description: Netmask for source IP address, valid with IPV4 address. + type: str + any: + description: + - Match any source address. + type: bool + any4: + description: + - Match any ipv4 source address. + type: bool + any6: + description: + - Match any ipv6 source address. + type: bool + host: + description: A single source host + type: str + interface: + description: Use interface address as source address + type: str + object_group: + description: Network object-group for source address + type: str + port_protocol: + description: + - Specify the destination port along with protocol. + - Note, Valid with TCP/UDP protocol_options + type: dict + suboptions: + eq: + description: Match only packets on a given port number. + type: str + gt: + description: Match only packets with a greater port number. + type: str + lt: + description: Match only packets with a lower port number. + type: str + neq: + description: Match only packets not on a given port number. + type: str + range: + description: Port range operator + type: dict + suboptions: + start: + description: Specify the start of the port range. + type: int + end: + description: Specify the end of the port range. + type: int + destination: + description: Specify the packet destination. + type: dict + suboptions: + address: + description: Host address to match, or any single host address. + type: str + netmask: + description: Netmask for destination IP address, valid with IPV4 + address. + type: str + any: + description: Match any destination address. + type: bool + any4: + description: + - Match any ipv4 destination address. + type: bool + any6: + description: + - Match any ipv6 destination address. + type: bool + host: + description: A single destination host + type: str + interface: + description: Use interface address as destination address + type: str + object_group: + description: Network object-group for destination address + type: str + port_protocol: + description: + - Specify the destination port along with protocol. + - Note, Valid with TCP/UDP protocol_options + type: dict + suboptions: + eq: + description: Match only packets on a given port number. + type: str + gt: + description: Match only packets with a greater port number. + type: str + lt: + description: Match only packets with a lower port number. + type: str + neq: + description: Match only packets not on a given port number. + type: str + range: + description: Port range operator + type: dict + suboptions: + start: + description: Specify the start of the port range. + type: int + end: + description: Specify the end of the port range. + type: int + inactive: + description: Keyword for disabling an ACL element. + type: bool + log: + description: Log matches against this entry. + type: str + choices: + - default + - alerts + - critical + - debugging + - disable + - emergencies + - errors + - informational + - interval + - notifications + - warnings + time_range: + description: Specify a time-range. + type: str + running_config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. + There are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(running_config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged + description: + - The state of the configuration after module completion + type: str + +""" + +EXAMPLES = """ +# Using merged +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 2 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list R1_traffic; 1 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 + +- name: Merge provided configuration with device configuration + cisco.asa.asa_acls: + config: + acls: + - name: temp_access + acl_type: extended + aces: + - grant: deny + line: 1 + protocol_options: + tcp: true + source: + address: 192.0.2.0 + netmask: 255.255.255.0 + destination: + address: 192.0.3.0 + netmask: 255.255.255.0 + port_protocol: + eq: www + log: default + - grant: deny + line: 2 + protocol_options: + igrp: true + source: + address: 198.51.100.0 + netmask: 255.255.255.0 + destination: + address: 198.51.110.0 + netmask: 255.255.255.0 + time_range: temp + - grant: deny + line: 3 + protocol_options: + tcp: true + source: + interface: management + destination: + interface: management + port_protocol: + eq: www + log: warnings + - grant: deny + line: 4 + protocol_options: + tcp: true + source: + object_group: test_og_network + destination: + object_group: test_network_og + port_protocol: + eq: www + log: default + - name: global_access + acl_type: extended + aces: + - line: 3 + remark: test global access + - grant: deny + line: 4 + protocol_options: + tcp: true + source: + any: true + destination: + any: true + port_protocol: + eq: www + log: errors + - name: R1_traffic + aces: + - line: 1 + remark: test_v6_acls + - grant: deny + line: 2 + protocol_options: + tcp: true + source: + address: 2001:db8:0:3::/64 + port_protocol: + eq: www + destination: + address: 2001:fc8:0:4::/64 + port_protocol: + eq: telnet + inactive: true + state: merged + +# Commands fired: +# --------------- +# access-list global_access line 3 remark test global access +# access-list global_access line 4 extended deny tcp any any eq www log errors interval 300 +# access-list R1_traffic line 1 remark test_v6_acls +# access-list R1_traffic line 2 extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet inactive +# access-list temp_access line 1 extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www log default +# access-list temp_access line 2 extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp inactive +# access-list temp_access line 2 extended deny tcp interface management interface management +# eq www log warnings +# access-list test_access line 3 extended deny tcp object-group test_og_network object-group test_network_og +# eq www log default + +# After state: +# ------------ +# +# vasa#sh access-lists +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list global_access line 3 remark test global access (hitcnt=0) 0xae78337e +# access-list global_access line 4 extended deny tcp any any eq www log errors interval 300 (hitcnt=0) 0x605f2421 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 remark test_v6_acls +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae +# access-list test_access line 3 +# extended deny tcp interface management interface management eq www log warnings +# interval 300 (hitcnt=0) 0x78aa233d +# access-list test_access line 2 extended deny tcp object-group test_og_network object-group test_network_og +# eq www log default (hitcnt=0) 0x477aec1e +# access-list test_access line 2 extended deny tcp 192.0.2.0 255.255.255.0 host 192.0.3.1 eq www +# log default (hitcnt=0) 0xdc7edff8 +# access-list test_access line 2 extended deny tcp 192.0.2.0 255.255.255.0 host 192.0.3.2 eq www +# log default (hitcnt=0) 0x7b0e9fde +# access-list test_access line 2 extended deny tcp 198.51.100.0 255.255.255.0 2001:db8:3::/64 eq www +# log default (hitcnt=0) 0x97c75adc + +# Using Merged to Rename ACLs +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 2 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list R1_traffic; 1 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 + +- name: Rename ACL with different name using Merged state + cisco.asa.asa_acls: + config: + acls: + - name: global_access + rename: global_access_renamed + - name: R1_traffic + rename: R1_traffic_renamed + state: merged + +# Commands fired: +# --------------- +# access-list global_access rename global_access_renamed +# access-list R1_traffic rename R1_traffic_renamed + +# After state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access_renamed; 2 elements; name hash: 0xbd6c87a7 +# access-list global_access_renamed line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access_renamed line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list R1_traffic_renamed; 1 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic_renamed line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 + + +# Using replaced + +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 (hitcnt=0) 0x605f2421 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + +- name: Replaces device configuration of listed acl with provided configuration + cisco.asa.asa_acls: + config: + acls: + - name: global_access + acl_type: extended + aces: + - grant: deny + line: 1 + protocol_options: + tcp: true + source: + address: 192.0.4.0 + netmask: 255.255.255.0 + port_protocol: + eq: telnet + destination: + address: 192.0.5.0 + netmask: 255.255.255.0 + port_protocol: + eq: www + state: replaced + +# Commands fired: +# --------------- +# no access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 +# no access-list global_access line 2 extended deny tcp any any eq telnet +# no access-list global_access line 1 extended permit icmp any any log disable +# access-list global_access line 1 extended deny tcp 192.0.4.0 255.255.255.0 eq telnet 192.0.5.0 255.255.255.0 eq www + +# After state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 1 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended deny tcp 192.0.4.0 255.255.255.0 eq telnet +# 192.0.5.0 255.255.255.0 eq www (hitcnt=0) 0x3e5b2757 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + +# Using overridden + +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 (hitcnt=0) 0x605f2421 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + + +- name: Override device configuration of all acl with provided configuration + cisco.asa.asa_acls: + config: + acls: + - name: global_access + acl_type: extended + aces: + - grant: deny + line: 1 + protocol_options: + tcp: true + source: + address: 192.0.4.0 + netmask: 255.255.255.0 + port_protocol: + eq: telnet + destination: + address: 192.0.5.0 + netmask: 255.255.255.0 + port_protocol: + eq: www + state: overridden + +# Commands fired: +# --------------- +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 time-range temp +# no access-list temp_access line 1 +# extended grant deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www log default +# no access-list R1_traffic line 2 +# extended grant deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet inactive +# no access-list R1_traffic line 1 +# extended grant deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www log errors +# no access-list global_access line 3 extended grant deny tcp any any eq www log errors +# no access-list global_access line 2 extended grant deny tcp any any eq telnet +# no access-list global_access line 1 extended grant permit icmp any any log disable +# access-list global_access line 4 extended deny tcp 192.0.4.0 255.255.255.0 eq telnet 192.0.5.0 255.255.255.0 eq www + +# After state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 1 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 + +# Using Deleted + +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 (hitcnt=0) 0x605f2421 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + +- name: "Delete module attributes of given acl (Note: This won't delete ALL of the ACLs configured)" + cisco.asa.asa_acls: + config: + acls: + - name: temp_access + - name: global_access + state: deleted + +# Commands fired: +# --------------- +# no access-list temp_access line 2 extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp inactive +# no access-list temp_access line 1 extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default +# no access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 +# no access-list global_access line 2 extended deny tcp any any eq telnet +# no access-list global_access line 1 extended permit icmp any any log disable + +# After state: +# ------------- +# +# vasa#sh access-lists +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 + +# Using Deleted without any config passed +#"(NOTE: This will delete all of configured resource module attributes)" + +# Before state: +# ------------- +# +# vasa#sh access-lists +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 (hitcnt=0) 0x605f2421 +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + +- name: 'Delete ALL ACLs in one go (Note: This WILL delete the ALL of configured ACLs)' + cisco.asa.asa_acls: + state: deleted + +# Commands fired: +# --------------- +# no access-list global_access line 1 extended permit icmp any any log disable +# no access-list global_access line 2 extended deny tcp any any eq telnet +# no access-list global_access line 3 extended deny tcp any any eq www log errors interval 300 +# no access-list R1_traffic line 1 extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 +# no access-list R1_traffic line 2 extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet inactive +# no access-list temp_access line 1 extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www log default +# no access-list temp_access line 2 extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp inactive + + +# After state: +# ------------- +# +# vasa#sh access-lists + +# Using Gathered + +# Before state: +# ------------- +# +# access-list global_access; 3 elements; name hash: 0xbd6c87a7 +# access-list global_access line 1 extended permit icmp any any log disable (hitcnt=0) 0xf1efa630 +# access-list global_access line 2 extended deny tcp any any eq telnet (hitcnt=0) 0xae5833af +# access-list R1_traffic; 2 elements; name hash: 0xaf40d3c2 +# access-list R1_traffic line 1 +# extended deny tcp 2001:db8:0:3::/64 eq telnet 2001:fc8:0:4::/64 eq www +# log errors interval 300 (hitcnt=0) 0x4a4660f3 +# access-list R1_traffic line 2 +# extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet +# inactive (hitcnt=0) (inactive) 0xe922b432 +# access-list temp_access; 2 elements; name hash: 0xaf1b712e +# access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www +# log default (hitcnt=0) 0xb58abb0d +# access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp (hitcnt=0) (inactive) 0xcd6b92ae + + +- name: Gather listed ACLs with provided configurations + cisco.asa.asa_acls: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "any": true +# }, +# "grant": "permit", +# "line": 1, +# "log": "disable", +# "protocol": "icmp", +# "source": { +# "any": true +# } +# }, +# { +# "destination": { +# "any": true, +# "port_protocol": { +# "eq": "telnet" +# } +# }, +# "grant": "deny", +# "line": 2, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "any": true +# } +# } +# ], +# "acl_type": "extended", +# "name": "global_access" +# }, +# { +# "aces": [ +# { +# "destination": { +# "address": "2001:fc8:0:4::/64", +# "port_protocol": { +# "eq": "www" +# } +# }, +# "grant": "deny", +# "line": 1, +# "log": "errors", +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "address": "2001:db8:0:3::/64", +# "port_protocol": { +# "eq": "telnet" +# } +# } +# }, +# { +# "destination": { +# "address": "2001:fc8:0:4::/64", +# "port_protocol": { +# "eq": "telnet" +# } +# }, +# "grant": "deny", +# "inactive": true, +# "line": 2, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "address": "2001:db8:0:3::/64", +# "port_protocol": { +# "eq": "www" +# } +# } +# } +# ], +# "acl_type": "extended", +# "name": "R1_traffic" +# }, +# { +# "aces": [ +# { +# "destination": { +# "address": "192.0.3.0", +# "netmask": "255.255.255.0", +# "port_protocol": { +# "eq": "www" +# } +# }, +# "grant": "deny", +# "line": 1, +# "log": "default", +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "address": "192.0.2.0", +# "netmask": "255.255.255.0" +# } +# }, +# { +# "destination": { +# "address": "198.51.110.0", +# "netmask": "255.255.255.0" +# }, +# "grant": "deny", +# "inactive": true, +# "line": 2, +# "protocol": "igrp", +# "protocol_options": { +# "igrp": true +# }, +# "source": { +# "address": "198.51.100.0", +# "netmask": "255.255.255.0" +# }, +# "time_range": "temp" +# } +# ], +# "acl_type": "extended", +# "name": "temp_access" +# } +# ] +# } +# ] + +# Using Rendered + +- name: Rendered the provided configuration with the exisiting running configuration + cisco.asa.asa_acls: + config: + acls: + - name: temp_access + acl_type: extended + aces: + - grant: deny + line: 1 + protocol_options: + tcp: true + source: + address: 192.0.2.0 + netmask: 255.255.255.0 + destination: + address: 192.0.3.0 + netmask: 255.255.255.0 + port_protocol: + eq: www + log: default + - grant: deny + line: 2 + protocol_options: + igrp: true + source: + address: 198.51.100.0 + netmask: 255.255.255.0 + destination: + address: 198.51.110.0 + netmask: 255.255.255.0 + time_range: temp + - name: R1_traffic + aces: + - grant: deny + protocol_options: + tcp: true + source: + address: 2001:db8:0:3::/64 + port_protocol: + eq: www + destination: + address: 2001:fc8:0:4::/64 + port_protocol: + eq: telnet + inactive: true + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "access-list temp_access line 1 +# extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 +# eq www log default" +# "access-list temp_access line 2 +# extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 +# time-range temp" +# "access-list R1_traffic +# deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet inactive" +# ] + +# Using Parsed + +# parsed.cfg +# +# access-list test_access; 2 elements; name hash: 0xaf1b712e +# access-list test_access line 1 extended deny tcp 192.0.2.0 255.255.255.0 192.0.3.0 255.255.255.0 eq www log default +# access-list test_access line 2 extended deny igrp 198.51.100.0 255.255.255.0 198.51.110.0 255.255.255.0 log errors +# access-list test_R1_traffic; 1 elements; name hash: 0xaf40d3c2 +# access-list test_R1_traffic line 1 extended deny tcp 2001:db8:0:3::/64 eq www 2001:fc8:0:4::/64 eq telnet inactive + +- name: Parse the commands for provided configuration + cisco.asa.asa_acls: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "destination": { +# "address": "192.0.3.0", +# "netmask": "255.255.255.0", +# "port_protocol": { +# "eq": "www" +# } +# }, +# "grant": "deny", +# "line": 1, +# "log": "default", +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "address": "192.0.2.0", +# "netmask": "255.255.255.0" +# } +# }, +# { +# "destination": { +# "address": "198.51.110.0", +# "netmask": "255.255.255.0" +# }, +# "grant": "deny", +# "line": 2, +# "log": "errors", +# "protocol": "igrp", +# "protocol_options": { +# "igrp": true +# }, +# "source": { +# "address": "198.51.100.0", +# "netmask": "255.255.255.0" +# } +# } +# ], +# "acl_type": "extended", +# "name": "test_access" +# }, +# { +# "aces": [ +# { +# "destination": { +# "address": "2001:fc8:0:4::/64", +# "port_protocol": { +# "eq": "telnet" +# } +# }, +# "grant": "deny", +# "inactive": true, +# "line": 1, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": true +# }, +# "source": { +# "address": "2001:db8:0:3::/64", +# "port_protocol": { +# "eq": "www" +# } +# } +# } +# ], +# "acl_type": "extended", +# "name": "test_R1_TRAFFIC" +# } +# ] +# } +# ] + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['access-list global_access line 1 extended permit icmp any any log disable'] +""" + +from ansible.module_utils.basic import AnsibleModule +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.config.acls.acls import ( + Acls, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=AclsArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Acls(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_command.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_command.py new file mode 100644 index 00000000..ce5f2f77 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_command.py @@ -0,0 +1,197 @@ +#!/usr/bin/python +# +# Copyright: Ansible Project +# 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 + + +DOCUMENTATION = """ +module: asa_command +author: Peter Sprygada (@privateip), Patrick Ogenstad (@ogenstad) +short_description: Run arbitrary commands on Cisco ASA devices +description: +- Sends arbitrary commands to an ASA node and returns the results read from the device. + The C(asa_command) module includes an argument that will cause the module to wait + for a specific condition before returning or timing out if the condition is not + met. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.asa.asa +options: + commands: + description: + - List of commands to send to the remote device over the configured provider. + The resulting output from the command is returned. If the I(wait_for) argument + is provided, the module is not returned until the condition is satisfied or + the number of retires as expired. + required: true + type: list + elements: str + wait_for: + description: + - List of conditions to evaluate against the output of the command. The task will + wait for each condition to be true before moving forward. If the conditional + is not true within the configured number of retries, the task fails. See examples. + aliases: + - waitfor + type: list + elements: str + match: + description: + - The I(match) argument is used in conjunction with the I(wait_for) argument to + specify the match policy. Valid values are C(all) or C(any). If the value + is set to C(all) then all conditionals in the wait_for must be satisfied. If + the value is set to C(any) then only one of the values must be satisfied. + default: all + choices: + - any + - all + type: str + retries: + description: + - Specifies the number of retries a command should by tried before it is considered + failed. The command is run on the target device every retry and evaluated against + the I(wait_for) conditions. + default: 10 + type: int + interval: + description: + - Configures the interval in seconds to wait between retries of the command. If + the command does not pass the specified conditions, the interval indicates how + long to wait before trying the command again. + default: 1 + type: int +notes: +- When processing wait_for, each commands' output is stored as an element of the I(result) + array. The allowed operators for conditional evaluation are I(eq), I(==), I(neq), + I(ne), I(!=), I(gt), I(>), I(ge), I(>=), I(lt), I(<), I(le), I(<=), I(contains), + I(matches). Operators can be prefaced by I(not) to negate their meaning. The I(contains) + operator searches for a substring match (like the Python I(in) operator). The I(matches) + operator searches using a regex search operation. +""" + +EXAMPLES = """ +- name: Show the ASA version + cisco.asa.asa_command: + commands: + - show version + +- name: Show ASA drops and memory + cisco.asa.asa_command: + commands: + - show asp drop + - show memory + +- name: Send repeat pings and wait for the result to pass 100% + cisco.asa.asa_command: + commands: + - ping 8.8.8.8 repeat 20 size 350 + wait_for: + - result[0] contains 100 + retries: 2 +""" + +RETURN = """ +stdout: + description: the set of responses from the commands + returned: always + type: list + sample: ['...', '...'] + +stdout_lines: + description: The value of stdout split into a list + returned: always + type: list + sample: [['...', '...'], ['...'], ['...']] + +failed_conditions: + description: the conditionals that failed + returned: failed + type: list + sample: ['...', '...'] +""" +import time + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + asa_argument_spec, + check_args, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + run_commands, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import ( + Conditional, +) +from ansible.module_utils.six import string_types + + +def to_lines(stdout): + for item in stdout: + if isinstance(item, string_types): + item = str(item).split("\n") + yield item + + +def main(): + spec = dict( + # { command: <str>, prompt: <str>, response: <str> } + commands=dict(type="list", required=True, elements="str"), + wait_for=dict(type="list", aliases=["waitfor"], elements="str"), + match=dict(default="all", choices=["all", "any"], type="str"), + retries=dict(default=10, type="int"), + interval=dict(default=1, type="int"), + ) + + spec.update(asa_argument_spec) + + module = AnsibleModule(argument_spec=spec, supports_check_mode=True) + check_args(module) + + result = {"changed": False} + + wait_for = module.params["wait_for"] or list() + conditionals = [Conditional(c) for c in wait_for] + + commands = module.params["commands"] + retries = module.params["retries"] + interval = module.params["interval"] + match = module.params["match"] + + while retries > 0: + responses = run_commands(module, commands) + + for item in list(conditionals): + if item(responses): + if match == "any": + conditionals = list() + break + conditionals.remove(item) + + if not conditionals: + break + + time.sleep(interval) + retries -= 1 + + if conditionals: + failed_conditions = [item.raw for item in conditionals] + msg = "One or more conditional statements have not be satisfied" + module.fail_json(msg=msg, failed_conditions=failed_conditions) + + result.update( + { + "changed": False, + "stdout": responses, + "stdout_lines": list(to_lines(responses)), + } + ) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_config.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_config.py new file mode 100644 index 00000000..71cb9fb0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_config.py @@ -0,0 +1,368 @@ +#!/usr/bin/python +# +# Copyright: Ansible Project +# 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 + + +DOCUMENTATION = """ +module: asa_config +author: Peter Sprygada (@privateip), Patrick Ogenstad (@ogenstad) +short_description: Manage configuration sections on Cisco ASA devices +description: +- Cisco ASA configurations use a simple block indent file syntax for segmenting configuration + into sections. This module provides an implementation for working with ASA configuration + sections in a deterministic way. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.asa.asa +options: + lines: + description: + - The ordered set of commands that should be configured in the section. The commands + must be the exact same commands as found in the device running-config. Be sure + to note the configuration command syntax as some commands are automatically + modified by the device config parser. + aliases: + - commands + type: list + elements: str + parents: + description: + - The ordered set of parents that uniquely identify the section or hierarchy the + commands should be checked against. If the parents argument is omitted, the + commands are checked against the set of top level or global commands. + type: list + elements: str + src: + description: + - Specifies the source path to the file that contains the configuration or configuration + template to load. The path to the source file can either be the full path on + the Ansible control host or a relative path from the playbook or role root directory. This + argument is mutually exclusive with I(lines), I(parents). + type: path + before: + description: + - The ordered set of commands to push on to the command stack if a change needs + to be made. This allows the playbook designer the opportunity to perform configuration + commands prior to pushing any changes without affecting how the set of commands + are matched against the system. + type: list + elements: str + after: + description: + - The ordered set of commands to append to the end of the command stack if a change + needs to be made. Just like with I(before) this allows the playbook designer + to append a set of commands to be executed after the command set. + type: list + elements: str + match: + description: + - Instructs the module on the way to perform the matching of the set of commands + against the current device config. If match is set to I(line), commands are + matched line by line. If match is set to I(strict), command lines are matched + with respect to position. If match is set to I(exact), command lines must be + an equal match. Finally, if match is set to I(none), the module will not attempt + to compare the source configuration with the running configuration on the remote + device. + default: line + choices: + - line + - strict + - exact + - none + type: str + replace: + description: + - Instructs the module on the way to perform the configuration on the device. If + the replace argument is set to I(line) then the modified lines are pushed to + the device in configuration mode. If the replace argument is set to I(block) + then the entire command block is pushed to the device in configuration mode + if any line is not correct + default: line + choices: + - line + - block + type: str + backup: + description: + - This argument will cause the module to create a full backup of the current C(running-config) + from the remote device before any changes are made. If the C(backup_options) + value is not given, the backup file is written to the C(backup) folder in the + playbook root directory. If the directory does not exist, it is created. + type: bool + default: no + config: + description: + - The C(config) argument allows the playbook designer to supply the base configuration + to be used to validate configuration changes necessary. If this argument is + provided, the module will not download the running-config from the remote node. + type: str + defaults: + description: + - This argument specifies whether or not to collect all defaults when getting + the remote device running config. When enabled, the module will get the current + config by issuing the command C(show running-config all). + type: bool + default: no + passwords: + description: + - This argument specifies to include passwords in the config when retrieving the + running-config from the remote device. This includes passwords related to VPN + endpoints. This argument is mutually exclusive with I(defaults). + type: bool + default: false + save: + description: + - The C(save) argument instructs the module to save the running- config to the + startup-config at the conclusion of the module running. If check mode is specified, + this argument is ignored. + type: bool + default: no + backup_options: + description: + - This is a dict object containing configurable options related to backup file + path. The value of this option is read only when C(backup) is set to I(yes), + if C(backup) is set to I(no) this option will be silently ignored. + suboptions: + filename: + description: + - The filename to be used to store the backup configuration. If the filename + is not given it will be generated based on the hostname, current time and + date in format defined by <hostname>_config.<current-date>@<current-time> + type: str + dir_path: + description: + - This option provides the path ending with directory name in which the backup + configuration file will be stored. If the directory does not exist it will + be first created and the filename is either the value of C(filename) or + default filename as described in C(filename) options description. If the + path value is not given in that case a I(backup) directory will be created + in the current working directory and backup configuration will be copied + in C(filename) within I(backup) directory. + type: path + type: dict +""" + +EXAMPLES = """ +- cisco.asa.asa_config: + lines: + - network-object host 10.80.30.18 + - network-object host 10.80.30.19 + - network-object host 10.80.30.20 + parents: [object-group network OG-MONITORED-SERVERS] + provider: '{{ cli }}' + +- cisco.asa.asa_config: + host: '{{ inventory_hostname }}' + lines: + - message-length maximum client auto + - message-length maximum 512 + match: line + parents: [policy-map type inspect dns PM-DNS, parameters] + authorize: yes + auth_pass: cisco + username: admin + password: cisco + context: ansible + +- cisco.asa.asa_config: + lines: + - ikev1 pre-shared-key MyS3cretVPNK3y + parents: tunnel-group 1.1.1.1 ipsec-attributes + passwords: yes + provider: '{{ cli }}' + +- name: attach ASA acl on interface vlan13/nameif cloud13 + cisco.asa.asa_config: + lines: + - access-group cloud-acl_access_in in interface cloud13 + provider: '{{ cli }}' + +- name: configure ASA (>=9.2) default BGP + cisco.asa.asa_config: + lines: + - bgp log-neighbor-changes + - bgp bestpath compare-routerid + provider: '{{ cli }}' + parents: + - router bgp 65002 + register: bgp + when: bgp_default_config is defined +- name: configure ASA (>=9.2) BGP neighbor in default/single context mode + cisco.asa.asa_config: + lines: + - bgp router-id {{ bgp_router_id }} + - neighbor {{ bgp_neighbor_ip }} remote-as {{ bgp_neighbor_as }} + - neighbor {{ bgp_neighbor_ip }} description {{ bgp_neighbor_name }} + provider: '{{ cli }}' + parents: + - router bgp 65002 + - address-family ipv4 unicast + register: bgp + when: bgp_neighbor_as is defined +- name: configure ASA interface with standby + cisco.asa.asa_config: + lines: + - description my cloud interface + - nameif cloud13 + - security-level 50 + - ip address 192.168.13.1 255.255.255.0 standby 192.168.13.2 + provider: '{{ cli }}' + parents: [interface Vlan13] + register: interface +- name: Show changes to interface from task above + debug: + var: interface + +- name: configurable backup path + cisco.asa.asa_config: + lines: + - access-group cloud-acl_access_in in interface cloud13 + provider: '{{ cli }}' + backup: yes + backup_options: + filename: backup.cfg + dir_path: /home/user +""" + +RETURN = """ +updates: + description: The set of commands that will be pushed to the remote device + returned: always + type: list + sample: ['...', '...'] +backup_path: + description: The full path to the backup file + returned: when backup is yes + type: str + sample: /playbooks/ansible/backup/asa_config.2016-07-16@22:28:34 +""" +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + asa_argument_spec, + check_args, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + get_config, + load_config, + run_commands, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) + + +def get_candidate(module): + candidate = NetworkConfig(indent=1) + if module.params["src"]: + candidate.load(module.params["src"]) + elif module.params["lines"]: + parents = module.params["parents"] or list() + candidate.add(module.params["lines"], parents=parents) + return candidate + + +def run(module, result): + match = module.params["match"] + replace = module.params["replace"] + path = module.params["parents"] + + candidate = get_candidate(module) + if match != "none": + contents = module.params["config"] + if not contents: + contents = get_config(module) + config = NetworkConfig(indent=1, contents=contents) + configobjs = candidate.difference( + config, path=path, match=match, replace=replace + ) + + else: + configobjs = candidate.items + + if configobjs: + commands = dumps(configobjs, "commands").split("\n") + + if module.params["lines"]: + if module.params["before"]: + commands[:0] = module.params["before"] + + if module.params["after"]: + commands.extend(module.params["after"]) + + result["updates"] = commands + + # send the configuration commands to the device and merge + # them with the current running config + if not module.check_mode: + load_config(module, commands) + result["changed"] = True + + if module.params["save"]: + if not module.check_mode: + run_commands(module, "write mem") + result["changed"] = True + + +def main(): + """ main entry point for module execution + """ + backup_spec = dict(filename=dict(), dir_path=dict(type="path")) + argument_spec = dict( + src=dict(type="path"), + lines=dict(aliases=["commands"], type="list", elements="str"), + parents=dict(type="list", elements="str"), + before=dict(type="list", elements="str"), + after=dict(type="list", elements="str"), + match=dict( + default="line", choices=["line", "strict", "exact", "none"] + ), + replace=dict(default="line", choices=["line", "block"]), + backup_options=dict(type="dict", options=backup_spec), + config=dict(), + defaults=dict(type="bool", default=False), + passwords=dict(type="bool", default=False), + backup=dict(type="bool", default=False), + save=dict(type="bool", default=False), + ) + + argument_spec.update(asa_argument_spec) + + mutually_exclusive = [ + ("lines", "src"), + ("parents", "src"), + ("defaults", "passwords"), + ] + + required_if = [ + ("match", "strict", ["lines"]), + ("match", "exact", ["lines"]), + ("replace", "block", ["lines"]), + ] + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + supports_check_mode=True, + ) + + result = {"changed": False} + + check_args(module) + + if module.params["backup"]: + result["__backup__"] = get_config(module) + + run(module, result) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_facts.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_facts.py new file mode 100644 index 00000000..6efd2175 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_facts.py @@ -0,0 +1,209 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: asa_facts +author: +- Sumit Jaiswal (@justjais) +short_description: Collect facts from remote devices running Cisco ASA +description: +- Collects a base set of device facts from a remote device that is running ASA. This + module prepends all of the base network fact keys with C(ansible_net_<fact>). The + facts module will always collect a base set of facts from the device and can enable + or disable collection of additional facts. +- Note, to collects facts from ASA device properly user should elevate the privilege + to become. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.asa.asa +notes: +- Tested against asa 9.10(1)11 +options: + gather_subset: + description: + - When supplied, this argument restricts the facts collected to a given subset. + - Possible values for this argument include C(all), C(min), C(hardware), C(config). + - Specify a list of values to include a larger subset. + - Use a value with an initial C(!) to collect all facts except that subset. + required: false + type: list + elements: str + default: '!config' + gather_network_resources: + description: + - When supplied, this argument will restrict the facts collected to a given subset. + Possible values for this argument include all and the resources like interfaces, + vlans etc. Can specify a list of values to include a larger subset. Values can + also be used with an initial C(M(!)) to specify that a specific subset should + not be collected. Valid subsets are 'all', 'acls', 'ogs'. + required: false + type: list + elements: str +""" + +EXAMPLES = """ +- name: Gather all legacy facts + cisco.asa.asa_facts: + gather_subset: all + +- name: Gather only the config and default facts + cisco.asa.asa_facts: + gather_subset: + - config + +- name: Do not gather hardware facts + cisco.asa.asa_facts: + gather_subset: + - '!hardware' + +- name: Gather legacy and resource facts + cisco.asa.asa_facts: + gather_subset: all +""" + +RETURN = """ +ansible_net_gather_subset: + description: The list of fact subsets collected from the device + returned: always + type: list + +# default +ansible_net_model: + description: The model name returned from the device + returned: always + type: str +ansible_net_serialnum: + description: The serial number of the remote device + returned: always + type: str +ansible_net_version: + description: The operating system version running on the remote device + returned: always + type: str +ansible_net_firepower_version: + description: The Firepower operating system version running on the remote device. + returned: always + type: str +ansible_net_device_mgr_version: + description: The Device manager version running on the remote device. + returned: always + type: str +ansible_net_asatype: + description: The operating system type (Cisco ASA) running on the remote device. + returned: always + type: str +ansible_net_hostname: + description: The configured hostname of the device + returned: always + type: str +ansible_net_image: + description: The image file the device is running + returned: always + type: str +ansible_net_stacked_models: + description: The model names of each device in the stack + returned: when multiple devices are configured in a stack + type: list +ansible_net_stacked_serialnums: + description: The serial numbers of each device in the stack + returned: when multiple devices are configured in a stack + type: list +ansible_net_api: + description: The name of the transport + returned: always + type: str +ansible_net_python_version: + description: The Python version Ansible controller is using + returned: always + type: str + +# hardware +ansible_net_filesystems: + description: All file system names available on the device + returned: when hardware is configured + type: list +ansible_net_filesystems_info: + description: A hash of all file systems containing info about each file system (e.g. free and total space) + returned: when hardware is configured + type: dict +ansible_net_memfree_mb: + description: The available free memory on the remote device in Mb + returned: when hardware is configured + type: int +ansible_net_memused_mb: + description: The used memory on the remote device in Mb + returned: when hardware is configured + type: int +ansible_net_memtotal_mb: + description: The total memory on the remote device in Mb + returned: when hardware is configured + type: int + +# config +ansible_net_config: + description: The current active config from the device + returned: when config is configured + type: str +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.argspec.facts.facts import ( + FactsArgs, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.facts.facts import ( + Facts, +) +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + asa_argument_spec, +) + + +def main(): + """ + Main entry point for module execution + + :returns: ansible_facts + """ + argument_spec = FactsArgs.argument_spec + argument_spec.update(asa_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, supports_check_mode=True + ) + + warnings = [] + if module.params["gather_subset"] == "!config": + warnings.append( + "default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards" + ) + + result = Facts(module).get_facts() + + ansible_facts, additional_warnings = result + warnings.extend(additional_warnings) + + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_og.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_og.py new file mode 100644 index 00000000..de37aebb --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_og.py @@ -0,0 +1,1034 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: asa_og +author: +- Federico Olivieri (@Federico87) +short_description: (deprecated, removed after 2022-06-01) Manage object groups on + a Cisco ASA +description: +- This module allows you to create and update object-group network/service on Cisco + ASA device. +version_added: 1.0.0 +deprecated: + alternative: asa_ogs + why: Newer and updated modules released with more functionality in Ansible 2.10 + removed_at_date: '2022-06-01' +options: + name: + description: + - Name of the object group. + required: true + type: str + group_type: + description: + - The object group type. + choices: + - network-object + - service-object + - port-object + required: true + type: str + protocol: + description: + - The protocol for object-group service with port-object. + choices: + - udp + - tcp + - tcp-udp + type: str + host_ip: + description: + - The host IP address for object-group network. + type: list + elements: str + description: + description: + - The description for the object-group. + type: str + group_object: + description: + - The group-object for network object-group. + type: list + elements: str + ip_mask: + description: + - The IP address and mask for network object-group. + type: list + elements: str + port_range: + description: + - The port range for port-object. + type: list + elements: str + port_eq: + description: + - The single port for port-object. + type: list + elements: str + service_cfg: + description: + - The service-object configuration protocol, direction, range or port. + type: list + elements: str + state: + description: + - Manage the state of the resource. + type: str + default: present + choices: + - present + - absent + - replace + +""" + +EXAMPLES = """ +- name: configure network object-group + cisco.asa.asa_og: + name: ansible_test_0 + group_type: network-object + state: present + description: ansible_test object-group description + host_ip: + - 8.8.8.8 + - 8.8.4.4 + ip_mask: + - 10.0.0.0 255.255.255.0 + - 192.168.0.0 255.255.0.0 + group_object: + - awx_lon + - awx_ams + +- name: configure port-object object-group + cisco.asa.asa_og: + name: ansible_test_1 + group_type: port-object + state: replace + description: ansible_test object-group description + protocol: tcp-udp + port_eq: + - 1025 + - kerberos + port_range: + - 1025 5201 + - 0 1024 + +- name: configure service-object object-group + cisco.asa.asa_og: + name: ansible_test_2 + group_type: service-object + state: absent + description: ansible_test object-group description + service_cfg: + - tcp destination eq 8080 + - tcp destination eq www +""" + +RETURN = """ +commands: + description: command sent to the device + returned: always + type: list + sample: [ + "object-group network ansible_test_0", + "description ansible_test object-group description", + "network-object host 8.8.8.8", + "network-object host 8.8.4.4", + "network-object 10.0.0.0 255.255.255.0", + "network-object 192.168.0.0 255.255.0.0", + "network-object 192.168.0.0 255.255.0.0", + "group-object awx_lon", + "group-object awx_ams", + ] +""" +import re + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.asa.plugins.module_utils.network.asa.asa import ( + get_config, + load_config, +) + + +class Parser: + """Regex class for outputs parsing""" + + def __init__(self, config, protocol): + """Parser __init__ method""" + self.config = config + self.protocol = protocol + + def parse_obj_grp_name(self): + list_return = list() + match = re.search( + r"(?:object-group\s)(network\s|service\s)(\w+)\s?(tcp-udp|tcp|udp)?", + self.config, + re.M, + ) + + if match: + if match.group(3): + list_return.append(str(match.group(3))) + else: + list_return.append(False) + + if match.group(2): + list_return.append(str(match.group(2))) + + if match.group(1): + list_return.append(str(match.group(1))) + + return list_return + + def parse_description(self): + match = re.search(r"description(:)?\s(.*)", self.config, re.M) + if match: + description = match.group(2) + + return description + + def parse_host(self): + list_return = list() + match = re.findall(r"(host\s)(\d+\.\d+\.\d+\.\d+)", self.config, re.M) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + def parse_group_object(self): + list_return = list() + match = re.findall(r"(group-object\s)(.*)", self.config, re.M) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + def parse_address(self): + list_return = list() + match = re.findall( + r"(network-object\s)(\d+\.\d+\.\d+\.\d+\s\d+\.\d+\.\d+\.\d+)", + self.config, + re.M, + ) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + def parse_port_range(self): + list_return = list() + match = re.findall(r"(range\s)(.*)", self.config, re.M) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + def parse_port_eq(self): + list_return = list() + match = re.findall(r"(eq\s)(.*)", self.config, re.M) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + def parse_service_cfg(self): + list_return = list() + match = re.findall(r"(service-object\s)(.*)", self.config, re.M) + + if match: + for i in match: + if i[1]: + list_return.append(str(i[1])) + + return list_return + + +def map_config_to_obj(module): + + obj = list() + obj_dict = dict() + + group_name = module.params["name"] + protocol = module.params["protocol"] + + sh_run_group_name = get_config( + module, flags=["object-group | include {0}".format(group_name)] + ) + run_group_name = Parser(sh_run_group_name, protocol).parse_obj_grp_name() + + obj_dict["have_name"] = run_group_name + + if run_group_name: + if run_group_name[0] is not False: + obj_dict["have_group_type"] = "port-object" + obj_dict["have_protocol"] = run_group_name[0] + elif "network" in run_group_name[2]: + obj_dict["have_group_type"] = "network-object" + elif "service" in run_group_name[2] and run_group_name[0] is False: + obj_dict["have_group_type"] = "service-object" + else: + obj_dict["have_group_type"] = None + + sh_run_group_type = get_config( + module, flags=["object-group id {0}".format(group_name)] + ) + + have_description = Parser(sh_run_group_type, protocol).parse_description() + obj_dict["have_description"] = have_description + + have_host_ip = Parser(sh_run_group_type, protocol).parse_host() + obj_dict["have_host_ip"] = have_host_ip + + have_group_object = Parser( + sh_run_group_type, protocol + ).parse_group_object() + obj_dict["have_group_object"] = have_group_object + + have_ip_mask = Parser(sh_run_group_type, protocol).parse_address() + obj_dict["have_ip_mask"] = have_ip_mask + + have_port_range = Parser(sh_run_group_type, protocol).parse_port_range() + obj_dict["have_port_range"] = have_port_range + + have_port_eq = Parser(sh_run_group_type, protocol).parse_port_eq() + obj_dict["have_port_eq"] = have_port_eq + + have_service_cfg = Parser(sh_run_group_type, protocol).parse_service_cfg() + + if have_service_cfg: + have_lines = list() + for i in have_service_cfg: + have_lines.append(i.rstrip(" ")) + obj_dict["have_service_cfg"] = have_lines + elif have_service_cfg is None: + obj_dict["have_service_cfg"] = have_service_cfg + + obj.append(obj_dict) + + return obj + + +def replace(want_dict, have): + + commands = list() + add_lines = list() + remove_lines = list() + + have_group_type = have[0].get("have_group_type") + have_description = have[0].get("have_description") + have_host_ip = have[0].get("have_host_ip") + have_group_object = have[0].get("have_group_object") + have_ip_mask = have[0].get("have_ip_mask") + have_protocol = have[0].get("have_protocol") + have_port_range = have[0].get("have_port_range") + have_port_eq = have[0].get("have_port_eq") + have_service_cfg = have[0].get("have_service_cfg") + + name = want_dict["name"] + group_type = want_dict["group_type"] + protocol = want_dict["protocol"] + description = want_dict["description"] + host = want_dict["host_ip"] + group_object = want_dict["group_object"] + address = want_dict["ip_mask"] + port_range = want_dict["port_range"] + port_eq = want_dict["port_eq"] + service_cfg = want_dict["service_cfg"] + + if "network-object" in group_type: + + if have_group_type is None: + commands.append("object-group network {0}".format(name)) + + if host: + for i in host: + commands.append("network-object host " + i) + if description: + if have_description is None: + commands.append("description {0}".format(description)) + if group_object: + for i in group_object: + if i not in have_group_object: + commands.append("group-object " + i) + if address: + for i in address: + commands.append("network-object " + i) + + elif "network" in have_group_type: + + if host: + if sorted(host) != sorted(have_host_ip): + for i in host: + if i not in have_host_ip: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + add_lines.append("network-object host " + i) + for i in have_host_ip: + if i not in host: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + remove_lines.append("no network-object host " + i) + + if description: + if description != have_description: + if "object-group network {0}".format(name) not in commands: + commands.append( + "object-group network {0}".format(name) + ) + add_lines.append("description {0}".format(description)) + + if group_object: + if sorted(group_object) != sorted(have_group_object): + for i in group_object: + if i not in have_group_object: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + add_lines.append("group-object " + i) + for i in have_group_object: + if i not in group_object: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + remove_lines.append("no group-object " + i) + if address: + if sorted(address) != sorted(have_ip_mask): + for i in address: + if i not in have_ip_mask: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + add_lines.append("network-object " + i) + for i in have_ip_mask: + if i not in address: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + remove_lines.append("no network-object " + i) + + elif "port-object" in group_type: + + if have_group_type is None and have_protocol != protocol: + commands.append( + "object-group service {0} {1}".format(name, protocol) + ) + + if port_range: + for i in port_range: + commands.append("port-object range " + i) + if port_eq: + for i in port_eq: + commands.append("port-object eq " + i) + if description: + commands.append("description {0}".format(description)) + + elif "port" in have_group_type and have_protocol == protocol: + + if port_range: + if sorted(port_range) != sorted(have_port_range): + for i in port_range: + if i not in have_port_range: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + add_lines.append("port-object range " + i) + for i in have_port_range: + if i not in port_range: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + remove_lines.append("no port-object range " + i) + if port_eq: + if sorted(port_eq) != sorted(have_port_eq): + for i in port_eq: + if i not in have_port_eq: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + add_lines.append("port-object eq " + i) + for i in have_port_eq: + if i not in port_eq: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + remove_lines.append("no port-object eq " + i) + if description: + if description != have_description: + if ( + "object-group service {0} {1}".format(name, protocol) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("description {0}".format(description)) + + elif "service-object" in group_type: + + if have_group_type is None: + commands.append("object-group service {0}".format(name)) + + if description: + if have_description is None: + commands.append("description {0}".format(description)) + if service_cfg: + for i in service_cfg: + commands.append("service-object " + i) + + elif "service" in have_group_type: + if description: + if description != have_description: + if "object-group service {0}".format(name) not in commands: + commands.append( + "object-group service {0}".format(name) + ) + commands.append("description {0}".format(description)) + if service_cfg: + for i in service_cfg: + if i not in have_service_cfg: + if ( + "object-group service {0}".format(name) + not in commands + ): + commands.append( + "object-group service {0}".format(name) + ) + add_lines.append("service " + i) + for i in have_service_cfg: + if i not in service_cfg: + if ( + "object-group service {0}".format(name) + not in commands + ): + commands.append( + "object-group service {0}".format(name) + ) + remove_lines.append("no service " + i) + + set_add_lines = set(add_lines) + set_remove_lines = set(remove_lines) + + for i in list(set_add_lines) + list(set_remove_lines): + commands.append(i) + + return commands + + +def present(want_dict, have): + + commands = list() + + have_group_type = have[0].get("have_group_type") + have_description = have[0].get("have_description") + have_host_ip = have[0].get("have_host_ip") + have_group_object = have[0].get("have_group_object") + have_ip_mask = have[0].get("have_ip_mask") + have_protocol = have[0].get("have_protocol") + have_port_range = have[0].get("have_port_range") + have_port_eq = have[0].get("have_port_eq") + have_service_cfg = have[0].get("have_service_cfg") + + name = want_dict["name"] + group_type = want_dict["group_type"] + protocol = want_dict["protocol"] + description = want_dict["description"] + host = want_dict["host_ip"] + group_object = want_dict["group_object"] + address = want_dict["ip_mask"] + port_range = want_dict["port_range"] + port_eq = want_dict["port_eq"] + service_cfg = want_dict["service_cfg"] + + if "network-object" in group_type: + + if have_group_type is None: + commands.append("object-group network {0}".format(name)) + + if host: + for i in host: + commands.append("network-object host " + i) + if description: + if have_description is None: + commands.append("description {0}".format(description)) + if group_object: + for i in group_object: + commands.append("group-object " + i) + if address: + for i in address: + commands.append("network-object " + i) + + elif "network" in have_group_type: + + if host: + for i in host: + if i not in have_host_ip: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("network-object host " + i) + if description: + if description != have_description: + if "object-group network {0}".format(name) not in commands: + commands.append( + "object-group network {0}".format(name) + ) + commands.append("description {0}".format(description)) + if group_object: + for i in group_object: + if i not in have_group_object: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("group-object " + i) + if address: + for i in address: + if i not in have_ip_mask: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("network-object " + i) + + elif "port-object" in group_type: + + if have_group_type is None and have_protocol != protocol: + commands.append( + "object-group service {0} {1}".format(name, protocol) + ) + + if port_range: + for i in port_range: + commands.append("port-object range " + i) + if port_eq: + for i in port_eq: + commands.append("port-object eq " + i) + if description: + commands.append("description {0}".format(description)) + + elif "port" in have_group_type and have_protocol == protocol: + + if port_range: + for i in port_range: + if i not in have_port_range: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("port-object range " + i) + if port_eq: + for i in port_eq: + if i not in have_port_eq: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("port-object eq " + i) + if description: + if description != have_description: + if ( + "object-group service {0} {1}".format(name, protocol) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("description {0}".format(description)) + + elif "service-object" in group_type: + + if have_group_type is None: + commands.append("object-group service {0}".format(name)) + + if description: + if have_description is None: + commands.append("description {0}".format(description)) + if service_cfg: + for i in service_cfg: + commands.append("service-object " + i) + + elif "service" in have_group_type: + + if description: + if description != have_description: + if "object-group service {0}".format(name) not in commands: + commands.append( + "object-group service {0}".format(name) + ) + commands.append("description {0}".format(description)) + if service_cfg: + for i in service_cfg: + if i not in have_service_cfg: + if ( + "object-group service {0}".format(name) + not in commands + ): + commands.append( + "object-group service {0}".format(name) + ) + commands.append("service " + i) + + return commands + + +def absent(want_dict, have): + + commands = list() + + have_group_type = have[0].get("have_group_type") + have_description = have[0].get("have_description") + have_host_ip = have[0].get("have_host_ip") + have_group_object = have[0].get("have_group_object") + have_ip_mask = have[0].get("have_ip_mask") + have_protocol = have[0].get("have_protocol") + have_port_range = have[0].get("have_port_range") + have_port_eq = have[0].get("have_port_eq") + have_service_cfg = have[0].get("have_service_cfg") + + name = want_dict["name"] + group_type = want_dict["group_type"] + protocol = want_dict["protocol"] + description = want_dict["description"] + host = want_dict["host_ip"] + group_object = want_dict["group_object"] + address = want_dict["ip_mask"] + port_range = want_dict["port_range"] + port_eq = want_dict["port_eq"] + service_cfg = want_dict["service_cfg"] + + if "network-object" in group_type: + + if have_group_type is None: + return commands + + elif "network" in have_group_type: + + if host: + for i in host: + if i in have_host_ip: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("no network-object host " + i) + if description: + if description == have_description: + if "object-group network {0}".format(name) not in commands: + commands.append( + "object-group network {0}".format(name) + ) + commands.append("no description {0}".format(description)) + if group_object: + for i in group_object: + if i in have_group_object: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("no group-object " + i) + if address: + for i in address: + if i in have_ip_mask: + if ( + "object-group network {0}".format(name) + not in commands + ): + commands.append( + "object-group network {0}".format(name) + ) + commands.append("no network-object " + i) + + elif "port-object" in group_type: + + if have_group_type is None and have_protocol is None: + return commands + + elif "port" in have_group_type and have_protocol == protocol: + + if port_range: + for i in port_range: + if i in have_port_range: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("no port-object range " + i) + if port_eq: + for i in port_eq: + if i in have_port_eq: + if ( + "object-group service {0} {1}".format( + name, protocol + ) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("no port-object eq " + i) + if description: + if description == have_description: + if ( + "object-group service {0} {1}".format(name, protocol) + not in commands + ): + commands.append( + "object-group service {0} {1}".format( + name, protocol + ) + ) + commands.append("no description {0}".format(description)) + + elif "service-object" in group_type: + + if have_group_type is None: + return commands + + elif "service" in have_group_type: + if description: + if description == have_description: + if "object-group service {0}".format(name) not in commands: + commands.append( + "object-group service {0}".format(name) + ) + commands.append("no description {0}".format(description)) + if service_cfg: + for i in service_cfg: + if i in have_service_cfg: + if ( + "object-group service {0}".format(name) + not in commands + ): + commands.append( + "object-group service {0}".format(name) + ) + commands.append("no service " + i) + + return commands + + +def map_obj_to_commands(want, have, module): + + for w in want: + + want_dict = dict() + + want_dict["name"] = w["name"] + want_dict["group_type"] = w["group_type"] + want_dict["protocol"] = w["protocol"] + want_dict["description"] = w["description"] + want_dict["host_ip"] = w["host_ip"] + want_dict["group_object"] = w["group_object"] + want_dict["ip_mask"] = w["ip_mask"] + want_dict["port_range"] = w["port_range"] + want_dict["port_eq"] = w["port_eq"] + want_dict["service_cfg"] = w["service_cfg"] + state = w["state"] + + if state == "replace": + return replace(want_dict, have) + elif state == "present": + return present(want_dict, have) + elif state == "absent": + return absent(want_dict, have) + + +def map_params_to_obj(module): + + obj = list() + + obj.append( + { + "name": module.params["name"], + "group_type": module.params["group_type"], + "protocol": module.params["protocol"], + "state": module.params["state"], + "description": module.params["description"], + "host_ip": module.params["host_ip"], + "group_object": module.params["group_object"], + "port_range": module.params["port_range"], + "port_eq": module.params["port_eq"], + "service_cfg": module.params["service_cfg"], + "ip_mask": module.params["ip_mask"], + } + ) + + return obj + + +def main(): + + argument_spec = dict( + name=dict(required=True), + group_type=dict( + choices=["network-object", "service-object", "port-object"], + required=True, + ), + protocol=dict(choices=["udp", "tcp", "tcp-udp"]), + host_ip=dict(type="list", elements="str"), + description=dict(), + group_object=dict(type="list", elements="str"), + ip_mask=dict(type="list", elements="str"), + port_range=dict(type="list"), + port_eq=dict(type="list", elements="str"), + service_cfg=dict(type="list", elements="str"), + state=dict( + choices=["present", "absent", "replace"], default="present" + ), + ) + + required_if = [ + ("group_type", "port-object", ["protocol"]), + ("group_type", "service-object", ["service_cfg"]), + ] + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + + result = {"changed": False} + + want = map_params_to_obj(module) + have = map_config_to_obj(module) + config_commans = map_obj_to_commands(want, have, module) + + result["commands"] = config_commans + + if config_commans: + if not module.check_mode: + load_config(module, config_commans) + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_ogs.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_ogs.py new file mode 100644 index 00000000..5792bc80 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/modules/asa_ogs.py @@ -0,0 +1,892 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for asa_ogs +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = """ +module: asa_ogs +short_description: Object Group resource module +description: This module configures and manages Objects and Groups on ASA platforms. +version_added: 1.0.0 +author: Sumit Jaiswal (@justjais) +notes: +- Tested against Cisco ASA Version 9.10(1)11 +- This module works with connection C(network_cli). See L(ASA Platform Options,../network/user_guide/platform_asa.html). +options: + config: + description: A list of Object Group options. + type: list + elements: dict + suboptions: + object_type: + description: The object group type. + type: str + required: true + choices: + - icmp-type + - network + - protocol + - security + - service + - user + object_groups: + description: The object groups. + type: list + elements: dict + suboptions: + name: + description: Specifies object-group ID + required: true + type: str + description: + description: The description for the object-group. + type: str + icmp_type: + description: Configure an ICMP-type object + type: dict + suboptions: + icmp_object: + description: Defines the ICMP types in the group. + 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: + description: Configure a network object + type: dict + suboptions: + host: + description: Set this to specify a single host object. + type: list + elements: str + address: + description: Enter an IPv4 network address with space seperated netmask. + type: list + elements: str + ipv6_address: + description: Enter an IPv6 prefix. + type: list + elements: str + protocol_object: + description: Configure a protocol object + type: dict + suboptions: + protocol: + description: Defines the protocols in the group. + type: list + elements: str + choices: [ah, eigrp, esp, gre, icmp, icmp6, igmp, igrp, ip, ipinip, + ipsec, nos, ospf, pcp, pim, pptp, sctp, snp, tcp, udp] + security_group: + description: Configure a security-group + type: dict + suboptions: + sec_name: + description: Enter this keyword to specify a security-group name. + type: list + elements: str + tag: + description: Enter this keyword to specify a security-group tag. + type: list + elements: str + service_object: + description: Configure a service object + type: dict + suboptions: + protocol: + description: Defines the protocols in the group. + 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: + description: Enter this keyword to specify a service object + type: str + user_object: + description: Configures single user, local or import user group + type: dict + suboptions: + user: + description: Configure a user objectUser name to configure a user + object. + type: list + elements: dict + suboptions: + name: + description: Enter the name of the user + type: str + required: true + domain: + description: User domain + type: str + required: true + user_group: + description: Configure a user group object. + type: list + elements: dict + suboptions: + name: + description: Enter the name of the group + type: str + required: true + domain: + description: Group domain + type: str + required: true + running_config: + description: + - The module, by default, will connect to the remote device and retrieve the current + running-config to use as a base for comparing against the contents of source. + There are times when it is not desirable to have the task get the current running-config + for every task in a playbook. The I(running_config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. This + value of this option should be the output received from device by executing + command. + type: str + state: + description: + - The state the configuration should be left in + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged +""" + +EXAMPLES = """ + +# Using merged + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_network_og +# network-object host 192.0.3.1 + +- name: "Merge module attributes of given object-group" + cisco.asa.asa_ogs: + config: + - object_type: network + object_groups: + - name: test_og_network + description: test_og_network + network_object: + host: + - 192.0.2.1 + - 192.0.2.2 + address: + - 192.0.2.0 255.255.255.0 + - 198.51.100.0 255.255.255.0 + - name: test_network_og + description: test_network_og + network_object: + host: + - 192.0.3.1 + - 192.0.3.2 + ipv6_address: + - 2001:db8:3::/64 + - object_type: security + object_groups: + - name: test_og_security + description: test_security + security_group: + sec_name: + - test_1 + - test_2 + tag: + - 10 + - 20 + - object_type: user + object_groups: + - name: test_og_user + description: test_user + user_object: + user: + - name: new_user_1 + domain: LOCAL + - name: new_user_2 + domain: LOCAL + state: merged + +# Commands fired: +# --------------- +# +# object-group security test_og_security +# description test_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group network test_og_network +# description test_og_network +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# object-group network test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:3::/64 +# object-group user test_og_user +# description test_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +# After state: +# ------------ +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# network-object host 192.0.3.1 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# description test_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +# Using Replaced + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +- name: "Replace module attributes of given object-group" + cisco.asa.asa_ogs: + config: + - object_type: network + object_groups: + - name: test_og_network + description: test_og_network_replace + network_object: + host: + - 192.0.3.1 + address: + - 192.0.3.0 255.255.255.0 + - object_type: protocol + object_groups: + - name: test_og_protocol + description: test_og_protocol + protocol_object: + protocol: + - tcp + - udp + state: replaced + +# Commands Fired: +# --------------- +# +# object-group protocol test_og_protocol +# description test_og_protocol +# protocol tcp +# protocol udp +# object-group network test_og_network +# description test_og_network_replace +# no network-object 192.0.2.0 255.255.255.0 +# no network-object 198.51.100.0 255.255.255.0 +# network-object 192.0.3.0 255.255.255.0 +# no network-object host 192.0.2.1 +# no network-object host 192.0.2.2 +# network-object host 192.0.3.1 + +# After state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network_replace +# network-object host 192.0.3.1 +# network-object 192.0.3.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 +# object-group protocol test_og_protocol +# protocol-object tcp +# protocol-object udp + +# Using Overridden + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +- name: "Overridden module attributes of given object-group" + cisco.asa.asa_ogs: + config: + - object_type: network + object_groups: + - name: test_og_network + description: test_og_network_override + network_object: + host: + - 192.0.3.1 + address: + - 192.0.3.0 255.255.255.0 + - object_type: protocol + object_groups: + - name: test_og_protocol + description: test_og_protocol + protocol_object: + protocol: + - tcp + - udp + state: overridden + +# Commands Fired: +# --------------- +# +# no object-group security test_og_security +# no object-group user test_og_user +# object-group protocol test_og_protocol +# description test_og_protocol +# protocol tcp +# protocol udp +# object-group network test_og_network +# description test_og_network_override +# no network-object 192.0.2.0 255.255.255.0 +# no network-object 198.51.100.0 255.255.255.0 +# network-object 192.0.3.0 255.255.255.0 +# no network-object host 192.0.2.1 +# no network-object host 192.0.2.2 +# network-object host 192.0.3.1 +# no object-group network test_network_og + +# After state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network_override +# network-object host 192.0.3.1 +# network-object 192.0.3.0 255.255.255.0 +# object-group protocol test_og_protocol +# protocol-object tcp +# protocol-object udp + +# Using Deleted + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +- name: "Delete given module attributes" + cisco.asa.asa_ogs: + config: + - object_type: network + object_groups: + - name: test_og_network + - name: test_network_og + - object_type: security + object_groups: + - name: test_og_security + state: deleted + +# Commands Fired: +# --------------- +# +# no object-group network test_og_network +# no object-group network test_network_og +# no object-group security test_og_security + +# After state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +# Using DELETED without any config passed +#"(NOTE: This will delete all of configured resource module attributes)" + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +- name: Delete ALL configured module attributes + cisco.asa.asa_ogs: + config: + state: deleted + +# Commands Fired: +# --------------- +# +# no object-group network test_og_network +# no object-group network test_network_og +# no object-group security test_og_security +# no object-group user test_og_user + +# After state: +# ------------- +# +# ciscoasa# sh running-config object-group + +# Using Gathered + +# Before state: +# ------------- +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +- name: Gather listed OGs with provided configurations + cisco.asa.asa_ogs: + config: + state: gathered + +# Module Execution Result: +# ------------------------ +# +# "gathered": [ +# { +# "object_groups": [ +# { +# "description": "test_security", +# "name": "test_og_security", +# "security_group": { +# "sec_name": [ +# "test_2", +# "test_1" +# ], +# "tag": [ +# 10, +# 20 +# ] +# } +# } +# ], +# "object_type": "security" +# }, +# { +# "object_groups": [ +# { +# "description": "test_network_og", +# "name": "test_network_og", +# "network_object": { +# "host": [ +# "192.0.3.1", +# "192.0.3.2" +# ], +# "ipv6_address": [ +# "2001:db8:3::/64" +# ] +# } +# }, +# { +# "description": "test_og_network", +# "name": "test_og_network", +# "network_object": { +# "address": [ +# "192.0.2.0 255.255.255.0", +# "198.51.100.0 255.255.255.0" +# ], +# "host": [ +# "192.0.2.1", +# "192.0.2.2" +# ] +# } +# } +# ], +# "object_type": "network" +# }, +# { +# "object_groups": [ +# { +# "description": "test_user", +# "name": "test_og_user", +# "user_object": { +# "user": [ +# { +# "domain": "LOCAL", +# "name": "new_user_1" +# }, +# { +# "domain": "LOCAL", +# "name": "new_user_2" +# } +# ] +# } +# } +# ], +# "object_type": "user" +# } +# ] + +# After state: +# ------------ +# +# ciscoasa# sh running-config object-group +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object host 192.0.2.2 +# network-object 192.0.2.0 255.255.255.0 +# network-object 198.51.100.0 255.255.255.0 +# object-group network test_network_og +# description test_network_og +# network-object host 192.0.3.1 +# network-object host 192.0.3.2 +# network-object 2001:db8:0:3::/64 +# group-object test_og_network +# object-group security test_og_security +# security-group name test_1 +# security-group name test_2 +# security-group tag 10 +# security-group tag 20 +# object-group user test_og_user +# user LOCAL\\new_user_1 +# user LOCAL\\new_user_2 + +# Using Rendered + +- name: Render the commands for provided configuration + cisco.asa.asa_ogs: + config: + - object_type: network + object_groups: + - name: test_og_network + description: test_og_network + network_object: + host: + - 192.0.2.1 + - 192.0.2.2 + address: + - 192.0.2.0 255.255.255.0 + - 198.51.100.0 255.255.255.0 + - name: test_network_og + description: test_network_og + network_object: + host: + - 192.0.3.1 + - 192.0.3.2 + ipv6_address: + - 2001:db8:3::/64 + - object_type: security + object_groups: + - name: test_og_security + description: test_security + security_group: + sec_name: + - test_1 + - test_2 + tag: + - 10 + - 20 + - object_type: user + object_groups: + - name: test_og_user + description: test_user + user_object: + user: + - name: new_user_1 + domain: LOCAL + - name: new_user_2 + domain: LOCAL + state: rendered + +# Module Execution Result: +# ------------------------ +# +# "rendered": [ +# "object-group security test_og_security", +# "description test_security", +# "security-group name test_1", +# "security-group name test_2", +# "security-group tag 10", +# "security-group tag 20", +# "object-group network test_og_network", +# "description test_og_network", +# "network-object 192.0.2.0 255.255.255.0", +# "network-object 198.51.100.0 255.255.255.0", +# "network-object host 192.0.2.1", +# "network-object host 192.0.2.2", +# "object-group network test_network_og", +# "description test_network_og", +# "network-object host 192.0.3.1", +# "network-object host 192.0.3.2", +# "network-object 2001:db8:3::/64", +# "object-group user test_og_user", +# "description test_user", +# "user LOCAL\\new_user_1", +# "user LOCAL\\new_user_2" +# ] + +# Using Parsed + +# parsed.cfg +# +# object-group network test_og_network +# description test_og_network +# network-object host 192.0.2.1 +# network-object 192.0.2.0 255.255.255.0 +# object-group network test_network_og +# network-object 2001:db8:3::/64 +# object-group service test_og_service +# service-object tcp-udp + +- name: Parse the commands for provided configuration + cisco.asa.asa_ogs: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# +# "parsed": [ +# { +# "object_groups": [ +# { +# "name": "test_network_og" +# }, +# { +# "description": "test_og_network", +# "name": "test_og_network", +# "network_object": { +# "host": [ +# "192.0.2.2" +# ] +# } +# } +# ], +# "object_type": "network" +# }, +# { +# "object_groups": [ +# { +# "name": "test_og_service", +# "service_object": { +# "protocol": [ +# "tcp-udp", +# "ipinip" +# ] +# } +# } +# ], +# "object_type": "service" +# } +# ] + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['object-group network test_network_og', 'description test_network_og', 'network-object host 192.0.2.1'] +""" + +from ansible.module_utils.basic import AnsibleModule +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.config.ogs.ogs import ( + OGs, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=OGsArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + result = OGs(module).execute_module() + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/__init__.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/__init__.py diff --git a/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/asa.py b/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/asa.py new file mode 100644 index 00000000..83f33918 --- /dev/null +++ b/collections-debian-merged/ansible_collections/cisco/asa/plugins/terminal/asa.py @@ -0,0 +1,76 @@ +# +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +# +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import re +import json + +from ansible.errors import AnsibleConnectionFailure +from ansible.module_utils._text import to_text, to_bytes +from ansible.plugins.terminal import TerminalBase + + +class TerminalModule(TerminalBase): + + terminal_stdout_re = [ + re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(br"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$"), + ] + + terminal_stderr_re = [ + re.compile(br"error:", re.I), + re.compile(br"Removing.* not allowed, it is being used"), + re.compile(br"^Command authorization failed\r?$", re.MULTILINE), + ] + + def on_open_shell(self): + if self._get_prompt().strip().endswith(b"#"): + self.disable_pager() + + def disable_pager(self): + try: + self._exec_cli_command(u"no terminal pager") + except AnsibleConnectionFailure: + raise AnsibleConnectionFailure("unable to disable terminal pager") + + def on_become(self, passwd=None): + if self._get_prompt().strip().endswith(b"#"): + return + + cmd = {u"command": u"enable"} + if passwd: + # Note: python-3.5 cannot combine u"" and r"" together. Thus make + # an r string and use to_text to ensure it's text on both py2 and py3. + cmd[u"prompt"] = to_text( + r"[\r\n]?[Pp]assword: $", errors="surrogate_or_strict" + ) + cmd[u"answer"] = passwd + + try: + self._exec_cli_command( + to_bytes(json.dumps(cmd), errors="surrogate_or_strict") + ) + except AnsibleConnectionFailure: + raise AnsibleConnectionFailure( + "unable to elevate privilege to enable mode" + ) + + self.disable_pager() |