Skip to content

T6820: Add HA/VRRP module#438

Open
omnom62 wants to merge 113 commits intovyos:mainfrom
omnom62:t6820_vrrp
Open

T6820: Add HA/VRRP module#438
omnom62 wants to merge 113 commits intovyos:mainfrom
omnom62:t6820_vrrp

Conversation

@omnom62
Copy link
Copy Markdown
Contributor

@omnom62 omnom62 commented Oct 20, 2025

Change Summary

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes)
  • Migration from an old Vyatta component to vyos-1x, please link to related PR inside obsoleted component
  • Other (please describe):

Related Task(s)

https://vyos.dev/T6820

Related PR(s)

Component(s) name

Proposed changes

How to test

Test results

  • Sanity tests passed
  • Unit tests passed

Tested against VyOS versions:

  • 1.4.2
  • 1.5q2

Checklist:

  • I have read the CONTRIBUTING document
  • I have linked this PR to one or more Phabricator Task(s)
  • I have run the ansible sanity and unit tests
  • My commit headlines contain a valid Task id
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have added unit tests to cover my changes
  • I have added a file to changelogs/fragments to describe the changes

@omnom62 omnom62 requested a review from a team as a code owner October 20, 2025 10:44
@omnom62 omnom62 changed the title T6820 VRRP support T6820 VRRP module Oct 20, 2025
@gaige
Copy link
Copy Markdown
Contributor

gaige commented Oct 21, 2025

@omnom62 Can you update the PR template, it seems rather empty.

@gaige
Copy link
Copy Markdown
Contributor

gaige commented Oct 21, 2025

RST file is missing as well, which is odd because that should be auto-created. Sanity checks are failing as well. This seem s not quite ready, should it be in Draft?

@omnom62 omnom62 marked this pull request as draft October 21, 2025 09:00
@omnom62
Copy link
Copy Markdown
Contributor Author

omnom62 commented Oct 21, 2025

RST file is missing as well, which is odd because that should be auto-created. Sanity checks are failing as well. This seem s not quite ready, should it be in Draft?

My bad, @gaige , yes, indeed, this is still in Draft - finishing rm_templates section

Comment thread plugins/module_utils/network/vyos/facts/vrrp/vrrp.py Outdated
@omnom62 omnom62 changed the title T6820 VRRP module WIP T6820 VRRP module Oct 29, 2025
Comment thread plugins/module_utils/network/vyos/config/vrrp/vrrp.old
Copy link
Copy Markdown
Contributor

@gaige gaige left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mostly OK with this. I do think we should consider breaking out the load balancer components, since although they are HA, they're not strictly VRRP. A few other small items and I noticed we're now failing some tests.

Comment thread plugins/module_utils/network/vyos/config/vrrp/vrrp.py Outdated
Comment thread plugins/modules/vyos_ha.py
Comment thread tests/integration/targets/vyos_ha/tests/cli/deleted_all.yaml Outdated
Comment thread tests/integration/targets/vyos_vrrp/tests/cli/deleted_objs.yaml Outdated
Comment thread tests/integration/targets/vyos_vrrp/tests/cli/parsed.yaml Outdated
Comment thread tests/integration/targets/vyos_vrrp/tests/cli/rendered.yaml Outdated
@omnom62
Copy link
Copy Markdown
Contributor Author

omnom62 commented Mar 9, 2026

Speaking about the linter and spaces around '|' - I have found a number of such expressions in tests and modules.
Attn @gaige

@omnom62 omnom62 requested a review from gaige March 17, 2026 19:59
@omnom62 omnom62 changed the title T6820: Add VRRP module T6820: Add HA/VRRP module Mar 17, 2026
@omnom62 omnom62 marked this pull request as draft March 22, 2026 21:47
auto-merge was automatically disabled March 22, 2026 21:47

Pull request was converted to draft

@omnom62 omnom62 changed the title T6820: Add HA/VRRP module WIP T6820: Add HA/VRRP module Mar 22, 2026
@omnom62 omnom62 changed the title WIP T6820: Add HA/VRRP module T6820: Add HA/VRRP module Apr 2, 2026
@omnom62 omnom62 marked this pull request as ready for review April 2, 2026 20:36
Copilot AI review requested due to automatic review settings April 17, 2026 12:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new vyos_ha network resource module to manage High Availability configuration (VRRP + LVS virtual servers) on VyOS, including facts support and full test coverage.

Changes:

  • Introduces vyos_ha module plus argspec/config/facts/template plumbing for render/parse/gather/merge/replace/override/delete/purge.
  • Adds unit + integration (CLI) test suites and fixtures for HA/VRRP workflows.
  • Wires module into collection routing, changelog, README, sanity ignores, and repo housekeeping.

