diff --git a/docs/vyos.vyos.vyos_nat_module.rst b/docs/vyos.vyos.vyos_nat_module.rst index 607ad0ca..d22515b5 100644 --- a/docs/vyos.vyos.vyos_nat_module.rst +++ b/docs/vyos.vyos.vyos_nat_module.rst @@ -1,301 +1,2804 @@ .. _vyos.vyos.vyos_nat_module: ****************** vyos.vyos.vyos_nat ****************** **NAT resource module** Version added: 1.0.0 .. contents:: :local: :depth: 1 Synopsis -------- - This module manages NAT configuration on devices running Vyos Parameters ---------- .. raw:: html - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
ParameterParameter Choices/Defaults Comments
+
+ config + +
+ dictionary +
+
+ +
The desired configuration for the NAT resource represented as a dictionary.
+
+
+ nat + +
+ dictionary +
+
+ +
Configuration for NAT rules.
+
+
+ cgnat + +
+ dictionary +
+
+ +
Configuration for Carrier Grade NAT (CGNAT).
+
+
+ log_allocation + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Whether to log CGNAT address allocations.
+
+
+ pool + +
+ dictionary +
+
+ +
Configuration for CGNAT pools.
+
+
+ external + +
+ list + / elements=dictionary +
+
+ +
List of external NAT pools for CGNAT.
+
+
+ external_port_range + +
+ string +
+
+ +
Port range to use for NAT translations in this external pool.
+
+
+ name + +
+ string + / required +
+
+ +
Name of the external NAT pool.
+
+
+ per_user_limit + +
+ dictionary +
+
+ +
Per-user limit configuration for the external pool.
+
+
+ port + +
+ integer +
+
+ +
Maximum number of ports allocated per user.
+
+
+ range + +
+ list + / elements=string +
+
+ +
List of external IP addresses or prefixes in the pool.
+
+
+ internal + +
+ list + / elements=dictionary +
+
+ +
List of internal NAT pools for CGNAT.
+
+
+ name + +
+ string + / required +
+
+ +
Name of the internal NAT pool.
+
+
+ range + +
+ list + / elements=string +
+
+ +
List of internal IP addresses or prefixes in the pool.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of CGNAT rules.
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for CGNAT.
+
+
+ source + +
+ dictionary +
+
+ +
Source configuration for CGNAT translation.
+
+
+ pool + +
+ string +
+
+ +
Source pool to use for CGNAT translation.
+
+
+ translation + +
+ dictionary +
+
+ +
Translation configuration for CGNAT.
+
+
+ pool + +
+ string +
+
+ +
Translation pool to use for CGNAT translation.
+
+
+ destination + +
+ dictionary +
+
+ +
Configuration for destination NAT rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of destination NAT rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the destination NAT rule.
+
+
+ destination + +
+ dictionary +
+
+ +
Match criteria for destination NAT.
+
+
+ address + +
+ string +
+
+ +
IP address, subnet, or range to match for destination NAT.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this destination NAT rule.
+
+
+ exclude + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Exclude packets matching this rule from NAT.
+
+
+ fqdn + +
+ string +
+
+ +
Fully qualified domain name to match for destination NAT.
+
+
+ group + +
+ dictionary +
+
+ +
Address/network/port group to match for destination NAT.
+
+
+ address_group + +
+ string +
+
+ +
Address group name to match.
+
+
+ domain_group + +
+ string +
+
+ +
Domain group name to match.
+
+
+ mac_group + +
+ string +
+
+ +
MAC address group name to match.
+
+
+ network_group + +
+ string +
+
+ +
Network group name to match.
+
+
+ port_group + +
+ string +
+
+ +
Port group name to match.
+
+
+ log + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Log packets hitting this destination NAT rule.
+
+
+ port + +
+ string +
+
+ +
Port number or range for destination NAT.
+
+
+ protocol + +
+ string +
+
+ +
Protocol to match (TCP, UDP, ICMP, etc.).
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for destination NAT.
+
+
+ source + +
+ dictionary +
+
+ +
Configuration for source NAT rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of source NAT rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the source NAT rule.
+
+
+ destination + +
+ dictionary +
+
+ +
Match criteria for source NAT.
+
+
+ address + +
+ string +
+
+ +
IP address, subnet, or range to match for source NAT.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this source NAT rule.
+
+
+ exclude + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Exclude packets matching this rule from NAT.
+
+
+ fqdn + +
+ string +
+
+ +
Fully qualified domain name to match for source NAT.
+
+
+ group + +
+ dictionary +
+
+ +
Address/network/port group to match for source NAT.
+
+
+ address_group + +
+ string +
+
+ +
Address group name to match.
+
+
+ domain_group + +
+ string +
+
+ +
Domain group name to match.
+
+
+ mac_group + +
+ string +
+
+ +
MAC address group name to match.
+
+
+ network_group + +
+ string +
+
+ +
Network group name to match.
+
+
+ port_group + +
+ string +
+
+ +
Port group name to match.
+
+
+ log + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Log packets hitting this source NAT rule.
+
+
+ port + +
+ string +
+
+ +
Port number or range for source NAT.
+
+
+ protocol + +
+ string +
+
+ +
Protocol to match (TCP, UDP, ICMP, etc.).
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for source NAT.
+
+
+ static + +
+ dictionary +
+
+ +
Configuration for static NAT rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of static NAT rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the static NAT rule.
+
+
+ destination + +
+ dictionary +
+
+ +
Match criteria for static NAT.
+
+
+ address + +
+ string +
+
+ +
IP address, subnet, or range to match for static NAT.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this static NAT rule.
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for static NAT (one-to-one).
+
+
+ inbound_interface + +
+ list + / elements=string +
+
+ +
List of inbound interfaces that this static NAT rule applies to.
+
+
+ log + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Log packets hitting this static NAT rule.
+
+
+ translation + +
+ dictionary +
+
+ +
Translation configuration for static NAT.
+
+
+ address + +
+ string +
+
+ +
IP address or prefix to translate to.
+
+
+ nat64 + +
+ dictionary +
+
+ +
Configuration for NAT64 (IPv6-to-IPv4 NAT) rules.
+
+
+ source + +
+ dictionary +
+
+ +
Configuration for NAT64 source rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of NAT64 source rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the NAT64 source rule.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this NAT64 source rule.
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for NAT64 source rule.
+
+
+ match + +
+ dictionary +
+
+ +
Match criteria for NAT64 source rule.
+
+
+ mark + +
+ integer +
+
+ +
Match on firewall mark value (1-2147483647).
+
+
+ source + +
+ dictionary +
+
+ +
Source prefix to match for NAT64 translation.
+
+
+ prefix + +
+ string +
+
+ +
IPv6 source prefix to match (h:h:h:h:h:h:h:h/x).
+
+
+ translation + +
+ dictionary +
+
+ +
Translation configuration for NAT64 source rule.
+
+
+ pool + +
+ list + / elements=dictionary +
+
+ +
List of translation pools for NAT64.
+
+
+ address + +
+ string +
+
+ +
IPv4 address or prefix for translation pool.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the translation pool.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this translation pool.
+
+
+ id + +
+ integer + / required +
+
+ +
Pool number (1-999999).
+
+
+ port + +
+ string +
+
+ +
Port number or range for translation pool.
+
+
+ protocol + +
+ string +
+
+
    Choices: +
  • icmp
  • +
  • tcp
  • +
  • udp
  • +
