diff --git a/docs/vyos.vyos.vyos_vrf_module.rst b/docs/vyos.vyos.vyos_vrf_module.rst index 7c6c5540..276c66fa 100644 --- a/docs/vyos.vyos.vyos_vrf_module.rst +++ b/docs/vyos.vyos.vyos_vrf_module.rst @@ -1,999 +1,1156 @@ .. _vyos.vyos.vyos_vrf_module: ****************** vyos.vyos.vyos_vrf ****************** **VRF resource module** Version added: 1.0.0 .. contents:: :local: :depth: 1 Synopsis -------- - This module manages vrf configuration on devices running Vyos Parameters ---------- .. raw:: html - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - -
ParameterParameter Choices/Defaults Comments
+
config
dictionary
List of vrf configuration.
+
bind_to_all
boolean
    Choices:
  • no ←
  • yes
Enable binding services to all VRFs
+
instances
list / elements=dictionary
Virtual Routing and Forwarding instance
+
+ address_family + +
+ list + / elements=dictionary +
+
+ +
Address family configuration
+
+
+ afi + +
+ string +
+
+
    Choices: +
  • ipv4
  • +
  • ipv6
  • +
+
+
Address family identifier
+
+
+ disable_forwarding + +
+ boolean +
+
+
    Choices: +
  • no ←
  • +
  • yes
  • +
+
+
Disable forwarding for this address family
+
+
+ nht_no_resolve_via_default + +
+ boolean +
+
+
    Choices: +
  • no ←
  • +
  • yes
  • +
+
+
Disable next-hop resolution via default route
+
+
+ route_maps + +
+ list + / elements=dictionary +
+
+ +
List of route maps for this address family
+
+
+ protocol + +
+ string +
+
+
    Choices: +
  • any
  • +
  • babel
  • +
  • bgp
  • +
  • connected
  • +
  • eigrp
  • +
  • isis
  • +
  • kernel
  • +
  • ospf
  • +
  • rip
  • +
  • static
  • +
  • table
  • +
+
+
Protocol to which the route map applies
+
+
+ rm_name + +
+ string + / required +
+
+ +
Route map name
+
description
string
Description
+
disable
boolean
    Choices:
  • no ←
  • yes
Administratively disable interface

aliases: disabled
+
name
string
VRF instance name
+
table_id
integer
Routing table associated with this instance
+
vni
integer
Virtual Network Identifier
+
running_config
string
This option is used only with state parsed.
-
The value of this option should be the output received from the VYOS device by executing the command show configuration commands | grep ntp.
+
The value of this option should be the output received from the VYOS device by executing the command show configuration commands | match "set vrf".
The states replaced and overridden have identical behaviour for this module.
-
The state parsed reads the configuration from show configuration commands | grep ntp option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the parsed key within the result.
+
The state parsed reads the configuration from show configuration commands | match "set vrf" option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the parsed key within the result.
+
state
string
    Choices:
  • deleted
  • merged ←
  • overridden
  • replaced
  • gathered
  • rendered
  • parsed
The state the configuration should be left in.