Reviewed changes

Copilot reviewed 41 out of 46 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/unit/modules/network/vyos/test_vyos_ha.py New unit tests for vyos_ha behaviors across all supported states.
tests/unit/modules/network/vyos/fixtures/vyos_ha_config.cfg Fixture running-config used by unit tests for HA parsing/gathering.
tests/sanity/ignore-2.22.txt Adds action plugin docs ignore entry for new ha action plugin.
tests/sanity/ignore-2.21.txt Same as above for Ansible 2.21 sanity profile.
tests/sanity/ignore-2.20.txt Same as above for Ansible 2.20 sanity profile.
tests/sanity/ignore-2.19.txt Same as above for Ansible 2.19 sanity profile.
tests/sanity/ignore-2.18.txt Same as above for Ansible 2.18 sanity profile.
tests/sanity/ignore-2.17.txt Same as above for Ansible 2.17 sanity profile.
tests/sanity/ignore-2.16.txt Same as above for Ansible 2.16 sanity profile.
tests/sanity/ignore-2.15.txt Same as above for Ansible 2.15 sanity profile.
tests/integration/targets/vyos_ha/vars/main.yaml Integration test data: before/after configs and expected command sets for each state.
tests/integration/targets/vyos_ha/tests/cli/rtt.yaml Round-trip (facts → config → revert) integration test.
tests/integration/targets/vyos_ha/tests/cli/replaced.yaml Integration test coverage for state: replaced + idempotency.
tests/integration/targets/vyos_ha/tests/cli/rendered.yaml Integration test for offline rendering (state: rendered).
tests/integration/targets/vyos_ha/tests/cli/purged.yaml Integration test for state: purged + idempotency.
tests/integration/targets/vyos_ha/tests/cli/parsed.yaml Integration test for parsing a provided running config (state: parsed).
tests/integration/targets/vyos_ha/tests/cli/overridden.yaml Integration test for state: overridden + idempotency.
tests/integration/targets/vyos_ha/tests/cli/merged.yaml Integration test for state: merged + idempotency.
tests/integration/targets/vyos_ha/tests/cli/gathered.yaml Integration test for state: gathered vs facts output.
tests/integration/targets/vyos_ha/tests/cli/empty_config.yaml Integration tests for expected error messages on empty config inputs.
tests/integration/targets/vyos_ha/tests/cli/deleted_vrrp_groups.yaml Integration test deleting VRRP groups/sync-groups by name.
tests/integration/targets/vyos_ha/tests/cli/deleted_bulk.yaml Integration test deleting “stub”/bulk objects and verifying after-state.
tests/integration/targets/vyos_ha/tests/cli/deleted_all.yaml Integration test for state: deleted with empty config (delete everything) + idempotency.
tests/integration/targets/vyos_ha/tests/cli/_remove_config.yaml Helper to purge HA config and clean up dummy scripts before/after tests.
tests/integration/targets/vyos_ha/tests/cli/_populate_config.yaml Helper to pre-populate device config for scenario tests.
tests/integration/targets/vyos_ha/tests/cli/_parsed.cfg Input config used by parsed-state integration test.
tests/integration/targets/vyos_ha/tests/cli/_add_dummy_scripts.yaml Helper to create dummy scripts referenced by HA config.
tests/integration/targets/vyos_ha/tasks/main.yaml Integration test entrypoint for vyos_ha target.
tests/integration/targets/vyos_ha/tasks/cli.yaml Test harness to discover/run per-scenario CLI testcases.
tests/integration/targets/vyos_ha/defaults/main.yaml Default vars for testcase selection/discovery.
plugins/modules/vyos_ha.py New public module with DOCUMENTATION/EXAMPLES/RETURN and module entrypoint.
plugins/module_utils/network/vyos/utils/utils.py Extends combine() to support multiple list-merge modes used by HA merge behavior.
plugins/module_utils/network/vyos/rm_templates/ha.py New resource template: parsers + command generation for HA/VRRP/LVS.
plugins/module_utils/network/vyos/facts/ha/ha.py New facts gatherer/parser/normalizer for HA resource into ansible_network_resources.
plugins/module_utils/network/vyos/facts/ha/init.py Initializes HA facts package.
plugins/module_utils/network/vyos/facts/facts.py Registers ha facts provider in the facts dispatcher map.
plugins/module_utils/network/vyos/config/ha/ha.py New ResourceModule implementation for HA state machine + diff/compare logic.
plugins/module_utils/network/vyos/config/ha/init.py Initializes HA config package.
plugins/module_utils/network/vyos/argspec/ha/ha.py Auto-generated argspec for HA module options/structure.
plugins/module_utils/network/vyos/argspec/ha/init.py Initializes HA argspec package.
meta/runtime.yml Adds plugin routing redirect for havyos_ha.
changelogs/fragments/t6820_vrrp.yml Changelog fragment announcing HA/VRRP support.
README.md Adds vyos_ha to the module listing table.
.gitignore Ignores *.bak files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

]
self.execute_module(changed=True, commands=commands)