+
+
Protocol for this translation pool entry.
+
+
+ nat66 + +
+ dictionary +
+
+ +
Configuration for NAT66 (IPv6-to-IPv6 NAT) rules.
+
+
+ destination + +
+ dictionary +
+
+ +
Configuration for NAT66 destination rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of NAT66 destination rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the NAT66 destination rule.
+
+
+ destination + +
+ dictionary +
+
+ +
Match criteria for NAT66 destination rule.
+
+
+ address + +
+ string +
+
+ +
IPv6 address or prefix to match. Supports single address (h:h:h:h:h:h:h:h), prefix (h:h:h:h:h:h:h:h/x), and negated forms (!h:h:h:h:h:h:h:h, !h:h:h:h:h:h:h:h/x).
+
+
+ port + +
+ string +
+
+ +
Port number, range, or name to match.
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this NAT66 destination rule.
+
+
+ exclude + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Exclude packets matching this rule from NAT66.
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for NAT66 destination rule.
+
+
+ inbound_interface + +
+ dictionary +
+
+ +
Inbound interface to match for NAT66 destination rule.
+
+
+ name + +
+ string +
+
+ +
Interface name to match. Supports wildcard (txt*) and negated (!text) forms.
+
+
+ log + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Log packets hitting this NAT66 destination rule.
+
+
+ protocol + +
+ string +
+
+ +
Protocol to match. Supports named protocols, numeric (0-255), negated (!protocol), all, and tcp_udp.
+
+
+ source + +
+ dictionary +
+
+ +
Source match criteria for NAT66 destination rule.
+
+
+ address + +
+ string +
+
+ +
IPv6 source address or prefix to match. Supports single address, prefix, and negated forms.
+
+
+ port + +
+ string +
+
+ +
Source port number, range, or name to match.
+
+
+ translation + +
+ dictionary +
+
+ +
Translation configuration for NAT66 destination rule.
+
+
+ address + +
+ string +
+
+ +
IPv6 address or prefix to translate destination to.
+
+
+ port + +
+ string +
+
+ +
Port number or range to translate destination port to.
+
+
+ source + +
+ dictionary +
+
+ +
Configuration for NAT66 source rules.
+
+
+ rule + +
+ list + / elements=dictionary +
+
+ +
List of NAT66 source rules.
+
+
+ description + +
+ string +
+
+ +
User-friendly description of the NAT66 source rule.
+
+
+ destination + +
+ dictionary +
+
+ +
Destination match criteria for NAT66 source rule.
+
- config + port + +
+ string +
+
+ +
Destination port number, range, or name to match.
+
+
+ prefix + +
+ string +
+
+ +
IPv6 destination prefix to match (h:h:h:h:h:h:h:h/x). Supports negated form (!h:h:h:h:h:h:h:h/x).
+
+
+ disable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Disable this NAT66 source rule.
+
+
+ exclude + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Exclude packets matching this rule from NAT66.
+
+
+ id + +
+ integer + / required +
+
+ +
Rule number for NAT66 source rule.
+
+
+ log + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Log packets hitting this NAT66 source rule.
+
+
+ outbound_interface
dictionary
-
The desired configuration for the NAT resource represented as a dictionary.
+
Outbound interface to match for NAT66 source rule.
+
- nat + name + +
+ string +
+
+ +
Interface name to match. Supports wildcard (txt*) and negated (!text) forms.
+
+
+ protocol + +
+ string +
+
+ +
Protocol to match. Supports named protocols, numeric (0-255), negated (!protocol), all, and tcp_udp.
+
+
+ source
dictionary
-
Configuration for NAT rules.
+
Source match criteria for NAT66 source rule.
+
+
+ port + +
+ string +
+
+ +
Source port number, range, or name to match.
+
+
+ prefix + +
+ string +
+
+ +
IPv6 source prefix to match (h:h:h:h:h:h:h:h/x). Supports negated form (!h:h:h:h:h:h:h:h/x).
+
+ translation + +
+ dictionary +
+
+ +
Translation configuration for NAT66 source rule.
+
+
+ address + +
+ string +
+
+ +
IPv6 address or prefix to translate source to. Use masquerade to masquerade as the outbound interface address.
+
+
+ port + +
+ string +
+
+ +
Port number or range to translate source port to.
+
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 nat.
The states replaced and overridden have identical behaviour for this module.
The state parsed reads the configuration from show configuration commands | grep nat 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.3.8, 1.4.2, the upcoming 1.5, and the rolling release of spring 2025 - This module works with connection ``network_cli``. Examples -------- .. code-block:: yaml # Using merged - name: Merge NAT source rule vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Outbound masquerade" state: merged # Using gathered - name: Gather NAT config vyos.vyos.vyos_nat: state: gathered # Using deleted - name: Delete NAT config vyos.vyos.vyos_nat: state: deleted # Using replaced - name: Replace NAT config vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Replaced rule" state: replaced # Using parsed - name: Parse NAT config vyos.vyos.vyos_nat: running_config: "{{ lookup('file', './nat_config.cfg') }}" state: parsed # Using rendered - name: Render NAT config offline vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Rendered rule" state: rendered 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 nat source rule 100 description 'Outbound masquerade'"]
gathered
dictionary
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
dictionary
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 nat source rule 100 description 'Rendered rule'"]