Notes ----- .. note:: - - Tested against vyos 1.4+ + - Tested against vyos 1.5-stream-2025-Q1 - This module works with connection ``network_cli``. Examples -------- .. code-block:: yaml # # ------------------- # # 1. Using merged # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Replace the existing ntp config with the new config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.6.6.0/24 listen_addresses: - 10.1.3.1 servers: - server: 203.0.113.0 options: - prefer # Task output: # ------------- # "after": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # }, # "changed": true, # "commands": [ # "set service ntp allow-clients address 10.6.6.0/24", # "set service ntp listen-address 10.1.3.1", # "set service ntp server 203.0.113.0 prefer" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 2. Using replaced # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.4.9.0/24' # set service ntp allow-clients address '10.4.7.0/24' # set service ntp allow-clients address '10.1.2.0/24' # set service ntp allow-clients address '10.2.3.0/24' # set service ntp listen-address '10.1.9.16' # set service ntp listen-address '10.5.3.2' # set service ntp listen-address '10.7.9.21' # set service ntp listen-address '10.8.9.4' # set service ntp listen-address '10.4.5.1' # set service ntp server 10.3.6.5 noselect # set service ntp server 10.3.6.5 dynamic # set service ntp server 10.3.6.5 preempt # set service ntp server 10.3.6.5 prefer # set service ntp server server4 noselect # set service ntp server server4 dynamic # set service ntp server server5 # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Replace the existing ntp config with the new config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.6.6.0/24 listen_addresses: - 10.1.3.1 servers: - server: 203.0.113.0 options: - prefer state: replaced # # Task output: # # ------------- # "after": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.4.7.0/24", # "10.2.3.0/24", # "10.1.2.0/24", # "10.4.9.0/24" # ], # "listen_addresses": [ # "10.7.9.21", # "10.4.5.1", # "10.5.3.2", # "10.8.9.4", # "10.1.9.16" # ], # "servers": [ # { # "server": "10.3.6.5", # "options": [ # "noselect", # "dynamic", # "preempt", # "prefer" # ] # }, # { # "server": "server4", # "options": [ # "noselect", # "dynamic" # ] # }, # { # "server": "server5" # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients address 10.4.7.0/24", # "delete service ntp allow-clients address 10.2.3.0/24", # "delete service ntp allow-clients address 10.1.2.0/24", # "delete service ntp allow-clients address 10.4.9.0/24", # "delete service ntp listen-address 10.7.9.21", # "delete service ntp listen-address 10.4.5.1", # "delete service ntp listen-address 10.5.3.2", # "delete service ntp listen-address 10.8.9.4", # "delete service ntp listen-address 10.1.9.16", # "delete service ntp server 10.3.6.5", # "delete service ntp server server4", # "delete service ntp server server5", # "set service ntp allow-clients address 10.6.6.0/24", # "set service ntp listen-address 10.1.3.1", # "set service ntp server 203.0.113.0 prefer" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 3. Using overridden # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Override ntp config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.3.3.0/24 listen_addresses: - 10.7.8.1 servers: - server: server1 options: - dynamic - prefer - server: server2 options: - noselect - preempt - server: serv state: overridden # # Task output: # # ------------- # "after": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients address 10.6.6.0/24", # "delete service ntp listen-address 10.1.3.1", # "delete service ntp server ser", # "set service ntp allow-clients address 10.3.3.0/24", # "set service ntp listen-address 10.7.8.1", # "set service ntp server server1 dynamic", # "set service ntp server server1 prefer", # "set service ntp server server2 noselect", # "set service ntp server server2 preempt", # "set service ntp server serv" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # 4. Using gathered # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Gather ntp config vyos.vyos.vyos_ntp_global: state: gathered # # Task output: # # ------------- # "gathered": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # } # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 5. Using deleted # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Delete ntp config vyos.vyos.vyos_ntp_global: state: deleted # # Task output: # # ------------- # "after": { # "servers": [ # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients", # "delete service ntp listen-address", # "delete service ntp server serv", # "delete service ntp server server1", # "delete service ntp server server2" # # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 6. Using rendered # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Render ntp config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.7.7.0/24 - 10.8.8.0/24 listen_addresses: - 10.7.9.1 servers: - server: server7 - server: server45 options: - noselect - prefer - pool - server: time1.vyos.net - server: time2.vyos.net - server: time3.vyos.net state: rendered # # Task output: # # ------------- # "rendered": [ # "set service ntp allow-clients address 10.7.7.0/24", # "set service ntp allow-clients address 10.8.8.0/24", # "set service ntp listen-address 10.7.9.1", # "set service ntp server server7", # "set service ntp server server45 noselect", # "set service ntp server server45 prefer", # "set service ntp server server45 pool", # "set service ntp server time1.vyos.net", # "set service ntp server time2.vyos.net", # "set service ntp server time3.vyos.net" # ] # # ------------------- # # 7. Using parsed # # ------------------- # # sample_config.cfg: # # ------------- # "set service ntp allow-clients address 10.7.7.0/24", # "set service ntp listen-address 10.7.9.1", # "set service ntp server server45 noselect", # "set service ntp allow-clients addres 10.8.6.0/24", # "set service ntp listen-address 10.5.4.1", # "set service ntp server server45 dynamic", # "set service ntp server time1.vyos.net", # "set service ntp server time2.vyos.net", # "set service ntp server time3.vyos.net" # Task: # ------------- - name: Parse externally provided ntp configuration vyos.vyos.vyos_ntp_global: running_config: "{{ lookup('file', './sample_config.cfg') }}" state: parsed # # Task output: # # ------------- # parsed = { # "allow_clients": [ # "10.7.7.0/24", # "10.8.6.0/24 # ], # "listen_addresses": [ # "10.5.4.1", # "10.7.9.1" # ], # "servers": [ # { # "server": "server45", # "options": [ # "noselect", # "dynamic" # # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # # ] # } Return Values ------------- Common return values are documented `here `_, the following are the fields unique to this module: .. raw:: html
Key Returned Description
after
dictionary
when changed
The resulting configuration after module execution.

Sample:
This output will always be in the same format as the module argspec.
before
dictionary
when state is merged, replaced, overridden, deleted or purged
The configuration prior to the module execution.

Sample:
This output will always be in the same format as the module argspec.
commands
list
when state is merged, replaced, overridden, deleted or purged
The set of commands pushed to the remote device.

Sample:
['set system ntp server server1 dynamic', 'set system ntp server server1 prefer', 'set system ntp server server2 noselect', 'set system ntp server server2 preempt', 'set system ntp server server_add preempt']
gathered
list
when state is gathered
Facts about the network resource gathered from the remote device as structured data.

