summaryrefslogtreecommitdiff
path: root/plugins/module_utils
diff options
context:
space:
mode:
authorPriyam Sahoo <42550351+priyamsahoo@users.noreply.github.com>2021-07-06 00:53:20 +0530
committerGitHub <noreply@github.com>2021-07-05 19:23:20 +0000
commitaf07511dee4d74b4159482c6b7aed6efff0e5949 (patch)
tree559e0093e82118d601108dc81efb88200e3a2c6b /plugins/module_utils
parent8264a29424c79c25d03cf89c376a72ec6a0f600f (diff)
downloadvyos-ansible-old-af07511dee4d74b4159482c6b7aed6efff0e5949.tar.gz
vyos-ansible-old-af07511dee4d74b4159482c6b7aed6efff0e5949.zip
VyOS Prefix Lists Resource Module Added (#178)
VyOS Prefix Lists Resource Module Added SUMMARY PR for vyos_prefix_lists rm resolves: #99 ISSUE TYPE New Module Pull Request COMPONENT NAME ADDITIONAL INFORMATION Reviewed-by: Rohit Thakur <rohitthakur2590@outlook.com> Reviewed-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com> Reviewed-by: Priyam Sahoo <None>
Diffstat (limited to 'plugins/module_utils')
-rw-r--r--plugins/module_utils/network/vyos/argspec/prefix_lists/__init__.py0
-rw-r--r--plugins/module_utils/network/vyos/argspec/prefix_lists/prefix_lists.py82
-rw-r--r--plugins/module_utils/network/vyos/config/prefix_lists/__init__.py0
-rw-r--r--plugins/module_utils/network/vyos/config/prefix_lists/prefix_lists.py182
-rw-r--r--plugins/module_utils/network/vyos/facts/facts.py4
-rw-r--r--plugins/module_utils/network/vyos/facts/prefix_lists/__init__.py0
-rw-r--r--plugins/module_utils/network/vyos/facts/prefix_lists/prefix_lists.py93
-rw-r--r--plugins/module_utils/network/vyos/rm_templates/prefix_lists.py265
8 files changed, 626 insertions, 0 deletions
diff --git a/plugins/module_utils/network/vyos/argspec/prefix_lists/__init__.py b/plugins/module_utils/network/vyos/argspec/prefix_lists/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/module_utils/network/vyos/argspec/prefix_lists/__init__.py
diff --git a/plugins/module_utils/network/vyos/argspec/prefix_lists/prefix_lists.py b/plugins/module_utils/network/vyos/argspec/prefix_lists/prefix_lists.py
new file mode 100644
index 0000000..c7d2e98
--- /dev/null
+++ b/plugins/module_utils/network/vyos/argspec/prefix_lists/prefix_lists.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the
+# cli_rm_builder.
+#
+# Manually editing this file is not advised.
+#
+# To update the argspec make the desired changes
+# in the module docstring and re-run
+# cli_rm_builder.
+#
+#############################################
+
+"""
+The arg spec for the vyos_prefix_lists module
+"""
+
+
+class Prefix_listsArgs(object): # pylint: disable=R0903
+ """The arg spec for the vyos_prefix_lists module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ "required": True,
+ },
+ "prefix_lists": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "description": {"type": "str"},
+ "entries": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "sequence": {"type": "int", "required": True},
+ "description": {"type": "str"},
+ "action": {
+ "type": "str",
+ "choices": ["permit", "deny"],
+ },
+ "ge": {"type": "int"},
+ "le": {"type": "int"},
+ "prefix": {"type": "str"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/config/prefix_lists/__init__.py b/plugins/module_utils/network/vyos/config/prefix_lists/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/module_utils/network/vyos/config/prefix_lists/__init__.py
diff --git a/plugins/module_utils/network/vyos/config/prefix_lists/prefix_lists.py b/plugins/module_utils/network/vyos/config/prefix_lists/prefix_lists.py
new file mode 100644
index 0000000..b2c119d
--- /dev/null
+++ b/plugins/module_utils/network/vyos/config/prefix_lists/prefix_lists.py
@@ -0,0 +1,182 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The vyos_prefix_lists config file.
+It is in this file where the current configuration (as dict)
+is compared to the provided configuration (as dict) and the command set
+necessary to bring the current configuration to its desired end-state is
+created.
+"""
+
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ dict_merge,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import (
+ ResourceModule,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (
+ Facts,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.prefix_lists import (
+ Prefix_listsTemplate,
+)
+
+
+class Prefix_lists(ResourceModule):
+ """
+ The vyos_prefix_lists config class
+ """
+
+ def __init__(self, module):
+ super(Prefix_lists, self).__init__(
+ empty_fact_val=[],
+ facts_module=Facts(module),
+ module=module,
+ resource="prefix_lists",
+ tmplt=Prefix_listsTemplate(),
+ )
+ self.plist_parsers = [
+ "name",
+ "description",
+ ]
+ self.entries_parsers = [
+ "sequence",
+ "action",
+ "rule_description",
+ "ge",
+ "le",
+ "prefix",
+ ]
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ if self.state not in ["parsed", "gathered"]:
+ self.generate_commands()
+ self.run_commands()
+ return self.result
+
+ def generate_commands(self):
+ """Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ wantd = {entry["afi"]: entry for entry in self.want}
+ haved = {entry["afi"]: entry for entry in self.have}
+
+ self._prefix_list_list_to_dict(wantd)
+ self._prefix_list_list_to_dict(haved)
+
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted":
+ haved = {
+ k: v for k, v in iteritems(haved) if k in wantd or not wantd
+ }
+ for key, hvalue in iteritems(haved):
+ wvalue = wantd.pop(key, {})
+ if wvalue:
+ wplists = wvalue.get("prefix_lists", {})
+ hplists = hvalue.get("prefix_lists", {})
+ hvalue["prefix_lists"] = {
+ k: v
+ for k, v in iteritems(hplists)
+ if k in wplists or not wplists
+ }
+
+ # remove superfluous config for overridden and deleted
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self._compare(want={}, have=have)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ """Leverages the base class `compare()` method and
+ populates the list of commands to be run by comparing
+ the `want` and `have` data with the `parsers` defined
+ for the Prefix_lists network resource.
+ """
+ wplists = want.get("prefix_lists", {})
+ hplists = have.get("prefix_lists", {})
+
+ self._compare_plists(want=wplists, have=hplists)
+
+ if self.state in ["overridden", "deleted"]:
+ # remove remaining prefix lists
+ for h in hplists.values():
+ self.commands.append(
+ "delete policy prefix-{0} {1}".format(
+ "list" if h["afi"] == "ipv4" else "list6", h["name"]
+ )
+ )
+
+ def _compare_plists(self, want, have):
+ for wk, wentry in iteritems(want):
+ hentry = have.pop(wk, {})
+
+ # parser list for name and descriptions
+ self.compare(
+ parsers=self.plist_parsers,
+ want=wentry,
+ have=hentry,
+ )
+
+ wplrules = wentry.get("entries", {})
+ hplrules = hentry.get("entries", {})
+
+ self._compare_rules(want=wplrules, have=hplrules)
+
+ def _compare_rules(self, want, have):
+ for wr, wrule in iteritems(want):
+ hrule = have.pop(wr, {})
+
+ # parser list for entries
+ self.compare(
+ parsers=self.entries_parsers,
+ want=wrule,
+ have=hrule,
+ )
+
+ # remove remaining entries
+ for hr in have.values():
+ self.commands.append(
+ "delete policy prefix-{0} {1} rule {2}".format(
+ "list" if hr["afi"] == "ipv4" else "list6",
+ hr["name"],
+ hr["sequence"],
+ )
+ )
+
+ def _prefix_list_list_to_dict(self, entry):
+ for afi, value in iteritems(entry):
+ if "prefix_lists" in value:
+ for pl in value["prefix_lists"]:
+ pl.update({"afi": afi})
+ if "entries" in pl:
+ for entry in pl["entries"]:
+ entry.update({"afi": afi, "name": pl["name"]})
+ pl["entries"] = {
+ x["sequence"]: x for x in pl["entries"]
+ }
+ value["prefix_lists"] = {
+ entry["name"]: entry for entry in value["prefix_lists"]
+ }
diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py
index 81518f8..90ee03c 100644
--- a/plugins/module_utils/network/vyos/facts/facts.py
+++ b/plugins/module_utils/network/vyos/facts/facts.py
@@ -58,6 +58,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_a
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps import (
Route_mapsFacts,
)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.prefix_lists.prefix_lists import (
+ Prefix_listsFacts,
+)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (
Default,
Neighbors,
@@ -82,6 +85,7 @@ FACT_RESOURCE_SUBSETS = dict(
bgp_global=Bgp_globalFacts,
bgp_address_family=Bgp_address_familyFacts,
route_maps=Route_mapsFacts,
+ prefix_lists=Prefix_listsFacts,
)
diff --git a/plugins/module_utils/network/vyos/facts/prefix_lists/__init__.py b/plugins/module_utils/network/vyos/facts/prefix_lists/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/module_utils/network/vyos/facts/prefix_lists/__init__.py
diff --git a/plugins/module_utils/network/vyos/facts/prefix_lists/prefix_lists.py b/plugins/module_utils/network/vyos/facts/prefix_lists/prefix_lists.py
new file mode 100644
index 0000000..15a2db9
--- /dev/null
+++ b/plugins/module_utils/network/vyos/facts/prefix_lists/prefix_lists.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The vyos prefix_lists 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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
+ utils,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.prefix_lists import (
+ Prefix_listsTemplate,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.prefix_lists.prefix_lists import (
+ Prefix_listsArgs,
+)
+
+
+class Prefix_listsFacts(object):
+ """The vyos prefix_lists facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Prefix_listsArgs.argument_spec
+
+ def get_config(self, connection):
+ return connection.get("show configuration commands | grep prefix-list")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Prefix_lists network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = []
+
+ if not data:
+ data = self.get_config(connection)
+
+ # parse native config using the Prefix_lists template
+ prefix_lists_parser = Prefix_listsTemplate(
+ lines=data.splitlines(), module=self._module
+ )
+
+ objs = prefix_lists_parser.parse()
+ objs = sorted(
+ list(objs.values()),
+ key=lambda k: k["afi"],
+ )
+
+ if objs:
+ for item in objs:
+ item["prefix_lists"] = sorted(
+ list(item["prefix_lists"].values()),
+ key=lambda k: k["name"],
+ )
+ for pl in item["prefix_lists"]:
+ if "entries" in pl:
+ pl["entries"] = sorted(
+ list(pl["entries"].values()),
+ key=lambda k: k["sequence"],
+ )
+
+ ansible_facts["ansible_network_resources"].pop("prefix_lists", None)
+
+ params = utils.remove_empties(
+ prefix_lists_parser.validate_config(
+ self.argument_spec, {"config": objs}, redact=True
+ )
+ )
+
+ if params.get("config"):
+ facts["prefix_lists"] = params["config"]
+ else:
+ facts["prefix_lists"] = []
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
diff --git a/plugins/module_utils/network/vyos/rm_templates/prefix_lists.py b/plugins/module_utils/network/vyos/rm_templates/prefix_lists.py
new file mode 100644
index 0000000..9a66a8d
--- /dev/null
+++ b/plugins/module_utils/network/vyos/rm_templates/prefix_lists.py
@@ -0,0 +1,265 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+The Prefix_lists parser templates file. This contains
+a list of parser definitions and associated functions that
+facilitates both facts gathering and native command generation for
+the given network resource.
+"""
+
+import re
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+
+class Prefix_listsTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ prefix = {"set": "set", "remove": "delete"}
+ super(Prefix_listsTemplate, self).__init__(
+ lines=lines, tmplt=self, module=module, prefix=prefix
+ )
+
+ # fmt: off
+ PARSERS = [
+ # policy prefix-list <list-name>
+ {
+ "name": "name",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }}",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> description <desc>
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \sdescription\s'(?P<description>.+)'
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} description '{{ description }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "description": "{{ description }}"
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num>
+ {
+ "name": "sequence",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }}",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num> action
+ {
+ "name": "action",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ \saction\s'(?P<action>permit|deny)'
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }} action '{{ action }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}",
+ "action": "{{ action }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num> description <desc>
+ {
+ "name": "rule_description",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ \sdescription\s'(?P<rule_description>.+)'
+ $""", re.VERBOSE),
+ "compval": "description",
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }} description '{{ description }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}",
+ "description": "{{ rule_description }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num> ge <value>
+ {
+ "name": "ge",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ \sge\s'(?P<ge>\d+)'
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }} ge '{{ ge }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}",
+ "ge": "{{ ge }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num> le <value>
+ {
+ "name": "le",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ \sle\s'(?P<le>\d+)'
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }} le '{{ le }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}",
+ "le": "{{ le }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+
+ # policy prefix-list <list-name> rule <rule-num> prefix <ip>
+ {
+ "name": "prefix",
+ "getval": re.compile(
+ r"""
+ ^set
+ \spolicy
+ \sprefix-(?P<afi>\S+)
+ \s(?P<name>\S+)
+ \srule\s(?P<sequence>\d+)
+ \sprefix\s'(?P<prefix>\S+)'
+ $""", re.VERBOSE),
+ "setval": "policy prefix-{{ 'list' if afi == 'ipv4' else 'list6' }} {{ name }} rule {{ sequence }} prefix '{{ prefix }}'",
+ "result": {
+ "{{ 'ipv4' if afi == 'list' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'list' else 'ipv6' }}",
+ "prefix_lists": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "entries": {
+ "{{ sequence }}": {
+ "sequence": "{{ sequence }}",
+ "prefix": "{{ prefix }}"
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ ]
+ # fmt: on