Status ------ Authors ~~~~~~~ - Evgeny Molotkov (@omnom62) diff --git a/plugins/module_utils/network/vyos/argspec/nat/nat.py b/plugins/module_utils/network/vyos/argspec/nat/nat.py index ada8a1cd..859d2cd9 100644 --- a/plugins/module_utils/network/vyos/argspec/nat/nat.py +++ b/plugins/module_utils/network/vyos/argspec/nat/nat.py @@ -1,307 +1,516 @@ # -*- 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) 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_nat module """ class NatArgs(object): # pylint: disable=R0903 """The arg spec for the vyos_nat module""" argument_spec = { "config": { "type": "dict", "nat": { "type": "dict", "options": { "cgnat": { "type": "dict", "options": { "log_allocation": { "type": "bool", }, "pool": { "type": "dict", "options": { "external": { "type": "list", "elements": "dict", "options": { "name": { "type": "str", "required": True, }, "external_port_range": { "type": "str", }, "per_user_limit": { "type": "dict", "options": { "port": { "type": "int", }, }, }, "range": { "type": "list", "elements": "str", }, }, }, "internal": { "type": "list", "elements": "dict", "options": { "name": { "type": "str", "required": True, }, "range": { "type": "list", "elements": "str", }, }, }, }, }, "rule": { "type": "list", "elements": "dict", "options": { "id": { "type": "int", "required": True, }, "source": { "type": "dict", "options": { "pool": { "type": "str", }, }, }, "translation": { "type": "dict", "options": { "pool": { "type": "str", }, }, }, }, }, }, }, "destination": { "type": "dict", "options": { "rule": { "type": "list", "elements": "dict", "options": { "id": { "type": "int", "required": True, }, "description": { "type": "str", }, "destination": { "type": "dict", "options": { "address": { "type": "str", }, "fqdn": { "type": "str", }, "group": { "type": "dict", "options": { "address_group": { "type": "str", }, "domain_group": { "type": "str", }, "mac_group": { "type": "str", }, "network_group": { "type": "str", }, "port_group": { "type": "str", }, }, }, "port": { "type": "str", }, "protocol": { "type": "str", }, "exclude": { "type": "bool", }, "log": { "type": "bool", }, "disable": { "type": "bool", }, }, }, }, }, }, }, "source": { "type": "dict", "options": { "rule": { "type": "list", "elements": "dict", "options": { "id": { "type": "int", "required": True, }, "description": { "type": "str", }, "destination": { "type": "dict", "options": { "address": { "type": "str", }, "fqdn": { "type": "str", }, "group": { "type": "dict", "options": { "address_group": { "type": "str", }, "domain_group": { "type": "str", }, "mac_group": { "type": "str", }, "network_group": { "type": "str", }, "port_group": { "type": "str", }, }, }, "port": { "type": "str", }, "protocol": { "type": "str", }, "exclude": { "type": "bool", }, "log": { "type": "bool", }, "disable": { "type": "bool", }, }, }, }, }, }, }, "static": { "type": "dict", "options": { "rule": { "type": "list", "elements": "dict", "options": { "id": { "type": "int", "required": True, }, "description": { "type": "str", }, "destination": { "type": "dict", "options": { "address": { "type": "str", }, }, }, "inbound_interface": { "type": "list", "elements": "str", }, "log": { "type": "bool", }, "disable": { "type": "bool", }, "translation": { "type": "dict", "options": { "address": { "type": "str", }, }, }, }, }, }, }, }, }, + "nat64": { + "type": "dict", + "options": { + "source": { + "type": "dict", + "options": { + "rule": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "description": { + "type": "str", + }, + "disable": { + "type": "bool", + }, + "match": { + "type": "dict", + "options": { + "mark": { + "type": "int", + }, + }, + }, + "source": { + "type": "dict", + "options": { + "prefix": { + "type": "str", + }, + }, + }, + "translation": { + "type": "dict", + "options": { + "pool": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "address": { + "type": "str", + }, + "description": { + "type": "str", + }, + "disable": { + "type": "bool", + }, + "port": { + "type": "str", + }, + "protocol": { + "type": "str", + "choices": [ + "icmp", + "tcp", + "udp", + ], + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "nat66": { + "type": "dict", + "options": { + "destination": { + "type": "dict", + "options": { + "rule": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "description": { + "type": "str", + }, + "destination": { + "type": "dict", + "options": { + "address": { + "type": "str", + }, + "port": { + "type": "str", + }, + }, + }, + "disable": { + "type": "bool", + }, + "exclude": { + "type": "bool", + }, + "inbound_interface": { + "type": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "log": { + "type": "bool", + }, + "protocol": { + "type": "str", + }, + "source": { + "type": "dict", + "options": { + "address": { + "type": "str", + }, + "port": { + "type": "str", + }, + }, + }, + "translation": { + "type": "dict", + "options": { + "address": { + "type": "str", + }, + "port": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + "source": { + "type": "dict", + "options": { + "rule": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "description": { + "type": "str", + }, + "destination": { + "type": "dict", + "options": { + "port": { + "type": "str", + }, + "prefix": { + "type": "str", + }, + }, + }, + "disable": { + "type": "bool", + }, + "exclude": { + "type": "bool", + }, + "log": { + "type": "bool", + }, + "outbound_interface": { + "type": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "protocol": { + "type": "str", + }, + "source": { + "type": "dict", + "options": { + "port": { + "type": "str", + }, + "prefix": { + "type": "str", + }, + }, + }, + "translation": { + "type": "dict", + "options": { + "address": { + "type": "str", + }, + "port": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, }, "running_config": {"type": "str"}, "state": { "type": "str", "choices": [ "deleted", "merged", "overridden", "replaced", "gathered", "rendered", "parsed", ], "default": "merged", }, } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/nat/nat.py b/plugins/module_utils/network/vyos/config/nat/nat.py index d64ea1b1..332279ac 100644 --- a/plugins/module_utils/network/vyos/config/nat/nat.py +++ b/plugins/module_utils/network/vyos/config/nat/nat.py @@ -1,185 +1,193 @@ # # -*- 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_nat 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_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.nat import ( NatTemplate, ) # from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( # dict_merge, # ) class Nat(ResourceModule): """ The vyos_nat config class """ def __init__(self, module): super(Nat, self).__init__( empty_fact_val={}, facts_module=Facts(module), module=module, resource="nat", tmplt=NatTemplate(), ) self.parsers = [] def execute_module(self): """Execute the module :rtype: A dictionary :returns: The result from module execution """ if self.state not in ["parsed", "gathered"]: self.generate_commands() self.run_commands() return self.result def generate_commands(self): """Generate configuration commands to send based on want, have and desired state. """ + wantd = {} + haved = {} + wantd = deepcopy(self.want) + haved = deepcopy(self.have) + + self._module.fail_json(msg={"want": wantd, "have": haved}) # wantd = self._ntp_list_to_dict(self.want) # haved = self._ntp_list_to_dict(self.have) # # 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 haved.items() if k in wantd or not wantd} # wantd = {} # commandlist = self._commandlist(haved) # servernames = self._servernames(haved) # # removing the servername and commandlist from the list after deleting it from haved # # iterate through the top-level items to delete # for k, have in haved.items(): # if k not in wantd: # for hk, hval in have.items(): # if hk == "allow_clients" and hk in commandlist: # self.commands.append( # self._tmplt.render({"": hk}, "allow_clients_delete", True), # ) # commandlist.remove(hk) # elif hk == "listen_addresses" and hk in commandlist: # self.commands.append( # self._tmplt.render({"": hk}, "listen_addresses_delete", True), # ) # commandlist.remove(hk) # elif hk == "server" and have["server"] in servernames: # self._compareoverride(want={}, have=have) # servernames.remove(have["server"]) # # if everything is deleted add the delete command for {path} ntp # # this should be equiv: servernames == [] and commandlist == ["server"]: # if wantd == {} and haved != {}: # self.commands.append( # self._tmplt.render({}, "service_delete", True), # ) # # remove existing config for overridden and replaced # # Getting the list of the server names from haved # # to avoid the duplication of overridding/replacing the servers # if self.state in ["overridden", "replaced"]: # commandlist = self._commandlist(haved) # servernames = self._servernames(haved) # for k, have in haved.items(): # if k not in wantd: # if "server" not in have: # self._compareoverride(want={}, have=have) # # removing the servername from the list after deleting it from haved # elif have["server"] in servernames: # self._compareoverride(want={}, have=have) # servernames.remove(have["server"]) # for k, want in wantd.items(): # 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 Ntp network resource. # """ # if "options" in want: # self.compare(parsers="options", want=want, have=have) # else: # self.compare(parsers=self.parsers, want=want, have=have) # def _compareoverride(self, want, have): # # do not delete configuration with options level # for i, val in have.items(): # if i == "options": # pass # else: # self.compare(parsers=i, want={}, have=have) # def _ntp_list_to_dict(self, entry): # servers_dict = {} # for k, data in entry.items(): # if k == "servers": # for value in data: # if "options" in value: # result = self._serveroptions_list_to_dict(value) # for res, resvalue in result.items(): # servers_dict.update({res: resvalue}) # else: # servers_dict.update({value["server"]: value}) # else: # for value in data: # servers_dict.update({"ip_" + value: {k: value}}) # return servers_dict # def _serveroptions_list_to_dict(self, entry): # serveroptions_dict = {} # for Opk, Op in entry.items(): # if Opk == "options": # for val in Op: # dict = {} # dict.update({"server": entry["server"]}) # dict.update({Opk: val}) # serveroptions_dict.update({entry["server"] + "_" + val: dict}) # return serveroptions_dict # def _commandlist(self, haved): # commandlist = [] # for k, have in haved.items(): # for ck, cval in have.items(): # if ck != "options" and ck not in commandlist: # commandlist.append(ck) # return commandlist # def _servernames(self, haved): # servernames = [] # for k, have in haved.items(): # for sk, sval in have.items(): # if sk != "options" and sval not in servernames: # servernames.append(sval) # return servernames diff --git a/plugins/module_utils/network/vyos/config/vrf/vrf.old b/plugins/module_utils/network/vyos/config/vrf/vrf.old deleted file mode 100644 index b9f56cc6..00000000 --- a/plugins/module_utils/network/vyos/config/vrf/vrf.old +++ /dev/null @@ -1,313 +0,0 @@ -# -# -*- 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_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. -""" - -import importlib - -from copy import deepcopy - -from ansible.module_utils.six import iteritems -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( - ResourceModule, -) - -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import ( - Bgp_global, -) -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", - ] - self.bgp = Bgp_global(module) - - 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 = 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) - if w == {} and haved != {}: - self.commands = ["delete vrf"] - return - 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: - # self._module.fail_json(msg="Want: " + str(entry) + "**** H: " + str(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) - - if "protocols" in entry: - for protocol_name in entry["protocols"]: - protocol_module = self._load_protocol_module(protocol_name) - w_p_dict = entry["protocols"][protocol_name] - h_p_dict = next( - ( - v.get("protocols", {}).get(protocol_name) - for v in have - if v.get("name") == wname - ), - {}, - ) - if protocol_name == "bgp": - protocol_module._validate_template() - protocol_module.want = w_p_dict - protocol_module.have = h_p_dict - protocol_module.generate_commands() - elif protocol_name in [ - # "ospf", - # "ospfv3", - "static", - ]: - self._module.fail_json(msg=str(protocol_module)) - protocol_module._module.params["config"] = w_p_dict - protocol_module.state = self.state - self._module.fail_json(msg=str(protocol_module.set_config(h_p_dict))) - - protocol_module.commands = protocol_module.set_config(h_p_dict) - self.commands.extend( - [ - cmd.replace("protocols", "vrf name " + wname + " protocols", 1) - for cmd in protocol_module.commands - ], - ) - protocol_module = None # Clear the module to free resources - - 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}, - ) - - def _load_protocol_module(self, protocol_name): - if protocol_name == "bgp": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import ( - Bgp_global, - ) - - return Bgp_global(self._module) - elif protocol_name == "ospf": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import ( - Ospfv2, - ) - - return Ospfv2(self._module) - elif protocol_name == "ospfv3": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import ( - Ospfv3, - ) - - return Ospfv3(self._module) - elif protocol_name == "static": - from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.static_routes.static_routes import ( - Static_routes, - ) - - return Static_routes(self._module) - else: - self._module.fail_json(msg="The protocol is not supported") diff --git a/plugins/module_utils/network/vyos/facts/nat/nat.py b/plugins/module_utils/network/vyos/facts/nat/nat.py index f7cfa86e..0981e5f0 100644 --- a/plugins/module_utils/network/vyos/facts/nat/nat.py +++ b/plugins/module_utils/network/vyos/facts/nat/nat.py @@ -1,77 +1,75 @@ # -*- 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 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. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.nat.nat import ( NatArgs, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.nat import ( NatTemplate, ) class NatFacts(object): """The vyos nat facts class""" def __init__(self, module, subspec="config", options="options"): self._module = module self.argument_spec = NatArgs.argument_spec def get_config(self, connection): return connection.get("show configuration commands | match 'nat'") def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for Ntp network resource :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ facts = {} objs = [] config_lines = [] if not data: data = self.get_config(connection) for resource in data.splitlines(): config_lines.append(re.sub("'", "", resource)) # parse native config using the Nat template nat_parser = NatTemplate(lines=config_lines, module=self._module) objs = nat_parser.parse() ansible_facts["ansible_network_resources"].pop("nat", None) - # self._module.fail_json(msg=objs) params = utils.remove_empties( nat_parser.validate_config(self.argument_spec, {"config": objs}, redact=True), ) if params.get("config"): facts["nat"] = params["config"] ansible_facts["ansible_network_resources"].update(facts) - self._module.fail_json(msg=ansible_facts) return ansible_facts diff --git a/plugins/modules/vyos_nat.py b/plugins/modules/vyos_nat.py index c2dec5ef..91c20c02 100644 --- a/plugins/modules/vyos_nat.py +++ b/plugins/modules/vyos_nat.py @@ -1,418 +1,640 @@ #!/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_nat """ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: vyos_nat version_added: 1.0.0 short_description: NAT resource module description: - This module manages NAT configuration on devices running Vyos author: - Evgeny Molotkov (@omnom62) notes: - Tested against VyOS 1.3.8, 1.4.2, the upcoming 1.5, and the rolling release of spring 2025 - This module works with connection C(network_cli). options: config: description: - The desired configuration for the NAT resource represented as a dictionary. type: dict suboptions: nat: type: dict description: Configuration for NAT rules. suboptions: - cgnat: - type: dict - description: Configuration for Carrier Grade NAT (CGNAT). - suboptions: - log_allocation: - type: bool - description: Whether to log CGNAT address allocations. - pool: - type: dict - description: Configuration for CGNAT pools. - suboptions: - external: - type: list - elements: dict - description: List of external NAT pools for CGNAT. - suboptions: - name: - type: str - required: true - description: Name of the external NAT pool. - external_port_range: - type: str - description: Port range to use for NAT translations in this external pool. - per_user_limit: - type: dict - description: Per-user limit configuration for the external pool. - suboptions: - port: - type: int - description: Maximum number of ports allocated per user. - range: - type: list - elements: str - description: List of external IP addresses or prefixes in the pool. - internal: - type: list - elements: dict - description: List of internal NAT pools for CGNAT. - suboptions: - name: - type: str - required: true - description: Name of the internal NAT pool. - range: - type: list - elements: str - description: List of internal IP addresses or prefixes in the pool. - rule: - type: list - elements: dict - description: List of CGNAT rules. - suboptions: - id: - type: int - required: true - description: Rule number for CGNAT. - source: - type: dict - description: Source configuration for CGNAT translation. - suboptions: - pool: - type: str - description: Source pool to use for CGNAT translation. - translation: - type: dict - description: Translation configuration for CGNAT. - suboptions: - pool: - type: str - description: Translation pool to use for CGNAT translation. - destination: - type: dict - description: Configuration for destination NAT rules. - suboptions: - rule: - type: list - elements: dict - description: List of destination NAT rules. - suboptions: - id: - type: int - required: true - description: Rule number for destination NAT. - description: - type: str - description: User-friendly description of the destination NAT rule. - destination: - type: dict - description: Match criteria for destination NAT. - suboptions: - address: - type: str - description: IP address, subnet, or range to match for destination NAT. - fqdn: - type: str - description: Fully qualified domain name to match for destination NAT. - group: - type: dict - description: Address/network/port group to match for destination NAT. - suboptions: - address_group: - type: str - description: Address group name to match. - domain_group: - type: str - description: Domain group name to match. - mac_group: - type: str - description: MAC address group name to match. - network_group: - type: str - description: Network group name to match. - port_group: - type: str - description: Port group name to match. - port: - type: str - description: Port number or range for destination NAT. - protocol: - type: str - description: Protocol to match (TCP, UDP, ICMP, etc.). - exclude: - type: bool - description: Exclude packets matching this rule from NAT. - log: - type: bool - description: Log packets hitting this destination NAT rule. - disable: - type: bool - description: Disable this destination NAT rule. - source: - type: dict - description: Configuration for source NAT rules. - suboptions: - rule: - type: list - elements: dict - description: List of source NAT rules. - suboptions: - id: - type: int - required: true - description: Rule number for source NAT. - description: - type: str - description: User-friendly description of the source NAT rule. - destination: - type: dict - description: Match criteria for source NAT. - suboptions: - address: - type: str - description: IP address, subnet, or range to match for source NAT. - fqdn: - type: str - description: Fully qualified domain name to match for source NAT. - group: - type: dict - description: Address/network/port group to match for source NAT. - suboptions: - address_group: - type: str - description: Address group name to match. - domain_group: - type: str - description: Domain group name to match. - mac_group: - type: str - description: MAC address group name to match. - network_group: - type: str - description: Network group name to match. - port_group: - type: str - description: Port group name to match. - port: - type: str - description: Port number or range for source NAT. - protocol: - type: str - description: Protocol to match (TCP, UDP, ICMP, etc.). - exclude: - type: bool - description: Exclude packets matching this rule from NAT. - log: - type: bool - description: Log packets hitting this source NAT rule. - disable: - type: bool - description: Disable this source NAT rule. - static: - type: dict - description: Configuration for static NAT rules. - suboptions: - rule: - type: list - elements: dict - description: List of static NAT rules. - suboptions: - id: - type: int - required: true - description: Rule number for static NAT (one-to-one). - destination: - type: dict - description: Match criteria for static NAT. - suboptions: - address: - type: str - description: IP address, subnet, or range to match for static NAT. - log: - type: bool - description: Log packets hitting this static NAT rule. - disable: - type: bool - description: Disable this static NAT rule. - description: - type: str - description: User-friendly description of the static NAT rule. - inbound_interface: - type: list - elements: str - description: List of inbound interfaces that this static NAT rule applies to. - translation: - type: dict - description: Translation configuration for static NAT. - suboptions: - address: - type: str - description: IP address or prefix to translate to. + cgnat: + type: dict + description: Configuration for Carrier Grade NAT (CGNAT). + suboptions: + log_allocation: + type: bool + description: Whether to log CGNAT address allocations. + pool: + type: dict + description: Configuration for CGNAT pools. + suboptions: + external: + type: list + elements: dict + description: List of external NAT pools for CGNAT. + suboptions: + name: + type: str + required: true + description: Name of the external NAT pool. + external_port_range: + type: str + description: Port range to use for NAT translations in this external pool. + per_user_limit: + type: dict + description: Per-user limit configuration for the external pool. + suboptions: + port: + type: int + description: Maximum number of ports allocated per user. + range: + type: list + elements: str + description: List of external IP addresses or prefixes in the pool. + internal: + type: list + elements: dict + description: List of internal NAT pools for CGNAT. + suboptions: + name: + type: str + required: true + description: Name of the internal NAT pool. + range: + type: list + elements: str + description: List of internal IP addresses or prefixes in the pool. + rule: + type: list + elements: dict + description: List of CGNAT rules. + suboptions: + id: + type: int + required: true + description: Rule number for CGNAT. + source: + type: dict + description: Source configuration for CGNAT translation. + suboptions: + pool: + type: str + description: Source pool to use for CGNAT translation. + translation: + type: dict + description: Translation configuration for CGNAT. + suboptions: + pool: + type: str + description: Translation pool to use for CGNAT translation. + destination: + type: dict + description: Configuration for destination NAT rules. + suboptions: + rule: + type: list + elements: dict + description: List of destination NAT rules. + suboptions: + id: + type: int + required: true + description: Rule number for destination NAT. + description: + type: str + description: User-friendly description of the destination NAT rule. + destination: + type: dict + description: Match criteria for destination NAT. + suboptions: + address: + type: str + description: IP address, subnet, or range to match for destination NAT. + fqdn: + type: str + description: Fully qualified domain name to match for destination NAT. + group: + type: dict + description: Address/network/port group to match for destination NAT. + suboptions: + address_group: + type: str + description: Address group name to match. + domain_group: + type: str + description: Domain group name to match. + mac_group: + type: str + description: MAC address group name to match. + network_group: + type: str + description: Network group name to match. + port_group: + type: str + description: Port group name to match. + port: + type: str + description: Port number or range for destination NAT. + protocol: + type: str + description: Protocol to match (TCP, UDP, ICMP, etc.). + exclude: + type: bool + description: Exclude packets matching this rule from NAT. + log: + type: bool + description: Log packets hitting this destination NAT rule. + disable: + type: bool + description: Disable this destination NAT rule. + source: + type: dict + description: Configuration for source NAT rules. + suboptions: + rule: + type: list + elements: dict + description: List of source NAT rules. + suboptions: + id: + type: int + required: true + description: Rule number for source NAT. + description: + type: str + description: User-friendly description of the source NAT rule. + destination: + type: dict + description: Match criteria for source NAT. + suboptions: + address: + type: str + description: IP address, subnet, or range to match for source NAT. + fqdn: + type: str + description: Fully qualified domain name to match for source NAT. + group: + type: dict + description: Address/network/port group to match for source NAT. + suboptions: + address_group: + type: str + description: Address group name to match. + domain_group: + type: str + description: Domain group name to match. + mac_group: + type: str + description: MAC address group name to match. + network_group: + type: str + description: Network group name to match. + port_group: + type: str + description: Port group name to match. + port: + type: str + description: Port number or range for source NAT. + protocol: + type: str + description: Protocol to match (TCP, UDP, ICMP, etc.). + exclude: + type: bool + description: Exclude packets matching this rule from NAT. + log: + type: bool + description: Log packets hitting this source NAT rule. + disable: + type: bool + description: Disable this source NAT rule. + static: + type: dict + description: Configuration for static NAT rules. + suboptions: + rule: + type: list + elements: dict + description: List of static NAT rules. + suboptions: + id: + type: int + required: true + description: Rule number for static NAT (one-to-one). + description: + type: str + description: User-friendly description of the static NAT rule. + destination: + type: dict + description: Match criteria for static NAT. + suboptions: + address: + type: str + description: IP address, subnet, or range to match for static NAT. + log: + type: bool + description: Log packets hitting this static NAT rule. + disable: + type: bool + description: Disable this static NAT rule. + inbound_interface: + type: list + elements: str + description: List of inbound interfaces that this static NAT rule applies to. + translation: + type: dict + description: Translation configuration for static NAT. + suboptions: + address: + type: str + description: IP address or prefix to translate to. + nat64: + type: dict + description: Configuration for NAT64 (IPv6-to-IPv4 NAT) rules. + suboptions: + source: + type: dict + description: Configuration for NAT64 source rules. + suboptions: + rule: + type: list + elements: dict + description: List of NAT64 source rules. + suboptions: + id: + type: int + required: true + description: Rule number for NAT64 source rule. + description: + type: str + description: User-friendly description of the NAT64 source rule. + disable: + type: bool + description: Disable this NAT64 source rule. + match: + type: dict + description: Match criteria for NAT64 source rule. + suboptions: + mark: + type: int + description: Match on firewall mark value (1-2147483647). + source: + type: dict + description: Source prefix to match for NAT64 translation. + suboptions: + prefix: + type: str + description: IPv6 source prefix to match (h:h:h:h:h:h:h:h/x). + translation: + type: dict + description: Translation configuration for NAT64 source rule. + suboptions: + pool: + type: list + elements: dict + description: List of translation pools for NAT64. + suboptions: + id: + type: int + required: true + description: Pool number (1-999999). + address: + type: str + description: IPv4 address or prefix for translation pool. + description: + type: str + description: User-friendly description of the translation pool. + disable: + type: bool + description: Disable this translation pool. + port: + type: str + description: Port number or range for translation pool. + protocol: + type: str + choices: + - icmp + - tcp + - udp + description: Protocol for this translation pool entry. + nat66: + type: dict + description: Configuration for NAT66 (IPv6-to-IPv6 NAT) rules. + suboptions: + destination: + type: dict + description: Configuration for NAT66 destination rules. + suboptions: + rule: + type: list + elements: dict + description: List of NAT66 destination rules. + suboptions: + id: + type: int + required: true + description: Rule number for NAT66 destination rule. + description: + type: str + description: User-friendly description of the NAT66 destination rule. + destination: + type: dict + description: Match criteria for NAT66 destination rule. + suboptions: + address: + type: str + description: > + IPv6 address or prefix to match. Supports single address + (h:h:h:h:h:h:h:h), prefix (h:h:h:h:h:h:h:h/x), and negated + forms (!h:h:h:h:h:h:h:h, !h:h:h:h:h:h:h:h/x). + port: + type: str + description: Port number, range, or name to match. + disable: + type: bool + description: Disable this NAT66 destination rule. + exclude: + type: bool + description: Exclude packets matching this rule from NAT66. + inbound_interface: + type: dict + description: Inbound interface to match for NAT66 destination rule. + suboptions: + name: + type: str + description: > + Interface name to match. Supports wildcard (txt*) and + negated (!text) forms. + log: + type: bool + description: Log packets hitting this NAT66 destination rule. + protocol: + type: str + description: > + Protocol to match. Supports named protocols, numeric (0-255), + negated (!protocol), all, and tcp_udp. + source: + type: dict + description: Source match criteria for NAT66 destination rule. + suboptions: + address: + type: str + description: > + IPv6 source address or prefix to match. Supports single + address, prefix, and negated forms. + port: + type: str + description: Source port number, range, or name to match. + translation: + type: dict + description: Translation configuration for NAT66 destination rule. + suboptions: + address: + type: str + description: IPv6 address or prefix to translate destination to. + port: + type: str + description: Port number or range to translate destination port to. + source: + type: dict + description: Configuration for NAT66 source rules. + suboptions: + rule: + type: list + elements: dict + description: List of NAT66 source rules. + suboptions: + id: + type: int + required: true + description: Rule number for NAT66 source rule. + description: + type: str + description: User-friendly description of the NAT66 source rule. + destination: + type: dict + description: Destination match criteria for NAT66 source rule. + suboptions: + port: + type: str + description: Destination port number, range, or name to match. + prefix: + type: str + description: > + IPv6 destination prefix to match (h:h:h:h:h:h:h:h/x). + Supports negated form (!h:h:h:h:h:h:h:h/x). + disable: + type: bool + description: Disable this NAT66 source rule. + exclude: + type: bool + description: Exclude packets matching this rule from NAT66. + log: + type: bool + description: Log packets hitting this NAT66 source rule. + outbound_interface: + type: dict + description: Outbound interface to match for NAT66 source rule. + suboptions: + name: + type: str + description: > + Interface name to match. Supports wildcard (txt*) and + negated (!text) forms. + protocol: + type: str + description: > + Protocol to match. Supports named protocols, numeric (0-255), + negated (!protocol), all, and tcp_udp. + source: + type: dict + description: Source match criteria for NAT66 source rule. + suboptions: + port: + type: str + description: Source port number, range, or name to match. + prefix: + type: str + description: > + IPv6 source prefix to match (h:h:h:h:h:h:h:h/x). + Supports negated form (!h:h:h:h:h:h:h:h/x). + translation: + type: dict + description: Translation configuration for NAT66 source rule. + suboptions: + address: + type: str + description: > + IPv6 address or prefix to translate source to. + Use masquerade to masquerade as the outbound interface address. + port: + type: str + description: Port number or range to translate source port to. 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 nat). - 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 nat) 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 = """ # Using merged - name: Merge NAT source rule vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Outbound masquerade" state: merged # Using gathered - name: Gather NAT config vyos.vyos.vyos_nat: state: gathered # Using deleted - name: Delete NAT config vyos.vyos.vyos_nat: state: deleted # Using replaced - name: Replace NAT config vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Replaced rule" state: replaced # Using parsed - name: Parse NAT config vyos.vyos.vyos_nat: running_config: "{{ lookup('file', './nat_config.cfg') }}" state: parsed # Using rendered - name: Render NAT config offline vyos.vyos.vyos_nat: config: source: rule: - id: 100 description: "Rendered rule" state: rendered """ 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 nat source rule 100 description 'Outbound masquerade' 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 nat source rule 100 description 'Rendered rule' gathered: description: Facts about the network resource gathered from the remote device as structured data. returned: when I(state) is C(gathered) type: dict 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: dict 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.nat.nat import ( NatArgs, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.nat.nat import ( Nat, ) def main(): """ Main entry point for module execution :returns: the result form module invocation """ module = AnsibleModule( argument_spec=NatArgs.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 = Nat(module).execute_module() module.exit_json(**result) if __name__ == "__main__": main()