Page MenuHomeVyOS Platform

No OneTemporary

Size
395 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.gitignore b/.gitignore
index 1dbe8b0e..2f5df4fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,128 +1,129 @@
# CML/virl lab cache
.virl/
# A collection directory, resulting from the use of the pytest-ansible-units plugin
collections/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# ide
*.code-workspace
.vscode/
.DS_Store
+*.bak
changelogs/.plugin-cache.yaml
# inventory for testing
inventory.network
*.bak
# Git worktrees
.worktrees/
# Claude Code
.claude/
diff --git a/README.md b/README.md
index 0a4b8f48..3e54f27c 100644
--- a/README.md
+++ b/README.md
@@ -1,266 +1,267 @@
# VyOS Collection
[![codecov](https://codecov.io/gh/vyos/vyos.vyos/graph/badge.svg?token=J217GFD69W)](https://codecov.io/gh/vyos/vyos.vyos)
[![CI](https://github.com/vyos/vyos.vyos/actions/workflows/tests.yml/badge.svg?branch=main&event=schedule)](https://github.com/vyos/vyos.vyos/actions/workflows/tests.yml)
The Ansible VyOS collection includes a variety of Ansible content to help automate the management of VyOS network appliances.
This collection has been tested against VyOS 1.3.8, 1.4.1 and the current rolling release for 1.5. Where possible,
compatibility with older versions of VyOS are maintained but not guaranteed.
## Communication
* Join the VyOS forum:
* [FAQ](https://forum.vyos.io/faq): find answers to frequently asked questions.
* [Guides and How To](https://forum.vyos.io/c/howto-guies/27): find guides and how-to articles.
* [News & Announcements](https://forum.vyos.io/c/announcements/6): track project-wide announcements .
<!--start requires_ansible-->
## Ansible version compatibility
This collection has been tested against the following Ansible versions: **>=2.15.0**.
Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions.
PEP440 is the schema used to describe the versions of Ansible.
<!--end requires_ansible-->
### Supported connections
The VyOS collection supports ``network_cli`` connections.
## Included content
<!--start collection content-->
### Cliconf plugins
Name | Description
--- | ---
[vyos.vyos.vyos](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_cliconf.rst)|Use vyos cliconf to run command on VyOS platform
### Modules
Name | Description
--- | ---
[vyos.vyos.vyos_banner](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_banner_module.rst)|Manage multiline banners on VyOS devices
[vyos.vyos.vyos_bgp_address_family](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_bgp_address_family_module.rst)|BGP Address Family resource module
[vyos.vyos.vyos_bgp_global](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_bgp_global_module.rst)|BGP global resource module
[vyos.vyos.vyos_command](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_command_module.rst)|Run one or more commands on VyOS devices
[vyos.vyos.vyos_config](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_config_module.rst)|Manage VyOS configuration on remote device
[vyos.vyos.vyos_facts](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_facts_module.rst)|Get facts about vyos devices.
[vyos.vyos.vyos_file](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_file_module.rst)|Manage files, directories, and their ownership on VyOS devices
[vyos.vyos.vyos_firewall_global](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_global_module.rst)|Firewall global resource module
[vyos.vyos.vyos_firewall_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_interfaces_module.rst)|Firewall interfaces resource module
[vyos.vyos.vyos_firewall_rules](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_rules_module.rst)|Firewall rules resource module
+[vyos.vyos.vyos_ha](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ha_module.rst)|Manage VRRP and load balancer configuration on VyOS
[vyos.vyos.vyos_hostname](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_hostname_module.rst)|Manages hostname resource module
[vyos.vyos.vyos_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_interfaces_module.rst)|Manages interface attributes of VyOS network devices.
[vyos.vyos.vyos_l3_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_l3_interfaces_module.rst)|Layer 3 interfaces resource module.
[vyos.vyos.vyos_lag_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_lag_interfaces_module.rst)|LAG interfaces resource module
[vyos.vyos.vyos_lldp_global](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_lldp_global_module.rst)|LLDP global resource module
[vyos.vyos.vyos_lldp_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_lldp_interfaces_module.rst)|LLDP interfaces resource module
[vyos.vyos.vyos_logging_global](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_logging_global_module.rst)|Logging resource module
[vyos.vyos.vyos_ntp_global](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ntp_global_module.rst)|NTP global resource module
[vyos.vyos.vyos_ospf_interfaces](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ospf_interfaces_module.rst)|OSPF Interfaces Resource Module.
[vyos.vyos.vyos_ospfv2](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ospfv2_module.rst)|OSPFv2 resource module
[vyos.vyos.vyos_ospfv3](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ospfv3_module.rst)|OSPFv3 resource module
[vyos.vyos.vyos_ping](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_ping_module.rst)|Tests reachability using ping from VyOS network devices
[vyos.vyos.vyos_prefix_lists](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_prefix_lists_module.rst)|Prefix-Lists resource module for VyOS
[vyos.vyos.vyos_route_maps](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_route_maps_module.rst)|Route Map resource module
[vyos.vyos.vyos_snmp_server](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_snmp_server_module.rst)|Manages snmp_server resource module
[vyos.vyos.vyos_static_routes](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_static_routes_module.rst)|Static routes resource module
[vyos.vyos.vyos_system](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_system_module.rst)|Run `set system` commands on VyOS devices
[vyos.vyos.vyos_user](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_user_module.rst)|Manage the collection of local users on VyOS device
[vyos.vyos.vyos_vlan](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_vlan_module.rst)|Manage VLANs on VyOS network devices
[vyos.vyos.vyos_vrf](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_vrf_module.rst)|VRF resource module
<!--end collection content-->
Click the ``Content`` button to see the list of content included in this collection.
## Installing this collection
You can install the VyOS collection with the Ansible Galaxy CLI:
ansible-galaxy collection install vyos.vyos
You can also include it in a `requirements.yml` file and install it with `ansible-galaxy collection install -r requirements.yml`, using the format:
```yaml
---
collections:
- name: vyos.vyos
```
## Using this collection
This collection includes [network resource modules](https://docs.ansible.com/ansible/latest/network/user_guide/network_resource_modules.html).
### Using modules from the VyOS collection in your playbooks
You can call modules by their Fully Qualified Collection Namespace (FQCN), such as `vyos.vyos.vyos_static_routes`.
The following example task replaces configuration changes in the existing configuration on a VyOS network device, using the FQCN:
```yaml
---
- name: Replace device configurations of listed static routes with provided
configurations
register: result
vyos.vyos.vyos_static_routes: &id001
config:
- address_families:
- afi: ipv4
routes:
- dest: 192.0.2.32/28
blackhole_config:
distance: 2
next_hops:
- forward_router_address: 192.0.2.7
- forward_router_address: 192.0.2.8
- forward_router_address: 192.0.2.9
state: replaced
```
**NOTE**: For Ansible 2.9, you may not see deprecation warnings when you run your playbooks with this collection. Use this documentation to track when a module is deprecated.
### See Also:
* [VyOS Platform Options](https://docs.ansible.com/ansible/latest/network/user_guide/platform_vyos.html)
* [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
## Contributing to this collection
We welcome community contributions to this collection. If you find problems, please open an issue or create a PR against the [VyOS collection repository](https://github.com/vyos/vyos.vyos). See [Contributing to VyOS](https://vyos.net/contribute/) for complete details.
You can also join us on:
- Forum - https://forum.vyos.io
See the [Contributing to VyOS](https://vyos.net/contribute/) for details on contributing to Ansible.
### Code of Conduct
This collection follows the Ansible project's
[Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html).
Please read and familiarize yourself with this document.
### Updating from resource module models
Some of our modules were templated using `resource_module_builder`, but some use
the newer [`cli_rm_builder`](https://github.com/ansible-network/cli_rm_builder)
which tempaltes baed on in-place device information, but also uses a new network
parsing engine designed to simplify and standardize the parsing of network
configuration.
#### Using older *resource_module_builder* modules
Last build was with a slightly-modified version of resource_module_builder.
This changes the calling parameters for the resources.
To update the collection from the resource module models, run the following command:
```bash
ansible-playbook -e rm_dest=`pwd` \
-e structure=collection \
-e collection_org=vyos \
-e collection_name=vyos \
-e model=../../../resource_module_models/models/vyos/firewall_rules/vyos_firewall_rules.yaml \
../../../resource_module_builder/site.yml
```
#### Using *cli_rm_builder* modules
The newer `cli_rm_builder` works similarly to the older `resource_module_builder`, but
pulls the information directly from the `DOCUMENTATION`, `EXAMPLES` and `RETURN`
blocks in the module itself.
To update the collection from the `cli_rm_builder` models, run the following command:
```bash
ansible-playbook -e rm_dest=`pwd` \
-e collection_org=vyos \
-e collection_name=vyos \
-e resource=bgp_address_family \
../../../cli_rm_builder/run.yml
```
Unlike the `resource_module_builder`, the `cli_rm_builder` does not require the `model` parameter. Instead, it uses the `resource` parameter to specify the resource to build.
### Testing playbooks
You can use `ANSIBLE_COLLECTIONS_PATH` to test the collection locally. For example:
```
ANSIBLE_COLLECTIONS_PATHS=~/my_dev_path ansible-playbook -i inventory.network test.yml
```
### Integration Tests
Integration tests are run using `ansible-test` and require that there be an inventory
defined (you can pass this in with `--inventory <filename>`) and that the system be
configured for access (recommended to use SSH keys).
Additionally:
- eth0 should be configured for `address dhcp` and should have an assigned address
on the local network
- eth1 and eth2 should be defined and uncofirgured (they'll be overwritten by the tests)
- eth3 and beyond should not be present or interface-related tests will fail
- when using VMs for testing, ensure that the interfaces don't use `virtio`, as it will supress
some interface configurations. `e1000e` is a good choice for testing.
- eth0 is also expected to show `duplex auto` and `speed auto` in the output of `show interfaces`,
however others are not due to the fact that they are repeatedly deleted and recreated
which causes the default values to be hidden.
## Changelogs
Change logs are available [here](https://github.com/vyos/vyos.vyos/blob/main/CHANGELOG.rst).
## Release notes
Release notes are available [here](https://github.com/vyos/vyos.vyos/blob/main/CHANGELOG.rst).
## Roadmap
<!-- Optional. Include the roadmap for this collection, and the proposed release/versioning strategy so users can anticipate the upgrade/update cycle. -->
Major Version | Ansible Support | VyOS Support | Details
--- | --- | --- | ---
4.1.0 | 2.15 | 1.1.2 | Final release for the 4.x series
5.0.0 | 2.16 | 1.1.2 | First relase under VyOS control as a separate collection
6.0.0 | 2.18 | 1.3.8 | *Planned* release for supporting VyOS 1.3.8+
7.0.0 | x.xx | 1.4.x | *Prospective* release deprecating incompatible 1.3.x modules
Note:
- Unreleased versions are not guaranteed to be released as described.
- Some modules may support a wider variety of versions depending upon the compatibility
with prior versions of VyOS.
- The roadmap is subject to change based on community feedback and contributions.
## More information
VyOS resources
- [Contributing to VyOS](https://vyos.net/contribute)
- [VyOS documentation](https://docs.vyos.io/en/latest/)
- [VyOS forum](https://forum.vyos.io)
Ansible Resources
- [Ansible network resources](https://docs.ansible.com/ansible/latest/network/getting_started/network_resources.html)
- [Ansible Collection overview](https://github.com/ansible-collections/overview)
- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
## Licensing
GNU General Public License v3.0 or later.
See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text.
diff --git a/changelogs/fragments/t6820_vrrp.yml b/changelogs/fragments/t6820_vrrp.yml
new file mode 100644
index 00000000..94145121
--- /dev/null
+++ b/changelogs/fragments/t6820_vrrp.yml
@@ -0,0 +1,3 @@
+---
+minor_changes:
+ - vyos_ha - Add VRRP (High Availability) support.
diff --git a/docs/vyos.vyos.vyos_ha_module.rst b/docs/vyos.vyos.vyos_ha_module.rst
new file mode 100644
index 00000000..5e03661c
--- /dev/null
+++ b/docs/vyos.vyos.vyos_ha_module.rst
@@ -0,0 +1,2523 @@
+.. _vyos.vyos.vyos_ha_module:
+
+
+*****************
+vyos.vyos.vyos_ha
+*****************
+
+**Manage VRRP and load balancer configuration on VyOS**
+
+
+Version added: 1.0.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- This module configures VRRP groups, global VRRP parameters, VRRP sync groups, and LVS-style virtual servers on VyOS 1.4+.
+- Supports creation, modification, deletion, replacement, rendering, and parsing of VRRP-related configuration.
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+ <table border=0 cellpadding=0 class="documentation-table">
+ <tr>
+ <th colspan="5">Parameter</th>
+ <th>Choices/<font color="blue">Defaults</font></th>
+ <th width="100%">Comments</th>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>config</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Full VRRP and virtual server configuration.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td colspan="4">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>disable</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">boolean</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
+ <li>yes</li>
+ </ul>
+ </td>
+ <td>
+ <div>Disable all VRRP and L4-LB configuration under this module.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td colspan="4">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>virtual_servers</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>List of load balancer virtual server (LVS) definitions.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Virtual IP address for the server.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>algorithm</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Load balancing algorithm used for dispatching connections.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>delay_loop</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Delay loop interval in seconds.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>forward_method</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li>direct</li>
+ <li>nat</li>
+ </ul>
+ </td>
+ <td>
+ <div>Forwarding method used by LVS.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>fwmark</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Firewall mark for LVS traffic classification.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>name</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ / <span style="color: red">required</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Unique identifier for the virtual server.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>persistence_timeout</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Client persistence timeout in seconds.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>port</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>TCP/UDP port provided by the virtual service.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>protocol</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li>tcp</li>
+ <li>udp</li>
+ </ul>
+ </td>
+ <td>
+ <div>Transport protocol for the virtual server.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>real_server</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Backend real servers behind the virtual service.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ / <span style="color: red">required</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Real server IP address.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>connection_timeout</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Backend server connection timeout.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>health_check_script</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Path to health check script used for backend validation.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>port</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Backend server port.</div>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td colspan="4">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>vrrp</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP configuration including groups, global parameters, SNMP settings, and sync-groups.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>global_parameters</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Global VRRP tuning parameters.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>garp</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Gratuitous ARP related configuration.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interval</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP interval in seconds.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_delay</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Delay before sending GARP as master.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_refresh</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Refresh interval for master GARP announcements.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_refresh_repeat</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Number of times to repeat refresh announcements.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_repeat</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Number of GARP repeats when transitioning to master.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>startup_delay</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Delay before VRRP starts after boot.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>version</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP protocol version.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>groups</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP instance configuration groups.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Virtual router IP addresses.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>advertise_interval</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP advertisement interval.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>authentication</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP group authentication options.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>password</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Authentication password.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>type</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Authentication type.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>description</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Text description for the VRRP group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>disable</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">boolean</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
+ <li>yes</li>
+ </ul>
+ </td>
+ <td>
+ <div>Disable this VRRP group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>excluded_address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>IP address excluded from source checks.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>garp</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP-specific settings for this group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interval</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP interval.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_delay</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP master delay.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_refresh</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP master refresh interval.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_refresh_repeat</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Repeated refresh sends.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master_repeat</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>GARP repeat count.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>health_check</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP group health check options.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>failure_count</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Allowed number of failed checks.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interval</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Health check interval.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>ping</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Host to ping for checks.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>script</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Script to execute for health checking.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>hello_source_address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Source address for VRRP hello packets.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interface</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Interface used by the VRRP group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>name</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ / <span style="color: red">required</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP group name.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>no_preempt</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">boolean</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
+ <li>yes</li>
+ </ul>
+ </td>
+ <td>
+ <div>Disable preemption.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>peer_address</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Peer VRRP router address.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>preempt_delay</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Delay before taking master role.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>priority</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP priority (higher = preferred master).</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>rfc3768_compatibility</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">boolean</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
+ <li>yes</li>
+ </ul>
+ </td>
+ <td>
+ <div>Enable or disable RFC3768 compatibility mode.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>track</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Track interface and VRRP behaviour.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>exclude_vrrp_interface</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">boolean</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li>no</li>
+ <li>yes</li>
+ </ul>
+ </td>
+ <td>
+ <div>Exclude VRRP interface from tracking.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interface</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Interface to track.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>transition_script</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Scripts executed during VRRP state transitions.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>backup</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Path to backup script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>fault</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Path to fault script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Path to master script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>stop</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Path to stop script.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>vrid</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP Virtual Router ID.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>snmp</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li>enabled</li>
+ <li>disabled</li>
+ </ul>
+ </td>
+ <td>
+ <div>Enable SNMP support for VRRP.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="3">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>sync_groups</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>VRRP sync-groups for coordinated failover.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>health_check</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Health check options for sync group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>failure_count</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Allowed number of failures.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>interval</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">integer</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Health check interval.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>ping</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Host to ping.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>script</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Script to run for health checking.</div>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>member</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ / <span style="color: purple">elements=string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>List of VRRP groups participating in this sync group.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>name</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ / <span style="color: red">required</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Sync-group name.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="2">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>transition_script</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Transition scripts for sync group events.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>backup</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Backup state script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>fault</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Fault state script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>master</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Master state script.</div>
+ </td>
+ </tr>
+ <tr>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td class="elbow-placeholder"></td>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>stop</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Stop state script.</div>
+ </td>
+ </tr>
+
+
+
+
+ <tr>
+ <td colspan="5">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>running_config</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ </td>
+ <td>
+ <div>Used only when <code>state=parsed</code>. Must contain the output of <code>show configuration commands | grep high-availability</code>.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <div class="ansibleOptionAnchor" id="parameter-"></div>
+ <b>state</b>
+ <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
+ <div style="font-size: small">
+ <span style="color: purple">string</span>
+ </div>
+ </td>
+ <td>
+ <ul style="margin: 0; padding: 0"><b>Choices:</b>
+ <li>deleted</li>
+ <li><div style="color: blue"><b>merged</b>&nbsp;&larr;</div></li>
+ <li>purged</li>
+ <li>replaced</li>
+ <li>gathered</li>
+ <li>rendered</li>
+ <li>parsed</li>
+ <li>overridden</li>
+ </ul>
+ </td>
+ <td>
+ <div>Desired end state of the VRRP configuration.</div>
+ </td>
+ </tr>
+ </table>
+ <br/>
+
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ # Using merged
+ # Before state
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # vyos@vyos:~$
+
+ - name: Merge provided configuration with device configuration
+ vyos.vyos.vyos_ha:
+ config:
+ disable: true
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.5
+ algorithm: round-robin
+ real_server:
+ - address: 10.10.50.2
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 30
+ port: 81
+ protocol: tcp
+ - name: s3
+ address: 10.10.10.3
+ port: 88
+ protocol: udp
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 30
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.3
+ priority: 100
+ disable: false
+ no_preempt: false
+ vrid: 20
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 5
+ state: merged
+
+ # After State
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s1 address '10.10.10.5'
+ # set high-availability virtual-server s1 algorithm 'round-robin'
+ # set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp global-parameters startup-delay '30'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+ # vyos@vyos:~$
+ #
+ # # Module Execution:
+ #
+ # "after": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.5",
+ # "algorithm": "round-robin",
+ # "name": "s1",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.2",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # },
+ # "startup_delay": 30
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "before": {
+ # "disable": false
+ # },
+ # "changed": true,
+ # "commands": [
+ # "set high-availability disable",
+ # "set high-availability virtual-server s1 address 10.10.10.5",
+ # "set high-availability virtual-server s1 algorithm round-robin",
+ # "set high-availability virtual-server s1 real-server 10.10.50.2 port 8443",
+ # "set high-availability virtual-server s2 address 10.10.10.2",
+ # "set high-availability virtual-server s2 persistence-timeout 30",
+ # "set high-availability virtual-server s2 port 81",
+ # "set high-availability virtual-server s2 protocol tcp",
+ # "set high-availability virtual-server s3 address 10.10.10.3",
+ # "set high-availability virtual-server s3 port 88",
+ # "set high-availability virtual-server s3 protocol udp",
+ # "set high-availability vrrp global-parameters garp master-repeat 6",
+ # "set high-availability vrrp global-parameters startup-delay 30",
+ # "set high-availability vrrp group g1 peer-address 192.168.1.3",
+ # "set high-availability vrrp group g1 priority 100",
+ # "set high-availability vrrp group g1 vrid 20",
+ # "set high-availability vrrp snmp",
+ # "set high-availability vrrp sync-group sg1 health-check failure-count 5"
+ # ],
+
+ # Using replaced:
+ # --------------
+
+ # Before state:
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s1 address '10.10.10.5'
+ # set high-availability virtual-server s1 algorithm 'round-robin'
+ # set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp global-parameters startup-delay '30'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+ # vyos@vyos:~$
+
+ - name: Replace
+ vyos.vyos.vyos_ha:
+ config:
+ disable: false
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.3
+ algorithm: round-robin
+ port: 8443
+ real_server:
+ - address: 10.10.50.3
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 300
+ port: 81
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.30
+ port: 8443
+ - name: s3
+ address: 10.10.10.3
+ port: 88
+ protocol: udp
+ real_server:
+ - address: 10.10.50.6
+ port: 8443
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 30
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.13
+ priority: 100
+ disable: false
+ no_preempt: true
+ interface: eth1
+ address: 192.168.51.13
+ vrid: 20
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 3
+ state: replaced
+
+ # After state:
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability virtual-server s1 address '10.10.10.3'
+ # set high-availability virtual-server s1 algorithm 'round-robin'
+ # set high-availability virtual-server s1 port '8443'
+ # set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+ # set high-availability virtual-server s1 real-server 10.10.50.3 port '8443'
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '300'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s2 real-server 10.10.50.3 port '8443'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability virtual-server s3 real-server 10.10.50.6 port '8443'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp global-parameters startup-delay '30'
+ # set high-availability vrrp group g1 address 192.168.51.13
+ # set high-availability vrrp group g1 interface 'eth1'
+ # set high-availability vrrp group g1 no-preempt
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 peer-address '192.168.1.13'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '3'
+ # vyos@vyos:~$
+ #
+ #
+ # Module Execution:
+ #
+ # "after": {
+ # "disable": false,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.3",
+ # "algorithm": "round-robin",
+ # "name": "s1",
+ # "port": 8443,
+ # "real_server": [
+ # {
+ # "address": "10.10.50.2",
+ # "port": 8443
+ # },
+ # {
+ # "address": "10.10.50.3",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 300,
+ # "port": 81,
+ # "protocol": "tcp",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.3",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.6",
+ # "port": 8443
+ # }
+ # ]
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # },
+ # "startup_delay": 30
+ # },
+ # "groups": [
+ # {
+ # "address": "192.168.51.13",
+ # "disable": false,
+ # "interface": "eth1",
+ # "name": "g1",
+ # "no_preempt": true,
+ # "peer_address": "192.168.1.13",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 3
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "before": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.5",
+ # "algorithm": "round-robin",
+ # "name": "s1",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.2",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # },
+ # "startup_delay": 30
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete high-availability disable",
+ # "set high-availability virtual-server s1 address 10.10.10.3",
+ # "set high-availability virtual-server s1 port 8443",
+ # "set high-availability virtual-server s1 real-server 10.10.50.3 port 8443",
+ # "set high-availability virtual-server s2 persistence-timeout 300",
+ # "set high-availability virtual-server s2 real-server 10.10.50.3 port 8443",
+ # "set high-availability virtual-server s3 real-server 10.10.50.6 port 8443",
+ # "set high-availability vrrp group g1 address 192.168.51.13",
+ # "set high-availability vrrp group g1 interface eth1",
+ # "set high-availability vrrp group g1 no-preempt",
+ # "set high-availability vrrp group g1 peer-address 192.168.1.13",
+ # "set high-availability vrrp sync-group sg1 health-check failure-count 3"
+ # ],
+
+ # Using deleted:
+ # -------------
+
+ # Before state:
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s1 address '10.10.10.5'
+ # set high-availability virtual-server s1 algorithm 'round-robin'
+ # set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp global-parameters startup-delay '30'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+ # vyos@vyos:~$
+
+ - name: Delete configuration
+ vyos.vyos.vyos_ha:
+ config:
+ disable: false
+ vrrp:
+ snmp: disabled
+ global_parameters:
+ startup_delay: 32
+ version: 3
+ virtual_servers:
+ - name: 's1'
+ address: '10.10.10.1'
+ algorithm: 'round-robin'
+ delay_loop: 60
+ forward_method: 'direct'
+ persistence_timeout: 30
+ port: 443
+ protocol: 'tcp'
+ real_server:
+ - address: '10.10.10.1'
+ connection_timeout: 61
+ port: 443
+ state: deleted
+
+ # After state:
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+
+ # vyos@vyos:~$
+ #
+ #
+ # Module Execution:
+ #
+ # "after": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # }
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "before": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.5",
+ # "algorithm": "round-robin",
+ # "name": "s1",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.2",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # },
+ # "startup_delay": 30
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete high-availability virtual-server s1",
+ # "delete high-availability vrrp global-parameters startup-delay"
+ # ],
+
+ # Using purged:
+
+ # Before state:
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+ # vyos@vyos:~$
+
+
+ - name: Purge configuration
+ vyos.vyos.vyos_ha:
+ config:
+ state: purged
+
+ # After state:
+
+ # vyos@vyos:~$ show configuration commands | match "set high-availability"
+ # vyos@vyos:~$
+ #
+ # Module Execution:
+ #
+ # "after": {
+ # "disable": false
+ # },
+ # "before": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # }
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete high-availability"
+ # ],
+
+
+ # using gathered:
+ # --------------
+
+ # Before state:
+ # vyos@vyos:~$
+ # show configuration commands | match "set high-availability"
+ # set high-availability disable
+ # set high-availability virtual-server s1 address '10.10.10.5'
+ # set high-availability virtual-server s1 algorithm 'round-robin'
+ # set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+ # set high-availability virtual-server s2 address '10.10.10.2'
+ # set high-availability virtual-server s2 persistence-timeout '30'
+ # set high-availability virtual-server s2 port '81'
+ # set high-availability virtual-server s2 protocol 'tcp'
+ # set high-availability virtual-server s3 address '10.10.10.3'
+ # set high-availability virtual-server s3 port '88'
+ # set high-availability virtual-server s3 protocol 'udp'
+ # set high-availability vrrp global-parameters garp master-repeat '6'
+ # set high-availability vrrp global-parameters startup-delay '30'
+ # set high-availability vrrp group g1 peer-address '192.168.1.3'
+ # set high-availability vrrp group g1 priority '100'
+ # set high-availability vrrp group g1 vrid '20'
+ # set high-availability vrrp snmp
+ # set high-availability vrrp sync-group sg1 health-check failure-count '5'
+ # vyos@vyos:~$
+
+ - name: gather configs
+ vyos.vyos.vyos_ha:
+ state: gathered
+
+ # Module Execution:
+ # "changed": false,
+ # "gathered": {
+ # "disable": true,
+ # "virtual_servers": [
+ # {
+ # "address": "10.10.10.5",
+ # "algorithm": "round-robin",
+ # "name": "s1",
+ # "real_server": [
+ # {
+ # "address": "10.10.50.2",
+ # "port": 8443
+ # }
+ # ]
+ # },
+ # {
+ # "address": "10.10.10.2",
+ # "name": "s2",
+ # "persistence_timeout": 30,
+ # "port": 81,
+ # "protocol": "tcp"
+ # },
+ # {
+ # "address": "10.10.10.3",
+ # "name": "s3",
+ # "port": 88,
+ # "protocol": "udp"
+ # }
+ # ],
+ # "vrrp": {
+ # "global_parameters": {
+ # "garp": {
+ # "master_repeat": 6
+ # },
+ # "startup_delay": 30
+ # },
+ # "groups": [
+ # {
+ # "disable": false,
+ # "name": "g1",
+ # "no_preempt": false,
+ # "peer_address": "192.168.1.3",
+ # "priority": 100,
+ # "rfc3768_compatibility": false,
+ # "vrid": 20
+ # }
+ # ],
+ # "snmp": "enabled",
+ # "sync_groups": [
+ # {
+ # "health_check": {
+ # "failure_count": 5
+ # },
+ # "name": "sg1"
+ # }
+ # ]
+ # }
+ # },
+ #
+
+ # Using parsed:
+ # ------------
+
+ # parsed.cfg
+ # set high-availability vrrp group g1 interface eth2
+ # set high-availability vrrp group g1 address 1.1.1.1
+ # set high-availability vrrp group g1 disable
+ # set high-availability vrrp group g1 no-preempt
+ # set high-availability vrrp group g1 advertise-interval 10
+ # set high-availability vrrp group g1 peer-address 2.2.2.2
+ # set high-availability vrrp group g1 rfc3768-compatibility
+ # set high-availability vrrp group g1 vrid 20
+
+ - name: parse configs
+ vyos.vyos.vyos_ha:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+
+ # Module execution:
+ # "parsed": {
+ # "disable": false,
+ # "vrrp": {
+ # "groups": [
+ # {
+ # "address": "1.1.1.1",
+ # "advertise_interval": 10,
+ # "disable": true,
+ # "interface": "eth2",
+ # "name": "g1",
+ # "no_preempt": true,
+ # "peer_address": "2.2.2.2",
+ # "rfc3768_compatibility": true,
+ # "vrid": 20
+ # }
+ # ]
+ # }
+ # }
+ #
+
+ # Using rendered:
+ # --------------
+
+ - name: Render
+ vyos.vyos.vyos_ha:
+ config:
+ disable: true
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 32
+ version: 3
+ garp:
+ interval: 30
+ master_delay: 11
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 5
+ state: rendered
+
+ # Module Execution:
+ # "rendered": [
+ # "set high-availability disable",
+ # "set high-availability vrrp global-parameters garp interval 30",
+ # "set high-availability vrrp global-parameters garp master-delay 11",
+ # "set high-availability vrrp global-parameters garp master-refresh 100",
+ # "set high-availability vrrp global-parameters garp master-refresh-repeat 200",
+ # "set high-availability vrrp global-parameters garp master-repeat 5",
+ # "set high-availability vrrp global-parameters startup-delay 32",
+ # "set high-availability vrrp global-parameters version 3",
+ # "set high-availability vrrp snmp"
+ # ]
+
+
+
+Return Values
+-------------
+Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
+
+.. raw:: html
+
+ <table border=0 cellpadding=0 class="documentation-table">
+ <tr>
+ <th colspan="1">Key</th>
+ <th>Returned</th>
+ <th width="100%">Description</th>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>after</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>when changed</td>
+ <td>
+ <div>The resulting configuration after module execution.</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>before</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">dictionary</span>
+ </div>
+ </td>
+ <td>when <em>state</em> is <code>merged</code>, <code>replaced</code>, <code>overridden</code>, <code>deleted</code> or <code>purged</code></td>
+ <td>
+ <div>The configuration prior to the module execution.</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>commands</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ </div>
+ </td>
+ <td>when <em>state</em> is <code>merged</code>, <code>replaced</code>, <code>overridden</code>, <code>deleted</code> or <code>purged</code></td>
+ <td>
+ <div>The set of commands pushed to the remote device.</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&quot;set high-availability vrrp group g1 address &#x27;1.1.1.1&#x27;&quot;, &quot;set high-availability vrrp group g1 advertise-interval &#x27;10&#x27;&quot;, &quot;set high-availability vrrp group g1 description &#x27;Group 1&#x27;&quot;]</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>gathered</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ </div>
+ </td>
+ <td>when <em>state</em> is <code>gathered</code></td>
+ <td>
+ <div>Facts about the network resource gathered from the remote device as structured data.</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>parsed</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ </div>
+ </td>
+ <td>when <em>state</em> is <code>parsed</code></td>
+ <td>
+ <div>The device native config provided in <em>running_config</em> option parsed into structured data as per module argspec.</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="1">
+ <div class="ansibleOptionAnchor" id="return-"></div>
+ <b>rendered</b>
+ <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
+ <div style="font-size: small">
+ <span style="color: purple">list</span>
+ </div>
+ </td>
+ <td>when <em>state</em> is <code>rendered</code></td>
+ <td>
+ <div>The provided configuration in the task rendered in device-native format (offline).</div>
+ <br/>
+ <div style="font-size: smaller"><b>Sample:</b></div>
+ <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&quot;set high-availability vrrp global-parameters garp master-delay &#x27;10&#x27;&quot;, &quot;set high-availability vrrp global-parameters garp master-refresh &#x27;100&#x27;&quot;, &quot;set high-availability vrrp global-parameters garp master-refresh-repeat &#x27;200&#x27;&quot;]</div>
+ </td>
+ </tr>
+ </table>
+ <br/><br/>
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Evgeny Molotkov (@omnom62)
diff --git a/meta/runtime.yml b/meta/runtime.yml
index fe819fdf..9bee831f 100644
--- a/meta/runtime.yml
+++ b/meta/runtime.yml
@@ -1,70 +1,72 @@
---
requires_ansible: ">=2.15.0"
plugin_routing:
modules:
banner:
redirect: vyos.vyos.vyos_banner
bgp_global:
redirect: vyos.vyos.vyos_bgp_global
bgp_address_family:
redirect: vyos.vyos.vyos_bgp_address_family
command:
redirect: vyos.vyos.vyos_command
config:
redirect: vyos.vyos.vyos_config
facts:
redirect: vyos.vyos.vyos_facts
file:
redirect: vyos.vyos.vyos_file
firewall_global:
redirect: vyos.vyos.vyos_firewall_global
firewall_interfaces:
redirect: vyos.vyos.vyos_firewall_interfaces
firewall_rules:
redirect: vyos.vyos.vyos_firewall_rules
hostname:
redirect: vyos.vyos.vyos_hostname
interfaces:
redirect: vyos.vyos.vyos_interfaces
l3_interfaces:
redirect: vyos.vyos.vyos_l3_interfaces
lag_interfaces:
redirect: vyos.vyos.vyos_lag_interfaces
lldp_global:
redirect: vyos.vyos.vyos_lldp_global
lldp_interfaces:
redirect: vyos.vyos.vyos_lldp_interfaces
logging:
tombstone:
removal_version: 6.0.0
warning_text: use vyos_logging_global instead
vyos_logging:
tombstone:
removal_version: 6.0.0
warning_text: use vyos_logging_global instead
logging_global:
redirect: vyos.vyos.vyos_logging_global
ntp_global:
redirect: vyos.vyos.vyos_ntp_global
ospfv2:
redirect: vyos.vyos.vyos_ospfv2
ospfv3:
redirect: vyos.vyos.vyos_ospfv3
ospf_interfaces:
redirect: vyos.vyos.vyos_ospf_interfaces
ping:
redirect: vyos.vyos.vyos_ping
prefix_lists:
redirect: vyos.vyos.vyos_prefix_lists
snmp_server:
redirect: vyos.vyos.vyos_snmp_server
static_routes:
redirect: vyos.vyos.vyos_static_routes
system:
redirect: vyos.vyos.vyos_system
user:
redirect: vyos.vyos.vyos_user
vlan:
redirect: vyos.vyos.vyos_vlan
vrf:
redirect: vyos.vyos.vyos_vrf
+ ha:
+ redirect: vyos.vyos.vyos_ha
diff --git a/plugins/action/ha.py b/plugins/action/ha.py
new file mode 120000
index 00000000..331a791f
--- /dev/null
+++ b/plugins/action/ha.py
@@ -0,0 +1 @@
+vyos.py
\ No newline at end of file
diff --git a/plugins/module_utils/network/vyos/argspec/ha/__init__.py b/plugins/module_utils/network/vyos/argspec/ha/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/argspec/ha/ha.py b/plugins/module_utils/network/vyos/argspec/ha/ha.py
new file mode 100644
index 00000000..4fe431cd
--- /dev/null
+++ b/plugins/module_utils/network/vyos/argspec/ha/ha.py
@@ -0,0 +1,196 @@
+# -*- 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_ha module
+"""
+
+
+class HaArgs(object): # pylint: disable=R0903
+ """The arg spec for the vyos_ha module"""
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "required": False,
+ "options": {
+ "disable": {"type": "bool", "default": False},
+ "virtual_servers": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "address": {"type": "str"},
+ "algorithm": {"type": "str"},
+ "delay_loop": {"type": "int"},
+ "forward_method": {"type": "str", "choices": ["direct", "nat"]},
+ "fwmark": {"type": "int"},
+ "persistence_timeout": {"type": "int"},
+ "port": {"type": "int"},
+ "protocol": {"type": "str", "choices": ["tcp", "udp"]},
+ "real_server": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str", "required": True},
+ "port": {"type": "int"},
+ "connection_timeout": {"type": "int"},
+ "health_check_script": {"type": "str"},
+ },
+ },
+ },
+ },
+ "vrrp": {
+ "type": "dict",
+ "options": {
+ "global_parameters": {
+ "type": "dict",
+ "options": {
+ "garp": {
+ "type": "dict",
+ "options": {
+ "interval": {"type": "int"},
+ "master_delay": {"type": "int"},
+ "master_refresh": {"type": "int"},
+ "master_refresh_repeat": {"type": "int"},
+ "master_repeat": {"type": "int"},
+ },
+ },
+ "startup_delay": {"type": "int"},
+ "version": {"type": "str"},
+ },
+ },
+ "groups": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "address": {"type": "list", "elements": "str"},
+ "advertise_interval": {"type": "int"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "password": {"type": "str", "no_log": True},
+ "type": {"type": "str"},
+ },
+ },
+ "description": {"type": "str"},
+ "disable": {"type": "bool", "default": False},
+ "excluded_address": {"type": "list", "elements": "str"},
+ "garp": {
+ "type": "dict",
+ "options": {
+ "interval": {"type": "int"},
+ "master_delay": {"type": "int"},
+ "master_refresh": {"type": "int"},
+ "master_refresh_repeat": {"type": "int"},
+ "master_repeat": {"type": "int"},
+ },
+ },
+ "health_check": {
+ "type": "dict",
+ "options": {
+ "failure_count": {"type": "int"},
+ "interval": {"type": "int"},
+ "ping": {"type": "str"},
+ "script": {"type": "str"},
+ },
+ },
+ "hello_source_address": {"type": "str"},
+ "interface": {"type": "str"},
+ "no_preempt": {"type": "bool", "default": False},
+ "peer_address": {"type": "str"},
+ "preempt_delay": {"type": "int"},
+ "priority": {"type": "int"},
+ "rfc3768_compatibility": {"type": "bool", "default": False},
+ "track": {
+ "type": "dict",
+ "options": {
+ "exclude_vrrp_interface": {"type": "bool"},
+ "interface": {"type": "list", "elements": "str"},
+ },
+ },
+ "transition_script": {
+ "type": "dict",
+ "options": {
+ "backup": {"type": "str"},
+ "fault": {"type": "str"},
+ "master": {"type": "str"},
+ "stop": {"type": "str"},
+ },
+ },
+ "vrid": {"type": "int", "required": False},
+ },
+ },
+ "snmp": {
+ "type": "str",
+ "choices": ["disabled", "enabled"],
+ },
+ "sync_groups": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "health_check": {
+ "type": "dict",
+ "options": {
+ "failure_count": {"type": "int"},
+ "interval": {"type": "int"},
+ "ping": {"type": "str"},
+ "script": {"type": "str"},
+ },
+ },
+ "member": {"type": "list", "elements": "str"},
+ "transition_script": {
+ "type": "dict",
+ "options": {
+ "backup": {"type": "str"},
+ "fault": {"type": "str"},
+ "master": {"type": "str"},
+ "stop": {"type": "str"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "state": {
+ "type": "str",
+ "choices": [
+ "deleted",
+ "merged",
+ "purged",
+ "replaced",
+ "gathered",
+ "rendered",
+ "parsed",
+ "overridden",
+ ],
+ "default": "merged",
+ },
+ "running_config": {"type": "str"},
+ } # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/config/ha/__init__.py b/plugins/module_utils/network/vyos/config/ha/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/config/ha/ha.py b/plugins/module_utils/network/vyos/config/ha/ha.py
new file mode 100644
index 00000000..7fc96a35
--- /dev/null
+++ b/plugins/module_utils/network/vyos/config/ha/ha.py
@@ -0,0 +1,705 @@
+#
+# -*- 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_ha 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.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+)
+
+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.ha import (
+ HaTemplate,
+)
+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
+
+
+class Ha(ResourceModule):
+ """
+ The vyos_ha config class
+ """
+
+ def __init__(self, module):
+ super(Ha, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ha",
+ tmplt=HaTemplate(),
+ )
+ self.parsers = [
+ "disable",
+ ]
+
+ self._validate_template()
+
+ def _validate_template(self):
+ version = get_os_version(self._module)
+ if LooseVersion(version) >= LooseVersion("1.4"):
+ self._tmplt = HaTemplate()
+ else:
+ self._module.fail_json(msg="High Availability is not supported in this version of VyOS")
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+
+ if self.state not in ["parsed", "gathered", "purged"]:
+ self.generate_commands()
+ self.run_commands()
+
+ if self.state == "purged":
+ wantd = {"disable": False}
+ haved = deepcopy(self.have)
+ if wantd != haved:
+ self.commands = ["delete high-availability"]
+ self.run_commands()
+ if "before" in self.result:
+ self._normalize_lists(self.result["before"])
+ if "after" in self.result:
+ self._normalize_lists(self.result["after"])
+ if "parsed" in self.result:
+ self._normalize_lists(self.result["parsed"])
+ return self.result
+
+ def generate_commands(self):
+ """Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ wantd = deepcopy(self.want)
+ haved = deepcopy(self.have)
+ for entry in wantd, haved:
+ self._list_to_named_dict(entry)
+ self._normalize_lists(entry)
+
+ if self.state in ["deleted"]:
+ wantd, haved, p = self._prune_stubs(self._module.params.get("config", {}), haved)
+
+ if self.state in ["overridden"]:
+ wo = deepcopy(wantd)
+ self._diff_w_h(wo, haved)
+
+ haved_disable = haved.get("disable")
+
+ for k1, v1 in wo.items():
+
+ if not isinstance(v1, dict):
+ continue
+
+ for name, obj in v1.items():
+ if isinstance(obj, dict) and not obj:
+ wi, hi, pi = self._prune_stubs({k1: {name: {}}}, haved)
+ haved = hi
+
+ for k2, v2 in v1.items():
+ if not isinstance(v2, dict):
+ continue
+
+ for name, obj in v2.items():
+ if isinstance(obj, dict) and not obj:
+ wi, hi, pi = self._prune_stubs({k1: {k2: {name: {}}}}, haved)
+ haved = hi
+
+ if haved_disable is not None:
+ haved["disable"] = haved_disable
+
+ keys = set(wantd) | set(haved)
+
+ for k in keys:
+
+ want = wantd.get(k, {})
+ have = haved.get(k, {})
+
+ if k == "vrrp":
+ if self.state in ["merged"]:
+ want = combine(have, want, recursive=True, list_merge="append_rp")
+ self._compare_vrrp(want, have)
+
+ if k == "virtual_servers":
+ if self.state in ["merged"]:
+ want = combine(have, want, recursive=True)
+ self._compare_vsrvs(want, have)
+
+ if self.state in ["deleted"] and k == "disable":
+ want = have
+ if self.state in ["overridden"] and k == "disable" and not want:
+ want = False
+ if self.state in ["rendered"]:
+ have = None
+
+ self.compare(
+ parsers=self.parsers,
+ want={k: want},
+ have={k: have},
+ )
+
+ self.commands = list(dict.fromkeys(self.commands))
+
+ def _compare_vsrvs(self, want, have):
+ """Compare virtual servers.
+
+ Pre-index both want and have by (name, attribute) signature so that
+ each lookup is O(1) instead of O(n). Groups that are identical
+ between want and have are skipped entirely via an equality
+ short-circuit before leaf decomposition.
+ """
+ vs_parsers = [
+ "virtual_servers.address",
+ "virtual_servers.algorithm",
+ "virtual_servers.delay_loop",
+ "virtual_servers.forward_method",
+ "virtual_servers.persistence_timeout",
+ "virtual_servers.fwmark",
+ "virtual_servers.port",
+ "virtual_servers.protocol",
+ "virtual_servers.real_server.port",
+ "virtual_servers.real_server.health_check_script",
+ "virtual_servers.real_server.connection_timeout",
+ ]
+
+ want_index = (
+ {vs["name"]: vs for vs in want.values() if isinstance(vs, dict) and vs.get("name")}
+ if isinstance(want, dict)
+ else {}
+ )
+ have_index = (
+ {vs["name"]: vs for vs in have.values() if isinstance(vs, dict) and vs.get("name")}
+ if isinstance(have, dict)
+ else {}
+ )
+
+ all_names = set(want_index) | set(have_index)
+
+ for name in all_names:
+ w = want_index.get(name, {})
+ h = have_index.get(name, {})
+
+ if w == h and self.state not in ["rendered"]:
+ continue
+
+ wlist = self._extract_named_leafs(w) if w else []
+ hlist = self._extract_named_leafs(h) if h else []
+
+ if self.state == "rendered":
+ hlist = []
+
+ def _vsrv_sig(item):
+ if not isinstance(item, dict):
+ return None
+ iname = item.get("name")
+ if not iname:
+ return None
+ if "real_server" in item:
+ rs = item["real_server"]
+ if not isinstance(rs, dict) or "address" not in rs:
+ return None
+ addr = rs["address"]
+ for k in rs:
+ if k != "address":
+ return ("real_server", iname, addr, k)
+ return ("real_server", iname, addr, None)
+ for k in item:
+ if k != "name":
+ return ("attr", iname, k)
+ return None
+
+ have_leaf_index = {}
+ for hdict in hlist:
+ sig = _vsrv_sig(hdict)
+ if sig is not None:
+ have_leaf_index[sig] = hdict
+
+ want_leaf_index = {}
+ for wdict in wlist:
+ sig = _vsrv_sig(wdict)
+ if sig is not None:
+ want_leaf_index[sig] = wdict
+
+ if self.state in ["replaced", "deleted"]:
+ for sig, hdict in have_leaf_index.items():
+ wdict = want_leaf_index.get(sig, {})
+ if self.state == "deleted" and wdict:
+ wdict = {}
+ elif not wdict:
+ hdict = {}
+ self.compare(
+ parsers=vs_parsers,
+ want={"virtual_servers": wdict},
+ have={"virtual_servers": hdict},
+ )
+
+ if self.state in ["merged", "replaced", "rendered", "overridden"]:
+ for sig, wdict in want_leaf_index.items():
+ hdict = have_leaf_index.get(sig, {})
+ self.compare(
+ parsers=vs_parsers,
+ want={"virtual_servers": wdict},
+ have={"virtual_servers": hdict},
+ )
+
+ def _compare_vrrp(self, want, have):
+ """Compare VRRP groups and sync-groups.
+
+ Pre-index groups by name so matching is O(1). Groups that are
+ identical between want and have are skipped via equality
+ short-circuit before any leaf decomposition occurs — this is the
+ dominant performance win for large idempotent runs.
+ """
+ vrrp_parsers = [
+ "vrrp.snmp",
+ "vrrp.global_parameters",
+ "vrrp.global_parameters.garp",
+ "vrrp.groups",
+ "vrrp.groups.disable",
+ "vrrp.groups.no_preempt",
+ "vrrp.groups.rfc3768_compatibility",
+ "vrrp.groups.address",
+ "vrrp.groups.excluded_address",
+ "vrrp.groups.garp",
+ "vrrp.groups.authentication",
+ "vrrp.groups.transition_script",
+ "vrrp.groups.health_check",
+ "vrrp.groups.track.interface",
+ "vrrp.groups.track.exclude_vrrp_interface",
+ "vrrp.sync_groups.member",
+ "vrrp.sync_groups.transition_script",
+ "vrrp.sync_groups.health_check",
+ ]
+
+ if (
+ have.get("snmp") == "enabled"
+ and want.get("snmp") != "enabled"
+ and self.state not in ["deleted", "overridden"]
+ and (self.state != "merged" or "snmp" in want)
+ ):
+ self.commands.append("delete high-availability vrrp snmp")
+
+ non_named = {k: v for k, v in (want or {}).items() if k not in ("groups", "sync_groups")}
+ non_named_have = {
+ k: v for k, v in (have or {}).items() if k not in ("groups", "sync_groups")
+ }
+
+ hlist_non = self._extract_leaf_items(non_named_have)
+ wlist_non = self._extract_leaf_items(non_named)
+
+ if self.state == "rendered":
+ hlist_non = []
+
+ have_non_index = {}
+ for hdict in hlist_non:
+ sig = self._vrrp_leaf_sig(hdict)
+ have_non_index[sig] = hdict
+
+ want_non_index = {}
+ for wdict in wlist_non:
+ sig = self._vrrp_leaf_sig(wdict)
+ want_non_index[sig] = wdict
+
+ if self.state in ["replaced", "deleted"]:
+ for sig, hdict in have_non_index.items():
+ wdict = want_non_index.get(sig, {})
+ if self.state == "deleted" and wdict:
+ wdict = {}
+ if self.state == "replaced" and wdict and wdict != hdict:
+ wdict = {}
+ elif not wdict:
+ hdict = {}
+ self.compare(parsers=vrrp_parsers, want={"vrrp": wdict}, have={"vrrp": hdict})
+
+ if self.state in ["merged", "replaced", "rendered", "overridden"]:
+ for sig, wdict in want_non_index.items():
+ hdict = have_non_index.get(sig, {})
+ self.compare(parsers=vrrp_parsers, want={"vrrp": wdict}, have={"vrrp": hdict})
+
+ for section in ("groups", "sync_groups"):
+ want_objs = (want or {}).get(section, {})
+ have_objs = (have or {}).get(section, {})
+
+ if not isinstance(want_objs, dict):
+ want_objs = {}
+ if not isinstance(have_objs, dict):
+ have_objs = {}
+
+ all_names = set(want_objs) | set(have_objs)
+
+ for name in all_names:
+ w = want_objs.get(name, {})
+ h = have_objs.get(name, {})
+
+ if w == h and self.state not in ["rendered"]:
+ continue
+
+ wlist = self._extract_leaf_items({section: {name: w}}) if w else []
+ hlist = self._extract_leaf_items({section: {name: h}}) if h else []
+
+ if self.state == "rendered":
+ hlist = []
+
+ have_leaf_index = {}
+ for hdict in hlist:
+ sig = self._vrrp_leaf_sig(hdict)
+ have_leaf_index[sig] = hdict
+
+ want_leaf_index = {}
+ for wdict in wlist:
+ sig = self._vrrp_leaf_sig(wdict)
+ want_leaf_index[sig] = wdict
+
+ if self.state in ["replaced", "deleted"]:
+ for sig, hdict in have_leaf_index.items():
+ wdict = want_leaf_index.get(sig, {})
+ if self.state == "deleted" and wdict:
+ wdict = {}
+ if self.state == "replaced" and wdict and wdict != hdict:
+ wdict = {}
+ elif not wdict:
+ hdict = {}
+ self.compare(
+ parsers=vrrp_parsers,
+ want={"vrrp": wdict},
+ have={"vrrp": hdict},
+ )
+
+ if self.state in ["merged", "replaced", "rendered", "overridden"]:
+ for sig, wdict in want_leaf_index.items():
+ hdict = have_leaf_index.get(sig, {})
+ self.compare(
+ parsers=vrrp_parsers,
+ want={"vrrp": wdict},
+ have={"vrrp": hdict},
+ )
+
+ def _vrrp_leaf_sig(self, item):
+ """Build a hashable signature for a VRRP leaf dict for O(1) indexing."""
+ if not isinstance(item, dict) or not item:
+ return ()
+
+ container = next(iter(item))
+ inner = item[container]
+
+ sig = [container]
+
+ if isinstance(inner, dict) and "name" in inner:
+ sig.append(("name", inner["name"]))
+
+ if isinstance(inner, dict):
+ for k, v in inner.items():
+ if k == "name":
+ continue
+ if not isinstance(v, dict):
+ sig.append(k)
+ break
+ sig.append(k)
+ for leaf in v:
+ sig.append(leaf)
+ break
+ break
+
+ return tuple(sig)
+
+ def _list_to_named_dict(self, data):
+ """Convert all named-object lists to name-keyed dicts in-place.
+
+ Replaces the three separate _vrrp_groups_list_to_dict,
+ _vrrp_sync_groups_list_to_dict, and _virtual_servers_list_to_dict
+ methods with a single helper. Also normalises real_server lists
+ inside virtual servers.
+ """
+ # VRRP groups and sync_groups
+ vrrp = data.get("vrrp", {})
+ for key in ("groups", "sync_groups"):
+ items = vrrp.get(key)
+ if isinstance(items, list):
+ vrrp[key] = {
+ item["name"]: item
+ for item in items
+ if isinstance(item, dict) and item.get("name")
+ }
+
+ # Virtual servers
+ vss = data.get("virtual_servers")
+ if isinstance(vss, list):
+ new_vss = {}
+ for vs in vss:
+ if not isinstance(vs, dict):
+ continue
+ name = vs.get("name")
+ if not name:
+ continue
+ rs = vs.get("real_server")
+ if isinstance(rs, list):
+ vs["real_server"] = {
+ item["address"]: item
+ for item in rs
+ if isinstance(item, dict) and item.get("address")
+ }
+ new_vss[name] = vs
+ data["virtual_servers"] = new_vss
+ elif isinstance(vss, dict):
+ for vs in vss.values():
+ if not isinstance(vs, dict):
+ continue
+ rs = vs.get("real_server")
+ if isinstance(rs, list):
+ vs["real_server"] = {
+ item["address"]: item
+ for item in rs
+ if isinstance(item, dict) and item.get("address")
+ }
+
+ return data
+
+ def _extract_leaf_items(self, data, path=None, parent_name=None):
+ path = path or []
+ results = []
+
+ if isinstance(data, dict):
+ current_name = data.get("name", parent_name)
+
+ for k, v in data.items():
+ if k == "name" or (k == "snmp" and v == "disabled"):
+ continue
+ results.extend(self._extract_leaf_items(v, path + [k], current_name))
+ return results
+
+ leaf_key = path[-1]
+ top_key = path[0]
+
+ if top_key in ["groups", "sync_groups"]:
+ subkeys = path[2:]
+ else:
+ subkeys = path[1:]
+
+ nested = {leaf_key: data}
+
+ for p in reversed(subkeys[:-1]):
+ nested = {p: nested}
+ if parent_name:
+ out = {top_key: {"name": parent_name}}
+ out[top_key].update(nested)
+ else:
+ out = {top_key: nested}
+
+ results.append(out)
+ return results
+
+ def _normalize_lists(self, node):
+ """
+ Recursively normalize all lists inside a dict or list.
+ All lists are sorted to ensure consistent ordering for comparison.
+ """
+ if isinstance(node, dict):
+ for k, v in node.items():
+ if isinstance(v, list):
+ if all(not isinstance(i, (dict, list)) for i in v):
+ node[k] = sorted(v)
+ else:
+ for item in v:
+ self._normalize_lists(item)
+ elif isinstance(v, dict):
+ self._normalize_lists(v)
+ elif isinstance(node, list):
+ for item in node:
+ self._normalize_lists(item)
+
+ def _extract_named_leafs(self, data, parent_name=None, prefix_key=None):
+ results = []
+
+ if prefix_key == "real_server" and isinstance(data, dict):
+ for d, server_data in data.items():
+ if not isinstance(server_data, dict):
+ continue
+
+ address = server_data.get("address")
+ if not address:
+ continue
+
+ for k, v in server_data.items():
+ if k == "address":
+ continue
+
+ results.append(
+ {
+ "name": parent_name,
+ "real_server": {
+ "address": address,
+ k: v,
+ },
+ },
+ )
+ return results
+
+ if isinstance(data, dict):
+ current_name = data.get("name", parent_name)
+
+ for k, v in data.items():
+ if k == "name":
+ continue
+
+ results.extend(
+ self._extract_named_leafs(v, current_name, k),
+ )
+
+ return results
+
+ return [
+ {
+ "name": parent_name,
+ prefix_key: data,
+ },
+ ]
+
+ def _prune_stubs(self, w, h, path=""):
+ wc = {}
+ hc = self._remove_defaults(h)
+
+ if not self._remove_defaults(w) and remove_empties(hc):
+ self.commands = ["delete high-availability"]
+ return {}, {}, path
+
+ for k, wg in (self._remove_defaults(w) or {}).items():
+ next_path = f"{path} {k}".strip()
+ stub = self._cli_path(next_path)
+ hg = remove_empties(hc).get(k)
+
+ if hg is None:
+ continue
+
+ if not isinstance(wg, (dict, list)):
+ self.commands.append(f"delete high-availability {stub}")
+ hc.pop(k, None)
+ wc.pop(k, None)
+ continue
+
+ if not wg:
+ self.commands.append(f"delete high-availability {stub}")
+ hc.pop(k, None)
+ wc.pop(k, None)
+ continue
+
+ if isinstance(wg, list) and isinstance(hg, dict):
+ for item in wg:
+ name = item.get("name")
+ if not name:
+ continue
+
+ if name in hg:
+ self.commands.append(
+ f"delete high-availability {stub} {name}",
+ )
+
+ hg.pop(name, None)
+
+ if hg:
+ hc[k] = hg
+ else:
+ hc.pop(k, None)
+
+ if self._remove_defaults(wg):
+ wc[k] = wg
+ else:
+ wc.pop(k, None)
+
+ continue
+
+ if isinstance(wg, dict) and isinstance(hg, dict):
+ wi, hi, p = self._prune_stubs(wg, hg, next_path)
+
+ if wi:
+ wc[k] = wi
+
+ if hi:
+ hc[k] = hi
+ else:
+ hc.pop(k, None)
+
+ return wc, hc, path
+
+ def _remove_defaults(self, data):
+ """Strip None and False from config dicts, but preserve "disabled".
+
+ False is the argspec default for boolean flags (disable, no_preempt,
+ rfc3768_compatibility) and carries no config intent — stripping it
+ prevents spurious `delete` commands for fields already at their
+ default state.
+
+ "disabled" is an explicit user choice for snmp and must be preserved
+ so that _prune_stubs can act on it. The original code stripped it,
+ which made `snmp: disabled` invisible to the deleted-state logic.
+ """
+ if isinstance(data, dict):
+ cleaned = {}
+ for k, v in data.items():
+ if v is None or v is False:
+ continue
+ v = self._remove_defaults(v)
+ cleaned[k] = v
+ return cleaned
+ return data
+
+ def _cli_path(self, path):
+ token_map = {
+ "groups": "group",
+ "sync_groups": "sync-group",
+ "virtual_servers": "virtual-server",
+ }
+
+ parts = []
+ for p in path.split():
+ p = token_map.get(p, p)
+ parts.append(p.replace("_", "-"))
+
+ return " ".join(parts)
+
+ def _diff_w_h(self, w, h):
+
+ NAMED_OBJECT_KEYS = {
+ "groups",
+ "sync_groups",
+ "virtual_servers",
+ "global_parameters",
+ }
+
+ if not isinstance(w, dict) or not isinstance(h, dict):
+ return w
+
+ for key in w.keys() & h.keys():
+ wv = w[key]
+ hv = h[key]
+
+ if key in NAMED_OBJECT_KEYS and isinstance(wv, dict) and isinstance(hv, dict):
+ for name in wv.keys() & hv.keys():
+ if wv[name] != hv[name] and isinstance(wv[name], (dict, list)):
+ wv[name] = {}
+ elif wv[name] != hv[name]:
+ wv[name] = None
+ continue
+ self._diff_w_h(wv, hv)
+ return w
diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py
index 24c444dd..7f7bad8a 100644
--- a/plugins/module_utils/network/vyos/facts/facts.py
+++ b/plugins/module_utils/network/vyos/facts/facts.py
@@ -1,133 +1,137 @@
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The facts class for vyos
this file validates each subset of facts and selectively
calls the appropriate facts gathering function
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import (
FactsBase,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_address_family.bgp_address_family import (
Bgp_address_familyFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_global.bgp_global import (
Bgp_globalFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_global.firewall_global import (
Firewall_globalFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_interfaces.firewall_interfaces import (
Firewall_interfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firewall_rules.firewall_rules import (
Firewall_rulesFacts,
)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ha.ha import (
+ HaFacts,
+)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.hostname.hostname import (
HostnameFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.interfaces.interfaces import (
InterfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import (
L3_interfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lag_interfaces.lag_interfaces import (
Lag_interfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (
Config,
Default,
Neighbors,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lldp_global.lldp_global import (
Lldp_globalFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.lldp_interfaces.lldp_interfaces import (
Lldp_interfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.logging_global.logging_global import (
Logging_globalFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ntp_global.ntp_global import (
Ntp_globalFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospf_interfaces.ospf_interfaces import (
Ospf_interfacesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv2.ospfv2 import (
Ospfv2Facts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3 import (
Ospfv3Facts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.prefix_lists.prefix_lists import (
Prefix_listsFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps import (
Route_mapsFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.snmp_server.snmp_server import (
Snmp_serverFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.static_routes.static_routes import (
Static_routesFacts,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.vrf.vrf import VrfFacts
FACT_LEGACY_SUBSETS = dict(default=Default, neighbors=Neighbors, config=Config)
FACT_RESOURCE_SUBSETS = dict(
interfaces=InterfacesFacts,
l3_interfaces=L3_interfacesFacts,
lag_interfaces=Lag_interfacesFacts,
lldp_global=Lldp_globalFacts,
lldp_interfaces=Lldp_interfacesFacts,
static_routes=Static_routesFacts,
firewall_rules=Firewall_rulesFacts,
firewall_global=Firewall_globalFacts,
firewall_interfaces=Firewall_interfacesFacts,
+ ha=HaFacts,
ospfv3=Ospfv3Facts,
ospfv2=Ospfv2Facts,
ospf_interfaces=Ospf_interfacesFacts,
bgp_global=Bgp_globalFacts,
bgp_address_family=Bgp_address_familyFacts,
route_maps=Route_mapsFacts,
prefix_lists=Prefix_listsFacts,
logging_global=Logging_globalFacts,
ntp_global=Ntp_globalFacts,
snmp_server=Snmp_serverFacts,
hostname=HostnameFacts,
vrf=VrfFacts,
)
class Facts(FactsBase):
"""The fact class for vyos"""
VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys())
VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys())
def __init__(self, module):
super(Facts, self).__init__(module)
def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None):
"""Collect the facts for vyos
:param legacy_facts_type: List of legacy facts types
:param resource_facts_type: List of resource fact types
:param data: previously collected conf
:rtype: dict
:return: the facts gathered
"""
if self.VALID_RESOURCE_SUBSETS:
self.get_network_resources_facts(FACT_RESOURCE_SUBSETS, resource_facts_type, data)
if self.VALID_LEGACY_GATHER_SUBSETS:
self.get_network_legacy_facts(FACT_LEGACY_SUBSETS, legacy_facts_type)
return self.ansible_facts, self._warnings
diff --git a/plugins/module_utils/network/vyos/facts/ha/__init__.py b/plugins/module_utils/network/vyos/facts/ha/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/facts/ha/ha.py b/plugins/module_utils/network/vyos/facts/ha/ha.py
new file mode 100644
index 00000000..fc559783
--- /dev/null
+++ b/plugins/module_utils/network/vyos/facts/ha/ha.py
@@ -0,0 +1,174 @@
+# -*- 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_ha 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.ha.ha import (
+ HaArgs,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.ha import (
+ HaTemplate,
+)
+
+
+class HaFacts(object):
+ """The vyos_ha facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = HaArgs.argument_spec
+
+ def get_config(self, connection):
+ return connection.get('show configuration commands | match "set high-availability"')
+
+ def get_config_set(self, data, connection):
+ """Classify config lines into per-object buckets for isolated parsing.
+
+ Each bucket is parsed by a single HaTemplate instance so that facts
+ from different objects (groups, sync-groups, virtual-servers) never
+ bleed into each other.
+
+ Keys are namespaced to avoid collisions between a VRRP group and a
+ sync-group that share the same name (e.g. both named "g1").
+ An elif chain ensures each line lands in exactly one bucket.
+ """
+ config_dict = {}
+ for config_line in data.splitlines():
+ vrrp_disable = re.search(r"set high-availability disable", config_line)
+ vrrp_snmp = re.search(r"set high-availability vrrp snmp", config_line)
+ vrrp_gp = re.search(
+ r"set high-availability vrrp global-parameters (\S+).*",
+ config_line,
+ )
+ vrrp_grp = re.search(r"set high-availability vrrp group (\S+).*", config_line)
+ vrrp_sg = re.search(r"set high-availability vrrp sync-group (\S+).*", config_line)
+ vrrp_vsrv = re.search(r"set high-availability virtual-server (\S+).*", config_line)
+
+ if vrrp_disable:
+ config_dict.setdefault("disable", []).append(config_line)
+ elif vrrp_snmp:
+ config_dict.setdefault("vrrp", []).append(config_line)
+ elif vrrp_gp:
+ config_dict.setdefault("global_parameters", []).append(config_line)
+ elif vrrp_grp:
+ key = "vrrp_group_{0}".format(vrrp_grp.group(1))
+ config_dict.setdefault(key, []).append(config_line)
+ elif vrrp_sg:
+ key = "vrrp_sg_{0}".format(vrrp_sg.group(1))
+ config_dict.setdefault(key, []).append(config_line)
+ elif vrrp_vsrv:
+ config_dict.setdefault(vrrp_vsrv.group(1), []).append(config_line)
+
+ return list(config_dict.values())
+
+ def deep_merge(self, dest, src):
+ for key, value in src.items():
+ if key in dest and isinstance(dest[key], dict) and isinstance(value, dict):
+ self.deep_merge(dest[key], value)
+ else:
+ dest[key] = value
+ return dest
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for vrrp network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = {}
+
+ if not data:
+ data = self.get_config(connection)
+ resources = self.get_config_set(data, connection)
+ vrrp_facts = {"disable": False, "virtual_servers": {}, "vrrp": {}}
+ for resource in resources:
+ vrrp_parser = HaTemplate(
+ lines=resource,
+ module=self._module,
+ )
+ objs = vrrp_parser.parse()
+ if "disable" in objs:
+ vrrp_facts["disable"] = objs["disable"]
+
+ for section in ("virtual_servers", "vrrp"):
+ if section in objs:
+ for name, data in objs[section].items():
+ if not isinstance(data, dict):
+ vrrp_facts[section][name] = data
+ continue
+ existing = vrrp_facts[section].get(name, {})
+ vrrp_facts[section][name] = self.deep_merge(existing, data)
+
+ ansible_facts["ansible_network_resources"].pop("ha", None)
+
+ vrrp_facts = self.normalize_config(vrrp_facts)
+
+ validate_parser = HaTemplate(lines=[], module=self._module)
+ params = utils.remove_empties(
+ validate_parser.validate_config(
+ self.argument_spec,
+ {"config": vrrp_facts},
+ redact=True,
+ ),
+ )
+
+ facts["ha"] = params.get("config", {})
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def normalize_config(self, config):
+ if not config:
+ return config
+
+ if isinstance(config.get("virtual_servers"), dict):
+ config["virtual_servers"] = list(config["virtual_servers"].values())
+
+ vrrp = config.get("vrrp", {})
+
+ if isinstance(vrrp.get("groups"), dict):
+ vrrp["groups"] = list(vrrp["groups"].values())
+
+ if isinstance(vrrp.get("sync_groups"), dict):
+ vrrp["sync_groups"] = list(vrrp["sync_groups"].values())
+
+ # Normalize real_server inside each virtual_server
+ for vs in config.get("virtual_servers", []):
+ if isinstance(vs.get("real_server"), dict):
+ vs["real_server"] = list(vs["real_server"].values())
+
+ for group in vrrp.get("groups", []):
+ if isinstance(group.get("address"), list):
+ group["address"] = sorted(group["address"])
+
+ if isinstance(group.get("excluded_address"), list):
+ group["excluded_address"] = sorted(group["excluded_address"])
+
+ if isinstance(group.get("track", {}).get("interface"), list):
+ group["track"]["interface"] = sorted(group["track"]["interface"])
+
+ for sg in vrrp.get("sync_groups", []):
+ if isinstance(sg.get("member"), list):
+ sg["member"] = sorted(sg["member"])
+
+ return config
diff --git a/plugins/module_utils/network/vyos/rm_templates/ha.py b/plugins/module_utils/network/vyos/rm_templates/ha.py
new file mode 100644
index 00000000..300b14a7
--- /dev/null
+++ b/plugins/module_utils/network/vyos/rm_templates/ha.py
@@ -0,0 +1,1011 @@
+# -*- 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 Ha 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,
+)
+
+
+def _tmplt_vsrvs(config_data):
+ config_data = config_data["virtual_servers"]
+ command = []
+
+ cmd = "high-availability virtual-server {name}".format(**config_data)
+ for key, value in config_data.items():
+ if key == "name" or isinstance(value, dict) or value is None:
+ continue
+ else:
+ command.append(f"{cmd} {key.replace('_', '-')} {value}")
+
+ return command
+
+
+def _tmplt_vsrvs_rsrv(config_data):
+ config_data = config_data["virtual_servers"]
+ command = []
+ cmd = "high-availability virtual-server {name}".format(**config_data)
+ config_data = config_data["real_server"]
+ address = config_data["address"]
+ for key, value in config_data.items():
+ if key == "address" or value is None:
+ continue
+ if value is not None and key == "health_check_script":
+ command.append(cmd + " real-server " + address + " health-check script " + value)
+ else:
+ command.append(cmd + " real-server " + f"{address} {key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_sgroup_hc(config_data):
+ config_data = config_data["vrrp"]["sync_groups"]
+ command = []
+ cmd = "high-availability vrrp sync-group {name}".format(**config_data)
+ config_data = config_data["health_check"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " health-check " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_sgroup_ts(config_data):
+ config_data = config_data["vrrp"]["sync_groups"]
+ command = []
+ cmd = "high-availability vrrp sync-group {name}".format(**config_data)
+ config_data = config_data["transition_script"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " transition-script " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_gp(config_data):
+ config_data = config_data["vrrp"]["global_parameters"]
+ command = []
+
+ cmd = "high-availability vrrp global-parameters".format(**config_data)
+ for key, value in config_data.items():
+ if isinstance(value, dict) or value is None:
+ continue
+ else:
+ command.append(f"{cmd} {key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_gp_garp(config_data):
+ config_data = config_data["vrrp"]["global_parameters"]["garp"]
+ command = []
+ cmd = "high-availability vrrp global-parameters garp"
+
+ for key, value in config_data.items():
+ if value is None:
+ continue
+ command.append(f"{cmd} {key.replace('_', '-')} {value}")
+
+ return command
+
+
+def _tmplt_vrrp_group(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+
+ for key, value in config_data.items():
+ if (
+ key == "name"
+ or isinstance(value, dict)
+ or isinstance(value, list)
+ or isinstance(value, bool)
+ or value is None
+ ):
+ continue
+ else:
+ if key == "description":
+ value = f"'{value}'"
+ command.append(f"{cmd} {key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_group_bool(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+
+ for key, value in config_data.items():
+ if key != "name" and value is not None:
+ command.append(f"{cmd} {key.replace('_', '-')}")
+ return command
+
+
+def _tmplt_vrrp_group_garp(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["garp"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " garp " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_group_auth(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["authentication"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " authentication " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_group_ts(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["transition_script"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " transition-script " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_sgroup_member(config_data):
+ sgroup = config_data["vrrp"]["sync_groups"]
+ command = []
+ cmd = "high-availability vrrp sync-group {name}".format(**sgroup)
+ members = sgroup.get("member", [])
+ for member in members:
+ if member is None:
+ continue
+ command.append(f"{cmd} member {member}")
+ return command
+
+
+def _tmplt_vrrp_group_exaddress(config_data):
+ group = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**group)
+ exaddresses = group.get("excluded_address", [])
+ for exaddress in exaddresses:
+ if exaddress is None:
+ continue
+ command.append(f"{cmd} excluded-address {exaddress}")
+ return command
+
+
+def _tmplt_vrrp_group_address(config_data):
+ group = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**group)
+ addresses = group.get("address", [])
+ for address in addresses:
+ if address is None:
+ continue
+ command.append(f"{cmd} address {address}")
+ return command
+
+
+def _tmplt_vrrp_group_hc(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["health_check"]
+ for key, value in config_data.items():
+ if value is not None:
+ command.append(cmd + " health-check " + f"{key.replace('_', '-')} {value}")
+ return command
+
+
+def _tmplt_vrrp_group_track_list(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["track"]
+ for key, value in config_data.items():
+ if isinstance(value, list) and value is not None and key != "name":
+ for item in value:
+ command.append(cmd + " track " + f"{key.replace('_', '-')} {item}")
+ return command
+
+
+def _tmplt_vrrp_group_track_bool(config_data):
+ config_data = config_data["vrrp"]["groups"]
+ command = []
+ cmd = "high-availability vrrp group {name}".format(**config_data)
+ config_data = config_data["track"]
+ for key, value in config_data.items():
+ if key != "name" and value is not None:
+ command.append(cmd + " track " + f"{key.replace('_', '-')}")
+ return command
+
+
+class HaTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ prefix = {"set": "set", "remove": "delete"}
+ super(HaTemplate, self).__init__(
+ lines=lines,
+ tmplt=self,
+ prefix=prefix,
+ module=module,
+ )
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "disable",
+ "getval": re.compile(
+ r"""
+ ^set
+ \shigh-availability
+ \s(?P<disable>disable)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "high-availability disable",
+ "result": {
+ "disable": "{{ True if disable is defined else False }}",
+ },
+ },
+ {
+ "name": "virtual_servers.address",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+address\s+(?P<address>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "address": "{{ address if address is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.algorithm",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+algorithm\s+(?P<algorithm>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "algorithm": "{{ algorithm if algorithm is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.delay_loop",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+delay-loop\s+(?P<delay_loop>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "delay_loop": "{{ delay_loop if delay_loop is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.forward_method",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+forward-method\s+(?P<forward_method>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "forward_method": "{{ forward_method if forward_method is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.fwmark",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+fwmark\s+(?P<fwmark>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "fwmark": "{{ fwmark if fwmark is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.persistence_timeout",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+persistence-timeout\s+(?P<persistence_timeout>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "persistence_timeout": "{{ persistence_timeout if persistence_timeout is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.port",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+port\s+(?P<port>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "port": "{{ port if port is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.protocol",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ (?:\s+protocol\s+(?P<protocol>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "protocol": "{{ protocol if protocol is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.real_server.port",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ \sreal-server
+ \s+(?P<address>\S+)
+ (?:\s+port\s+(?P<port>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs_rsrv,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "real_server": {
+ "{{ address }}": {
+ "address": "{{ address }}",
+ "port": "{{ port if port is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.real_server.health_check_script",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ \sreal-server
+ \s+(?P<address>\S+)
+ (?:\s+health-check\sscript\s+(?P<hcscript>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs_rsrv,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "real_server": {
+ "{{ address }}": {
+ "address": "{{ address }}",
+ "health_check_script": "{{ hcscript if hcscript is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "virtual_servers.real_server.connection_timeout",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svirtual-server
+ \s+(?P<name>\S+)
+ \sreal-server
+ \s+(?P<address>\S+)
+ (?:\s+connection-timeout\s+(?P<cont>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vsrvs_rsrv,
+ "result": {
+ "virtual_servers": {
+ "{{ name }}": {
+ "name": "{{ name }}",
+ "real_server": {
+ "{{ address }}": {
+ "address": "{{ address }}",
+ "connection_timeout": "{{ cont if cont is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.sync_groups.member",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\ssync-group
+ \s+(?P<sgname>\S+)
+ \smember
+ \s+(?P<member>\S+)
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_sgroup_member,
+ "result": {
+ "vrrp": {
+ "sync_groups": {
+ "{{ sgname }}": {
+ "name": "{{ sgname }}",
+ "member": [
+ "{{ member }}",
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.sync_groups.health_check",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\ssync-group
+ \s+(?P<sgname>\S+)
+ \shealth-check
+ (?:\s+failure-count\s+(?P<failure_count>\S+))?
+ (?:\s+interval\s+(?P<int>\S+))?
+ (?:\s+ping\s+(?P<ping>\S+))?
+ (?:\s+script\s+(?P<script>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_sgroup_hc,
+ "result": {
+ "vrrp": {
+ "sync_groups": {
+ "{{ sgname }}": {
+ "name": "{{ sgname }}",
+ "health_check": {
+ "failure_count": "{{ failure_count if failure_count is defined else None }}",
+ "interval": "{{ int if int is defined else None }}",
+ "ping": "{{ ping if ping is defined else None }}",
+ "script": "{{ script if script is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.sync_groups.transition_script",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\ssync-group
+ \s+(?P<sgname>\S+)
+ \stransition-script
+ (?:\s+backup\s+(?P<backup>\S+))?
+ (?:\s+fault\s+(?P<fault>\S+))?
+ (?:\s+master\s+(?P<master>\S+))?
+ (?:\s+stop\s+(?P<stop>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_sgroup_ts,
+ "result": {
+ "vrrp": {
+ "sync_groups": {
+ "{{ sgname }}": {
+ "name": "{{ sgname }}",
+ "transition_script": {
+ "backup": "{{ backup if backup is defined else None }}",
+ "fault": "{{ fault if fault is defined else None }}",
+ "master": "{{ master if master is defined else None }}",
+ "stop": "{{ stop if stop is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.global_parameters.garp",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sglobal-parameters
+ \s+garp
+ (?:\s+interval\s+(?P<interval>\S+))?
+ (?:\s+master-delay\s+(?P<master_delay>\S+))?
+ (?:\s+master-refresh\s+(?P<master_refresh>\S+))?
+ (?:\s+master-refresh-repeat\s+(?P<master_refresh_repeat>\S+))?
+ (?:\s+master-repeat\s+(?P<master_repeat>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_gp_garp,
+ "result": {
+ "vrrp": {
+ "global_parameters": {
+ "garp": {
+ "interval": "{{ interval if interval is defined else None }}",
+ "master_delay": "{{ master_delay if master_delay is defined else None }}",
+ "master_refresh": "{{ master_refresh if master_refresh is defined else None }}",
+ "master_refresh_repeat": "{{ master_refresh_repeat if master_refresh_repeat is defined else None }}",
+ "master_repeat": "{{ master_repeat if master_repeat is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.global_parameters",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sglobal-parameters
+ (?=\s+(?:startup-delay|version)\s)
+ (?:\s+startup-delay\s+(?P<startup_delay>\S+))?
+ (?:\s+version\s+(?P<version>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_gp,
+ "result": {
+ "vrrp": {
+ "global_parameters": {
+ "startup_delay": "{{ startup_delay if startup_delay is defined else None }}",
+ "version": "{{ version if version is defined else None }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ (?:\s+description\s+(?P<description>'.+?'|\S+))?
+ (?:\s+advertise-interval\s+(?P<advertise_interval>\S+))?
+ (?:\s+hello-source-address\s+(?P<hello_source>\S+))?
+ (?:\s+interface\s+(?P<interface>\S+))?
+ (?:\s+peer-address\s+(?P<peer_address>\S+))?
+ (?:\s+preempt-delay\s+(?P<preempt_delay>\S+))?
+ (?:\s+priority\s+(?P<priority>\S+))?
+ (?:\s+vrid\s+(?P<vrid>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "description": "{{ description | replace(\"'\", \"\") if description is defined else None }}",
+ "advertise_interval": "{{ advertise_interval if advertise_interval is defined else None }}",
+ "hello_source_address": "{{ hello_source if hello_source is defined else None }}",
+ "interface": "{{ interface if interface is defined else None }}",
+ "peer_address": "{{ peer_address if peer_address is defined else None }}",
+ "preempt_delay": "{{ preempt_delay if preempt_delay is defined else None }}",
+ "priority": "{{ priority if priority is defined else None }}",
+ "vrid": "{{ vrid if vrid is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.excluded_address",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \sexcluded-address
+ \s+(?P<excluded_address>.*)
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_exaddress,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "excluded_address": [
+ "{{ excluded_address | replace(\"'\", \"\") }}",
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.address",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \saddress
+ \s+(?P<address>.*)
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_address,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "address": [
+ "{{ address | replace(\"'\", \"\") }}",
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.garp",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \s+garp
+ (?:\s+interval\s+(?P<interval>\S+))?
+ (?:\s+master-delay\s+(?P<master_delay>\S+))?
+ (?:\s+master-refresh\s+(?P<master_refresh>\S+))?
+ (?:\s+master-refresh-repeat\s+(?P<master_refresh_repeat>\S+))?
+ (?:\s+master-repeat\s+(?P<master_repeat>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_garp,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "garp": {
+ "interval": "{{ interval if interval is defined else None }}",
+ "master_delay": "{{ master_delay if master_delay is defined else None }}",
+ "master_refresh": "{{ master_refresh if master_refresh is defined else None }}",
+ "master_refresh_repeat": "{{ master_refresh_repeat if master_refresh_repeat is defined else None }}",
+ "master_repeat": "{{ master_repeat if master_repeat is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.authentication",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \s+authentication
+ (?:\s+password\s+(?P<password>\S+))?
+ (?:\s+type\s+(?P<type>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_auth,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "authentication": {
+ "password": "{{ password if password is defined else None }}",
+ "type": "{{ type if type is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.transition_script",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \stransition-script
+ (?:\s+backup\s+(?P<backup>\S+))?
+ (?:\s+fault\s+(?P<fault>\S+))?
+ (?:\s+master\s+(?P<master>\S+))?
+ (?:\s+stop\s+(?P<stop>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_ts,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "transition_script": {
+ "backup": "{{ backup if backup is defined else None }}",
+ "fault": "{{ fault if fault is defined else None }}",
+ "master": "{{ master if master is defined else None }}",
+ "stop": "{{ stop if stop is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.health_check",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \shealth-check
+ (?:\s+failure-count\s+(?P<failure_count>\S+))?
+ (?:\s+interval\s+(?P<int>\S+))?
+ (?:\s+ping\s+(?P<ping>\S+))?
+ (?:\s+script\s+(?P<script>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_hc,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "health_check": {
+ "failure_count": "{{ failure_count if failure_count is defined else None }}",
+ "interval": "{{ int if int is defined else None }}",
+ "ping": "{{ ping if ping is defined else None }}",
+ "script": "{{ script if script is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.track.interface",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \strack
+ (?:\s+interface\s+(?P<interface>\S+))?
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_track_list,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "track": {
+ "interface": "{{ [interface.strip(\"'\")] if interface is defined else [] }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.snmp",
+ "getval": re.compile(
+ r"""
+ ^set
+ \shigh-availability
+ \svrrp
+ \s(?P<snmp>snmp)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "high-availability vrrp snmp",
+ "result": {
+ "vrrp": {
+ "snmp": "{{ 'enabled' if snmp is defined else 'disabled' }}",
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.disable",
+ "getval": re.compile(
+ r"""
+ ^set
+ \shigh-availability\svrrp\sgroup
+ \s(?P<gname>\S+)
+ \s(?P<disable>disable)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_bool,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "disable": "{{ True if disable is defined else False }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.no_preempt",
+ "getval": re.compile(
+ r"""
+ ^set
+ \shigh-availability\svrrp\sgroup
+ \s(?P<gname>\S+)
+ \s(?P<no_preempt>no-preempt)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_bool,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "no_preempt": "{{ True if no_preempt is defined else False }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.rfc3768_compatibility",
+ "getval": re.compile(
+ r"""
+ ^set
+ \shigh-availability\svrrp\sgroup
+ \s(?P<gname>\S+)
+ \s(?P<rfc3768_compatibility>rfc3768-compatibility)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_bool,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "rfc3768_compatibility": "{{ True if rfc3768_compatibility is defined else False }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "vrrp.groups.track.exclude_vrrp_interface",
+ "getval": re.compile(
+ r"""
+ ^set\shigh-availability\svrrp\sgroup
+ \s+(?P<gname>\S+)
+ \strack
+ \s(?P<exclude_vrrp_inter>exclude-vrrp-interface)
+ $
+ """,
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_vrrp_group_track_bool,
+ "result": {
+ "vrrp": {
+ "groups": {
+ "{{ gname }}": {
+ "name": "{{ gname }}",
+ "track": {
+ "exclude_vrrp_interface": "{{ True if exclude_vrrp_inter is defined else False }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ ]
+ # fmt: on
diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py
index 78445c02..df0a72ca 100644
--- a/plugins/module_utils/network/vyos/utils/utils.py
+++ b/plugins/module_utils/network/vyos/utils/utils.py
@@ -1,309 +1,347 @@
# -*- 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
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 want_dict.items():
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 functi 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)
+ """Merge dict ``b`` into dict ``a``, returning a new dict.
+
+ :param a: Base dictionary.
+ :param b: Dictionary whose values take precedence over ``a``.
+ :param recursive: When True, nested dicts are merged recursively rather
+ than replaced wholesale.
+ :param list_merge: Controls how list values are combined when the same key
+ exists in both dicts. Supported modes:
+
+ - ``"replace"`` *(default)* — ``b``'s list replaces ``a``'s list.
+ - ``"append"`` — ``b``'s list is appended to ``a``'s list (duplicates
+ kept).
+ - ``"prepend"`` — ``b``'s list is prepended to ``a``'s list
+ (duplicates kept).
+ - ``"append_rp"`` — like ``"append"`` but duplicates are removed,
+ preserving the first occurrence (rp = remove-preserve).
+ - ``"prepend_rp"`` — like ``"prepend"`` but duplicates are removed,
+ preserving the first occurrence.
+
+ Passing any other value raises ``ValueError``.
+ :returns: New merged dict.
+ :raises ValueError: If either argument is not a dict, or if an
+ unsupported ``list_merge`` mode is given.
"""
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)
+ if k in result:
+ # dict merge
+ if recursive and isinstance(result[k], dict) and isinstance(v, dict):
+ result[k] = combine(result[k], v, recursive=True, list_merge=list_merge)
+
+ # list merge
+ elif isinstance(result[k], list) and isinstance(v, list):
+ if list_merge == "replace":
+ result[k] = v
+ elif list_merge == "append":
+ result[k] = result[k] + v
+ elif list_merge == "prepend":
+ result[k] = v + result[k]
+ elif list_merge == "append_rp":
+ result[k] = list(dict.fromkeys(result[k] + v))
+ elif list_merge == "prepend_rp":
+ result[k] = list(dict.fromkeys(v + result[k]))
+ else:
+ raise ValueError(f"Unsupported list_merge mode: {list_merge}")
+
+ # everything else
+ else:
+ result[k] = v
else:
result[k] = v
return result
diff --git a/plugins/modules/vyos_ha.py b/plugins/modules/vyos_ha.py
new file mode 100644
index 00000000..ddd02b48
--- /dev/null
+++ b/plugins/modules/vyos_ha.py
@@ -0,0 +1,1327 @@
+#!/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_ha module, which manages VRRP and load balancer configuration on VyOS
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+---
+module: vyos_ha
+author: Evgeny Molotkov (@omnom62)
+short_description: Manage VRRP and load balancer configuration on VyOS
+version_added: "1.0.0"
+description:
+ - This module configures VRRP groups, global VRRP parameters, VRRP sync groups,
+ and LVS-style virtual servers on VyOS 1.4+.
+ - Supports creation, modification, deletion, replacement, rendering, and parsing
+ of VRRP-related configuration.
+
+options:
+ config:
+ description:
+ - Full VRRP and virtual server configuration.
+ type: dict
+ suboptions:
+ disable:
+ description:
+ - Disable all VRRP and L4-LB configuration under this module.
+ type: bool
+ default: false
+ virtual_servers:
+ description:
+ - List of load balancer virtual server (LVS) definitions.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Unique identifier for the virtual server.
+ type: str
+ required: true
+ address:
+ description:
+ - Virtual IP address for the server.
+ type: str
+ algorithm:
+ description:
+ - Load balancing algorithm used for dispatching connections.
+ type: str
+ delay_loop:
+ description:
+ - Delay loop interval in seconds.
+ type: int
+ forward_method:
+ description:
+ - Forwarding method used by LVS.
+ type: str
+ choices: [direct, nat]
+ fwmark:
+ description:
+ - Firewall mark for LVS traffic classification.
+ type: int
+ persistence_timeout:
+ description:
+ - Client persistence timeout in seconds.
+ type: int
+ port:
+ description:
+ - TCP/UDP port provided by the virtual service.
+ type: int
+ protocol:
+ description:
+ - Transport protocol for the virtual server.
+ type: str
+ choices: [tcp, udp]
+
+ real_server:
+ description:
+ - Backend real servers behind the virtual service.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description:
+ - Real server IP address.
+ type: str
+ required: true
+ port:
+ description:
+ - Backend server port.
+ type: int
+ connection_timeout:
+ description:
+ - Backend server connection timeout.
+ type: int
+ health_check_script:
+ description:
+ - Path to health check script used for backend validation.
+ type: str
+
+ vrrp:
+ description:
+ - VRRP configuration including groups, global parameters, SNMP settings,
+ and sync-groups.
+ type: dict
+ suboptions:
+
+ global_parameters:
+ description:
+ - Global VRRP tuning parameters.
+ type: dict
+ suboptions:
+ garp:
+ description:
+ - Gratuitous ARP related configuration.
+ type: dict
+ suboptions:
+ interval:
+ description:
+ - GARP interval in seconds.
+ type: int
+ master_delay:
+ description:
+ - Delay before sending GARP as master.
+ type: int
+ master_refresh:
+ description:
+ - Refresh interval for master GARP announcements.
+ type: int
+ master_refresh_repeat:
+ description:
+ - Number of times to repeat refresh announcements.
+ type: int
+ master_repeat:
+ description:
+ - Number of GARP repeats when transitioning to master.
+ type: int
+
+ startup_delay:
+ description:
+ - Delay before VRRP starts after boot.
+ type: int
+
+ version:
+ description:
+ - VRRP protocol version.
+ type: str
+
+ groups:
+ description:
+ - VRRP instance configuration groups.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - VRRP group name.
+ type: str
+ required: true
+ address:
+ description:
+ - Virtual router IP addresses.
+ type: list
+ elements: str
+
+ advertise_interval:
+ description:
+ - VRRP advertisement interval.
+ type: int
+
+ authentication:
+ description:
+ - VRRP group authentication options.
+ type: dict
+ suboptions:
+ password:
+ description:
+ - Authentication password.
+ type: str
+ type:
+ description:
+ - Authentication type.
+ type: str
+
+ description:
+ description:
+ - Text description for the VRRP group.
+ type: str
+
+ disable:
+ description:
+ - Disable this VRRP group.
+ type: bool
+ default: false
+
+ excluded_address:
+ description:
+ - IP address excluded from source checks.
+ type: list
+ elements: str
+
+ garp:
+ description:
+ - GARP-specific settings for this group.
+ type: dict
+ suboptions:
+ interval:
+ description: GARP interval.
+ type: int
+ master_delay:
+ description: GARP master delay.
+ type: int
+ master_refresh:
+ description: GARP master refresh interval.
+ type: int
+ master_refresh_repeat:
+ description: Repeated refresh sends.
+ type: int
+ master_repeat:
+ description: GARP repeat count.
+ type: int
+
+ health_check:
+ description:
+ - VRRP group health check options.
+ type: dict
+ suboptions:
+ failure_count:
+ description: Allowed number of failed checks.
+ type: int
+ interval:
+ description: Health check interval.
+ type: int
+ ping:
+ description: Host to ping for checks.
+ type: str
+ script:
+ description: Script to execute for health checking.
+ type: str
+
+ hello_source_address:
+ description:
+ - Source address for VRRP hello packets.
+ type: str
+
+ interface:
+ description:
+ - Interface used by the VRRP group.
+ type: str
+
+ no_preempt:
+ description:
+ - Disable preemption.
+ type: bool
+ default: false
+
+ peer_address:
+ description:
+ - Peer VRRP router address.
+ type: str
+
+ preempt_delay:
+ description:
+ - Delay before taking master role.
+ type: int
+
+ priority:
+ description:
+ - VRRP priority (higher = preferred master).
+ type: int
+
+ rfc3768_compatibility:
+ description:
+ - Enable or disable RFC3768 compatibility mode.
+ type: bool
+ default: false
+
+ track:
+ description:
+ - Track interface and VRRP behaviour.
+ type: dict
+ suboptions:
+ exclude_vrrp_interface:
+ description:
+ - Exclude VRRP interface from tracking.
+ type: bool
+ interface:
+ description:
+ - Interface to track.
+ type: list
+ elements: str
+
+ transition_script:
+ description:
+ - Scripts executed during VRRP state transitions.
+ type: dict
+ suboptions:
+ backup:
+ description: Path to backup script.
+ type: str
+ fault:
+ description: Path to fault script.
+ type: str
+ master:
+ description: Path to master script.
+ type: str
+ stop:
+ description: Path to stop script.
+ type: str
+
+ vrid:
+ description:
+ - VRRP Virtual Router ID.
+ type: int
+
+ snmp:
+ description:
+ - Enable SNMP support for VRRP.
+ type: str
+ choices: ['enabled', 'disabled']
+
+ sync_groups:
+ description:
+ - VRRP sync-groups for coordinated failover.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Sync-group name.
+ type: str
+ required: true
+
+ health_check:
+ description:
+ - Health check options for sync group.
+ type: dict
+ suboptions:
+ failure_count:
+ description: Allowed number of failures.
+ type: int
+ interval:
+ description: Health check interval.
+ type: int
+ ping:
+ description: Host to ping.
+ type: str
+ script:
+ description: Script to run for health checking.
+ type: str
+
+ member:
+ description:
+ - List of VRRP groups participating in this sync group.
+ type: list
+ elements: str
+
+ transition_script:
+ description:
+ - Transition scripts for sync group events.
+ type: dict
+ suboptions:
+ backup:
+ description: Backup state script.
+ type: str
+ fault:
+ description: Fault state script.
+ type: str
+ master:
+ description: Master state script.
+ type: str
+ stop:
+ description: Stop state script.
+ type: str
+
+ state:
+ description:
+ - Desired end state of the VRRP configuration.
+ type: str
+ choices:
+ - deleted
+ - merged
+ - purged
+ - replaced
+ - gathered
+ - rendered
+ - parsed
+ - overridden
+ default: merged
+
+ running_config:
+ description:
+ - Used only when C(state=parsed). Must contain the output of
+ C(show configuration commands | grep high-availability).
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+# Before state
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# vyos@vyos:~$
+
+- name: Merge provided configuration with device configuration
+ vyos.vyos.vyos_ha:
+ config:
+ disable: true
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.5
+ algorithm: round-robin
+ real_server:
+ - address: 10.10.50.2
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 30
+ port: 81
+ protocol: tcp
+ - name: s3
+ address: 10.10.10.3
+ port: 88
+ protocol: udp
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 30
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.3
+ priority: 100
+ disable: false
+ no_preempt: false
+ vrid: 20
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 5
+ state: merged
+
+# After State
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s1 address '10.10.10.5'
+# set high-availability virtual-server s1 algorithm 'round-robin'
+# set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp global-parameters startup-delay '30'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+# vyos@vyos:~$
+#
+# # Module Execution:
+#
+# "after": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.5",
+# "algorithm": "round-robin",
+# "name": "s1",
+# "real_server": [
+# {
+# "address": "10.10.50.2",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# },
+# "startup_delay": 30
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "before": {
+# "disable": false
+# },
+# "changed": true,
+# "commands": [
+# "set high-availability disable",
+# "set high-availability virtual-server s1 address 10.10.10.5",
+# "set high-availability virtual-server s1 algorithm round-robin",
+# "set high-availability virtual-server s1 real-server 10.10.50.2 port 8443",
+# "set high-availability virtual-server s2 address 10.10.10.2",
+# "set high-availability virtual-server s2 persistence-timeout 30",
+# "set high-availability virtual-server s2 port 81",
+# "set high-availability virtual-server s2 protocol tcp",
+# "set high-availability virtual-server s3 address 10.10.10.3",
+# "set high-availability virtual-server s3 port 88",
+# "set high-availability virtual-server s3 protocol udp",
+# "set high-availability vrrp global-parameters garp master-repeat 6",
+# "set high-availability vrrp global-parameters startup-delay 30",
+# "set high-availability vrrp group g1 peer-address 192.168.1.3",
+# "set high-availability vrrp group g1 priority 100",
+# "set high-availability vrrp group g1 vrid 20",
+# "set high-availability vrrp snmp",
+# "set high-availability vrrp sync-group sg1 health-check failure-count 5"
+# ],
+
+# Using replaced:
+# --------------
+
+# Before state:
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s1 address '10.10.10.5'
+# set high-availability virtual-server s1 algorithm 'round-robin'
+# set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp global-parameters startup-delay '30'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+# vyos@vyos:~$
+
+- name: Replace
+ vyos.vyos.vyos_ha:
+ config:
+ disable: false
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.3
+ algorithm: round-robin
+ port: 8443
+ real_server:
+ - address: 10.10.50.3
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 300
+ port: 81
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.30
+ port: 8443
+ - name: s3
+ address: 10.10.10.3
+ port: 88
+ protocol: udp
+ real_server:
+ - address: 10.10.50.6
+ port: 8443
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 30
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.13
+ priority: 100
+ disable: false
+ no_preempt: true
+ interface: eth1
+ address: 192.168.51.13
+ vrid: 20
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 3
+ state: replaced
+
+# After state:
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability virtual-server s1 address '10.10.10.3'
+# set high-availability virtual-server s1 algorithm 'round-robin'
+# set high-availability virtual-server s1 port '8443'
+# set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+# set high-availability virtual-server s1 real-server 10.10.50.3 port '8443'
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '300'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s2 real-server 10.10.50.3 port '8443'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability virtual-server s3 real-server 10.10.50.6 port '8443'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp global-parameters startup-delay '30'
+# set high-availability vrrp group g1 address 192.168.51.13
+# set high-availability vrrp group g1 interface 'eth1'
+# set high-availability vrrp group g1 no-preempt
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 peer-address '192.168.1.13'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '3'
+# vyos@vyos:~$
+#
+#
+# Module Execution:
+#
+# "after": {
+# "disable": false,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.3",
+# "algorithm": "round-robin",
+# "name": "s1",
+# "port": 8443,
+# "real_server": [
+# {
+# "address": "10.10.50.2",
+# "port": 8443
+# },
+# {
+# "address": "10.10.50.3",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 300,
+# "port": 81,
+# "protocol": "tcp",
+# "real_server": [
+# {
+# "address": "10.10.50.3",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp",
+# "real_server": [
+# {
+# "address": "10.10.50.6",
+# "port": 8443
+# }
+# ]
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# },
+# "startup_delay": 30
+# },
+# "groups": [
+# {
+# "address": "192.168.51.13",
+# "disable": false,
+# "interface": "eth1",
+# "name": "g1",
+# "no_preempt": true,
+# "peer_address": "192.168.1.13",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 3
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "before": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.5",
+# "algorithm": "round-robin",
+# "name": "s1",
+# "real_server": [
+# {
+# "address": "10.10.50.2",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# },
+# "startup_delay": 30
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "delete high-availability disable",
+# "set high-availability virtual-server s1 address 10.10.10.3",
+# "set high-availability virtual-server s1 port 8443",
+# "set high-availability virtual-server s1 real-server 10.10.50.3 port 8443",
+# "set high-availability virtual-server s2 persistence-timeout 300",
+# "set high-availability virtual-server s2 real-server 10.10.50.3 port 8443",
+# "set high-availability virtual-server s3 real-server 10.10.50.6 port 8443",
+# "set high-availability vrrp group g1 address 192.168.51.13",
+# "set high-availability vrrp group g1 interface eth1",
+# "set high-availability vrrp group g1 no-preempt",
+# "set high-availability vrrp group g1 peer-address 192.168.1.13",
+# "set high-availability vrrp sync-group sg1 health-check failure-count 3"
+# ],
+
+# Using deleted:
+# -------------
+
+# Before state:
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s1 address '10.10.10.5'
+# set high-availability virtual-server s1 algorithm 'round-robin'
+# set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp global-parameters startup-delay '30'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+# vyos@vyos:~$
+
+- name: Delete configuration
+ vyos.vyos.vyos_ha:
+ config:
+ disable: false
+ vrrp:
+ snmp: disabled
+ global_parameters:
+ startup_delay: 32
+ version: 3
+ virtual_servers:
+ - name: 's1'
+ address: '10.10.10.1'
+ algorithm: 'round-robin'
+ delay_loop: 60
+ forward_method: 'direct'
+ persistence_timeout: 30
+ port: 443
+ protocol: 'tcp'
+ real_server:
+ - address: '10.10.10.1'
+ connection_timeout: 61
+ port: 443
+ state: deleted
+
+# After state:
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+
+# vyos@vyos:~$
+#
+#
+# Module Execution:
+#
+# "after": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# }
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "before": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.5",
+# "algorithm": "round-robin",
+# "name": "s1",
+# "real_server": [
+# {
+# "address": "10.10.50.2",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# },
+# "startup_delay": 30
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "delete high-availability virtual-server s1",
+# "delete high-availability vrrp global-parameters startup-delay"
+# ],
+
+# Using purged:
+
+# Before state:
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+# vyos@vyos:~$
+
+
+- name: Purge configuration
+ vyos.vyos.vyos_ha:
+ config:
+ state: purged
+
+# After state:
+
+# vyos@vyos:~$ show configuration commands | match "set high-availability"
+# vyos@vyos:~$
+#
+# Module Execution:
+#
+# "after": {
+# "disable": false
+# },
+# "before": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# }
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "delete high-availability"
+# ],
+
+
+# using gathered:
+# --------------
+
+# Before state:
+# vyos@vyos:~$
+# show configuration commands | match "set high-availability"
+# set high-availability disable
+# set high-availability virtual-server s1 address '10.10.10.5'
+# set high-availability virtual-server s1 algorithm 'round-robin'
+# set high-availability virtual-server s1 real-server 10.10.50.2 port '8443'
+# set high-availability virtual-server s2 address '10.10.10.2'
+# set high-availability virtual-server s2 persistence-timeout '30'
+# set high-availability virtual-server s2 port '81'
+# set high-availability virtual-server s2 protocol 'tcp'
+# set high-availability virtual-server s3 address '10.10.10.3'
+# set high-availability virtual-server s3 port '88'
+# set high-availability virtual-server s3 protocol 'udp'
+# set high-availability vrrp global-parameters garp master-repeat '6'
+# set high-availability vrrp global-parameters startup-delay '30'
+# set high-availability vrrp group g1 peer-address '192.168.1.3'
+# set high-availability vrrp group g1 priority '100'
+# set high-availability vrrp group g1 vrid '20'
+# set high-availability vrrp snmp
+# set high-availability vrrp sync-group sg1 health-check failure-count '5'
+# vyos@vyos:~$
+
+- name: gather configs
+ vyos.vyos.vyos_ha:
+ state: gathered
+
+# Module Execution:
+# "changed": false,
+# "gathered": {
+# "disable": true,
+# "virtual_servers": [
+# {
+# "address": "10.10.10.5",
+# "algorithm": "round-robin",
+# "name": "s1",
+# "real_server": [
+# {
+# "address": "10.10.50.2",
+# "port": 8443
+# }
+# ]
+# },
+# {
+# "address": "10.10.10.2",
+# "name": "s2",
+# "persistence_timeout": 30,
+# "port": 81,
+# "protocol": "tcp"
+# },
+# {
+# "address": "10.10.10.3",
+# "name": "s3",
+# "port": 88,
+# "protocol": "udp"
+# }
+# ],
+# "vrrp": {
+# "global_parameters": {
+# "garp": {
+# "master_repeat": 6
+# },
+# "startup_delay": 30
+# },
+# "groups": [
+# {
+# "disable": false,
+# "name": "g1",
+# "no_preempt": false,
+# "peer_address": "192.168.1.3",
+# "priority": 100,
+# "rfc3768_compatibility": false,
+# "vrid": 20
+# }
+# ],
+# "snmp": "enabled",
+# "sync_groups": [
+# {
+# "health_check": {
+# "failure_count": 5
+# },
+# "name": "sg1"
+# }
+# ]
+# }
+# },
+#
+
+# Using parsed:
+# ------------
+
+# parsed.cfg
+# set high-availability vrrp group g1 interface eth2
+# set high-availability vrrp group g1 address 1.1.1.1
+# set high-availability vrrp group g1 disable
+# set high-availability vrrp group g1 no-preempt
+# set high-availability vrrp group g1 advertise-interval 10
+# set high-availability vrrp group g1 peer-address 2.2.2.2
+# set high-availability vrrp group g1 rfc3768-compatibility
+# set high-availability vrrp group g1 vrid 20
+
+- name: parse configs
+ vyos.vyos.vyos_ha:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+
+# Module execution:
+# "parsed": {
+# "disable": false,
+# "vrrp": {
+# "groups": [
+# {
+# "address": "1.1.1.1",
+# "advertise_interval": 10,
+# "disable": true,
+# "interface": "eth2",
+# "name": "g1",
+# "no_preempt": true,
+# "peer_address": "2.2.2.2",
+# "rfc3768_compatibility": true,
+# "vrid": 20
+# }
+# ]
+# }
+# }
+#
+
+# Using rendered:
+# --------------
+
+- name: Render
+ vyos.vyos.vyos_ha:
+ config:
+ disable: true
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 32
+ version: 3
+ garp:
+ interval: 30
+ master_delay: 11
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 5
+ state: rendered
+
+# Module Execution:
+# "rendered": [
+# "set high-availability disable",
+# "set high-availability vrrp global-parameters garp interval 30",
+# "set high-availability vrrp global-parameters garp master-delay 11",
+# "set high-availability vrrp global-parameters garp master-refresh 100",
+# "set high-availability vrrp global-parameters garp master-refresh-repeat 200",
+# "set high-availability vrrp global-parameters garp master-repeat 5",
+# "set high-availability vrrp global-parameters startup-delay 32",
+# "set high-availability vrrp global-parameters version 3",
+# "set high-availability vrrp snmp"
+# ]
+"""
+
+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 high-availability vrrp group g1 address '1.1.1.1'
+ - set high-availability vrrp group g1 advertise-interval '10'
+ - set high-availability vrrp group g1 description 'Group 1'
+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 high-availability vrrp global-parameters garp master-delay '10'
+ - set high-availability vrrp global-parameters garp master-refresh '100'
+ - set high-availability vrrp global-parameters garp master-refresh-repeat '200'
+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.ha.ha import (
+ HaArgs,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ha.ha import (
+ Ha,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=HaArgs.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 = Ha(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/integration/targets/vyos_ha/defaults/main.yaml b/tests/integration/targets/vyos_ha/defaults/main.yaml
new file mode 100644
index 00000000..164afead
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/defaults/main.yaml
@@ -0,0 +1,3 @@
+---
+testcase: "[^_].*"
+test_items: []
diff --git a/tests/integration/targets/vyos_ha/tasks/cli.yaml b/tests/integration/targets/vyos_ha/tasks/cli.yaml
new file mode 100644
index 00000000..daccf720
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tasks/cli.yaml
@@ -0,0 +1,20 @@
+---
+- name: Collect all cli test cases
+ ansible.builtin.find:
+ paths: "{{ role_path }}/tests/cli"
+ patterns: "{{ testcase }}.yaml"
+ use_regex: true
+ register: test_cases
+ delegate_to: localhost
+
+- name: Set test_items
+ ansible.builtin.set_fact:
+ test_items: "{{ test_cases.files | map(attribute='path') | list }}"
+
+- name: Run test case (connection=ansible.netcommon.network_cli)
+ ansible.builtin.include_tasks: "{{ test_case_to_run }}"
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+ with_items: "{{ test_items }}"
+ loop_control:
+ loop_var: test_case_to_run
diff --git a/tests/integration/targets/vyos_ha/tasks/main.yaml b/tests/integration/targets/vyos_ha/tasks/main.yaml
new file mode 100644
index 00000000..e6378581
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tasks/main.yaml
@@ -0,0 +1,5 @@
+---
+- name: Run CLI tests
+ ansible.builtin.include_tasks: cli.yaml
+ tags:
+ - network_cli
diff --git a/tests/integration/targets/vyos_ha/tests/cli/_add_dummy_scripts.yaml b/tests/integration/targets/vyos_ha/tests/cli/_add_dummy_scripts.yaml
new file mode 100644
index 00000000..60a44758
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/_add_dummy_scripts.yaml
@@ -0,0 +1,6 @@
+---
+- name: Create dummy scripts for HA tests
+ vyos.vyos.vyos_command:
+ commands: touch /var/tmp/script.sh && chmod +x /var/tmp/script.sh
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
diff --git a/tests/integration/targets/vyos_ha/tests/cli/_parsed.cfg b/tests/integration/targets/vyos_ha/tests/cli/_parsed.cfg
new file mode 100644
index 00000000..d003d106
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/_parsed.cfg
@@ -0,0 +1,69 @@
+set high-availability virtual-server s1 address 10.10.10.1
+set high-availability virtual-server s1 algorithm round-robin
+set high-availability virtual-server s1 delay-loop 60
+set high-availability virtual-server s1 forward-method direct
+set high-availability virtual-server s1 fwmark 10
+set high-availability virtual-server s1 persistence-timeout 30
+set high-availability virtual-server s1 protocol tcp
+set high-availability virtual-server s1 real-server 10.10.50.1 health-check script /var/tmp/script.sh
+set high-availability virtual-server s1 real-server 10.10.50.1 port 443
+set high-availability virtual-server s2 address 10.10.10.2
+set high-availability virtual-server s2 port 81
+set high-availability virtual-server s2 real-server real1 connection-timeout 5
+set high-availability virtual-server s2 real-server real1 port 8081
+set high-availability virtual-server s2 real-server real2 port 8080
+set high-availability vrrp global-parameters startup-delay 31
+set high-availability vrrp global-parameters version 3
+set high-availability vrrp global-parameters garp interval 30
+set high-availability vrrp global-parameters garp master-delay 10
+set high-availability vrrp global-parameters garp master-refresh 100
+set high-availability vrrp global-parameters garp master-refresh-repeat 200
+set high-availability vrrp global-parameters garp master-repeat 5
+set high-availability vrrp group g1 address 1.1.1.1
+set high-availability vrrp group g1 address 5.5.5.5
+set high-availability vrrp group g1 address 8.8.8.8 interface eth2
+set high-availability vrrp group g1 advertise-interval 10
+set high-availability vrrp group g1 description 'Group_1'
+set high-availability vrrp group g1 disable
+set high-availability vrrp group g1 interface eth2
+set high-availability vrrp group g1 no-preempt
+set high-availability vrrp group g1 peer-address 192.168.1.3
+set high-availability vrrp group g1 preempt-delay 15
+set high-availability vrrp group g1 priority 100
+set high-availability vrrp group g1 rfc3768-compatibility
+set high-availability vrrp group g1 vrid 20
+set high-availability vrrp group g1 authentication password testpass
+set high-availability vrrp group g1 authentication type plaintext-password
+set high-availability vrrp group g1 excluded-address 192.168.1.7 interface eth3
+set high-availability vrrp group g1 excluded-address 192.168.1.8
+set high-availability vrrp group g1 garp interval 20
+set high-availability vrrp group g1 garp master-delay 5
+set high-availability vrrp group g1 garp master-refresh 50
+set high-availability vrrp group g1 garp master-refresh-repeat 100
+set high-availability vrrp group g1 garp master-repeat 3
+set high-availability vrrp group g1 track exclude-vrrp-interface
+set high-availability vrrp group g1 track interface eth0
+set high-availability vrrp group g1 track interface eth1
+set high-availability vrrp group g1 transition-script backup /var/tmp/script.sh
+set high-availability vrrp group g1 transition-script fault /var/tmp/script.sh
+set high-availability vrrp group g1 transition-script master /var/tmp/script.sh
+set high-availability vrrp group g1 transition-script stop /var/tmp/script.sh
+set high-availability vrrp group g2 address 2.2.2.2
+set high-availability vrrp group g2 description 'Group_2'
+set high-availability vrrp group g2 interface eth1
+set high-availability vrrp group g2 vrid 11
+set high-availability vrrp group g2 health-check failure-count 5
+set high-availability vrrp group g2 health-check interval 15
+set high-availability vrrp group g2 health-check ping 192.168.1.100
+set high-availability vrrp group g2 health-check script /var/tmp/script.sh
+set high-availability vrrp group g2 hello-source-address 2.2.2.2
+set high-availability vrrp sync-group sg1 health-check failure-count 3
+set high-availability vrrp sync-group sg1 health-check interval 10
+set high-availability vrrp sync-group sg1 health-check ping 192.168.2.100
+set high-availability vrrp sync-group sg1 health-check script /var/tmp/script.sh
+set high-availability vrrp sync-group sg1 member g1
+set high-availability vrrp sync-group sg1 member g2
+set high-availability vrrp sync-group sg1 transition-script backup /var/tmp/script.sh
+set high-availability vrrp sync-group sg1 transition-script fault /var/tmp/script.sh
+set high-availability vrrp sync-group sg1 transition-script master /var/tmp/script.sh
+set high-availability vrrp sync-group sg1 transition-script stop /var/tmp/script.sh
diff --git a/tests/integration/targets/vyos_ha/tests/cli/_populate_config.yaml b/tests/integration/targets/vyos_ha/tests/cli/_populate_config.yaml
new file mode 100644
index 00000000..95e81752
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/_populate_config.yaml
@@ -0,0 +1,8 @@
+---
+- ansible.builtin.include_tasks: _add_dummy_scripts.yaml
+
+- name: Setup initial HA configuration
+ vyos.vyos.vyos_config:
+ lines: "{{ populate_commands}}"
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
diff --git a/tests/integration/targets/vyos_ha/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_ha/tests/cli/_remove_config.yaml
new file mode 100644
index 00000000..416e5c4d
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/_remove_config.yaml
@@ -0,0 +1,15 @@
+---
+- name: Remove pre-existing HA config
+ vyos.vyos.vyos_ha:
+ config:
+ state: purged
+ ignore_errors: true
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+
+- name: Remove dummy scripts for HA tests
+ vyos.vyos.vyos_command:
+ commands:
+ - rm -f /var/tmp/script.sh
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
diff --git a/tests/integration/targets/vyos_ha/tests/cli/deleted_all.yaml b/tests/integration/targets/vyos_ha/tests/cli/deleted_all.yaml
new file mode 100644
index 00000000..f97e8802
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/deleted_all.yaml
@@ -0,0 +1,44 @@
+---
+- debug:
+ msg: Start vyos_ha purged / deleted_all integration tests ansible_connection={{ ansible_connection }}
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Purge all the HA configuration.
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config:
+ state: deleted
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ - "merged.before == result['before']"
+
+ - name: Assert that the correct set of commands were generated
+ assert:
+ that:
+ - "{{ purged.commands | symmetric_difference(result['commands']) | length == 0 }}"
+
+ - name: Assert that the after dicts were correctly generated
+ assert:
+ that:
+ - "purged.after == result['after']"
+
+ - name: Purge all the HA configuration. (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result.changed == false
+ - result.commands | length == 0
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ - "purged.after == result['before']"
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/deleted_bulk.yaml b/tests/integration/targets/vyos_ha/tests/cli/deleted_bulk.yaml
new file mode 100644
index 00000000..52a6477b
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/deleted_bulk.yaml
@@ -0,0 +1,50 @@
+---
+- debug:
+ msg: Start vyos_ha deleted integration tests ansible_connection={{ ansible_connection }}
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Delete stub objects.
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config:
+ disable: false
+ vrrp:
+ global_parameters:
+ startup_delay: 32
+ garp: {}
+ groups:
+ - name: g1
+ sync_groups: []
+ virtual_servers: []
+ state: deleted
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ # - "{{ merged.before | symmetric_difference(result['before']) | length == 0 }}"
+ - "merged.before == result['before']"
+
+ - name: Assert that the correct set of commands were generated
+ assert:
+ that:
+ - "{{ deleted_bulk['commands'] | symmetric_difference(result['commands']) | length == 0 }}"
+
+ - name: Assert that the after dicts were correctly generated
+ assert:
+ that:
+ - "{{ deleted_bulk['after'] | symmetric_difference(result['after']) | length == 0 }}"
+
+ - name: Delete stub objects (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result.changed == false
+ - result.commands | length == 0
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/deleted_vrrp_groups.yaml b/tests/integration/targets/vyos_ha/tests/cli/deleted_vrrp_groups.yaml
new file mode 100644
index 00000000..b84b6905
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/deleted_vrrp_groups.yaml
@@ -0,0 +1,45 @@
+---
+- debug:
+ msg: Start vyos_ha deleted integration tests ansible_connection={{ ansible_connection }}
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Delete a vrrp group and sync_group based on its name.
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config:
+ vrrp:
+ groups:
+ - name: "g1"
+ sync_groups:
+ - name: "sg1"
+ state: deleted
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ - "merged.before == result['before']"
+
+ - name: Assert that the correct set of commands were generated
+ assert:
+ that:
+ - "{{ deleted_vrrp_groups['commands'] | symmetric_difference(result['commands']) |length == 0 }}"
+
+ - name: Assert that the after dicts were correctly generated
+ assert:
+ that:
+ - "deleted_vrrp_groups['after'] == result['after']"
+
+ - name: Delete attributes of group (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result.changed == false
+ - result.commands|length == 0
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_ha/tests/cli/empty_config.yaml
new file mode 100644
index 00000000..676d2c66
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/empty_config.yaml
@@ -0,0 +1,58 @@
+---
+- debug:
+ msg: START vyos_ha empty_config integration tests on connection={{ ansible_connection }}
+
+- name: Merged with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_ha:
+ config:
+ state: merged
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state merged'
+
+- name: Replaced with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_ha:
+ config:
+ state: replaced
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state replaced'
+
+- name: Overridden with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_ha:
+ config:
+ state: overridden
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state overridden'
+
+- name: Parsed with empty running_config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_ha:
+ running_config:
+ state: parsed
+
+- assert:
+ that:
+ - result.msg == 'value of running_config parameter must not be empty for state parsed'
+
+- name: Rendered with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_ha:
+ config:
+ state: rendered
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state rendered'
diff --git a/tests/integration/targets/vyos_ha/tests/cli/gathered.yaml b/tests/integration/targets/vyos_ha/tests/cli/gathered.yaml
new file mode 100644
index 00000000..da39727a
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/gathered.yaml
@@ -0,0 +1,25 @@
+---
+- debug:
+ msg: START vyos_ha gathered integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Gather config from the device in structured format.
+ register: result
+ vyos.vyos.vyos_ha:
+ state: gathered
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: ha
+
+ - name: Assert that facts are correctly generated
+ assert:
+ that:
+ - result.changed == false
+ - "result.gathered == ansible_facts['network_resources']['ha']"
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/merged.yaml b/tests/integration/targets/vyos_ha/tests/cli/merged.yaml
new file mode 100644
index 00000000..cb870d01
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/merged.yaml
@@ -0,0 +1,42 @@
+---
+- debug:
+ msg: START vyos_ha merged integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Merge the provided configuration with the existing running configuration
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config: "{{ merged.config }}"
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: ha
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands | symmetric_difference(merged.commands) == []
+ - "result.after == ansible_facts['network_resources']['ha']"
+
+ - name: Assert that before dicts were correctly generated
+ assert:
+ that:
+ - "merged.before == result.before"
+
+ - name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+ - result['commands'] == []
+ - "result['before'] == ansible_facts['network_resources']['ha']"
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/overridden.yaml b/tests/integration/targets/vyos_ha/tests/cli/overridden.yaml
new file mode 100644
index 00000000..44a85b76
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/overridden.yaml
@@ -0,0 +1,35 @@
+---
+- debug:
+ msg: START vyos_ha overridden integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Override the existing configuration with the provided running configuration
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config: "{{ overridden.config }}"
+ state: overridden
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: ha
+
+ - name: Verify that the configuration was correctly overridden
+ assert:
+ that:
+ - result.changed == true
+ - result.after == ansible_facts['network_resources']['ha']
+
+ - name: Override the existing configuration with the provided running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/parsed.yaml b/tests/integration/targets/vyos_ha/tests/cli/parsed.yaml
new file mode 100644
index 00000000..c7134d6c
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/parsed.yaml
@@ -0,0 +1,15 @@
+---
+- debug:
+ msg: START vyos_ha parsed integration tests on connection={{ ansible_connection }}
+
+- name: Provide the running configuration for parsing (config to be parsed)
+ register: result
+ vyos.vyos.vyos_ha:
+ running_config: "{{ lookup('file', '_parsed.cfg') }}"
+ state: parsed
+
+- name: Assert that config was correctly parsed
+ assert:
+ that:
+ - result.changed == false
+ - "result.parsed == merged.before"
diff --git a/tests/integration/targets/vyos_ha/tests/cli/purged.yaml b/tests/integration/targets/vyos_ha/tests/cli/purged.yaml
new file mode 100644
index 00000000..ffc00d64
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/purged.yaml
@@ -0,0 +1,44 @@
+---
+- debug:
+ msg: Start vyos_ha purged / deleted_all integration tests ansible_connection={{ ansible_connection }}
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Purge all the HA configuration.
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config:
+ state: purged
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ - "merged.before == result['before']"
+
+ - name: Assert that the correct set of commands were generated
+ assert:
+ that:
+ - "{{ purged.commands | symmetric_difference(result['commands']) |length == 0 }}"
+
+ - name: Assert that the after dicts were correctly generated
+ assert:
+ that:
+ - "purged.after == result['after']"
+
+ - name: Purge all the HA configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result.changed == false
+ - result.commands | length == 0
+
+ - name: Assert that the before dicts were correctly generated
+ assert:
+ that:
+ - "purged.after == result['before']"
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/rendered.yaml b/tests/integration/targets/vyos_ha/tests/cli/rendered.yaml
new file mode 100644
index 00000000..efece2c6
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/rendered.yaml
@@ -0,0 +1,15 @@
+---
+- debug:
+ msg: START vyos_ha rendered integration tests on connection={{ ansible_connection }}
+
+- block:
+ - name: Structure provided configuration into device specific commands
+ register: result
+ vyos.vyos.vyos_ha:
+ config: "{{ rendered.config }}"
+ state: rendered
+
+ - assert:
+ that:
+ - result.changed == false
+ - "result.rendered | sort == rendered.commands | sort"
diff --git a/tests/integration/targets/vyos_ha/tests/cli/replaced.yaml b/tests/integration/targets/vyos_ha/tests/cli/replaced.yaml
new file mode 100644
index 00000000..d35f3345
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/replaced.yaml
@@ -0,0 +1,37 @@
+---
+- debug:
+ msg: START vyos_ha replaced integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate_config.yaml
+
+- block:
+ - name: Replace the provided configuration with the existing running configuration
+ register: result
+ vyos.vyos.vyos_ha: &id001
+ config: "{{ merged.config }}"
+ state: replaced
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: ha
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands | symmetric_difference(replaced.commands) == []
+ - "result.after == ansible_facts['network_resources']['ha']"
+
+ - name: Replace the provided configuration with the existing running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_ha: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+ - result['commands'] == []
+ - "result['before'] == ansible_facts['network_resources']['ha']"
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/tests/cli/rtt.yaml b/tests/integration/targets/vyos_ha/tests/cli/rtt.yaml
new file mode 100644
index 00000000..06e017be
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/tests/cli/rtt.yaml
@@ -0,0 +1,39 @@
+---
+- debug:
+ msg: START vyos_ha rtt integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: RTT Merge the provided configuration with the existing running configuration
+ register: baseconfig
+ vyos.vyos.vyos_ha:
+ config: "{{ merged.config }}"
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: ha
+
+ - assert:
+ that:
+ - baseconfig.changed == true
+ - baseconfig.commands|symmetric_difference(rtt.commands) == []
+ - "baseconfig.after == ansible_facts['network_resources']['ha']"
+
+ - name: RTT Merge the existing configuration with the provided running configuration
+ register: result
+ vyos.vyos.vyos_ha:
+ config: "{{ rtt.config }}"
+
+ - name: RTT Revert back to base config using facts round trip
+ register: revert
+ vyos.vyos.vyos_ha:
+ config: "{{ ansible_facts['network_resources']['ha'] }}"
+ state: overridden
+
+ - name: RTT Assert that config was reverted
+ assert:
+ that: baseconfig.after == revert.after
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ha/vars/main.yaml b/tests/integration/targets/vyos_ha/vars/main.yaml
new file mode 100644
index 00000000..6cf70f2e
--- /dev/null
+++ b/tests/integration/targets/vyos_ha/vars/main.yaml
@@ -0,0 +1,787 @@
+---
+merged:
+ before:
+ disable: false
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.1
+ algorithm: "round-robin"
+ delay_loop: 60
+ forward_method: direct
+ fwmark: 10
+ persistence_timeout: 30
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.1
+ health_check_script: "/var/tmp/script.sh"
+ port: 443
+ - name: s2
+ address: 10.10.10.2
+ port: 81
+ real_server:
+ - address: real1
+ connection_timeout: 5
+ port: 8081
+ - address: real2
+ port: 8080
+ vrrp:
+ global_parameters:
+ startup_delay: 31
+ version: "3"
+ garp:
+ interval: 30
+ master_delay: 10
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 5
+ groups:
+ - name: "g1"
+ description: "Group_1"
+ interface: "eth2"
+ address:
+ - "1.1.1.1"
+ - "5.5.5.5"
+ - "8.8.8.8 interface eth2"
+ advertise_interval: 10
+ peer_address: 192.168.1.3
+ preempt_delay: 15
+ priority: 100
+ disable: true
+ no_preempt: true
+ rfc3768_compatibility: true
+ vrid: 20
+ excluded_address:
+ - "192.168.1.7 interface eth3"
+ - "192.168.1.8"
+ garp:
+ interval: 20
+ master_delay: 5
+ master_refresh: 50
+ master_refresh_repeat: 100
+ master_repeat: 3
+ authentication:
+ type: "plaintext-password"
+ password: "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ track:
+ exclude_vrrp_interface: true
+ interface:
+ - eth0
+ - eth1
+ - name: "g2"
+ description: "Group_2"
+ interface: "eth1"
+ address:
+ - "2.2.2.2"
+ disable: false
+ no_preempt: false
+ rfc3768_compatibility: false
+ vrid: 11
+ health_check:
+ failure_count: 5
+ interval: 15
+ ping: "192.168.1.100"
+ script: "/var/tmp/script.sh"
+ hello_source_address: "2.2.2.2"
+ sync_groups:
+ - name: "sg1"
+ member:
+ - "g1"
+ - "g2"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ health_check:
+ failure_count: 3
+ interval: 10
+ ping: "192.168.2.100"
+ script: "/var/tmp/script.sh"
+ config:
+ disable: true
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.5
+ algorithm: round-robin
+ real_server:
+ - address: 10.10.50.2
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 30
+ port: 81
+ protocol: tcp
+ - name: s3
+ address: 10.10.10.3
+ port: 88
+ protocol: udp
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 30
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.3
+ priority: 100
+ disable: false
+ no_preempt: false
+ vrid: 20
+ - name: "g2"
+ address:
+ - "4.4.4.4"
+ - "6.6.6.6 interface eth3"
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 5
+ commands:
+ - delete high-availability vrrp group g1 disable
+ - delete high-availability vrrp group g1 no-preempt
+ - delete high-availability vrrp group g1 rfc3768-compatibility
+ - set high-availability disable
+ - set high-availability virtual-server s1 address 10.10.10.5
+ - set high-availability virtual-server s1 real-server 10.10.50.2 port 8443
+ - set high-availability virtual-server s2 persistence-timeout 30
+ - set high-availability virtual-server s2 protocol tcp
+ - set high-availability virtual-server s3 address 10.10.10.3
+ - set high-availability virtual-server s3 port 88
+ - set high-availability virtual-server s3 protocol udp
+ - set high-availability vrrp global-parameters garp master-repeat 6
+ - set high-availability vrrp global-parameters startup-delay 30
+ - set high-availability vrrp group g2 address 2.2.2.2
+ - set high-availability vrrp group g2 address 4.4.4.4
+ - set high-availability vrrp group g2 address 6.6.6.6 interface eth3
+ - set high-availability vrrp snmp
+ - set high-availability vrrp sync-group sg1 health-check failure-count 5
+
+populate_commands:
+ - set high-availability virtual-server s1 address 10.10.10.1
+ - set high-availability virtual-server s1 algorithm round-robin
+ - set high-availability virtual-server s1 delay-loop 60
+ - set high-availability virtual-server s1 forward-method direct
+ - set high-availability virtual-server s1 fwmark 10
+ - set high-availability virtual-server s1 persistence-timeout 30
+ - set high-availability virtual-server s1 protocol tcp
+ - set high-availability virtual-server s1 real-server 10.10.50.1 health-check script /var/tmp/script.sh
+ - set high-availability virtual-server s1 real-server 10.10.50.1 port 443
+ - set high-availability virtual-server s2 address 10.10.10.2
+ - set high-availability virtual-server s2 port 81
+ - set high-availability virtual-server s2 real-server real1 connection-timeout 5
+ - set high-availability virtual-server s2 real-server real1 port 8081
+ - set high-availability virtual-server s2 real-server real2 port 8080
+ - set high-availability vrrp global-parameters startup-delay 31
+ - set high-availability vrrp global-parameters version 3
+ - set high-availability vrrp global-parameters garp interval 30
+ - set high-availability vrrp global-parameters garp master-delay 10
+ - set high-availability vrrp global-parameters garp master-refresh 100
+ - set high-availability vrrp global-parameters garp master-refresh-repeat 200
+ - set high-availability vrrp global-parameters garp master-repeat 5
+ - set high-availability vrrp group g1 address 1.1.1.1
+ - set high-availability vrrp group g1 address 5.5.5.5
+ - set high-availability vrrp group g1 address 8.8.8.8 interface eth2
+ - set high-availability vrrp group g1 advertise-interval 10
+ - set high-availability vrrp group g1 description 'Group_1'
+ - set high-availability vrrp group g1 disable
+ - set high-availability vrrp group g1 interface eth2
+ - set high-availability vrrp group g1 no-preempt
+ - set high-availability vrrp group g1 peer-address 192.168.1.3
+ - set high-availability vrrp group g1 preempt-delay 15
+ - set high-availability vrrp group g1 priority 100
+ - set high-availability vrrp group g1 rfc3768-compatibility
+ - set high-availability vrrp group g1 vrid 20
+ - set high-availability vrrp group g1 authentication password testpass
+ - set high-availability vrrp group g1 authentication type plaintext-password
+ - set high-availability vrrp group g1 excluded-address 192.168.1.7 interface eth3
+ - set high-availability vrrp group g1 excluded-address 192.168.1.8
+ - set high-availability vrrp group g1 garp interval 20
+ - set high-availability vrrp group g1 garp master-delay 5
+ - set high-availability vrrp group g1 garp master-refresh 50
+ - set high-availability vrrp group g1 garp master-refresh-repeat 100
+ - set high-availability vrrp group g1 garp master-repeat 3
+ - set high-availability vrrp group g1 track exclude-vrrp-interface
+ - set high-availability vrrp group g1 track interface eth0
+ - set high-availability vrrp group g1 track interface eth1
+ - set high-availability vrrp group g1 transition-script backup /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script fault /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script master /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script stop /var/tmp/script.sh
+ - set high-availability vrrp group g2 address 2.2.2.2
+ - set high-availability vrrp group g2 description 'Group_2'
+ - set high-availability vrrp group g2 interface eth1
+ - set high-availability vrrp group g2 vrid 11
+ - set high-availability vrrp group g2 health-check failure-count 5
+ - set high-availability vrrp group g2 health-check interval 15
+ - set high-availability vrrp group g2 health-check ping 192.168.1.100
+ - set high-availability vrrp group g2 health-check script /var/tmp/script.sh
+ - set high-availability vrrp group g2 hello-source-address 2.2.2.2
+ - set high-availability vrrp sync-group sg1 health-check failure-count 3
+ - set high-availability vrrp sync-group sg1 health-check interval 10
+ - set high-availability vrrp sync-group sg1 health-check ping 192.168.2.100
+ - set high-availability vrrp sync-group sg1 health-check script /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 member g1
+ - set high-availability vrrp sync-group sg1 member g2
+ - set high-availability vrrp sync-group sg1 transition-script backup /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script fault /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script master /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script stop /var/tmp/script.sh
+
+rendered:
+ config:
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.1
+ algorithm: round-robin
+ delay_loop: 60
+ forward_method: direct
+ fwmark: 10
+ persistence_timeout: 30
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.1
+ health_check_script: /var/tmp/script.sh
+ port: 443
+ - name: s2
+ address: 10.10.10.2
+ port: 81
+ real_server:
+ - address: real1
+ connection_timeout: 5
+ port: 8081
+ - address: real2
+ port: 8080
+ vrrp:
+ snmp: enabled
+ global_parameters:
+ startup_delay: 31
+ version: "3"
+ garp:
+ interval: 30
+ master_delay: 10
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 5
+ groups:
+ - name: "g1"
+ description: "Group_1"
+ interface: "eth2"
+ address:
+ - "1.1.1.1"
+ - "2.2.2.2"
+ - "3.3.3.3 interface eth2"
+ advertise_interval: 10
+ peer_address: 192.168.1.3
+ preempt_delay: 15
+ priority: 100
+ disable: true
+ no_preempt: true
+ rfc3768_compatibility: true
+ vrid: 20
+ excluded_address:
+ - "192.168.1.7 interface eth3"
+ garp:
+ interval: 20
+ master_delay: 5
+ master_refresh: 50
+ master_refresh_repeat: 100
+ master_repeat: 3
+ authentication:
+ type: "plaintext-password"
+ password: "test123"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ track:
+ exclude_vrrp_interface: true
+ interface:
+ - eth0
+ - name: "g2"
+ description: "Group_2"
+ interface: "eth1"
+ address: "2.2.2.2"
+ disable: false
+ no_preempt: false
+ rfc3768_compatibility: false
+ vrid: 11
+ health_check:
+ failure_count: 5
+ interval: 15
+ ping: "192.168.1.100"
+ script: "/var/tmp/script.sh"
+ hello_source_address: "2.2.2.2"
+ sync_groups:
+ - name: "sg1"
+ member:
+ - "g1"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ health_check:
+ failure_count: 3
+ interval: 10
+ ping: "192.168.2.100"
+ script: "/var/tmp/script.sh"
+ commands:
+ - set high-availability virtual-server s1 address 10.10.10.1
+ - set high-availability virtual-server s1 algorithm round-robin
+ - set high-availability virtual-server s1 delay-loop 60
+ - set high-availability virtual-server s1 forward-method direct
+ - set high-availability virtual-server s1 fwmark 10
+ - set high-availability virtual-server s1 persistence-timeout 30
+ - set high-availability virtual-server s1 protocol tcp
+ - set high-availability virtual-server s1 real-server 10.10.50.1 health-check script /var/tmp/script.sh
+ - set high-availability virtual-server s1 real-server 10.10.50.1 port 443
+ - set high-availability virtual-server s2 address 10.10.10.2
+ - set high-availability virtual-server s2 port 81
+ - set high-availability virtual-server s2 real-server real1 connection-timeout 5
+ - set high-availability virtual-server s2 real-server real1 port 8081
+ - set high-availability virtual-server s2 real-server real2 port 8080
+ - set high-availability vrrp global-parameters garp interval 30
+ - set high-availability vrrp global-parameters garp master-delay 10
+ - set high-availability vrrp global-parameters garp master-refresh 100
+ - set high-availability vrrp global-parameters garp master-refresh-repeat 200
+ - set high-availability vrrp global-parameters garp master-repeat 5
+ - set high-availability vrrp global-parameters startup-delay 31
+ - set high-availability vrrp global-parameters version 3
+ - set high-availability vrrp group g1 address 1.1.1.1
+ - set high-availability vrrp group g1 address 2.2.2.2
+ - set high-availability vrrp group g1 address 3.3.3.3 interface eth2
+ - set high-availability vrrp group g1 advertise-interval 10
+ - set high-availability vrrp group g1 authentication password ********
+ - set high-availability vrrp group g1 authentication type plaintext-password
+ - set high-availability vrrp group g1 description 'Group_1'
+ - set high-availability vrrp group g1 disable
+ - set high-availability vrrp group g1 excluded-address 192.168.1.7 interface eth3
+ - set high-availability vrrp group g1 garp interval 20
+ - set high-availability vrrp group g1 garp master-delay 5
+ - set high-availability vrrp group g1 garp master-refresh 50
+ - set high-availability vrrp group g1 garp master-refresh-repeat 100
+ - set high-availability vrrp group g1 garp master-repeat 3
+ - set high-availability vrrp group g1 interface eth2
+ - set high-availability vrrp group g1 no-preempt
+ - set high-availability vrrp group g1 peer-address 192.168.1.3
+ - set high-availability vrrp group g1 preempt-delay 15
+ - set high-availability vrrp group g1 priority 100
+ - set high-availability vrrp group g1 rfc3768-compatibility
+ - set high-availability vrrp group g1 track exclude-vrrp-interface
+ - set high-availability vrrp group g1 track interface eth0
+ - set high-availability vrrp group g1 transition-script backup /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script fault /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script master /var/tmp/script.sh
+ - set high-availability vrrp group g1 transition-script stop /var/tmp/script.sh
+ - set high-availability vrrp group g1 vrid 20
+ - set high-availability vrrp group g2 address 2.2.2.2
+ - set high-availability vrrp group g2 description 'Group_2'
+ - set high-availability vrrp group g2 health-check failure-count 5
+ - set high-availability vrrp group g2 health-check interval 15
+ - set high-availability vrrp group g2 health-check ping 192.168.1.100
+ - set high-availability vrrp group g2 health-check script /var/tmp/script.sh
+ - set high-availability vrrp group g2 hello-source-address 2.2.2.2
+ - set high-availability vrrp group g2 interface eth1
+ - set high-availability vrrp group g2 vrid 11
+ - set high-availability vrrp snmp
+ - set high-availability vrrp sync-group sg1 health-check failure-count 3
+ - set high-availability vrrp sync-group sg1 health-check interval 10
+ - set high-availability vrrp sync-group sg1 health-check ping 192.168.2.100
+ - set high-availability vrrp sync-group sg1 health-check script /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 member g1
+ - set high-availability vrrp sync-group sg1 transition-script backup /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script fault /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script master /var/tmp/script.sh
+ - set high-availability vrrp sync-group sg1 transition-script stop /var/tmp/script.sh
+
+purged:
+ commands:
+ - delete high-availability
+ after:
+ disable: false
+
+deleted_vrrp_groups:
+ commands:
+ - delete high-availability vrrp group g1
+ - delete high-availability vrrp sync-group sg1
+ after:
+ disable: false
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.1
+ algorithm: round-robin
+ delay_loop: 60
+ forward_method: direct
+ fwmark: 10
+ persistence_timeout: 30
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.1
+ port: 443
+ health_check_script: /var/tmp/script.sh
+ - name: s2
+ address: 10.10.10.2
+ port: 81
+ real_server:
+ - address: real1
+ port: 8081
+ connection_timeout: 5
+ - address: real2
+ port: 8080
+ vrrp:
+ global_parameters:
+ startup_delay: 31
+ version: "3"
+ garp:
+ interval: 30
+ master_delay: 10
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 5
+ groups:
+ - name: g2
+ address:
+ - "2.2.2.2"
+ description: Group_2
+ disable: false
+ interface: eth1
+ vrid: 11
+ hello_source_address: 2.2.2.2
+ no_preempt: false
+ rfc3768_compatibility: false
+ health_check:
+ failure_count: 5
+ interval: 15
+ ping: 192.168.1.100
+ script: /var/tmp/script.sh
+
+deleted_bulk:
+ commands:
+ - delete high-availability virtual-server
+ - delete high-availability vrrp global-parameters garp
+ - delete high-availability vrrp global-parameters startup-delay
+ - delete high-availability vrrp group g1
+ - delete high-availability vrrp sync-group
+ after:
+ disable: false
+ vrrp:
+ global_parameters:
+ version: "3"
+ groups:
+ - name: g2
+ address:
+ - "2.2.2.2"
+ description: Group_2
+ disable: false
+ hello_source_address: 2.2.2.2
+ interface: eth1
+ vrid: 11
+ no_preempt: false
+ rfc3768_compatibility: false
+ health_check:
+ failure_count: 5
+ interval: 15
+ ping: 192.168.1.100
+ script: /var/tmp/script.sh
+
+overridden:
+ config:
+ disable: false
+ vrrp:
+ snmp: disabled
+ global_parameters:
+ startup_delay: 32
+ version: 3
+ garp:
+ interval: 30
+ master_delay: 11
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ description: "Group_1"
+ interface: "eth2"
+ address:
+ - "1.1.1.1"
+ - "3.3.3.3 interface eth3"
+ disable: true
+ no_preempt: true
+ rfc3768_compatibility: true
+ vrid: 20
+ peer_address: "192.168.1.3"
+ advertise_interval: 10
+ priority: 100
+ garp:
+ interval: 20
+ master_delay: 5
+ master_refresh: 50
+ master_refresh_repeat: 100
+ master_repeat: 3
+ authentication:
+ type: "plaintext-password"
+ password: "test123"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ track:
+ exclude_vrrp_interface: true
+ sync_groups:
+ - name: "sg1"
+ member:
+ - "g1"
+ - "g2"
+ transition_script:
+ master: "/var/tmp/script.sh"
+ backup: "/var/tmp/script.sh"
+ fault: "/var/tmp/script.sh"
+ stop: "/var/tmp/script.sh"
+ health_check:
+ failure_count: 4
+ interval: 10
+ ping: "192.168.1.100"
+ script: "/var/tmp/script.sh"
+ virtual_servers:
+ - name: "s1"
+ address: "10.10.10.15"
+ algorithm: "round-robin"
+ delay_loop: 60
+ fwmark: 12
+ forward_method: "direct"
+ persistence_timeout: 30
+ protocol: "tcp"
+ real_server:
+ - address: "10.10.10.1"
+ connection_timeout: 61
+ port: 443
+ after:
+ disable: false
+ virtual_servers:
+ - address: "10.10.10.15"
+ algorithm: round-robin
+ delay_loop: 60
+ forward_method: direct
+ fwmark: 12
+ name: s1
+ persistence_timeout: 30
+ protocol: tcp
+ real_server:
+ - address: "10.10.10.1"
+ connection_timeout: 61
+ port: 443
+ - address: "10.10.10.2"
+ name: s2
+ port: 81
+ real_server:
+ - address: real1
+ connection_timeout: 5
+ port: 8081
+ - address: real2
+ port: 8080
+ vrrp:
+ global_parameters:
+ garp:
+ interval: 30
+ master_delay: 11
+ master_refresh: 100
+ master_refresh_repeat: 200
+ master_repeat: 6
+ startup_delay: 32
+ version: "3"
+ groups:
+ - address: "1.1.1.1"
+ advertise_interval: 10
+ authentication:
+ password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
+ type: plaintext-password
+ description: Group_1
+ disable: true
+ garp:
+ interval: 20
+ master_delay: 5
+ master_refresh: 50
+ master_refresh_repeat: 100
+ master_repeat: 3
+ interface: eth2
+ name: g1
+ no_preempt: true
+ peer_address: "192.168.1.3"
+ priority: 100
+ rfc3768_compatibility: true
+ track:
+ exclude_vrrp_interface: true
+ transition_script:
+ backup: /var/tmp/script.sh
+ fault: /var/tmp/script.sh
+ master: /var/tmp/script.sh
+ stop: /var/tmp/script.sh
+ vrid: 20
+ - address: "2.2.2.2"
+ description: Group_2
+ disable: false
+ health_check:
+ failure_count: 5
+ interval: 15
+ ping: "192.168.1.100"
+ script: /var/tmp/script.sh
+ hello_source_address: "2.2.2.2"
+ interface: eth1
+ name: g2
+ no_preempt: false
+ rfc3768_compatibility: false
+ vrid: 11
+ sync_groups:
+ - health_check:
+ failure_count: 4
+ interval: 10
+ ping: "192.168.1.100"
+ script: /var/tmp/script.sh
+ member:
+ - g1
+ - g2
+ name: sg1
+ transition_script:
+ backup: /var/tmp/script.sh
+ fault: /var/tmp/script.sh
+ master: /var/tmp/script.sh
+ stop: /var/tmp/script.sh
+
+replaced:
+ commands:
+ - delete high-availability vrrp global-parameters garp master-repeat 5
+ - delete high-availability vrrp global-parameters startup-delay 31
+ - delete high-availability vrrp group g1 disable
+ - delete high-availability vrrp group g1 no-preempt
+ - delete high-availability vrrp group g1 rfc3768-compatibility
+ - delete high-availability vrrp group g2 address 2.2.2.2
+ - delete high-availability vrrp sync-group sg1 health-check failure-count 3
+ - set high-availability disable
+ - set high-availability virtual-server s1 address 10.10.10.5
+ - set high-availability virtual-server s1 real-server 10.10.50.2 port 8443
+ - set high-availability virtual-server s2 persistence-timeout 30
+ - set high-availability virtual-server s2 protocol tcp
+ - set high-availability virtual-server s3 address 10.10.10.3
+ - set high-availability virtual-server s3 port 88
+ - set high-availability virtual-server s3 protocol udp
+ - set high-availability vrrp global-parameters garp master-repeat 6
+ - set high-availability vrrp global-parameters startup-delay 30
+ - set high-availability vrrp group g2 address 4.4.4.4
+ - set high-availability vrrp group g2 address 6.6.6.6 interface eth3
+ - set high-availability vrrp snmp
+ - set high-availability vrrp sync-group sg1 health-check failure-count 5
+
+rtt:
+ commands:
+ - set high-availability disable
+ - set high-availability virtual-server s1 address 10.10.10.5
+ - set high-availability virtual-server s1 algorithm round-robin
+ - set high-availability virtual-server s1 real-server 10.10.50.2 port 8443
+ - set high-availability virtual-server s2 address 10.10.10.2
+ - set high-availability virtual-server s2 persistence-timeout 30
+ - set high-availability virtual-server s2 port 81
+ - set high-availability virtual-server s2 protocol tcp
+ - set high-availability virtual-server s3 address 10.10.10.3
+ - set high-availability virtual-server s3 port 88
+ - set high-availability virtual-server s3 protocol udp
+ - set high-availability vrrp global-parameters garp master-repeat 6
+ - set high-availability vrrp global-parameters startup-delay 30
+ - set high-availability vrrp group g1 peer-address 192.168.1.3
+ - set high-availability vrrp group g1 priority 100
+ - set high-availability vrrp group g1 vrid 20
+ - set high-availability vrrp group g2 address 4.4.4.4
+ - set high-availability vrrp group g2 address 6.6.6.6 interface eth3
+ - set high-availability vrrp snmp
+ - set high-availability vrrp sync-group sg1 health-check failure-count 5
+ config:
+ disable: false
+ virtual_servers:
+ - name: s1
+ address: 10.10.10.5
+ fwmark: 10
+ algorithm: least-connection
+ real_server:
+ - address: 10.10.50.2
+ port: 8443
+ - name: s2
+ address: 10.10.10.2
+ persistence_timeout: 36
+ port: 443
+ protocol: tcp
+ real_server:
+ - address: 10.10.50.3
+ port: 8443
+ - name: s3
+ address: 10.10.10.3
+ port: 80
+ protocol: udp
+ real_server:
+ - address: 10.10.50.4
+ port: 8443
+ vrrp:
+ snmp: disabled
+ global_parameters:
+ startup_delay: 36
+ garp:
+ master_repeat: 6
+ groups:
+ - name: "g1"
+ peer_address: 192.168.1.3
+ address: "1.1.1.1"
+ priority: 100
+ disable: true
+ no_preempt: false
+ interface: eth2
+ vrid: 20
+ - name: "g2"
+ address:
+ - "2.2.2.2"
+ interface: eth1
+ vrid: 11
+ sync_groups:
+ - name: "sg1"
+ health_check:
+ failure_count: 10
+ after:
+ disable: true
+ virtual_servers:
+ - address: "10.10.10.5"
+ algorithm: "round-robin"
+ name: "s1"
+ real_server:
+ - address: "10.10.50.2"
+ port: 8443
+ - address: "10.10.10.2"
+ name: "s2"
+ persistence_timeout: 30
+ port: 81
+ protocol: "tcp"
+ - address: "10.10.10.3"
+ name: "s3"
+ port: 88
+ protocol: "udp"
+ vrrp:
+ global_parameters:
+ garp:
+ master_repeat: 6
+ startup_delay: 30
+ groups:
+ - disable: false
+ name: "g1"
+ no_preempt: false
+ peer_address: "192.168.1.3"
+ priority: 100
+ rfc3768_compatibility: false
+ vrid: 20
+ snmp: "enabled"
+ sync_groups:
+ - health_check:
+ failure_count: 5
+ name: "sg1"
diff --git a/tests/sanity/ignore-2.15.txt b/tests/sanity/ignore-2.15.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.15.txt
+++ b/tests/sanity/ignore-2.15.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.16.txt
+++ b/tests/sanity/ignore-2.16.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.17.txt b/tests/sanity/ignore-2.17.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.17.txt
+++ b/tests/sanity/ignore-2.17.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.18.txt b/tests/sanity/ignore-2.18.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.18.txt
+++ b/tests/sanity/ignore-2.18.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.19.txt b/tests/sanity/ignore-2.19.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.19.txt
+++ b/tests/sanity/ignore-2.19.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.20.txt b/tests/sanity/ignore-2.20.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.20.txt
+++ b/tests/sanity/ignore-2.20.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.21.txt b/tests/sanity/ignore-2.21.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.21.txt
+++ b/tests/sanity/ignore-2.21.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/sanity/ignore-2.22.txt b/tests/sanity/ignore-2.22.txt
index bae35e38..255b0a87 100644
--- a/tests/sanity/ignore-2.22.txt
+++ b/tests/sanity/ignore-2.22.txt
@@ -1,37 +1,38 @@
plugins/action/vyos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
plugins/action/banner.py action-plugin-docs
plugins/action/bgp_address_family.py action-plugin-docs
plugins/action/bgp_global.py action-plugin-docs
plugins/action/command.py action-plugin-docs
plugins/action/config.py action-plugin-docs
plugins/action/facts.py action-plugin-docs
plugins/action/firewall_global.py action-plugin-docs
plugins/action/firewall_interfaces.py action-plugin-docs
plugins/action/firewall_rules.py action-plugin-docs
+plugins/action/ha.py action-plugin-docs
plugins/action/hostname.py action-plugin-docs
plugins/action/interface.py action-plugin-docs
plugins/action/interfaces.py action-plugin-docs
plugins/action/l3_interface.py action-plugin-docs
plugins/action/l3_interfaces.py action-plugin-docs
plugins/action/lag_interfaces.py action-plugin-docs
plugins/action/linkagg.py action-plugin-docs
plugins/action/lldp.py action-plugin-docs
plugins/action/lldp_global.py action-plugin-docs
plugins/action/lldp_interface.py action-plugin-docs
plugins/action/lldp_interfaces.py action-plugin-docs
plugins/action/logging_global.py action-plugin-docs
plugins/action/ntp_global.py action-plugin-docs
plugins/action/ospf_interfaces.py action-plugin-docs
plugins/action/ospfv2.py action-plugin-docs
plugins/action/ospfv3.py action-plugin-docs
plugins/action/ping.py action-plugin-docs
plugins/action/prefix_lists.py action-plugin-docs
plugins/action/route_maps.py action-plugin-docs
plugins/action/snmp_server.py action-plugin-docs
plugins/action/static_route.py action-plugin-docs
plugins/action/static_routes.py action-plugin-docs
plugins/action/system.py action-plugin-docs
plugins/action/user.py action-plugin-docs
plugins/action/vlan.py action-plugin-docs
plugins/action/vrf.py action-plugin-docs
plugins/action/file.py action-plugin-docs
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ha_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_ha_config.cfg
new file mode 100644
index 00000000..ee69c65d
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_ha_config.cfg
@@ -0,0 +1,64 @@
+set high-availability disable
+set high-availability virtual-server s1 address 10.10.10.1
+set high-availability virtual-server s1 algorithm round-robin
+set high-availability virtual-server s1 delay-loop 60
+set high-availability virtual-server s1 forward-method direct
+set high-availability virtual-server s1 fwmark 10
+set high-availability virtual-server s1 persistence-timeout 30
+set high-availability virtual-server s1 protocol tcp
+set high-availability virtual-server s1 real-server 10.10.50.1 health-check script '/var/tmp/script.sh'
+set high-availability virtual-server s1 real-server 10.10.50.1 port 443
+set high-availability virtual-server s2 address 10.10.10.2
+set high-availability virtual-server s2 port 81
+set high-availability virtual-server s2 real-server real1 connection-timeout 5
+set high-availability virtual-server s2 real-server real1 port 8081
+set high-availability virtual-server s2 real-server real2 port 8080
+set high-availability vrrp global-parameters garp interval 30
+set high-availability vrrp global-parameters garp master-delay 10
+set high-availability vrrp global-parameters garp master-refresh 100
+set high-availability vrrp global-parameters garp master-refresh-repeat 200
+set high-availability vrrp global-parameters garp master-repeat 5
+set high-availability vrrp global-parameters startup-delay 30
+set high-availability vrrp global-parameters version 3
+set high-availability vrrp group g1 address '1.1.1.1'
+set high-availability vrrp group g1 address '3.3.3.3'
+set high-availability vrrp group g1 address '5.5.5.5' interface 'eth2'
+set high-availability vrrp group g1 advertise-interval 10
+set high-availability vrrp group g1 authentication password 'testpass'
+set high-availability vrrp group g1 authentication type 'plaintext-password'
+set high-availability vrrp group g1 description 'Group_1'
+set high-availability vrrp group g1 disable
+set high-availability vrrp group g1 excluded-address '192.168.1.7' interface 'eth3'
+set high-availability vrrp group g1 excluded-address '192.168.1.8'
+set high-availability vrrp group g1 garp interval 20
+set high-availability vrrp group g1 garp master-delay 5
+set high-availability vrrp group g1 garp master-refresh 50
+set high-availability vrrp group g1 garp master-refresh-repeat 100
+set high-availability vrrp group g1 garp master-repeat 3
+set high-availability vrrp group g1 health-check failure-count 3
+set high-availability vrrp group g1 health-check interval 10
+set high-availability vrrp group g1 health-check ping '192.168.1.5'
+set high-availability vrrp group g1 health-check script 'script.sh'
+set high-availability vrrp group g1 hello-source-address '192.168.1.2'
+set high-availability vrrp group g1 interface 'eth2'
+set high-availability vrrp group g1 no-preempt
+set high-availability vrrp group g1 peer-address '192.168.1.3'
+set high-availability vrrp group g1 priority 100
+set high-availability vrrp group g1 rfc3768-compatibility
+set high-availability vrrp group g1 track exclude-vrrp-interface
+set high-availability vrrp group g1 track interface 'eth1'
+set high-availability vrrp group g1 transition-script backup '/var/tmp/script.sh'
+set high-availability vrrp group g1 transition-script fault '/var/tmp/script.sh'
+set high-availability vrrp group g1 transition-script master '/var/tmp/script.sh'
+set high-availability vrrp group g1 transition-script stop '/var/tmp/script.sh'
+set high-availability vrrp group g1 vrid 20
+set high-availability vrrp snmp
+set high-availability vrrp sync-group sg1 health-check failure-count 3
+set high-availability vrrp sync-group sg1 health-check interval 10
+set high-availability vrrp sync-group sg1 health-check ping '192.168.1.1'
+set high-availability vrrp sync-group sg1 health-check script '/var/tmp/script.sh'
+set high-availability vrrp sync-group sg1 member 'g1'
+set high-availability vrrp sync-group sg1 transition-script backup '/var/tmp/script.sh'
+set high-availability vrrp sync-group sg1 transition-script fault '/var/tmp/script.sh'
+set high-availability vrrp sync-group sg1 transition-script master '/var/tmp/script.sh'
+set high-availability vrrp sync-group sg1 transition-script stop '/var/tmp/script.sh'
diff --git a/tests/unit/modules/network/vyos/test_vyos_ha.py b/tests/unit/modules/network/vyos/test_vyos_ha.py
new file mode 100644
index 00000000..54833a36
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_ha.py
@@ -0,0 +1,1405 @@
+# (c) 2021 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from unittest.mock import patch
+
+from ansible_collections.vyos.vyos.plugins.modules import vyos_ha
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args
+
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosHaModule(TestVyosModule):
+ module = vyos_ha
+
+ def setUp(self):
+ super(TestVyosHaModule, self).setUp()
+
+ self.mock_get_resource_connection_config = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection",
+ )
+ self.get_resource_connection_config = self.mock_get_resource_connection_config.start()
+
+ self.mock_get_resource_connection_facts = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection",
+ )
+ self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start()
+
+ self.mock_execute_show_command = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ha.ha.HaFacts.get_config",
+ )
+
+ self.execute_show_command = self.mock_execute_show_command.start()
+
+ self.mock_get_os_version = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ha.ha.get_os_version",
+ )
+ self.get_os_version = self.mock_get_os_version.start()
+ self.get_os_version.return_value = "1.5"
+ self.maxDiff = None
+
+ def tearDown(self):
+ super(TestVyosHaModule, self).tearDown()
+ self.mock_get_resource_connection_config.stop()
+ self.mock_get_resource_connection_facts.stop()
+ self.mock_execute_show_command.stop()
+ self.mock_get_os_version.stop()
+
+ def load_fixtures(self, commands=None, filename=None):
+ if filename is None:
+ filename = "vyos_ha_config.cfg"
+
+ def load_from_file(*args, **kwargs):
+ output = load_fixture(filename)
+ return output
+
+ self.execute_show_command.side_effect = load_from_file
+
+ def test_vrrp_merged_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=True,
+ virtual_servers=[
+ dict(
+ address="10.10.10.1",
+ algorithm="round-robin",
+ delay_loop=60,
+ forward_method="direct",
+ fwmark=10,
+ name="s1",
+ persistence_timeout="30",
+ protocol="tcp",
+ real_server=[
+ dict(
+ address="10.10.50.1",
+ port=443,
+ health_check_script="/var/tmp/script.sh",
+ ),
+ ],
+ ),
+ dict(
+ address="10.10.10.2",
+ name="s2",
+ port=81,
+ real_server=[
+ dict(
+ address="real1",
+ port=8081,
+ connection_timeout=5,
+ ),
+ dict(
+ address="real2",
+ port=8080,
+ ),
+ ],
+ ),
+ ],
+ vrrp=dict(
+ global_parameters=dict(
+ garp=dict(
+ master_refresh=100,
+ ),
+ version="3",
+ ),
+ groups=[
+ dict(
+ authentication=dict(
+ password="testpass",
+ type="plaintext-password",
+ ),
+ address=[
+ "1.1.1.1",
+ "3.3.3.3",
+ "5.5.5.5 interface eth2",
+ ],
+ advertise_interval=10,
+ description="Group_1",
+ disable=True,
+ excluded_address=[
+ "192.168.1.8",
+ "192.168.1.7 interface eth3",
+ ],
+ garp=dict(
+ interval=20,
+ master_delay=5,
+ master_refresh_repeat=100,
+ master_repeat=3,
+ ),
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.1.5",
+ script="script.sh",
+ ),
+ hello_source_address="192.168.1.2",
+ interface="eth2",
+ name="g1",
+ no_preempt=True,
+ peer_address="192.168.1.3",
+ priority=100,
+ rfc3768_compatibility=True,
+ track=dict(
+ exclude_vrrp_interface=True,
+ interface=["eth1"],
+ ),
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ vrid=20,
+ ),
+ ],
+ snmp="enabled",
+ sync_groups=[
+ dict(
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ),
+ member=["g1"],
+ name="sg1",
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="merged",
+ ),
+ )
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrrp_merged(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=True,
+ virtual_servers=[
+ dict(
+ name="s1",
+ address="10.10.10.5",
+ algorithm="round-robin",
+ real_server=[
+ dict(
+ address="10.10.50.2",
+ port=8443,
+ ),
+ ],
+ ),
+ dict(
+ name="s2",
+ address="10.10.10.2",
+ persistence_timeout=30,
+ port=81,
+ protocol="tcp",
+ ),
+ dict(
+ name="s3",
+ address="10.10.10.3",
+ port=88,
+ protocol="udp",
+ ),
+ ],
+ vrrp=dict(
+ snmp="disabled",
+ global_parameters=dict(
+ startup_delay=35,
+ garp=dict(
+ master_repeat=6,
+ ),
+ ),
+ groups=[
+ dict(
+ name="g1",
+ peer_address="192.168.1.3",
+ priority=100,
+ disable=False,
+ no_preempt=False,
+ ),
+ dict(
+ name="g2",
+ address=[
+ "192.168.3.3",
+ "192.168.4.4 interface eth3",
+ ],
+ preempt_delay=15,
+ ),
+ ],
+ sync_groups=[
+ dict(
+ name="sg1",
+ health_check=dict(
+ failure_count=5,
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="merged",
+ ),
+ )
+ commands = [
+ "delete high-availability vrrp group g1 no-preempt",
+ "delete high-availability vrrp group g1 disable",
+ "delete high-availability vrrp group g1 rfc3768-compatibility",
+ "set high-availability vrrp group g2 address 192.168.3.3",
+ "set high-availability vrrp group g2 address 192.168.4.4 interface eth3",
+ "set high-availability vrrp group g2 preempt-delay 15",
+ "delete high-availability vrrp snmp",
+ "set high-availability virtual-server s1 address 10.10.10.5",
+ "set high-availability virtual-server s1 real-server 10.10.50.2 port 8443",
+ "set high-availability virtual-server s2 persistence-timeout 30",
+ "set high-availability virtual-server s2 protocol tcp",
+ "set high-availability virtual-server s3 address 10.10.10.3",
+ "set high-availability virtual-server s3 port 88",
+ "set high-availability virtual-server s3 protocol udp",
+ "set high-availability vrrp global-parameters garp master-repeat 6",
+ "set high-availability vrrp global-parameters startup-delay 35",
+ "set high-availability vrrp sync-group sg1 health-check failure-count 5",
+ ]
+
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_replaced(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=False,
+ virtual_servers=[
+ dict(
+ name="s1",
+ address="10.10.10.5",
+ algorithm="round-robin",
+ real_server=[
+ dict(
+ address="10.10.50.2",
+ port=8443,
+ ),
+ ],
+ ),
+ dict(
+ name="s2",
+ address="10.10.10.2",
+ persistence_timeout=30,
+ port=81,
+ protocol="tcp",
+ ),
+ dict(
+ name="s3",
+ address="10.10.10.3",
+ port=88,
+ protocol="udp",
+ ),
+ ],
+ vrrp=dict(
+ snmp="disabled",
+ global_parameters=dict(
+ startup_delay=32,
+ garp=dict(
+ master_repeat=6,
+ ),
+ ),
+ groups=[
+ dict(
+ name="g1",
+ peer_address="192.168.1.3",
+ priority=100,
+ disable=False,
+ no_preempt=False,
+ vrid=20,
+ ),
+ dict(
+ name="g2",
+ address=[
+ "192.168.3.3",
+ "192.168.4.4 interface eth3",
+ ],
+ ),
+ ],
+ sync_groups=[
+ dict(
+ name="sg1",
+ health_check=dict(
+ failure_count=5,
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="replaced",
+ ),
+ )
+ commands = [
+ "delete high-availability vrrp global-parameters garp master-repeat 5",
+ "delete high-availability vrrp global-parameters startup-delay 30",
+ "delete high-availability vrrp group g1 disable",
+ "delete high-availability vrrp group g1 no-preempt",
+ "delete high-availability vrrp group g1 rfc3768-compatibility",
+ "delete high-availability vrrp sync-group sg1 health-check failure-count 3",
+ "set high-availability vrrp group g2 address 192.168.3.3",
+ "set high-availability vrrp group g2 address 192.168.4.4 interface eth3",
+ "delete high-availability disable",
+ "delete high-availability vrrp snmp",
+ "set high-availability virtual-server s1 address 10.10.10.5",
+ "set high-availability virtual-server s1 real-server 10.10.50.2 port 8443",
+ "set high-availability virtual-server s2 persistence-timeout 30",
+ "set high-availability virtual-server s2 protocol tcp",
+ "set high-availability virtual-server s3 address 10.10.10.3",
+ "set high-availability virtual-server s3 port 88",
+ "set high-availability virtual-server s3 protocol udp",
+ "set high-availability vrrp global-parameters garp master-repeat 6",
+ "set high-availability vrrp global-parameters startup-delay 32",
+ "set high-availability vrrp sync-group sg1 health-check failure-count 5",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_replaced_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=True,
+ virtual_servers=[
+ dict(
+ address="10.10.10.1",
+ algorithm="round-robin",
+ delay_loop=60,
+ forward_method="direct",
+ fwmark=10,
+ name="s1",
+ persistence_timeout="30",
+ protocol="tcp",
+ real_server=[
+ dict(
+ address="10.10.50.1",
+ port=443,
+ health_check_script="/var/tmp/script.sh",
+ ),
+ ],
+ ),
+ dict(
+ address="10.10.10.2",
+ name="s2",
+ port=81,
+ real_server=[
+ dict(
+ address="real1",
+ port=8081,
+ connection_timeout=5,
+ ),
+ dict(
+ address="real2",
+ port=8080,
+ ),
+ ],
+ ),
+ ],
+ vrrp=dict(
+ global_parameters=dict(
+ garp=dict(
+ interval=30,
+ master_delay=10,
+ master_refresh=100,
+ master_refresh_repeat=200,
+ master_repeat=5,
+ ),
+ version="3",
+ startup_delay=30,
+ ),
+ groups=[
+ dict(
+ authentication=dict(
+ password="testpass",
+ type="plaintext-password",
+ ),
+ address=[
+ "1.1.1.1",
+ "3.3.3.3",
+ "5.5.5.5 interface eth2",
+ ],
+ advertise_interval=10,
+ description="Group_1",
+ disable=True,
+ excluded_address=[
+ "192.168.1.8",
+ "192.168.1.7 interface eth3",
+ ],
+ garp=dict(
+ interval=20,
+ master_delay=5,
+ master_refresh=50,
+ master_refresh_repeat=100,
+ master_repeat=3,
+ ),
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.1.5",
+ script="script.sh",
+ ),
+ hello_source_address="192.168.1.2",
+ interface="eth2",
+ name="g1",
+ no_preempt=True,
+ peer_address="192.168.1.3",
+ priority=100,
+ rfc3768_compatibility=True,
+ track=dict(
+ exclude_vrrp_interface=True,
+ interface=["eth1"],
+ ),
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ vrid=20,
+ ),
+ ],
+ snmp="enabled",
+ sync_groups=[
+ dict(
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.1.1",
+ script="/var/tmp/script.sh",
+ ),
+ member=["g1"],
+ name="sg1",
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="replaced",
+ ),
+ )
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrrp_overridden(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=False,
+ vrrp=dict(
+ snmp="disabled",
+ global_parameters=dict(
+ startup_delay=32,
+ version=3,
+ garp=dict(
+ interval=30,
+ master_delay=11,
+ master_refresh=100,
+ master_refresh_repeat=200,
+ master_repeat=6,
+ ),
+ ),
+ groups=[
+ dict(
+ name="g1",
+ description="Group_1",
+ interface="eth2",
+ address="1.1.1.1",
+ disable=True,
+ no_preempt=True,
+ rfc3768_compatibility=True,
+ vrid=20,
+ peer_address="192.168.1.3",
+ advertise_interval=10,
+ priority=100,
+ garp=dict(
+ interval=20,
+ master_delay=5,
+ master_refresh=50,
+ master_refresh_repeat=100,
+ master_repeat=3,
+ ),
+ authentication=dict(
+ type="plaintext-password",
+ password="testpass",
+ ),
+ transition_script=dict(
+ master="/var/tmp/script.sh",
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ track=dict(
+ exclude_vrrp_interface=True,
+ ),
+ ),
+ dict(
+ name="g2",
+ address=[
+ "192.168.3.3",
+ "192.168.4.4 interface eth3",
+ ],
+ ),
+ ],
+ sync_groups=[
+ dict(
+ name="sg1",
+ member=["g1", "g2"],
+ transition_script=dict(
+ master="/var/tmp/script.sh",
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ health_check=dict(
+ failure_count=4,
+ interval=10,
+ ping="192.168.1.100",
+ script="/var/tmp/script.sh",
+ ),
+ ),
+ ],
+ ),
+ virtual_servers=[
+ dict(
+ name="s1",
+ address="10.10.10.15",
+ algorithm="round-robin",
+ delay_loop=60,
+ fwmark=12,
+ forward_method="direct",
+ persistence_timeout=30,
+ protocol="tcp",
+ real_server=[
+ dict(
+ address="10.10.10.1",
+ connection_timeout=61,
+ port=443,
+ ),
+ ],
+ ),
+ ],
+ ),
+ state="overridden",
+ ),
+ )
+ commands = [
+ "delete high-availability disable",
+ "delete high-availability virtual-server s1",
+ "delete high-availability vrrp global-parameters garp",
+ "delete high-availability vrrp group g1",
+ "delete high-availability vrrp sync-group sg1",
+ "set high-availability virtual-server s1 address 10.10.10.15",
+ "set high-availability virtual-server s1 algorithm round-robin",
+ "set high-availability virtual-server s1 delay-loop 60",
+ "set high-availability virtual-server s1 forward-method direct",
+ "set high-availability virtual-server s1 fwmark 12",
+ "set high-availability virtual-server s1 persistence-timeout 30",
+ "set high-availability virtual-server s1 protocol tcp",
+ "set high-availability virtual-server s1 real-server 10.10.10.1 connection-timeout 61",
+ "set high-availability virtual-server s1 real-server 10.10.10.1 port 443",
+ "set high-availability vrrp global-parameters garp interval 30",
+ "set high-availability vrrp global-parameters garp master-delay 11",
+ "set high-availability vrrp global-parameters garp master-refresh 100",
+ "set high-availability vrrp global-parameters garp master-refresh-repeat 200",
+ "set high-availability vrrp global-parameters garp master-repeat 6",
+ "set high-availability vrrp global-parameters startup-delay 32",
+ "set high-availability vrrp group g1 address 1.1.1.1",
+ "set high-availability vrrp group g1 advertise-interval 10",
+ "set high-availability vrrp group g1 authentication password testpass",
+ "set high-availability vrrp group g1 authentication type plaintext-password",
+ "set high-availability vrrp group g1 description 'Group_1'",
+ "set high-availability vrrp group g1 disable",
+ "set high-availability vrrp group g1 garp interval 20",
+ "set high-availability vrrp group g1 garp master-delay 5",
+ "set high-availability vrrp group g1 garp master-refresh 50",
+ "set high-availability vrrp group g1 garp master-refresh-repeat 100",
+ "set high-availability vrrp group g1 garp master-repeat 3",
+ "set high-availability vrrp group g1 interface eth2",
+ "set high-availability vrrp group g1 no-preempt",
+ "set high-availability vrrp group g1 peer-address 192.168.1.3",
+ "set high-availability vrrp group g1 priority 100",
+ "set high-availability vrrp group g1 rfc3768-compatibility",
+ "set high-availability vrrp group g1 track exclude-vrrp-interface",
+ "set high-availability vrrp group g1 transition-script backup /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script fault /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script master /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script stop /var/tmp/script.sh",
+ "set high-availability vrrp group g1 vrid 20",
+ "set high-availability vrrp group g2 address 192.168.3.3",
+ "set high-availability vrrp group g2 address 192.168.4.4 interface eth3",
+ "set high-availability vrrp sync-group sg1 health-check failure-count 4",
+ "set high-availability vrrp sync-group sg1 health-check interval 10",
+ "set high-availability vrrp sync-group sg1 health-check ping 192.168.1.100",
+ "set high-availability vrrp sync-group sg1 health-check script /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 member g1",
+ "set high-availability vrrp sync-group sg1 member g2",
+ "set high-availability vrrp sync-group sg1 transition-script backup /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script fault /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script master /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script stop /var/tmp/script.sh",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_overridden_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=True,
+ virtual_servers=[
+ dict(
+ address="10.10.10.1",
+ algorithm="round-robin",
+ delay_loop=60,
+ forward_method="direct",
+ fwmark=10,
+ name="s1",
+ persistence_timeout="30",
+ protocol="tcp",
+ real_server=[
+ dict(
+ address="10.10.50.1",
+ port=443,
+ health_check_script="/var/tmp/script.sh",
+ ),
+ ],
+ ),
+ dict(
+ address="10.10.10.2",
+ name="s2",
+ port=81,
+ real_server=[
+ dict(
+ address="real1",
+ port=8081,
+ connection_timeout=5,
+ ),
+ dict(
+ address="real2",
+ port=8080,
+ ),
+ ],
+ ),
+ ],
+ vrrp=dict(
+ global_parameters=dict(
+ garp=dict(
+ interval=30,
+ master_delay=10,
+ master_refresh=100,
+ master_refresh_repeat=200,
+ master_repeat=5,
+ ),
+ version="3",
+ startup_delay=30,
+ ),
+ groups=[
+ dict(
+ authentication=dict(
+ password="testpass",
+ type="plaintext-password",
+ ),
+ address=[
+ "1.1.1.1",
+ "3.3.3.3",
+ "5.5.5.5 interface eth2",
+ ],
+ advertise_interval=10,
+ description="Group_1",
+ disable=True,
+ excluded_address=[
+ "192.168.1.8",
+ "192.168.1.7 interface eth3",
+ ],
+ garp=dict(
+ interval=20,
+ master_delay=5,
+ master_refresh=50,
+ master_refresh_repeat=100,
+ master_repeat=3,
+ ),
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.1.5",
+ script="script.sh",
+ ),
+ hello_source_address="192.168.1.2",
+ interface="eth2",
+ name="g1",
+ no_preempt=True,
+ peer_address="192.168.1.3",
+ priority=100,
+ rfc3768_compatibility=True,
+ track=dict(
+ exclude_vrrp_interface=True,
+ interface=["eth1"],
+ ),
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ vrid=20,
+ ),
+ ],
+ snmp="enabled",
+ sync_groups=[
+ dict(
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.1.1",
+ script="/var/tmp/script.sh",
+ ),
+ member=["g1"],
+ name="sg1",
+ transition_script=dict(
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ master="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="overridden",
+ ),
+ )
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrrp_rendered(self):
+ set_module_args(
+ dict(
+ config=dict(
+ virtual_servers=[
+ dict(
+ name="s1",
+ address="10.10.10.1",
+ algorithm="round-robin",
+ delay_loop=60,
+ forward_method="direct",
+ fwmark=10,
+ persistence_timeout=30,
+ protocol="tcp",
+ real_server=[
+ dict(
+ address="10.10.50.1",
+ health_check_script="/var/tmp/script.sh",
+ port=443,
+ ),
+ ],
+ ),
+ dict(
+ name="s2",
+ address="10.10.10.2",
+ port=81,
+ real_server=[
+ dict(
+ address="real1",
+ connection_timeout=5,
+ port=8081,
+ ),
+ dict(
+ address="real2",
+ port=8080,
+ ),
+ ],
+ ),
+ ],
+ vrrp=dict(
+ snmp="enabled",
+ global_parameters=dict(
+ startup_delay=31,
+ version="3",
+ garp=dict(
+ interval=30,
+ master_delay=10,
+ master_refresh=100,
+ master_refresh_repeat=200,
+ master_repeat=5,
+ ),
+ ),
+ groups=[
+ dict(
+ name="g1",
+ description="Group_1",
+ interface="eth2",
+ address="1.1.1.1",
+ advertise_interval=10,
+ peer_address="192.168.1.3",
+ priority=100,
+ disable=True,
+ no_preempt=True,
+ rfc3768_compatibility=True,
+ vrid=20,
+ excluded_address=[
+ "192.168.1.7 interface eth3",
+ ],
+ garp=dict(
+ interval=20,
+ master_delay=5,
+ master_refresh=50,
+ master_refresh_repeat=100,
+ master_repeat=3,
+ ),
+ authentication=dict(
+ type="plaintext-password",
+ password="testpass",
+ ),
+ transition_script=dict(
+ master="/var/tmp/script.sh",
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ track=dict(
+ exclude_vrrp_interface=True,
+ interface=[
+ "eth0",
+ ],
+ ),
+ ),
+ dict(
+ name="g2",
+ description="Group_2",
+ interface="eth1",
+ address=[
+ "2.2.2.2",
+ "2.2.2.3 interface eth3",
+ ],
+ disable=False,
+ no_preempt=False,
+ rfc3768_compatibility=False,
+ vrid=11,
+ health_check=dict(
+ failure_count=5,
+ interval=15,
+ ping="192.168.1.100",
+ script="/var/tmp/script.sh",
+ ),
+ hello_source_address="2.2.2.2",
+ ),
+ ],
+ sync_groups=[
+ dict(
+ name="sg1",
+ member=[
+ "g1",
+ ],
+ transition_script=dict(
+ master="/var/tmp/script.sh",
+ backup="/var/tmp/script.sh",
+ fault="/var/tmp/script.sh",
+ stop="/var/tmp/script.sh",
+ ),
+ health_check=dict(
+ failure_count=3,
+ interval=10,
+ ping="192.168.2.100",
+ script="/var/tmp/script.sh",
+ ),
+ ),
+ ],
+ ),
+ ),
+ state="rendered",
+ ),
+ )
+ rendered_commands = [
+ "set high-availability virtual-server s1 address 10.10.10.1",
+ "set high-availability virtual-server s1 algorithm round-robin",
+ "set high-availability virtual-server s1 delay-loop 60",
+ "set high-availability virtual-server s1 forward-method direct",
+ "set high-availability virtual-server s1 fwmark 10",
+ "set high-availability virtual-server s1 persistence-timeout 30",
+ "set high-availability virtual-server s1 protocol tcp",
+ "set high-availability virtual-server s1 real-server 10.10.50.1 health-check script /var/tmp/script.sh",
+ "set high-availability virtual-server s1 real-server 10.10.50.1 port 443",
+ "set high-availability virtual-server s2 address 10.10.10.2",
+ "set high-availability virtual-server s2 port 81",
+ "set high-availability virtual-server s2 real-server real1 connection-timeout 5",
+ "set high-availability virtual-server s2 real-server real1 port 8081",
+ "set high-availability virtual-server s2 real-server real2 port 8080",
+ "set high-availability vrrp global-parameters garp interval 30",
+ "set high-availability vrrp global-parameters garp master-delay 10",
+ "set high-availability vrrp global-parameters garp master-refresh 100",
+ "set high-availability vrrp global-parameters garp master-refresh-repeat 200",
+ "set high-availability vrrp global-parameters garp master-repeat 5",
+ "set high-availability vrrp global-parameters startup-delay 31",
+ "set high-availability vrrp global-parameters version 3",
+ "set high-availability vrrp group g1 address 1.1.1.1",
+ "set high-availability vrrp group g1 advertise-interval 10",
+ "set high-availability vrrp group g1 authentication password testpass",
+ "set high-availability vrrp group g1 authentication type plaintext-password",
+ "set high-availability vrrp group g1 description 'Group_1'",
+ "set high-availability vrrp group g1 disable",
+ "set high-availability vrrp group g1 excluded-address 192.168.1.7 interface eth3",
+ "set high-availability vrrp group g1 garp interval 20",
+ "set high-availability vrrp group g1 garp master-delay 5",
+ "set high-availability vrrp group g1 garp master-refresh 50",
+ "set high-availability vrrp group g1 garp master-refresh-repeat 100",
+ "set high-availability vrrp group g1 garp master-repeat 3",
+ "set high-availability vrrp group g1 interface eth2",
+ "set high-availability vrrp group g1 no-preempt",
+ "set high-availability vrrp group g1 peer-address 192.168.1.3",
+ "set high-availability vrrp group g1 priority 100",
+ "set high-availability vrrp group g1 rfc3768-compatibility",
+ "set high-availability vrrp group g1 track exclude-vrrp-interface",
+ "set high-availability vrrp group g1 track interface eth0",
+ "set high-availability vrrp group g1 transition-script backup /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script fault /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script master /var/tmp/script.sh",
+ "set high-availability vrrp group g1 transition-script stop /var/tmp/script.sh",
+ "set high-availability vrrp group g1 vrid 20",
+ "set high-availability vrrp group g2 address 2.2.2.2",
+ "set high-availability vrrp group g2 address 2.2.2.3 interface eth3",
+ "set high-availability vrrp group g2 description 'Group_2'",
+ "set high-availability vrrp group g2 health-check failure-count 5",
+ "set high-availability vrrp group g2 health-check interval 15",
+ "set high-availability vrrp group g2 health-check ping 192.168.1.100",
+ "set high-availability vrrp group g2 health-check script /var/tmp/script.sh",
+ "set high-availability vrrp group g2 hello-source-address 2.2.2.2",
+ "set high-availability vrrp group g2 interface eth1",
+ "set high-availability vrrp group g2 vrid 11",
+ "set high-availability vrrp snmp",
+ "set high-availability vrrp sync-group sg1 health-check failure-count 3",
+ "set high-availability vrrp sync-group sg1 health-check interval 10",
+ "set high-availability vrrp sync-group sg1 health-check ping 192.168.2.100",
+ "set high-availability vrrp sync-group sg1 health-check script /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 member g1",
+ "set high-availability vrrp sync-group sg1 transition-script backup /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script fault /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script master /var/tmp/script.sh",
+ "set high-availability vrrp sync-group sg1 transition-script stop /var/tmp/script.sh",
+ ]
+ result = self.execute_module(changed=False)
+ # rendered output order is not significant — use sorted comparison
+ self.assertEqual(
+ sorted(result["rendered"]),
+ sorted(rendered_commands),
+ result["rendered"],
+ )
+
+ def test_vrrp_parsed(self):
+ commands = (
+ "set high-availability disable",
+ "set high-availability virtual-server s1 address 10.10.10.1",
+ "set high-availability virtual-server s1 algorithm round-robin",
+ "set high-availability virtual-server s1 delay-loop 60",
+ "set high-availability virtual-server s1 forward-method direct",
+ "set high-availability virtual-server s1 fwmark 10",
+ "set high-availability virtual-server s1 persistence-timeout 30",
+ "set high-availability virtual-server s1 protocol tcp",
+ "set high-availability virtual-server s1 real-server 10.10.50.1 health-check script '/var/tmp/script.sh'",
+ "set high-availability virtual-server s1 real-server 10.10.50.1 port 443",
+ "set high-availability virtual-server s2 address 10.10.10.2",
+ "set high-availability virtual-server s2 port 81",
+ "set high-availability virtual-server s2 real-server real1 connection-timeout 5",
+ "set high-availability virtual-server s2 real-server real1 port 8081",
+ "set high-availability virtual-server s2 real-server real2 port 8080",
+ "set high-availability vrrp global-parameters garp interval 30",
+ "set high-availability vrrp global-parameters garp master-delay 10",
+ "set high-availability vrrp global-parameters garp master-refresh 100",
+ "set high-availability vrrp global-parameters garp master-refresh-repeat 200",
+ "set high-availability vrrp global-parameters garp master-repeat 5",
+ "set high-availability vrrp global-parameters startup-delay 30",
+ "set high-availability vrrp global-parameters version 3",
+ "set high-availability vrrp group g1 address '1.1.1.1'",
+ "set high-availability vrrp group g1 address '3.3.3.3'",
+ "set high-availability vrrp group g1 address '5.5.5.5' interface 'eth2'",
+ "set high-availability vrrp group g1 advertise-interval 10",
+ "set high-availability vrrp group g1 authentication password 'testpass'",
+ "set high-availability vrrp group g1 authentication type 'plaintext-password'",
+ "set high-availability vrrp group g1 description 'Group_1'",
+ "set high-availability vrrp group g1 disable",
+ "set high-availability vrrp group g1 excluded-address '192.168.1.7' interface 'eth3'",
+ "set high-availability vrrp group g1 excluded-address '192.168.1.8'",
+ "set high-availability vrrp group g1 garp interval 20",
+ "set high-availability vrrp group g1 garp master-delay 5",
+ "set high-availability vrrp group g1 garp master-refresh 50",
+ "set high-availability vrrp group g1 garp master-refresh-repeat 100",
+ "set high-availability vrrp group g1 garp master-repeat 3",
+ "set high-availability vrrp group g1 health-check failure-count 3",
+ "set high-availability vrrp group g1 health-check interval 10",
+ "set high-availability vrrp group g1 health-check ping '192.168.1.5'",
+ "set high-availability vrrp group g1 health-check script 'script.sh'",
+ "set high-availability vrrp group g1 hello-source-address '192.168.1.2'",
+ "set high-availability vrrp group g1 interface 'eth2'",
+ "set high-availability vrrp group g1 no-preempt",
+ "set high-availability vrrp group g1 peer-address '192.168.1.3'",
+ "set high-availability vrrp group g1 priority 100",
+ "set high-availability vrrp group g1 rfc3768-compatibility",
+ "set high-availability vrrp group g1 track exclude-vrrp-interface",
+ "set high-availability vrrp group g1 track interface 'eth1'",
+ "set high-availability vrrp group g1 transition-script backup '/var/tmp/script.sh'",
+ "set high-availability vrrp group g1 transition-script fault '/var/tmp/script.sh'",
+ "set high-availability vrrp group g1 transition-script master '/var/tmp/script.sh'",
+ "set high-availability vrrp group g1 transition-script stop '/var/tmp/script.sh'",
+ "set high-availability vrrp group g1 vrid 20",
+ "set high-availability vrrp group g2 address '192.168.3.3'",
+ "set high-availability vrrp group g2 address '192.168.4.4' interface 'eth3'",
+ "set high-availability vrrp snmp",
+ "set high-availability vrrp sync-group sg1 health-check failure-count 3",
+ "set high-availability vrrp sync-group sg1 health-check interval 10",
+ "set high-availability vrrp sync-group sg1 health-check ping '192.168.1.1'",
+ "set high-availability vrrp sync-group sg1 health-check script '/var/tmp/script.sh'",
+ "set high-availability vrrp sync-group sg1 member 'g1'",
+ "set high-availability vrrp sync-group sg1 transition-script backup '/var/tmp/script.sh'",
+ "set high-availability vrrp sync-group sg1 transition-script fault '/var/tmp/script.sh'",
+ "set high-availability vrrp sync-group sg1 transition-script master '/var/tmp/script.sh'",
+ "set high-availability vrrp sync-group sg1 transition-script stop '/var/tmp/script.sh'",
+ )
+ parsed_str = "\n".join(commands)
+ set_module_args(dict(running_config=parsed_str, state="parsed"))
+ result = self.execute_module(changed=False)
+ parsed_list = {
+ "disable": True,
+ "virtual_servers": [
+ {
+ "name": "s1",
+ "address": "10.10.10.1",
+ "algorithm": "round-robin",
+ "delay_loop": 60,
+ "forward_method": "direct",
+ "fwmark": 10,
+ "persistence_timeout": 30,
+ "protocol": "tcp",
+ "real_server": [
+ {
+ "address": "10.10.50.1",
+ "health_check_script": "/var/tmp/script.sh",
+ "port": 443,
+ },
+ ],
+ },
+ {
+ "name": "s2",
+ "address": "10.10.10.2",
+ "port": 81,
+ "real_server": [
+ {
+ "address": "real1",
+ "connection_timeout": 5,
+ "port": 8081,
+ },
+ {
+ "address": "real2",
+ "port": 8080,
+ },
+ ],
+ },
+ ],
+ "vrrp": {
+ "snmp": "enabled",
+ "global_parameters": {
+ "startup_delay": 30,
+ "version": "3",
+ "garp": {
+ "interval": 30,
+ "master_delay": 10,
+ "master_refresh": 100,
+ "master_refresh_repeat": 200,
+ "master_repeat": 5,
+ },
+ },
+ "groups": [
+ {
+ "name": "g1",
+ "description": "Group_1",
+ "disable": True,
+ "no_preempt": True,
+ "rfc3768_compatibility": True,
+ "interface": "eth2",
+ "address": ["1.1.1.1", "3.3.3.3", "5.5.5.5 interface eth2"],
+ "advertise_interval": 10,
+ "peer_address": "192.168.1.3",
+ "priority": 100,
+ "vrid": 20,
+ "garp": {
+ "interval": 20,
+ "master_delay": 5,
+ "master_refresh": 50,
+ "master_refresh_repeat": 100,
+ "master_repeat": 3,
+ },
+ "authentication": {
+ "type": "plaintext-password",
+ "password": "testpass",
+ },
+ "transition_script": {
+ "master": "/var/tmp/script.sh",
+ "backup": "/var/tmp/script.sh",
+ "fault": "/var/tmp/script.sh",
+ "stop": "/var/tmp/script.sh",
+ },
+ "health_check": {
+ "failure_count": 3,
+ "interval": 10,
+ "ping": "192.168.1.5",
+ "script": "script.sh",
+ },
+ "track": {
+ "exclude_vrrp_interface": True,
+ "interface": ["eth1"],
+ },
+ "excluded_address": [
+ "192.168.1.7 interface eth3",
+ "192.168.1.8",
+ ],
+ "hello_source_address": "192.168.1.2",
+ },
+ {
+ "name": "g2",
+ "address": ["192.168.3.3", "192.168.4.4 interface eth3"],
+ "disable": False,
+ "no_preempt": False,
+ "rfc3768_compatibility": False,
+ },
+ ],
+ "sync_groups": [
+ {
+ "name": "sg1",
+ "member": ["g1"],
+ "transition_script": {
+ "master": "/var/tmp/script.sh",
+ "backup": "/var/tmp/script.sh",
+ "fault": "/var/tmp/script.sh",
+ "stop": "/var/tmp/script.sh",
+ },
+ "health_check": {
+ "failure_count": 3,
+ "interval": 10,
+ "ping": "192.168.1.1",
+ "script": "/var/tmp/script.sh",
+ },
+ },
+ ],
+ },
+ }
+ self.assertEqual(parsed_list, result["parsed"])
+
+ def test_vrrp_gathered(self):
+ set_module_args(dict(state="gathered"))
+ result = self.execute_module(changed=False)
+ gathered_list = {
+ "disable": True,
+ "virtual_servers": [
+ {
+ "name": "s1",
+ "address": "10.10.10.1",
+ "algorithm": "round-robin",
+ "delay_loop": 60,
+ "forward_method": "direct",
+ "fwmark": 10,
+ "persistence_timeout": 30,
+ "protocol": "tcp",
+ "real_server": [
+ {
+ "address": "10.10.50.1",
+ "health_check_script": "/var/tmp/script.sh",
+ "port": 443,
+ },
+ ],
+ },
+ {
+ "name": "s2",
+ "address": "10.10.10.2",
+ "port": 81,
+ "real_server": [
+ {
+ "address": "real1",
+ "connection_timeout": 5,
+ "port": 8081,
+ },
+ {
+ "address": "real2",
+ "port": 8080,
+ },
+ ],
+ },
+ ],
+ "vrrp": {
+ "snmp": "enabled",
+ "global_parameters": {
+ "startup_delay": 30,
+ "version": "3",
+ "garp": {
+ "interval": 30,
+ "master_delay": 10,
+ "master_refresh": 100,
+ "master_refresh_repeat": 200,
+ "master_repeat": 5,
+ },
+ },
+ "groups": [
+ {
+ "name": "g1",
+ "description": "Group_1",
+ "disable": True,
+ "no_preempt": True,
+ "rfc3768_compatibility": True,
+ "interface": "eth2",
+ "address": ["1.1.1.1", "3.3.3.3", "5.5.5.5 interface eth2"],
+ "advertise_interval": 10,
+ "peer_address": "192.168.1.3",
+ "priority": 100,
+ "vrid": 20,
+ "garp": {
+ "interval": 20,
+ "master_delay": 5,
+ "master_refresh": 50,
+ "master_refresh_repeat": 100,
+ "master_repeat": 3,
+ },
+ "authentication": {
+ "type": "plaintext-password",
+ "password": "testpass",
+ },
+ "transition_script": {
+ "master": "/var/tmp/script.sh",
+ "backup": "/var/tmp/script.sh",
+ "fault": "/var/tmp/script.sh",
+ "stop": "/var/tmp/script.sh",
+ },
+ "health_check": {
+ "failure_count": 3,
+ "interval": 10,
+ "ping": "192.168.1.5",
+ "script": "script.sh",
+ },
+ "track": {
+ "exclude_vrrp_interface": True,
+ "interface": ["eth1"],
+ },
+ "excluded_address": [
+ "192.168.1.7 interface eth3",
+ "192.168.1.8",
+ ],
+ "hello_source_address": "192.168.1.2",
+ },
+ ],
+ "sync_groups": [
+ {
+ "name": "sg1",
+ "member": ["g1"],
+ "transition_script": {
+ "master": "/var/tmp/script.sh",
+ "backup": "/var/tmp/script.sh",
+ "fault": "/var/tmp/script.sh",
+ "stop": "/var/tmp/script.sh",
+ },
+ "health_check": {
+ "failure_count": 3,
+ "interval": 10,
+ "ping": "192.168.1.1",
+ "script": "/var/tmp/script.sh",
+ },
+ },
+ ],
+ },
+ }
+ self.assertEqual(gathered_list, result["gathered"])
+
+ def test_vrrp_groups_deleted(self):
+ set_module_args(
+ dict(
+ config=dict(
+ vrrp=dict(
+ groups=[
+ dict(name="g1"),
+ ],
+ sync_groups=[
+ dict(name="sg1"),
+ ],
+ ),
+ ),
+ state="deleted",
+ ),
+ )
+ commands = [
+ "delete high-availability vrrp group g1",
+ "delete high-availability vrrp sync-group sg1",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_objs_deleted(self):
+ set_module_args(
+ dict(
+ config=dict(
+ disable=False,
+ vrrp=dict(
+ global_parameters=dict(
+ startup_delay=32,
+ garp=dict(),
+ ),
+ groups=[
+ dict(name="g1"),
+ ],
+ sync_groups=[],
+ ),
+ virtual_servers=[],
+ ),
+ state="deleted",
+ ),
+ )
+ commands = [
+ "delete high-availability virtual-server",
+ "delete high-availability vrrp global-parameters garp",
+ "delete high-availability vrrp global-parameters startup-delay",
+ "delete high-availability vrrp group g1",
+ "delete high-availability vrrp sync-group",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_deleted_all(self):
+ set_module_args(
+ dict(
+ config=dict(),
+ state="deleted",
+ ),
+ )
+ commands = [
+ "delete high-availability",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrrp_purged(self):
+ set_module_args(
+ dict(
+ config=dict(),
+ state="purged",
+ ),
+ )
+ commands = [
+ "delete high-availability",
+ ]
+ self.execute_module(changed=True, commands=commands)

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 26, 11:25 AM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4225347
Default Alt Text
(395 KB)

Event Timeline