def test_ntp_replaced_idempotent(self):
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test name looks copy/pasted (test_ntp_replaced_idempotent) but the content is HA/VRRP. Rename to reflect the HA module/state being tested so failures are discoverable in CI output.

Copilot uses AI. Check for mistakes.
vrrp_snmp = re.search(r"set high-availability vrrp snmp", config_line)

if vrrp_disable:
config_dict["disable"] = [config_dict.get("disable", "") + config_line]
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The disable bucket is built with config_dict.get("disable", "") + config_line and then wrapped in a list; if the input ever contains multiple matching lines this will throw (list + str) and it also drops line separation. Use the same pattern as the other sections (e.g., setdefault("disable", []).append(config_line)).

Suggested change
config_dict["disable"] = [config_dict.get("disable", "") + config_line]
config_dict.setdefault("disable", []).append(config_line)

Copilot uses AI. Check for mistakes.
existing = vrrp_facts[section].get(name, {})
vrrp_facts[section][name] = self.deep_merge(existing, data)

ansible_facts["ansible_network_resources"].pop("vrrp", None)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This facts module updates ansible_network_resources['ha'], but it pops the unrelated key vrrp. This should likely be pop('ha', None) (or whatever key this facts module uses) to avoid leaving stale HA facts around across runs.

Suggested change
ansible_facts["ansible_network_resources"].pop("vrrp", None)
ansible_facts["ansible_network_resources"].pop("ha", None)

Copilot uses AI. Check for mistakes.
return connection.get('show configuration commands | match "set high-availability"')

def get_config_set(self, data, connection):
"""To classify the configurations beased on high availability sections"""
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in docstring: "beased" → "based".

Suggested change
"""To classify the configurations beased on high availability sections"""
"""To classify the configurations based on high availability sections"""

Copilot uses AI. Check for mistakes.
Comment on lines +291 to +311
# """
# Merge two dictionaries (shallow or deep).
# :param a: dict
# :param b: dict
# :param recursive: bool, deep merge
# :param list_merge: str, only 'replace' is supported (default Ansible behavior)
# """
# if not isinstance(a, dict) or not isinstance(b, dict):
# raise ValueError("combine expects two dictionaries")

# result = a.copy()

# for k, v in b.items():
# if recursive and k in result and isinstance(result[k], dict) and isinstance(v, dict):
# result[k] = combine(result[k], v, recursive=True, list_merge=list_merge)
# else:
# result[k] = v

# return result


Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the large commented-out previous implementation of combine(); keeping dead code in-tree makes future maintenance harder and obscures the current behavior.

Suggested change
# """
# Merge two dictionaries (shallow or deep).
# :param a: dict
# :param b: dict
# :param recursive: bool, deep merge
# :param list_merge: str, only 'replace' is supported (default Ansible behavior)
# """
# if not isinstance(a, dict) or not isinstance(b, dict):
# raise ValueError("combine expects two dictionaries")
# result = a.copy()
# for k, v in b.items():
# if recursive and k in result and isinstance(result[k], dict) and isinstance(v, dict):
# result[k] = combine(result[k], v, recursive=True, list_merge=list_merge)
# else:
# result[k] = v
# return result

Copilot uses AI. Check for mistakes.
Comment on lines +322 to +331
if isinstance(vss, dict):
for vs in vss.items():
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
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_virtual_servers_list_to_dict() incorrectly iterates over a dict with for vs in vss.items(); vs will be a (key, value) tuple, so vs.get(...) / vs[...] will raise. Iterate over vss.values() (or for _, vs in vss.items():) and update the dict values instead.

Copilot uses AI. Check for mistakes.
],
},
}
self.assertEqual(sorted(parsed_list), sorted(result["parsed"]))
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assertions only compare sorted dict keys (since iterating a dict yields keys), so the test can pass even when the parsed structure is wrong. Compare the full dicts (or use assertDictEqual) after normalizing ordering as needed.

Copilot uses AI. Check for mistakes.
},
}

self.assertEqual(sorted(gathered_list), sorted(result["gathered"]))
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: sorting a dict compares only keys, not values. This should assert equality of the full gathered structure (optionally after normalizing list ordering).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

6 participants