Sample:
This output will always be in the same format as the module argspec.
parsed
list
when state is parsed
The device native config provided in running_config option parsed into structured data as per module argspec.

Sample:
This output will always be in the same format as the module argspec.
rendered
list
when state is rendered
The provided configuration in the task rendered in device-native format (offline).

Sample:
['set system ntp server server1 dynamic', 'set system ntp server server1 prefer', 'set system ntp server server2 noselect', 'set system ntp server server2 preempt', 'set system ntp server server_add preempt']


Status ------ Authors ~~~~~~~ - Evgeny Molotkov (@omnom62) diff --git a/plugins/module_utils/network/vyos/config/vrf/vrf.py b/plugins/module_utils/network/vyos/config/vrf/vrf.py index de7a5ea0..58366034 100644 --- a/plugins/module_utils/network/vyos/config/vrf/vrf.py +++ b/plugins/module_utils/network/vyos/config/vrf/vrf.py @@ -1,235 +1,239 @@ # # -*- 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_ntp config file. +The vyos_vrf 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 copy import deepcopy from ansible.module_utils.six import iteritems -from ansible.plugins.filter.core import combine 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.vrf import ( VrfTemplate, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import combine from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import ( LooseVersion, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version +# from ansible.plugins.filter.core import combine + + class Vrf(ResourceModule): """ The vyos_vrf config class """ def __init__(self, module): super(Vrf, self).__init__( empty_fact_val={}, facts_module=Facts(module), module=module, resource="vrf", tmplt=VrfTemplate(), ) self.parsers = [ "bind_to_all", ] def _validate_template(self): version = get_os_version(self._module) if LooseVersion(version) >= LooseVersion("1.4"): self._tmplt = VrfTemplate() else: self._module.fail_json(msg="VRF is not supported in this version of VyOS") def parse(self): """override parse to check template""" self._validate_template() return super().parse() def get_parser(self, name): """get_parsers""" self._validate_template() return super().get_parser(name) def execute_module(self): """Execute the module :rtype: A dictionary :returns: The result from module execution """ if self.state not in ["parsed", "gathered"]: self.generate_commands() self.run_commands() return self.result def generate_commands(self): """Generate configuration commands to send based on want, have and desired state. """ wantd = {} haved = {} wantd = deepcopy(self.want) haved = deepcopy(self.have) # self._module.fail_json(msg="WanT: " + str(self.want) + "**** H: " + str(self.have)) # if state is merged, merge want onto have and then compare if self.state in ["merged", "replaced"]: # wantd = dict_merge(wantd, haved) - wantd = haved | combine(wantd, recursive=True) + # wantd = haved | combine(wantd, recursive=True) + wantd = combine(haved, wantd, recursive=True) # self._module.fail_json(msg="Want: " + str(wantd) + "**** H: " + str(haved)) # if state is deleted, delete and empty out wantd if self.state == "deleted": w = deepcopy(wantd) for k, want in iteritems(w): if not (k in haved and haved[k]): del wantd[k] else: if isinstance(want, list): for entry in want: wname = entry.get("name") haved["instances"] = [ i for i in haved.get("instances", []) if i.get("name") != wname ] self.commands.append("delete vrf name {}".format(wname)) else: self.commands.append("delete vrf {}".format(k.replace("_", "-"))) del wantd[k] if self.state == "overridden": w = deepcopy(wantd) h = deepcopy(haved) for k, want in iteritems(w): if k in haved and haved[k] != want: if isinstance(want, list): for entry in want: wname = entry.get("name") hdict = next( (inst for inst in haved["instances"] if inst["name"] == wname), None, ) if entry != hdict: haved["instances"] = [ i for i in haved.get("instances", []) if i.get("name") != wname ] self.commands.append("delete vrf name {}".format(wname)) self.commands.append("commit") for k, want in iteritems(wantd): if isinstance(want, list): self._compare_instances(want=want, have=haved.pop(k, {})) self.compare( parsers=self.parsers, want={k: want}, have={k: haved.pop(k, {})}, ) # self._module.fail_json(msg=self.commands) def _compare_instances(self, want, have): """Compare the instances of the VRF""" parsers = [ "table_id", "vni", "description", "disable_vrf", ] # self._module.fail_json(msg="want: " + str(want) + "**** have: " + str(have)) for entry in want: h = {} wname = entry.get("name") # h = next((vrf for vrf in have if vrf["name"] == wname), {}) h = { k: v for vrf in have if vrf.get("name") == wname for k, v in vrf.items() if k != "address_family" } self.compare(parsers=parsers, want=entry, have=h) if "address_family" in entry: wafi = {"name": wname, "address_family": entry.get("address_family", [])} # hdict = next((item for item in have if item["name"] == wname), None) hdict = next((d for d in have if d.get("name") == wname), None) hafi = { "name": (hdict or {"name": wname})["name"], "address_family": hdict.get("address_family", []) if hdict else [], } # self._module.fail_json(msg="wafi: " + str(wafi) + "**** hafi: " + str(hafi)) self._compare_addr_family(wafi, hafi) def _compare_addr_family(self, want, have): """Compare the address families of the VRF""" afi_parsers = [ # "address_family", "disable_forwarding", "disable_nht", ] # self._module.fail_json(msg="wAfi: " + str(want) + "**** hAfi: " + str(have)) wafi = self.afi_to_list(want) hafi = self.afi_to_list(have) lookup = {(d["name"], d["afi"]): d for d in hafi} pairs = [(d1, lookup.get((d1["name"], d1["afi"]), {})) for d1 in wafi] for wafd, hafd in pairs: # self._module.fail_json(msg="wAfd: " + str(wafd) + "**** hAfd: " + str(hafd)) if "route_maps" in wafd: self._compare_route_maps(wafd, hafd) self.compare(parsers=afi_parsers, want=wafd, have=hafd) # self.compare(parsers=afi_parsers, want=wafi, have=hafi) def afi_to_list(self, data): """Convert address family dict to list""" return [ {"name": data["name"], **{**af, "afi": "ip" if af["afi"] == "ipv4" else af["afi"]}} for af in data["address_family"] ] def _compare_route_maps(self, wafd, hafd): want_rms = wafd.get("route_maps", []) have_rms = hafd.get("route_maps", []) for want in want_rms: match = next( ( h for h in have_rms if h["rm_name"] == want["rm_name"] and h["protocol"] == want["protocol"] ), {}, ) base = {"name": wafd["name"], "afi": wafd["afi"]} self.compare( parsers="route_maps", want={**base, "route_maps": want}, have={**base, "route_maps": match}, ) diff --git a/plugins/module_utils/network/vyos/rm_templates/vrf.py b/plugins/module_utils/network/vyos/rm_templates/vrf.py index e39805f7..5171404e 100644 --- a/plugins/module_utils/network/vyos/rm_templates/vrf.py +++ b/plugins/module_utils/network/vyos/rm_templates/vrf.py @@ -1,249 +1,249 @@ # -*- 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 Ntp parser templates file. This contains +The VRF 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 VrfTemplate(NetworkTemplate): def __init__(self, lines=None, module=None): prefix = {"set": "set", "remove": "delete"} super(VrfTemplate, self).__init__(lines=lines, tmplt=self, prefix=prefix, module=module) # fmt: off PARSERS = [ { "name": "table_id", "getval": re.compile( r""" ^set \s+vrf \s+name \s+(?P\S+) \s+table \s+'(?P\S+)' $""", re.VERBOSE, ), "setval": "vrf name {{ name }} table {{ table_id }}", "result": { "name": "{{ name }}", "table_id": "{{ tid }}", }, }, { "name": "bind_to_all", "getval": re.compile( r""" ^set \svrf \s(?Pbind-to-all) $""", re.VERBOSE, ), "setval": "vrf bind-to-all", "result": { "bind_to_all": "{{ True if bta is defined }}", }, }, { "name": "vni", "getval": re.compile( r""" ^set \s+vrf \s+name \s+(?P\S+) \s+vni \s'(?P\S+)' $""", re.VERBOSE, ), "setval": "vrf name {{name}} vni {{vni}}", "result": { "name": "{{ name }}", "vni": "{{ vni }}", }, }, { "name": "description", "getval": re.compile( r""" ^set \svrf \sname \s(?P\S+) \sdescription \s(?P\S+) $""", re.VERBOSE, ), "setval": "vrf name {{name}} description {{description}}", "result": { "name": "{{ name }}", "description": "{{ desc }}", }, }, { "name": "disable_vrf", "getval": re.compile( r""" ^set \svrf \sname \s(?P\S+) \s(?Pdisable) $""", re.VERBOSE, ), "setval": "vrf name {{name}} disable", "compval": "disable", "result": { "name": "{{ name }}", "disable": "{{ True if disable is defined }}", }, }, # { # "name": "address_family", # "getval": re.compile( # r""" # ^set # \svrf # \sname # \s(?P\S+) # \s(?Pip|ipv6) # $""", # re.VERBOSE, # ), # "setval": "vrf name {{name}} {{ af }}", # 'compval': "address_family", # "result": { # "name": "{{ name }}", # "address_family": { # '{{ "ipv4" if af == "ip" else "ipv6" }}': { # "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}', # }, # }, # }, # }, # { # "name": "address_family.disable_forwarding", # "getval": re.compile( # r""" # ^set # \svrf # \sname # \s(?P\S+) # \s(?Pip|ipv6) # \s(?Pdisable-forwarding) # $""", # re.VERBOSE, # ), # "setval": "vrf name {{name}} {{ afi }} disable-forwarding", # # "compval": "address_family.ipv6.disable_forwarding", # "result": { # "name": "{{ name }}", # "address_family": { # '{{ "ipv4" if af == "ip" else "ipv6" }}': { # "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}', # "disable_forwarding": "{{ True if df is defined }}", # }, # }, # }, # }, { "name": "disable_forwarding", "getval": re.compile( r""" ^set \svrf \sname \s(?P\S+) \s(?Pip|ipv6) \s(?Pdisable-forwarding) $""", re.VERBOSE, ), "setval": "vrf name {{name}} {{ afi }} disable-forwarding", "compval": "disable_forwarding", "result": { "name": "{{ name }}", 'address_family': [{ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}', "disable_forwarding": "{{ True if df is defined }}", }], }, }, { "name": "disable_nht", "getval": re.compile( r""" ^set \svrf \sname \s(?P\S+) \s(?Pip|ipv6) \snht \s(?Pno-resolve-via-default) $""", re.VERBOSE, ), "setval": "vrf name {{name}} {{ afi }} nht no-resolve-via-default", "compval": "nht_no_resolve_via_default", "result": { "name": "{{ name }}", "address_family": [{ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}', "nht_no_resolve_via_default": "{{ True if nht is defined }}", }], }, }, { "name": "route_maps", "getval": re.compile( r""" ^set \svrf \sname \s(?P\S+) \s(?Pip|ipv6) \sprotocol \s(?P\S+) \sroute-map \s'(?P\S+)' $""", re.VERBOSE, ), "setval": "vrf name {{name}} {{ afi }} protocol {{ route_maps.protocol }} route-map {{ route_maps.rm_name }}", "compval": "route_maps", "remval": "vrf name {{name}} {{ afi }} protocol {{ route_maps.protocol }}", "result": { "name": "{{ name }}", "address_family": [{ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}', "route_maps": [{ "rm_name": "{{ rm }}", "protocol": "{{ proto }}", }], }], }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index 4c371962..5ba48947 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -1,288 +1,310 @@ # -*- 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 from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.six import iteritems try: import ipaddress HAS_IPADDRESS = True except ImportError: HAS_IPADDRESS = False def search_obj_in_list(name, lst, key="name"): if lst: for item in lst: if item[key] == name: return item return None def get_interface_type(interface): """Gets the type of interface""" if interface.startswith("eth"): return "ethernet" elif interface.startswith("bond"): return "bonding" elif interface.startswith("vti"): return "vti" elif interface.startswith("lo"): return "loopback" elif interface.startswith("vtun"): return "openvpn" elif interface.startswith("wg"): return "wireguard" elif interface.startswith("tun"): return "tunnel" elif interface.startswith("br"): return "bridge" elif interface.startswith("dum"): return "dummy" def get_interface_with_vif(interface): """Gets virtual interface if any or return as is""" vlan = None interface_real = interface if "." in interface: interface_real, vlan = interface.split(".") if vlan is not None: interface_real = interface_real + " vif " + vlan return interface_real def dict_delete(base, comparable): """ This function generates a dict containing key, value pairs for keys that are present in the `base` dict but not present in the `comparable` dict. :param base: dict object to base the diff on :param comparable: dict object to compare against base :returns: new dict object with key, value pairs that needs to be deleted. """ to_delete = dict() for key in base: if isinstance(base[key], dict): sub_diff = dict_delete(base[key], comparable.get(key, {})) if sub_diff: to_delete[key] = sub_diff else: if key not in comparable: to_delete[key] = base[key] return to_delete def diff_list_of_dicts(want, have): diff = [] set_w = set(tuple(d.items()) for d in want) set_h = set(tuple(d.items()) for d in have) difference = set_w.difference(set_h) for element in difference: diff.append(dict((x, y) for x, y in element)) return diff def get_lst_diff_for_dicts(want, have, lst): """ This function generates a list containing values that are only in want and not in list in have dict :param want: dict object to want :param have: dict object to have :param lst: list the diff on :return: new list object with values which are only in want. """ if not have: diff = want.get(lst) or [] else: want_elements = want.get(lst) or {} have_elements = have.get(lst) or {} diff = list_diff_want_only(want_elements, have_elements) return diff def get_lst_same_for_dicts(want, have, lst): """ This function generates a list containing values that are common for list in want and list in have dict :param want: dict object to want :param have: dict object to have :param lst: list the comparison on :return: new list object with values which are common in want and have. """ diff = None if want and have: want_list = want.get(lst) or {} have_list = have.get(lst) or {} diff = [i for i in want_list and have_list if i in have_list and i in want_list] return diff def list_diff_have_only(want_list, have_list): """ This function generated the list containing values that are only in have list. :param want_list: :param have_list: :return: new list with values which are only in have list """ if have_list and not want_list: diff = have_list elif not have_list: diff = None else: diff = [i for i in have_list + want_list if i in have_list and i not in want_list] return diff def list_diff_want_only(want_list, have_list): """ This function generated the list containing values that are only in want list. :param want_list: :param have_list: :return: new list with values which are only in want list """ if have_list and not want_list: diff = None elif not have_list: diff = want_list else: diff = [i for i in have_list + want_list if i in want_list and i not in have_list] return diff def search_dict_tv_in_list(d_val1, d_val2, lst, key1, key2): """ This function return the dict object if it exist in list. :param d_val1: :param d_val2: :param lst: :param key1: :param key2: :return: """ obj = next( (item for item in lst if item[key1] == d_val1 and item[key2] == d_val2), None, ) if obj: return obj else: return None def key_value_in_dict(have_key, have_value, want_dict): """ This function checks whether the key and values exist in dict :param have_key: :param have_value: :param want_dict: :return: """ for key, value in iteritems(want_dict): if key == have_key and value == have_value: return True return False def is_dict_element_present(dict, key): """ This function checks whether the key is present in dict. :param dict: :param key: :return: """ for item in dict: if item == key: return True return False def get_ip_address_version(address): """ This function returns the version of IP address :param address: IP address :return: """ if not HAS_IPADDRESS: raise Exception(missing_required_lib("ipaddress")) try: address = unicode(address) except NameError: address = str(address) version = ipaddress.ip_address(address.split("/")[0]).version return version def get_route_type(address): """ This function returns the route type based on IP address :param address: :return: """ version = get_ip_address_version(address) if version == 6: return "route6" elif version == 4: return "route" def _bool_to_str(val): """ This function converts the bool value into string. :param val: bool value. :return: enable/disable. """ return "enable" if str(val) == "True" else "disable" if str(val) == "False" else val def _is_w_same(w, h, key): """ This function checks whether the key value is same in desired and target config dictionary. :param w: base config. :param h: target config. :param key:attribute name. :return: True/False. """ return True if h and key in h and h[key] == w[key] else False def _in_target(h, key): """ This function checks whether the target exist and key present in target config. :param h: target config. :param key: attribute name. :return: True/False. """ return True if h and key in h else False def in_target_not_none(h, key): """ This function checks whether the target exist,key present in target config, and the value is not None. :param h: target config. :param key: attribute name. :return: True/False. """ return True if h and key in h and h[key] is not None else False + + +def combine(a, b, recursive=False, list_merge="replace"): + """ + Merge two dictionaries (shallow or deep). + :param a: dict + :param b: dict + :param recursive: bool, deep merge + :param list_merge: str, only 'replace' is supported (default Ansible behavior) + """ + if not isinstance(a, dict) or not isinstance(b, dict): + raise ValueError("combine expects two dictionaries") + + result = a.copy() + + for k, v in b.items(): + if recursive and k in result and isinstance(result[k], dict) and isinstance(v, dict): + result[k] = combine(result[k], v, recursive=True, list_merge=list_merge) + else: + result[k] = v + + return result diff --git a/plugins/modules/vyos_vrf.py b/plugins/modules/vyos_vrf.py index bc5cc94b..8ff8697d 100644 --- a/plugins/modules/vyos_vrf.py +++ b/plugins/modules/vyos_vrf.py @@ -1,799 +1,842 @@ #!/usr/bin/python # -*- coding: utf-8 -*- # Copyright 2024 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) """ The module file for vyos_vrf """ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: vyos_vrf version_added: 1.0.0 short_description: VRF resource module description: - This module manages vrf configuration on devices running Vyos author: - Evgeny Molotkov (@omnom62) notes: -- Tested against vyos 1.4+ +- Tested against vyos 1.5-stream-2025-Q1 - This module works with connection C(network_cli). options: config: description: List of vrf configuration. type: dict suboptions: bind_to_all: default: false description: Enable binding services to all VRFs type: bool instances: description: Virtual Routing and Forwarding instance type: list elements: dict suboptions: name: description: VRF instance name type: str description: description: Description type: str disable: default: false description: Administratively disable interface type: bool aliases: ['disabled'] table_id: description: Routing table associated with this instance type: int vni: description: Virtual Network Identifier type: int + address_family: + type: list + elements: dict + description: Address family configuration + suboptions: + afi: + description: Address family identifier + type: str + choices: + - ipv4 + - ipv6 + disable_forwarding: + default: false + description: Disable forwarding for this address family + type: bool + nht_no_resolve_via_default: + default: false + description: Disable next-hop resolution via default route + type: bool + route_maps: + description: List of route maps for this address family + type: list + elements: dict + suboptions: + rm_name: + description: Route map name + type: str + required: true + protocol: + description: Protocol to which the route map applies + type: str + choices: + - any + - babel + - bgp + - connected + - eigrp + - isis + - kernel + - ospf + - rip + - static + - table running_config: description: - This option is used only with state I(parsed). - The value of this option should be the output received from the VYOS device by - executing the command B(show configuration commands | grep ntp). + executing the command B(show configuration commands | match "set vrf"). - The states I(replaced) and I(overridden) have identical behaviour for this module. - - The state I(parsed) reads the configuration from C(show configuration commands | grep ntp) option and + - The state I(parsed) reads the configuration from C(show configuration commands | match "set vrf") option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the I(parsed) key within the result. type: str state: description: - The state the configuration should be left in. type: str choices: - deleted - merged - overridden - replaced - gathered - rendered - parsed default: merged """ EXAMPLES = """ # # ------------------- # # 1. Using merged # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Replace the existing ntp config with the new config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.6.6.0/24 listen_addresses: - 10.1.3.1 servers: - server: 203.0.113.0 options: - prefer # Task output: # ------------- # "after": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # }, # "changed": true, # "commands": [ # "set service ntp allow-clients address 10.6.6.0/24", # "set service ntp listen-address 10.1.3.1", # "set service ntp server 203.0.113.0 prefer" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 2. Using replaced # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.4.9.0/24' # set service ntp allow-clients address '10.4.7.0/24' # set service ntp allow-clients address '10.1.2.0/24' # set service ntp allow-clients address '10.2.3.0/24' # set service ntp listen-address '10.1.9.16' # set service ntp listen-address '10.5.3.2' # set service ntp listen-address '10.7.9.21' # set service ntp listen-address '10.8.9.4' # set service ntp listen-address '10.4.5.1' # set service ntp server 10.3.6.5 noselect # set service ntp server 10.3.6.5 dynamic # set service ntp server 10.3.6.5 preempt # set service ntp server 10.3.6.5 prefer # set service ntp server server4 noselect # set service ntp server server4 dynamic # set service ntp server server5 # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Replace the existing ntp config with the new config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.6.6.0/24 listen_addresses: - 10.1.3.1 servers: - server: 203.0.113.0 options: - prefer state: replaced # # Task output: # # ------------- # "after": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.4.7.0/24", # "10.2.3.0/24", # "10.1.2.0/24", # "10.4.9.0/24" # ], # "listen_addresses": [ # "10.7.9.21", # "10.4.5.1", # "10.5.3.2", # "10.8.9.4", # "10.1.9.16" # ], # "servers": [ # { # "server": "10.3.6.5", # "options": [ # "noselect", # "dynamic", # "preempt", # "prefer" # ] # }, # { # "server": "server4", # "options": [ # "noselect", # "dynamic" # ] # }, # { # "server": "server5" # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients address 10.4.7.0/24", # "delete service ntp allow-clients address 10.2.3.0/24", # "delete service ntp allow-clients address 10.1.2.0/24", # "delete service ntp allow-clients address 10.4.9.0/24", # "delete service ntp listen-address 10.7.9.21", # "delete service ntp listen-address 10.4.5.1", # "delete service ntp listen-address 10.5.3.2", # "delete service ntp listen-address 10.8.9.4", # "delete service ntp listen-address 10.1.9.16", # "delete service ntp server 10.3.6.5", # "delete service ntp server server4", # "delete service ntp server server5", # "set service ntp allow-clients address 10.6.6.0/24", # "set service ntp listen-address 10.1.3.1", # "set service ntp server 203.0.113.0 prefer" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 3. Using overridden # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.6.6.0/24' # set service ntp listen-address '10.1.3.1' # set service ntp server 203.0.113.0 prefer, # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Override ntp config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.3.3.0/24 listen_addresses: - 10.7.8.1 servers: - server: server1 options: - dynamic - prefer - server: server2 options: - noselect - preempt - server: serv state: overridden # # Task output: # # ------------- # "after": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.6.6.0/24" # ], # "listen_addresses": [ # "10.1.3.1" # ], # "servers": [ # { # "server": "ser", # "options": [ # "prefer" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients address 10.6.6.0/24", # "delete service ntp listen-address 10.1.3.1", # "delete service ntp server ser", # "set service ntp allow-clients address 10.3.3.0/24", # "set service ntp listen-address 10.7.8.1", # "set service ntp server server1 dynamic", # "set service ntp server server1 prefer", # "set service ntp server server2 noselect", # "set service ntp server server2 preempt", # "set service ntp server serv" # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # 4. Using gathered # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Gather ntp config vyos.vyos.vyos_ntp_global: state: gathered # # Task output: # # ------------- # "gathered": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # } # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 5. Using deleted # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp allow-clients address '10.3.3.0/24' # set service ntp listen-address '10.7.8.1' # set service ntp server serv # set service ntp server server1 dynamic # set service ntp server server1 prefer # set service ntp server server2 noselect # set service ntp server server2 preempt # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # Task # # ------------- - name: Delete ntp config vyos.vyos.vyos_ntp_global: state: deleted # # Task output: # # ------------- # "after": { # "servers": [ # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "before": { # "allow_clients": [ # "10.3.3.0/24" # ], # "listen_addresses": [ # "10.7.8.1" # ], # "servers": [ # { # "server": "serv" # }, # { # "server": "server1", # "options": [ # "dynamic", # "prefer" # ] # }, # { # "server": "server2", # "options": [ # "noselect", # "preempt" # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # ] # }, # "changed": true, # "commands": [ # "delete service ntp allow-clients", # "delete service ntp listen-address", # "delete service ntp server serv", # "delete service ntp server server1", # "delete service ntp server server2" # # ] # After state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # # ------------------- # # 6. Using rendered # # ------------------- # # Before state: # # ------------- # vyos@vyos:~$ show configuration commands | grep ntp # set service ntp server time1.vyos.net # set service ntp server time2.vyos.net # set service ntp server time3.vyos.net # vyos@vyos:~$ # Task # ------------- - name: Render ntp config vyos.vyos.vyos_ntp_global: config: allow_clients: - 10.7.7.0/24 - 10.8.8.0/24 listen_addresses: - 10.7.9.1 servers: - server: server7 - server: server45 options: - noselect - prefer - pool - server: time1.vyos.net - server: time2.vyos.net - server: time3.vyos.net state: rendered # # Task output: # # ------------- # "rendered": [ # "set service ntp allow-clients address 10.7.7.0/24", # "set service ntp allow-clients address 10.8.8.0/24", # "set service ntp listen-address 10.7.9.1", # "set service ntp server server7", # "set service ntp server server45 noselect", # "set service ntp server server45 prefer", # "set service ntp server server45 pool", # "set service ntp server time1.vyos.net", # "set service ntp server time2.vyos.net", # "set service ntp server time3.vyos.net" # ] # # ------------------- # # 7. Using parsed # # ------------------- # # sample_config.cfg: # # ------------- # "set service ntp allow-clients address 10.7.7.0/24", # "set service ntp listen-address 10.7.9.1", # "set service ntp server server45 noselect", # "set service ntp allow-clients addres 10.8.6.0/24", # "set service ntp listen-address 10.5.4.1", # "set service ntp server server45 dynamic", # "set service ntp server time1.vyos.net", # "set service ntp server time2.vyos.net", # "set service ntp server time3.vyos.net" # Task: # ------------- - name: Parse externally provided ntp configuration vyos.vyos.vyos_ntp_global: running_config: "{{ lookup('file', './sample_config.cfg') }}" state: parsed # # Task output: # # ------------- # parsed = { # "allow_clients": [ # "10.7.7.0/24", # "10.8.6.0/24 # ], # "listen_addresses": [ # "10.5.4.1", # "10.7.9.1" # ], # "servers": [ # { # "server": "server45", # "options": [ # "noselect", # "dynamic" # # ] # }, # { # "server": "time1.vyos.net" # }, # { # "server": "time2.vyos.net" # }, # { # "server": "time3.vyos.net" # } # # ] # } """ RETURN = """ before: description: The configuration prior to the module execution. returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) type: dict sample: > This output will always be in the same format as the module argspec. after: description: The resulting configuration after module execution. returned: when changed type: dict sample: > This output will always be in the same format as the module argspec. commands: description: The set of commands pushed to the remote device. returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) type: list sample: - set system ntp server server1 dynamic - set system ntp server server1 prefer - set system ntp server server2 noselect - set system ntp server server2 preempt - set system ntp server server_add preempt rendered: description: The provided configuration in the task rendered in device-native format (offline). returned: when I(state) is C(rendered) type: list sample: - set system ntp server server1 dynamic - set system ntp server server1 prefer - set system ntp server server2 noselect - set system ntp server server2 preempt - set system ntp server server_add preempt gathered: description: Facts about the network resource gathered from the remote device as structured data. returned: when I(state) is C(gathered) type: list sample: > This output will always be in the same format as the module argspec. parsed: description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. returned: when I(state) is C(parsed) type: list sample: > This output will always be in the same format as the module argspec. """ from ansible.module_utils.basic import AnsibleModule from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.vrf.vrf import VrfArgs from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.vrf.vrf import Vrf def main(): """ Main entry point for module execution :returns: the result form module invocation """ module = AnsibleModule( argument_spec=VrfArgs.argument_spec, mutually_exclusive=[["config", "running_config"]], required_if=[ ["state", "merged", ["config"]], ["state", "replaced", ["config"]], ["state", "overridden", ["config"]], ["state", "rendered", ["config"]], ["state", "parsed", ["running_config"]], ], supports_check_mode=True, ) result = Vrf(module).execute_module() module.exit_json(**result) if __name__ == "__main__": main()