Page MenuHomeVyOS Platform

No OneTemporary

Size
59 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/module_utils/network/vyos/config/vrrp/vrrp.py b/plugins/module_utils/network/vyos/config/vrrp/vrrp.py
index 2b93a144..e0cc3036 100644
--- a/plugins/module_utils/network/vyos/config/vrrp/vrrp.py
+++ b/plugins/module_utils/network/vyos/config/vrrp/vrrp.py
@@ -1,488 +1,574 @@
#
# -*- 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_vrrp config file.
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to its desired end-state is
created.
"""
from copy import deepcopy
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import (
ResourceModule,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.vrrp import (
VrrpTemplate,
)
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 Vrrp(ResourceModule):
"""
The vyos_vrrp config class
"""
def __init__(self, module):
super(Vrrp, self).__init__(
empty_fact_val={},
facts_module=Facts(module),
module=module,
resource="vrrp",
tmplt=VrrpTemplate(),
)
self.parsers = [
"disable",
]
def _validate_template(self):
version = get_os_version(self._module)
if LooseVersion(version) >= LooseVersion("1.4"):
self._tmplt = VrrpTemplate()
else:
self._module.fail_json(msg="VRRP is not supported in this version of VyOS")
def parse(self):
"""override parse to check template"""
self._validate_template()
return super().parse()
def get_parser(self, name):
"""get_parsers"""
self._validate_template()
return super().get_parser(name)
def execute_module(self):
"""Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
if self.state not in ["parsed", "gathered"]:
self.generate_commands()
self.run_commands()
return self.result
def generate_commands(self):
"""Generate configuration commands to send based on
want, have and desired state.
"""
wantd = {}
haved = {}
wantd = deepcopy(self.want)
haved = deepcopy(self.have)
# self._module.fail_json(msg="Generate commands - want: " + str(self.want) + " (((()))) have: " + str(haved))
for entry in wantd, haved:
# self._module.fail_json(msg="Before normalize_vrrp_groups - entry: " + str(entry))
self._vrrp_groups_list_to_dict(entry)
self._virtual_servers_list_to_dict(entry)
self._vrrp_sync_groups_list_to_dict(entry)
self._normalize_lists(entry)
# self._module.fail_json(msg="Normalise - want: " + str(wantd) + " (((()))) have: " + str(haved))
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)
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)
self.compare(
parsers=self.parsers,
want={k: want},
have={k: have},
)
# for k, want in wantd.items():
# if k == "vrrp":
# if self.state in ["merged"]:
# want = combine(haved.get(k, {}), want, recursive=True)
# self._compare_vrrp(want, haved.get(k, {}))
# if k == "virtual_servers":
# if self.state in ["merged"]:
# want = combine(haved.get(k, {}), want, recursive=True)
# self._compare_vsrvs(want, haved.get(k, {}))
# self.compare(
# parsers=self.parsers,
# want={k: want},
# have={k: haved.pop(k, {})},
# )
self.commands = list(dict.fromkeys(self.commands))
self._module.fail_json(msg=self.commands)
def _compare_vsrvs(self, want, have):
"""Compare virtual servers of VRRP"""
vs_parsers = [
- "virtual_servers",
- "virtual_servers.real_server",
+ # "virtual_servers",
+ "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",
]
-
+ # self._module.fail_json(msg=have)
pairs = []
hlist = self._extract_named_leafs(have)
wlist = self._extract_named_leafs(want)
# self._module.fail_json(msg="Want: " + str(wlist) + "&&&&&&&&&&&&&&&&&&&& have: " + str(hlist))
if self.state in ["replaced", "deleted", "overridden"]:
for hdict in hlist:
wdict = self._find_matching_by_path(hdict, wlist)
pairs.append((wdict, hdict))
self.compare(
parsers=vs_parsers,
want={"virtual_servers": wdict},
have={"virtual_servers": hdict},
)
- self._module.fail_json(msg=pairs)
+ # self._module.fail_json(msg=pairs)
for wdict in wlist:
hdict = self._find_matching_by_path(wdict, hlist)
pairs.append((wdict, hdict))
self.compare(
parsers=vs_parsers,
want={"virtual_servers": wdict},
have={"virtual_servers": hdict},
)
# self._module.fail_json(msg=pairs)
def _compare_vrrp(self, want, have):
"""Compare the instances of VRRP"""
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.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",
]
pairs = []
# self._module.fail_json(msg="Compare VRRP - want: " + str(want) + " (((()))) have: " + str(have))
hlist = self._extract_leaf_items(have)
wlist = self._extract_leaf_items(want)
# self._module.fail_json(msg="leaf VRRP - want: " + str(wlist) + " (((()))) have: " + str(hlist))
if self.state in ["replaced", "deleted", "overridden"]:
for hdict in hlist:
# self._module.fail_json(msg="here")
wdict = self._find_matching_by_path(hdict, wlist)
pairs.append((wdict, hdict))
self.compare(parsers=vrrp_parsers, want={"vrrp": wdict}, have={"vrrp": hdict})
# self._module.fail_json(msg=pairs)
# else:
for wdict in wlist:
hdict = self._find_matching_by_path(wdict, hlist)
pairs.append((wdict, hdict))
self.compare(parsers=vrrp_parsers, want={"vrrp": wdict}, have={"vrrp": hdict})
# self._module.fail_json(msg=pairs)
def _vrrp_groups_list_to_dict(self, data):
vrrp = data.get("vrrp", {})
groups = vrrp.get("groups")
if not groups:
return data
if isinstance(groups, dict):
return data
if isinstance(groups, list):
new_groups = {}
for item in groups:
name = item.get("name")
if not name:
continue
new_groups[name] = item
data["vrrp"]["groups"] = new_groups
return data
return data
def _vrrp_sync_groups_list_to_dict(self, data):
vrrp = data.get("vrrp", {})
groups = vrrp.get("sync_groups")
if not groups:
return data
if isinstance(groups, dict):
return data
if isinstance(groups, list):
new_groups = {}
for item in groups:
name = item.get("name")
if not name:
continue
new_groups[name] = item
data["vrrp"]["sync_groups"] = new_groups
return data
return data
def _virtual_servers_list_to_dict(self, data):
vss = data.get("virtual_servers")
if not vss:
return data
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
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
return data
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":
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 _extract_named_leafs(self, data, parent_name=None, prefix_key=None):
- results = []
-
- if prefix_key == "real_server" and isinstance(data, dict):
- for server_name, server_data in data.items():
- if isinstance(server_data, dict):
- results.append(
- {
- "name": parent_name,
- "real_server": server_data,
- },
- )
- return results
-
- if isinstance(data, dict):
- current_name = data.get("name", parent_name)
-
- for k, v in data.items():
- if k == "name":
- continue
- leaves = self._extract_named_leafs(v, current_name, k)
- results.extend(leaves)
- return results
- return [
- {
- "name": parent_name,
- prefix_key: data,
- },
- ]
+ # def _extract_named_leafs(self, data, parent_name=None, prefix_key=None):
+ # results = []
+
+ # if prefix_key == "real_server" and isinstance(data, dict):
+ # for server_name, server_data in data.items():
+ # if isinstance(server_data, dict):
+ # results.append(
+ # {
+ # "name": parent_name,
+ # "real_server": server_data,
+ # },
+ # )
+ # return results
+
+ # if isinstance(data, dict):
+ # current_name = data.get("name", parent_name)
+
+ # for k, v in data.items():
+ # if k == "name":
+ # continue
+ # leaves = self._extract_named_leafs(v, current_name, k)
+ # results.extend(leaves)
+ # return results
+ # return [
+ # {
+ # "name": parent_name,
+ # prefix_key: data,
+ # },
+ # ]
def _lookup_by_path(self, want_item, have_list):
"""
Find matching object in have_list by structural path + name (if present).
Ignore values. Return {} if not found.
"""
def extract_signature(d):
sig = []
while isinstance(d, dict) and d:
k = next(iter(d))
sig.append(k)
d = d[k]
if isinstance(d, dict) and "name" in d:
sig.append(("name", d["name"]))
return tuple(sig)
want_sig = extract_signature(want_item)
for obj in have_list:
if extract_signature(obj) == want_sig:
return obj
return {}
def _find_matching_by_path(self, want_item, have_list):
"""
Match extracted leaf dicts from _extract_named_leafs().
Supports both container-style and flat-style leaves.
"""
+ # def build_sig(item):
+ # if not isinstance(item, dict) or not item:
+ # return ()
+
+ # if len(item) == 1:
+ # top = next(iter(item))
+ # node = item[top]
+ # sig = [top]
+
+ # if isinstance(node, dict):
+ # if "name" in node:
+ # sig.append(("name", node["name"]))
+
+ # for k, v in node.items():
+ # if k == "name":
+ # continue
+ # sig.append(k)
+
+ # if isinstance(v, dict):
+ # if k == "real_server" and "address" in v:
+ # sig.append(("address", v["address"]))
+ # else:
+ # sig.append(next(iter(v)))
+ # break
+
+ # return tuple(sig)
+
+ # sig = []
+ # if "name" in item:
+ # sig.append(("name", item["name"]))
+
+ # for k, v in item.items():
+ # if k != "name":
+ # sig.append(k)
+ # if isinstance(v, dict) and k == "real_server" and "address" in v:
+ # sig.append(("address", v["address"]))
+ # break
+
+ # return tuple(sig)
def build_sig(item):
if not isinstance(item, dict) or not item:
return ()
- if len(item) == 1:
- top = next(iter(item))
- node = item[top]
- sig = [top]
-
- if isinstance(node, dict):
- if "name" in node:
- sig.append(("name", node["name"]))
-
- for k, v in node.items():
- if k == "name":
- continue
- sig.append(k)
-
- if isinstance(v, dict):
- if k == "real_server" and "address" in v:
- sig.append(("address", v["address"]))
- else:
- sig.append(next(iter(v)))
- break
-
- return tuple(sig)
-
sig = []
+
if "name" in item:
sig.append(("name", item["name"]))
for k, v in item.items():
- if k != "name":
- sig.append(k)
- if isinstance(v, dict) and k == "real_server" and "address" in v:
- sig.append(("address", v["address"]))
- break
+ if k == "name":
+ continue
+
+ sig.append(k)
+
+ if isinstance(v, dict) and k == "real_server" and "address" in v:
+ sig.append(("address", v["address"]))
+
+ # ✅ include leaf identity
+ for leaf_key in v:
+ if leaf_key != "address":
+ sig.append(("leaf", leaf_key))
+ break
+ break
return tuple(sig)
sig_want = build_sig(want_item)
for obj in have_list:
if build_sig(obj) == sig_want:
return obj
return {}
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):
# sort the list if it contains only scalars
if all(not isinstance(i, (dict, list)) for i in v):
node[k] = sorted(v)
else:
# recurse into each item if the list contains dicts
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 project_structure(self, have, want):
"""
Project the structure of `have` onto `want`.
- Existing values in `want` are preserved
- Missing paths are created with empty values
"""
if not isinstance(have, dict):
return want
if want is None or not isinstance(want, dict):
want = {}
for key, have_val in have.items():
if key not in want:
want[key] = self.empty_like(have_val)
else:
want[key] = self.project_structure(have_val, want[key])
return want
def empty_like(self, value):
if isinstance(value, dict):
return {}
if isinstance(value, list):
return []
return None
+
+ def _extract_named_leafs(self, data, parent_name=None, prefix_key=None):
+ results = []
+
+ # 🔑 SPECIAL CASE: real_server MUST be expanded pairwise
+ if prefix_key == "real_server" and isinstance(data, dict):
+ for _, 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 # ⛔ STOP recursion here
+
+ # Generic dict handling
+ 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
+
+ # Primitive leaf
+ return [
+ {
+ "name": parent_name,
+ prefix_key: data,
+ },
+ ]
diff --git a/plugins/module_utils/network/vyos/rm_templates/vrrp.py b/plugins/module_utils/network/vyos/rm_templates/vrrp.py
index 2bf8038a..149e4b99 100644
--- a/plugins/module_utils/network/vyos/rm_templates/vrrp.py
+++ b/plugins/module_utils/network/vyos/rm_templates/vrrp.py
@@ -1,784 +1,1037 @@
# -*- 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 Vrrp 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:
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_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 VrrpTemplate(NetworkTemplate):
def __init__(self, lines=None, module=None):
prefix = {"set": "set", "remove": "delete"}
super(VrrpTemplate, 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",
+ # "getval": re.compile(
+ # r"""
+ # ^set\shigh-availability\svirtual-server
+ # \s+(?P<name>\S+)
+ # # (?:\s+address\s+(?P<address>\S+))?
+ # (?:\s+algorithm\s+(?P<algorithm>\S+))?
+ # (?:\s+delay-loop\s+(?P<delay_loop>\S+))?
+ # (?:\s+forward-method\s+(?P<forward_method>\S+))?
+ # (?:\s+fwmark\s+(?P<fwmark>\S+))?
+ # (?:\s+persistence-timeout\s+(?P<persistence_timeout>\S+))?
+ # (?:\s+port\s+(?P<port>\S+))?
+ # (?:\s+protocol\s+(?P<protocol>\S+))?
+ # $
+ # """,
+ # re.VERBOSE,
+ # ),
+ # "setval": _tmplt_vsrvs,
+ # "result": {
+ # "virtual_servers": {
+ # "{{ name }}": {
+ # "name": "{{ name }}",
+ # # "address": "{{ address if address is defined else None }}",
+ # "algorithm": "{{ algorithm if algorithm is defined else None }}",
+ # "delay_loop": "{{ delay_loop if delay_loop is defined else None }}",
+ # "forward_method": "{{ forward_method if forward_method is defined else None }}",
+ # "fwmark": "{{ fwmark if fwmark is defined else None }}",
+ # "persistence_timeout": "{{ persistence_timeout if persistence_timeout is defined else None }}",
+ # "port": "{{ port if port is defined else None }}",
+ # "protocol": "{{ protocol if protocol is defined else None }}",
+ # },
+ # },
+ # },
+ # },
{
- "name": "virtual_servers",
+ "name": "virtual_servers.address",
"getval": re.compile(
r"""
^set\shigh-availability\svirtual-server
\s+(?P<name>\S+)
(?:\s+address\s+(?P<address>\S+))?
- (?:\s+algorithm\s+(?P<algorithm>\S+))?
- (?:\s+delay-loop\s+(?P<delay_loop>\S+))?
- (?:\s+forward-method\s+(?P<forward_method>\S+))?
- (?:\s+fwmark\s+(?P<fwmark>\S+))?
- (?:\s+persistence-timeout\s+(?P<persistence_timeout>\S+))?
- (?:\s+port\s+(?P<port>\S+))?
- (?:\s+protocol\s+(?P<protocol>\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",
+ # "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+))?
+ # (?:\s+health-check\sscript\s+(?P<hcscript>\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 }}",
+ # "port": "{{ port if port is defined else None }}",
+ # "health_check_script": "{{ hcscript if hcscript is defined else None }}",
+ # "connection_timeout": "{{ cont if cont is defined else None }}",
+ # },
+ # },
+ # },
+ # },
+ # },
+ # },
{
- "name": "virtual_servers.real_server",
+ "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+))?
- (?:\s+health-check\sscript\s+(?P<hcscript>\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 }}",
"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\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+address\s+(?P<address>\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+priority\s+(?P<priority>\S+))?
(?:\s+vrid\s+(?P<vrid>\S+))?
$
""",
re.VERBOSE,
),
"setval": _tmplt_vrrp_group,
"result": {
"vrrp": {
"groups": {
"{{ gname }}": {
"name": "{{ gname }}",
"address": "{{ address if address is defined else None }}",
"description": "{{ description.strip(\"'\") 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 }}",
"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.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": "{{ True if snmp is defined else False }}",
},
},
},
{
"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

File Metadata

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

Event Timeline