Page MenuHomeVyOS Platform

No OneTemporary

Size
118 KB
Referenced Files
None
Subscribers
None
diff --git a/changelogs/fragments/t9427_vrf_bgp_global_as.yml b/changelogs/fragments/t9427_vrf_bgp_global_as.yml
new file mode 100644
index 00000000..b35b995d
--- /dev/null
+++ b/changelogs/fragments/t9427_vrf_bgp_global_as.yml
@@ -0,0 +1,12 @@
+---
+minor_changes:
+ - vyos_vrf, vyos_bgp_global - Add error message for missing as_number (T9427).
+ - vyos_bgp_global - additional UAT/SIT test cases
+bugfixes:
+ - vyos_bgp_global - setting log_neighbor_changes no longer also sets
+ no-client-to-client-reflection, and no_client_to_client_reflection is now rendered on its own;
+ on a route reflector, enabling neighbour-change logging silently stopped reflection between
+ clients (VyOS 1.4 and later) (T9411).
+ - vyos_bgp_global - peer-group definitions (neighbor entries with peer_group true) are
+ configured as protocols bgp peer-group instead of an invalid neighbor, and are read back
+ from the device (VyOS 1.4 and later) (T9417).
diff --git a/plugins/module_utils/network/vyos/config/bgp_global/bgp_global.py b/plugins/module_utils/network/vyos/config/bgp_global/bgp_global.py
index 2d7d3e63..2c69ee29 100644
--- a/plugins/module_utils/network/vyos/config/bgp_global/bgp_global.py
+++ b/plugins/module_utils/network/vyos/config/bgp_global/bgp_global.py
@@ -1,415 +1,435 @@
#
# -*- 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
+import re
+
+
__metaclass__ = type
"""
The vyos_bgp_global 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 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 (
dict_merge,
)
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.bgp_global import (
Bgp_globalTemplate,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_global_14 import (
Bgp_globalTemplate14,
)
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 Bgp_global(ResourceModule):
"""
The vyos_bgp_global config class
"""
def __init__(self, module):
super(Bgp_global, self).__init__(
empty_fact_val={},
facts_module=Facts(module),
module=module,
resource="bgp_global",
tmplt=Bgp_globalTemplate(),
)
self.parsers = []
def _validate_template(self):
version = get_os_version(self._module)
if LooseVersion(version) >= LooseVersion("1.4"):
self._tmplt = Bgp_globalTemplate14()
else:
self._tmplt = Bgp_globalTemplate()
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
"""
version = get_os_version(self._module)
if LooseVersion(version) >= LooseVersion("1.4"):
self._asn_mod = ""
else:
self._asn_mod = " " + str(self.have.get("as_number"))
self._validate_template()
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 = {}
+ if self.want and self.want.get("as_number") is None and self.state != "deleted":
+ self._module.fail_json(
+ msg="as_number is required: VyOS needs a system-as for every BGP "
+ "instance, including the BGP instance of each VRF",
+ )
+
if (
self.want.get("as_number") == self.have.get("as_number")
or not self.have
or LooseVersion(get_os_version(self._module)) >= LooseVersion("1.4")
):
if self.want:
wantd = {self.want["as_number"]: self.want}
if self.have:
haved = {self.have["as_number"]: self.have}
else:
self._module.fail_json(msg="Only one bgp instance is allowed per device")
# turn all lists of dicts into dicts prior to merge
for entry in wantd, haved:
self._bgp_global_list_to_dict(entry)
# if state is merged, merge want onto have and then compare
if self.state == "merged":
wantd = dict_merge(haved, wantd)
# if state is deleted, empty out wantd and set haved to wantd
if self.state == "purged":
h_del = {}
for k, v in haved.items():
if k in wantd or not wantd:
h_del.update({k: v})
for num, entry in h_del.items():
self.commands.append(self._tmplt.render({"as_number": num}, "router", True))
wantd = {}
if self.state == "deleted":
self._compare(want={}, have=self.have)
wantd = {}
for k, want in wantd.items():
self._compare(want=want, have=haved.pop(k, {}))
def _compare(self, want, have):
"""Leverages the base class `compare()` method and
populates the list of commands to be run by comparing
the `want` and `have` data with the `parsers` defined
for the Bgp_global network resource.
"""
if LooseVersion(get_os_version(self._module)) >= LooseVersion("1.4"):
self._compare_asn(want, have)
parsers = ["maximum_paths", "timers"]
self._compare_neighbor(want, have)
self._compare_bgp_params(want, have)
for name, entry in want.items():
if name != "as_number":
self.compare(
parsers=parsers,
want={"as_number": want["as_number"], name: entry},
have={
"as_number": want["as_number"],
name: have.pop(name, {}),
},
)
for name, entry in have.items():
if name != "as_number":
self.compare(
parsers=parsers,
want={},
have={"as_number": have["as_number"], name: entry},
)
# Do the negation first
command_set = []
for cmd in self.commands:
if cmd not in command_set:
if "delete" in cmd:
command_set.insert(0, cmd)
else:
command_set.append(cmd)
self.commands = command_set
def _compare_neighbor(self, want, have):
parsers = [
"neighbor.advertisement_interval",
"neighbor.allowas_in",
"neighbor.as_override",
"neighbor.attribute_unchanged.as_path",
"neighbor.attribute_unchanged.med",
"neighbor.attribute_unchanged.next_hop",
"neighbor.capability_dynamic",
"neighbor.capability_orf",
"neighbor.default_originate",
"neighbor.description",
"neighbor.disable_capability_negotiation",
"neighbor.disable_connected_check",
"neighbor.disable_send_community",
"neighbor.distribute_list",
"neighbor.ebgp_multihop",
"neighbor.filter_list",
"neighbor.local_as",
"neighbor.maximum_prefix",
"neighbor.nexthop_self",
"neighbor.override_capability",
"neighbor.passive",
"neighbor.password",
"neighbor.peer_group_name",
"neighbor.port",
"neighbor.prefix_list",
"neighbor.remote_as",
"neighbor.remove_private_as",
"neighbor.route_map",
"neighbor.route_reflector_client",
"neighbor.route_server_client",
"neighbor.shutdown",
"neighbor.soft_reconfiguration",
"neighbor.strict_capability_match",
"neighbor.unsuppress_map",
"neighbor.update_source",
"neighbor.weight",
"neighbor.ttl_security",
"neighbor.timers",
]
wneigh = want.pop("neighbor", {})
hneigh = have.pop("neighbor", {})
+ peer_groups = [n for d in (wneigh, hneigh) for n, e in d.items() if e.get("peer_group")]
+ first = len(self.commands)
self._compare_neigh_lists(wneigh, hneigh)
for name, entry in wneigh.items():
for k, v in entry.items():
if k == "address":
continue
if hneigh.get(name):
h = {"address": name, k: hneigh[name].pop(k, {})}
else:
h = {}
self.compare(
parsers=parsers,
want={
"as_number": want["as_number"],
"neighbor": {"address": name, k: v},
},
have={"as_number": want["as_number"], "neighbor": h},
)
for name, entry in hneigh.items():
if name not in wneigh.keys():
if self._check_af(name):
msg = "Use the _bgp_address_family module to delete the address_family under neighbor {0}, before replacing/deleting the neighbor.".format(
name,
)
self._module.fail_json(msg=msg)
else:
self.commands.append(
"delete protocols bgp" + self._asn_mod + " neighbor " + name,
)
continue
for k, v in entry.items():
self.compare(
parsers=parsers,
want={},
have={
"as_number": have["as_number"],
"neighbor": {"address": name, k: v},
},
)
+ # peer-group definitions are compared like neighbors, then renamed
+ for i, cmd in enumerate(self.commands[first:], first):
+ for name in peer_groups:
+ cmd = re.sub(
+ r"^(\S+ protocols bgp )neighbor " + re.escape(name) + r"(?= |$)",
+ r"\1peer-group " + name,
+ cmd,
+ )
+ self.commands[i] = cmd
def _compare_bgp_params(self, want, have):
parsers = [
"bgp_params.always_compare_med",
"bgp_params.bestpath.as_path",
"bgp_params.bestpath.compare_routerid",
"bgp_params.bestpath.med",
"bgp_params.cluster_id",
"bgp_params.confederation",
"bgp_params.dampening_half_life",
"bgp_params.dampening_max_suppress_time",
"bgp_params.dampening_re_use",
"bgp_params.dampening_start_suppress_time",
"bgp_params.default",
"bgp_params.deterministic_med",
"bgp_params.disbale_network_import_check",
"bgp_params.enforce_first_as",
"bgp_params.graceful_restart",
"bgp_params.log_neighbor_changes",
"bgp_params.no_client_to_client_reflection",
"bgp_params.no_fast_external_failover",
"bgp_params.routerid",
"bgp_params.scan_time",
]
wbgp = want.pop("bgp_params", {})
hbgp = have.pop("bgp_params", {})
for name, entry in wbgp.items():
if name == "confederation":
if entry != hbgp.pop(name, {}):
self.addcmd(
{
"as_number": want["as_number"],
"bgp_params": {name: entry},
},
"bgp_params.confederation",
False,
)
elif name == "distance":
if entry != hbgp.pop(name, {}):
distance_parsers = [
"bgp_params.distance.global",
"bgp_params.distance.prefix",
]
for distance_type in entry:
self.compare(
parsers=distance_parsers,
want={
"as_number": want["as_number"],
"bgp_params": {name: distance_type},
},
have={
"as_number": want["as_number"],
"bgp_params": {name: hbgp.pop(name, {})},
},
)
else:
self.compare(
parsers=parsers,
want={
"as_number": want["as_number"],
"bgp_params": {name: entry},
},
have={
"as_number": want["as_number"],
"bgp_params": {name: hbgp.pop(name, {})},
},
)
if not wbgp and hbgp:
self.commands.append("delete protocols bgp" + self._asn_mod + " parameters")
hbgp = {}
for name, entry in hbgp.items():
if name == "confederation":
self.commands.append(
"delete protocols bgp" + self._asn_mod + " parameters confederation",
)
elif name == "distance":
distance_parsers = [
"bgp_params.distance.global",
"bgp_params.distance.prefix",
]
self.compare(
parsers=distance_parsers,
want={},
have={
"as_number": have["as_number"],
"bgp_params": {name: entry[0]},
},
)
else:
self.compare(
parsers=parsers,
want={},
have={
"as_number": have["as_number"],
"bgp_params": {name: entry},
},
)
def _compare_neigh_lists(self, want, have):
for attrib in [
"distribute_list",
"filter_list",
"prefix_list",
"route_map",
]:
wdict = want.pop(attrib, {})
hdict = have.pop(attrib, {})
for key, entry in wdict.items():
if entry != hdict.pop(key, {}):
self.addcmd(entry, "neighbor.{0}".format(attrib), False)
# remove remaining items in have for replaced
for entry in hdict.values():
self.addcmd(entry, "neighbor.{0}".format(attrib), True)
def _bgp_global_list_to_dict(self, entry):
for name, proc in entry.items():
if "neighbor" in proc:
neigh_dict = {}
for entry in proc.get("neighbor", []):
neigh_dict.update({entry["address"]: entry})
proc["neighbor"] = neigh_dict
if "network" in proc:
network_dict = {}
for entry in proc.get("network", []):
network_dict.update({entry["address"]: entry})
proc["network"] = network_dict
if "aggregate_address" in proc:
agg_dict = {}
for entry in proc.get("aggregate_address", []):
agg_dict.update({entry["prefix"]: entry})
proc["aggregate_address"] = agg_dict
if "redistribute" in proc:
redis_dict = {}
for entry in proc.get("redistribute", []):
redis_dict.update({entry["protocol"]: entry})
proc["redistribute"] = redis_dict
def _compare_asn(self, want, have):
if want.get("as_number") and not have.get("as_number"):
self.commands.append(
"set protocols bgp " + "system-as" + " " + str(want.get("as_number")),
)
def _check_af(self, neighbor):
af_present = False
if self._connection:
config_lines = self._get_config(self._connection).splitlines()
for line in config_lines:
if neighbor in line:
if "address-family" in line:
af_present = True
return af_present
def _get_config(self, connection):
return connection.get(
'show configuration commands | match "set protocols bgp .*neighbor"',
)
diff --git a/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py b/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py
index cf2e4475..f05968a2 100644
--- a/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py
+++ b/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py
@@ -1,91 +1,101 @@
# -*- 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 bgp_global 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.bgp_global.bgp_global import (
Bgp_globalArgs,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_global import (
Bgp_globalTemplate,
)
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.bgp_global_14 import (
Bgp_globalTemplate14,
)
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 Bgp_globalFacts(object):
"""The vyos bgp_global facts class"""
def __init__(self, module, subspec="config", options="options"):
self._module = module
self.argument_spec = Bgp_globalArgs.argument_spec
def get_device_data(self, connection):
return connection.get('show configuration commands | match "set protocols bgp"')
def populate_facts(self, connection, ansible_facts, data=None):
"""Populate the facts for Bgp_global network resource
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
facts = {}
objs = {}
config_lines = []
if not data:
data = self.get_device_data(connection)
+ peer_groups = set()
for resource in data.splitlines():
if "address-family" not in resource:
- config_lines.append(re.sub("'", "", resource))
+ line = re.sub("'", "", resource)
+ # parse peer-group definitions with the neighbor parsers
+ match = re.match(r"^set protocols bgp peer-group (\S+)(.*)$", line)
+ if match:
+ peer_groups.add(match.group(1))
+ line = "set protocols bgp neighbor " + "".join(match.groups())
+ config_lines.append(line)
if LooseVersion(get_os_version(self._module)) >= LooseVersion("1.4"):
bgp_global_parser = Bgp_globalTemplate14(lines=config_lines, module=self._module)
else:
bgp_global_parser = Bgp_globalTemplate(lines=config_lines, module=self._module)
objs = bgp_global_parser.parse()
if "neighbor" in objs:
+ for name in peer_groups & set(objs["neighbor"]):
+ objs["neighbor"][name]["peer_group"] = True
objs["neighbor"] = list(objs["neighbor"].values())
objs["neighbor"] = sorted(objs["neighbor"], key=lambda k: k["address"])
if "network" in objs:
objs["network"] = sorted(objs["network"], key=lambda k: k["address"])
if "aggregate_address" in objs:
objs["aggregate_address"] = sorted(objs["aggregate_address"], key=lambda k: k["prefix"])
ansible_facts["ansible_network_resources"].pop("bgp_global", None)
params = utils.remove_empties(
bgp_global_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
)
facts["bgp_global"] = params.get("config", [])
ansible_facts["ansible_network_resources"].update(facts)
return ansible_facts
diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py b/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py
index b86e233c..c041328b 100644
--- a/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py
+++ b/plugins/module_utils/network/vyos/rm_templates/bgp_global_14.py
@@ -1,1763 +1,1765 @@
# -*- 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 Bgp_global 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_bgp_params_confederation(config_data):
command = []
for list_el in config_data["bgp_params"]["confederation"]:
for k, v in list_el.items():
command.append(
"protocols bgp parameters confederation ".format(**config_data) + k + " " + str(v),
)
return command
def _tmplt_bgp_maximum_paths(config_data):
command = []
for list_el in config_data["maximum_paths"]:
command.append(
"protocols bgp maximum-paths ".format(**config_data)
+ list_el["path"]
+ " "
+ str(list_el["count"]),
)
return command
def _tmplt_delete_bgp_maximum_paths(config_data):
command = "protocols bgp maximum-paths".format(**config_data)
return command
def _tmplt_bgp_params_default(config_data):
command = "protocols bgp parameters default".format(**config_data)
if config_data["bgp_params"]["default"].get("no_ipv4_unicast"):
command += " no-ipv4-unicast"
if config_data["bgp_params"]["default"].get("local_pref"):
command += " local-pref {local_pref}".format(**config_data["bgp_params"]["default"])
return command
def _tmplt_bgp_neighbor_timers(config_data):
command = []
for k, v in config_data["neighbor"]["timers"].items():
command.append(
"protocols bgp neighbor ".format(**config_data)
+ config_data["neighbor"]["address"]
+ " timers "
+ k
+ " "
+ str(v),
)
return command
def _tmplt_bgp_timers(config_data):
command = []
for k, v in config_data["timers"].items():
command.append(
"protocols bgp ".format(**config_data) + "timers " + k + " " + str(v),
)
return command
def _tmplt_bgp_neighbor_attribute_unchanged_as_path(config_data):
command = "protocols bgp ".format(
**config_data,
) + "neighbor {address} attribute-unchanged as-path".format(**config_data["neighbor"])
return command
def _tmplt_bgp_neighbor_attribute_unchanged_med(config_data):
command = "protocols bgp ".format(
**config_data,
) + "neighbor {address} attribute-unchanged med".format(**config_data["neighbor"])
return command
def _tmplt_bgp_neighbor_attribute_unchanged_next_hop(config_data):
command = "protocols bgp ".format(
**config_data,
) + "neighbor {address} attribute-unchanged next-hop".format(**config_data["neighbor"])
return command
def _tmplt_bgp_neighbor_distribute_list(config_data):
command = []
for list_el in config_data["neighbor"]["distribute_list"]:
command.append(
"protocols bgp ".format(**config_data)
+ "neighbor {address} distribute-list ".format(**config_data["neighbor"])
+ list_el["action"]
+ " "
+ str(list_el["acl"]),
)
return command
def _tmplt_bgp_neighbor_route_map(config_data):
command = []
for list_el in config_data["neighbor"]["route_map"]:
command.append(
"protocols bgp ".format(**config_data)
+ "neighbor {address} route-map ".format(**config_data["neighbor"])
+ list_el["action"]
+ " "
+ str(list_el["route_map"]),
)
return command
def _tmplt_bgp_neighbor_prefix_list(config_data):
command = []
for list_el in config_data["neighbor"]["prefix_list"]:
command.append(
"protocols bgp ".format(**config_data)
+ "neighbor {address} prefix-list ".format(**config_data["neighbor"])
+ list_el["action"]
+ " "
+ str(list_el["prefix_list"]),
)
return command
def _tmplt_bgp_neighbor_filter_list(config_data):
command = []
for list_el in config_data["neighbor"]["filter_list"]:
command.append(
"protocols bgp ".format(**config_data)
+ "neighbor {address} filter-list ".format(**config_data["neighbor"])
+ list_el["action"]
+ " "
+ str(list_el["path_list"]),
)
return command
def _tmplt_bgp_params_distance(config_data):
command = (
"protocols bgp parameters distance global ".format(**config_data)
+ config_data["bgp_params"]["distance"]["type"]
+ " "
+ str(config_data["bgp_params"]["distance"]["value"])
)
return command
class Bgp_globalTemplate14(NetworkTemplate):
def __init__(self, lines=None, module=None):
prefix = {"set": "set", "remove": "delete"}
super(Bgp_globalTemplate14, self).__init__(
lines=lines,
tmplt=self,
prefix=prefix,
module=module,
)
# fmt: off
PARSERS = [
{
"name": "router",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s*system-as
\s+(?P<as_num>\d+)
*$""",
re.VERBOSE,
),
"setval": "protocols bgp system-as {{ as_number }}",
"remval": "protocols bgp",
"compval": "as_number",
"result": {
"as_number": "{{ as_num }}",
},
},
{
"name": "maximum_paths",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+maximum-paths
\s+(?P<path>ebgp|ibgp)
\s+(?P<count>\d+)
*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_maximum_paths,
"remval": _tmplt_delete_bgp_maximum_paths,
"compval": "maximum_paths",
"result": {
"as_number": "{{ as_num }}",
"maximum_paths": [
{
"path": "{{ path }}",
"count": "{{ count }}",
},
],
},
},
{
"name": "neighbor.advertisement_interval",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+advertisement-interval
\s+(?P<interval>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} advertisement-interval {{ neighbor.advertisement_interval }}",
"remval": "protocols bgp neighbor {{ neighbor.address }} advertisement-interval",
"compval": "neighbor.advertisement_interval",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"advertisement_interval": "{{ interval }}",
},
},
},
},
{
"name": "neighbor.allowas_in",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+allowas-in
\s+number
\s+(?P<num>\'\d+\')
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} allowas-in number {{ neighbor.allowas_in }}",
"compval": "neighbor.allowas_in",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"allowas_in": "{{ count }}",
},
},
},
},
{
"name": "neighbor.as_override",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+as-override
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} as-override",
"compval": "neighbor.as_override",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"as_override": "{{ True }}",
},
},
},
},
{
"name": "neighbor.attribute_unchanged.as_path",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+attribute-unchanged
\s+(?P<val>as-path)
*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_attribute_unchanged_as_path,
"compval": "neighbor.attribute_unchanged",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"attribute_unchanged": {
"{{ 'as_path' }}": "{{ True }}",
},
},
},
},
},
{
"name": "neighbor.attribute_unchanged.med",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+attribute-unchanged
\s+(?P<val>med)
*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_attribute_unchanged_med,
"compval": "neighbor.attribute_unchanged",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"attribute_unchanged": {
"{{ 'med' }}": "{{ True }}",
},
},
},
},
},
{
"name": "neighbor.attribute_unchanged.next_hop",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+attribute-unchanged
\s+(?P<val>next-hop)
*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_attribute_unchanged_next_hop,
"compval": "neighbor.attribute_unchanged",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"attribute_unchanged": {
"{{ 'next_hop' }}": "{{ True }}",
},
},
},
},
},
{
"name": "neighbor.capability_dynamic",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+capability
\s+(?P<dynamic>dynamic)
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} capability dynamic",
"compval": "neighbor.capability.dynamic",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"capability": {
"dynamic": "{{ True if dynamic is defined}}",
},
},
},
},
},
{
"name": "neighbor.capability_orf",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+capability
\s+orf
\s+prefix-list
\s+(?P<orf>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} capability orf prefix-list {{ neighbor.capability.orf }}",
"compval": "neighbor.capability.orf",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"capability": {
"orf": "{{ orf }}",
},
},
},
},
},
{
"name": "neighbor.default_originate",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+default-originate
\s+route-map
\s+(?P<map>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} default-originate route-map {{ neighbor.default_originate }}",
"compval": "neighbor.advertisement_interval",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"default_originate": "{{ map }}",
},
},
},
},
{
"name": "neighbor.description",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+description
\s+(?P<desc>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} description {{ neighbor.description }}",
"compval": "neighbor.description",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"description": "{{ desc }}",
},
},
},
},
{
"name": "neighbor.disable_capability_negotiation",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+disable-capability-negotiation
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} disable-capability-negotiation",
"compval": "neighbor.disable_capability_negotiation",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"disable_capability_negotiation": "{{ True }}",
},
},
},
},
{
"name": "neighbor.disable_connected_check",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+disable-connected-check
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} disable-connected-check",
"compval": "neighbor.disable_connected_check",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"disable_connected_check": "{{ True }}",
},
},
},
},
{
"name": "neighbor.disable_send_community",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+disable-send-community
\s+(?P<comm>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} disable-send-community {{ neighbor.disable_send_community }}",
"compval": "neighbor.disable_send_community",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"disable_send_community": "{{ comm }}",
},
},
},
},
{
"name": "neighbor.distribute_list",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+distribute-list
\s+(?P<action>export|import)
\s+(?P<list>\d+)
*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_distribute_list,
"compval": "neighbor.distribute_list",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"distribute_list": [
{
"action": "{{ action }}",
"acl": "{{ list }}",
},
],
},
},
},
},
{
"name": "neighbor.ebgp_multihop",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+ebgp-multihop
\s+(?P<hop>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} ebgp-multihop {{ neighbor.ebgp_multihop }}",
"compval": "neighbor.ebgp_multihop",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"ebgp_multihop": "{{ hop|int }}",
},
},
},
},
{
"name": "neighbor.filter_list",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+filter-list
\s+(?P<action>export|import)
\s+(?P<list>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_filter_list,
"compval": "neighbor.filter_list",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"filter_list": [
{
"action": "{{ action }}",
"path_list": "{{ list }}",
},
],
},
},
},
},
{
"name": "neighbor.local_as",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+local-as
\s+(?P<as>\S+)
\s+no-prepend
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} local-as {{ neighbor.local_as }} no-prepend",
"compval": "neighbor.local_as",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"local_as": "{{ as }}",
},
},
},
},
{
"name": "neighbor.maximum_prefix",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+maximum-prefix
\s+(?P<num>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} maximum-prefix {{ neighbor.maximum_prefix }}",
"compval": "neighbor.maximum_prefix",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"maximum_prefix": "{{ num }}",
},
},
},
},
{
"name": "neighbor.nexthop_self",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+nexthop-self
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} nexthop-self",
"compval": "neighbor.nexthop_self",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"nexthop_self": "{{ True }}",
},
},
},
},
{
"name": "neighbor.override_capability",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+override-capability
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} override-capability",
"compval": "neighbor.override_capability",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"override_capability": "{{ True }}",
},
},
},
},
{
"name": "neighbor.passive",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+passive
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} passive",
"compval": "neighbor.passive",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"passive": "{{ True }}",
},
},
},
},
{
"name": "neighbor.password",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+password
\s+(?P<pwd>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} password {{ neighbor.password }}",
"compval": "neighbor.password",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"password": "{{ pwd }}",
},
},
},
},
{
"name": "neighbor.peer_group_name",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+peer-group
\s+(?P<name>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} peer-group {{ neighbor.peer_group_name }}",
"compval": "neighbor.peer_group_name",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"peer_group_name": "{{ name }}",
},
},
},
},
{
"name": "neighbor.port",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+port
\s+(?P<num>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} port {{ neighbor.port }}",
"compval": "neighbor.port",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"port": "{{ num|int }}",
},
},
},
},
{
"name": "neighbor.prefix_list",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+prefix-list
\s+(?P<action>export|import)
\s+(?P<list>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_prefix_list,
"compval": "neighbor.prefix_list",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"prefix_list": [
{
"action": "{{ action }}",
"prefix_list": "{{ list }}",
},
],
},
},
},
},
{
"name": "neighbor.remote_as",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+remote-as
\s+(?P<num>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} remote-as {{ neighbor.remote_as }}",
"compval": "neighbor.remote_as",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"remote_as": "{{ num|int }}",
},
},
},
},
{
"name": "neighbor.remove_private_as",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+remote-private-as
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} remote-private-as",
"compval": "neighbor.remove_private_as",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"remove_private_as": "{{ True }}",
},
},
},
},
{
"name": "neighbor.route_map",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+route-map
\s+(?P<action>export|import)
\s+(?P<map>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_route_map,
"compval": "neighbor.route_map",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"route_map": [
{
"action": "{{ action }}",
"route_map": "{{ map }}",
},
],
},
},
},
},
{
"name": "neighbor.route_reflector_client",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+route-reflector-client
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} router-reflector-client",
"compval": "neighbor.route_reflector_client",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"route_reflector_client": "{{ True }}",
},
},
},
},
{
"name": "neighbor.route_server_client",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+route-server-client
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} route-server-client",
"compval": "neighbor.route_server_client",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"route_server_client": "{{ True }}",
},
},
},
},
{
"name": "neighbor.shutdown",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+shutdown
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} shutdown",
"compval": "neighbor.shutdown",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"shutdown": "{{ True }}",
},
},
},
},
{
"name": "neighbor.soft_reconfiguration",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+soft-reconfiguration
\s+inbound
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} soft-reconfiguration",
"compval": "neighbor.soft_reconfiguration",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"soft_reconfiguration": "{{ True }}",
},
},
},
},
{
"name": "neighbor.strict_capability_match",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+strict-capability-match
*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} strict-capability-match",
"compval": "neighbor.strict_capability_match",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"strict_capability_match": "{{ True }}",
},
},
},
},
{
"name": "neighbor.unsuppress_map",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+unsuppress-map
\s+(?P<map>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} unsuppress-map {{ neighbor.unsuppress_map }}",
"compval": "neighbor.unsuppress_map",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"unsuppress_map": "{{ map }}",
},
},
},
},
{
"name": "neighbor.update_source",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+update-source
\s+(?P<src>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} update-source {{ neighbor.update_source }}",
"compval": "neighbor.update_source",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"update_source": "{{ src }}",
},
},
},
},
{
"name": "neighbor.weight",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+weight
\s+(?P<num>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} weight {{ neighbor.weight }}",
"compval": "neighbor.weight",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"weight": "{{ num }}",
},
},
},
},
{
"name": "neighbor.ttl_security",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+ttl-security
\s+(?P<ttl>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp neighbor {{ neighbor.address }} ttl-security {{ neighbor.ttl_security }}",
"compval": "neighbor.ttl_security",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"ttl_security": "{{ ttl|int }}",
},
},
},
},
{
"name": "neighbor.timers",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+neighbor
\s+(?P<address>\S+)
\s+timers
\s+(?P<type>connect|holdtime|keepalive)
\s+(?P<sec>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_neighbor_timers,
"remval": "protocols bgp neighbor {{ neighbor.address }} timers",
"compval": "neighbor.timers",
"result": {
"as_number": "{{ as_num }}",
"neighbor": {
"{{ address }}": {
"address": "{{ address }}",
"timers": {
"{{ type }}": "{{ sec }}",
},
},
},
},
},
{
"name": "timers",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+timers
\s+(?P<type>\S+)
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_timers,
"remval": "protocols bgp timers",
"compval": "timers",
"result": {
"as_number": "{{ as_num }}",
"timers": {
"{{ type }}": "{{ val }}",
},
},
},
{
"name": "bgp_params.always_compare_med",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+always-compare-med
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters always-compare-med",
"compval": "bgp_params.always_compare_med",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"always_compare_med": "{{ True }}",
},
},
},
{
"name": "bgp_params.bestpath.as_path",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+bestpath
\s+as-path
\s+(?P<path>confed|ignore)
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters bestpath as-path {{ bgp_params.bestpath.as_path }}",
"compval": "bgp_params.bestpath.as_path",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"bestpath": {
"as_path": "{{ path }}",
},
},
},
},
{
"name": "bgp_params.bestpath.compare_routerid",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+bestpath
\s+compare-routerid
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters bestpath compare-routerid",
"compval": "bgp_params.bestpath.compare_routerid",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"bestpath": {
"compare_routerid": "{{ True }}",
},
},
},
},
{
"name": "bgp_params.bestpath.med",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+bestpath
\s+med
\s+(?P<path>confed|missing-as-worst)
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters bestpath med {{ bestpath.med }}",
"compval": "bgp_params.bestpath.med",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"bestpath": {
"med": "{{ path }}",
},
},
},
},
{
"name": "bgp_params.cluster_id",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+cluster-id
\s+(?P<id>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters cluster-id {{ bgp_params.cluster_id }}",
"compval": "bgp_params.cluster_id",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"cluster_id": "{{ id }}",
},
},
},
{
"name": "bgp_params.confederation",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+confederation
\s+(?P<type>identifier|peers)
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_params_confederation,
"compval": "bgp_params.always_compare_med",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"confederation": [
{
"peers": "{{ val if type == 'peers' }}",
"identifier": "{{ val if type == 'identifier' }}",
},
],
},
},
},
{
"name": "bgp_params.dampening_half_life",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+dampening
\s+half-life
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters dampening half-life {{ bgp_params.dampening.half_life}}",
"compval": "bgp_params.dampening.half_life",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"dampening": {
"half_life": "{{ val }}",
},
},
},
},
{
"name": "bgp_params.dampening_max_suppress_time",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+dampening
\s+max-suppress-time
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters dampening max-suppress-time {{ bgp_params.dampening.max_suppress_time}}",
"compval": "bgp_params.dampening.max_suppress_time",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"dampening": {
"max_suppress_time": "{{ val }}",
},
},
},
},
{
"name": "bgp_params.dampening_re_use",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+dampening
\s+re-use
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters dampening re-use {{ bgp_params.dampening.re_use}}",
"compval": "bgp_params.dampening.re_use",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"dampening": {
"re_use": "{{ val }}",
},
},
},
},
{
"name": "bgp_params.dampening_start_suppress_time",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+dampening
\s+start-suppress-time
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters dampening start-suppress-time {{ bgp_params.dampening.start_suppress_time}}",
"compval": "bgp_params.dampening.start_suppress_time",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"dampening": {
"start_suppress_time": "{{ val }}",
},
},
},
},
{
"name": "bgp_params.default",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+default
\s*(?P<no_ipv4_unicast>no-ipv4-unicast)?
\s*(?P<local_pref>local-pref\s\S+)?\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_params_default,
"remval": "protocols bgp parameters default",
"compval": "bgp_params.default",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"default": {
"no_ipv4_unicast": "{{ True if no_ipv4_unicast is defined }}",
"local_pref": "{{ local_pref.split(" " )[1] if local_pref is defined }}",
},
},
},
},
{
"name": "bgp_params.deterministic_med",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+deterministic-med
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters deterministic-med",
"compval": "bgp_params.deterministic_med",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"deterministic_med": "{{ True }}",
},
},
},
{
"name": "bgp_params.disbale_network_import_check",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+disable-network-import-check
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters disable-network-import-check",
"compval": "bgp_params.disable_network_import_check",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"disable_network_import_check": "{{ True }}",
},
},
},
{
"name": "bgp_params.distance.prefix",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+distance\sprefix
\s+(?P<prefix>\S+)
\s+distance
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters distance prefix {{ bgp_params.distance.prefix }} distance {{ bgp_params.distance.value }}",
"compval": "bgp_params.distance.prefix",
"remval": "protocols bgp parameters distance prefix",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"distance": [
{
"prefix": "{{ prefix }}",
"value": "{{ val }}",
},
],
},
},
},
{
"name": "bgp_params.distance.global",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+distance\sglobal
\s+(?P<type>\S+)
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": _tmplt_bgp_params_distance,
"remval": "protocols bgp parameters distance global",
"compval": "bgp_params.distance",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"distance": [
{
"type": "{{ type }}",
"value": "{{ val }}",
},
],
},
},
},
{
"name": "bgp_params.enforce_first_as",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+enforce-first-as
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters enforce-first-as",
"compval": "bgp_params.enforce_first_as",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"enforce_first_as": "{{ True }}",
},
},
},
{
"name": "bgp_params.graceful_restart",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+graceful-restart\s+stalepath-time
\s+(?P<val>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters graceful-restart stalepath-time {{ bgp_params.graceful_restart }}",
"compval": "bgp_params.graceful_restart",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"graceful_restart": "{{ val }}",
},
},
},
{
"name": "bgp_params.log_neighbor_changes",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+log-neighbor-changes
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters log-neighbor-changes",
"compval": "bgp_params.log_neighbor_changes",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"log_neighbor_changes": "{{ True }}",
},
},
},
{
"name": "bgp_params.no_client_to_client_reflection",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+no-client-to-client-reflection
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters no-client-to-client-reflection",
- "compval": "bgp_params.log_neighbor_changes",
+ # "compval": "bgp_params.log_neighbor_changes",
+ "compval": "bgp_params.no_client_to_client_reflection",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"no_client_to_client_reflection": "{{ True }}",
},
},
},
{
"name": "bgp_params.no_fast_external_failover",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+no-fast-external-failover
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters no-fast-external-failover",
"compval": "bgp_params.no_fast_external_failover",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"no_fast_external_failover": "{{ True }}",
},
},
},
{
"name": "bgp_params.routerid",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+router-id
\s+(?P<id>\S+)\s*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters router-id {{ bgp_params.router_id }}",
"compval": "bgp_params.router_id",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"router_id": "{{ id }}",
},
},
},
{
"name": "bgp_params.scan_time",
"getval": re.compile(
r"""
^set
\s+protocols
\s+bgp
\s+parameters
\s+scan-time
\s+(?P<sec>\d+)
*$""",
re.VERBOSE,
),
"setval": "protocols bgp parameters scan-time {{ bgp_params.scan_time }}",
"compval": "bgp_params.scan_time",
"result": {
"as_number": "{{ as_num }}",
"bgp_params": {
"scan_time": "{{ val }}",
},
},
},
]
# fmt: on
diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml
index 82fead73..36e9b92b 100644
--- a/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml
+++ b/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml
@@ -1,19 +1,48 @@
---
- debug:
msg: START vyos_bgp_global gathered integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Gather config from the device in structured format.
register: result
vyos.vyos.vyos_bgp_global:
state: gathered
- vyos.vyos.vyos_facts:
gather_network_resources: bgp_global
- assert:
that:
- result.changed == false
- result.gathered == ansible_facts['network_resources']['bgp_global']
+
+- include_tasks: _get_version.yaml
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: setup peer group
+ vyos.vyos.vyos_config:
+ lines:
+ - set protocols bgp system-as 65536
+ - set protocols bgp peer-group RR-CLIENTS remote-as '65536'
+ - set protocols bgp peer-group RR-CLIENTS update-source 'lo'
+ - set protocols bgp neighbor 192.0.2.1 peer-group 'RR-CLIENTS'
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+
+ - name: Gather the peer group from the device
+ register: result
+ vyos.vyos.vyos_bgp_global:
+ state: gathered
+
+ - assert:
+ that:
+ - result.changed == false
+ - result.gathered == gathered_peer_group.config
+
+ when: vyos_version is version('1.4.0', '>=', version_type='semver')
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml
index e11cd1ef..3223f976 100644
--- a/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml
+++ b/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml
@@ -1,48 +1,140 @@
---
- debug:
msg: START vyos_bgp_global merged integration tests on connection={{ ansible_connection }}
- include_tasks: _remove_config.yaml
- include_tasks: _preconfig.yaml
- block:
- name: Merge the provided configuration with the existing running configuration
register: result
vyos.vyos.vyos_bgp_global: &id001
config:
as_number: "65536"
timers:
keepalive: 35
bgp_params:
bestpath:
as_path: confed
compare_routerid: true
default:
local_pref: 100
router_id: 192.1.2.9
state: merged
- vyos.vyos.vyos_facts:
gather_network_resources: bgp_global
- assert:
that:
- result.commands|length == merged.commands | length
- result.changed == true
- result.commands|symmetric_difference(merged.commands) == []
- result.after == ansible_facts['network_resources']['bgp_global']
- result.before == {}
- result.after == merged.after
- name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
register: result
vyos.vyos.vyos_bgp_global: *id001
- name: Assert that the previous task was idempotent
assert:
that:
- result['changed'] == false
always:
- include_tasks: _remove_config.yaml
+
+- include_tasks: _get_version.yaml
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: Merge a peer group and a member
+ register: result
+ vyos.vyos.vyos_bgp_global: &id002
+ config:
+ as_number: 65536
+ neighbor:
+ - address: RR-CLIENTS
+ peer_group: true
+ remote_as: 65536
+ update_source: lo
+ - address: 192.0.2.1
+ peer_group_name: RR-CLIENTS
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: bgp_global
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(merged_peer_group.commands) == []
+ - result.after == ansible_facts['network_resources']['bgp_global']
+ - result.after == merged_peer_group.after
+
+ - name: Merge a peer group and a member (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_bgp_global: *id002
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ when: vyos_version is version('1.4.0', '>=', version_type='semver')
+ always:
+ - include_tasks: _remove_config.yaml
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: Merge log-neighbor-changes only
+ register: result
+ vyos.vyos.vyos_bgp_global: &id003
+ config:
+ as_number: 65536
+ bgp_params:
+ log_neighbor_changes: true
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: bgp_global
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(merged_reflection.commands) == []
+ - result.after == ansible_facts['network_resources']['bgp_global']
+ - result.after == merged_reflection.after
+
+ - name: Merge log-neighbor-changes only (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_bgp_global: *id003
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ - name: Merge without as_number
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_bgp_global:
+ config:
+ neighbor:
+ - address: 192.0.2.1
+ remote_as: 65002
+ state: merged
+
+ - assert:
+ that:
+ - result.failed == true
+ - "'as_number is required' in result.msg"
+
+ when: vyos_version is version('1.4.0', '>=', version_type='semver')
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml
index 22323c3d..5b41ec9a 100644
--- a/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml
+++ b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml
@@ -1,59 +1,109 @@
---
- debug:
msg: START vyos_bgp_global replaced integration tests on connection={{ ansible_connection }}
- include_tasks: _populate.yaml
- block:
- name: Replace the existing configuration with the provided running configuration
register: result
vyos.vyos.vyos_bgp_global: &id001
config:
as_number: "65536"
bgp_params:
always_compare_med: true
dampening:
start_suppress_time: 5
max_suppress_time: 20
half_life: 33
re_use: 60
bestpath:
as_path: confed
compare_routerid: true
neighbor:
- address: 192.0.2.43
disable_connected_check: true
advertisement_interval: 72
capability:
dynamic: true
timers:
holdtime: 30
keepalive: 10
remote_as: 102
- address: 203.0.113.0
capability:
dynamic: true
remote_as: 102
state: replaced
- vyos.vyos.vyos_facts:
gather_network_resources: bgp_global
- assert:
that:
- result.commands|length == replaced.commands|length
- result.changed == true
- result.commands|symmetric_difference(replaced.commands) == []
- result.after == ansible_facts['network_resources']['bgp_global']
- name: Replace the existing configuration with the provided running configuration (IDEMPOTENT)
register: result
vyos.vyos.vyos_bgp_global: *id001
- name: Assert that the previous task was idempotent
assert:
that:
- result['changed'] == false
always:
- include_tasks: _remove_config.yaml
+
+- include_tasks: _get_version.yaml
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: setup peer group
+ vyos.vyos.vyos_config:
+ lines:
+ - set protocols bgp system-as 65536
+ - set protocols bgp peer-group RR-CLIENTS remote-as '65536'
+ - set protocols bgp peer-group RR-CLIENTS update-source 'lo'
+ - set protocols bgp neighbor 192.0.2.1 peer-group 'RR-CLIENTS'
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+
+ - name: Replace the peer group without update-source
+ register: result
+ vyos.vyos.vyos_bgp_global: &id002
+ config:
+ as_number: 65536
+ neighbor:
+ - address: RR-CLIENTS
+ peer_group: true
+ remote_as: 65536
+ - address: 192.0.2.1
+ peer_group_name: RR-CLIENTS
+ state: replaced
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: bgp_global
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(replaced_peer_group.commands) == []
+ - result.after == ansible_facts['network_resources']['bgp_global']
+
+ - name: Replace the peer group without update-source (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_bgp_global: *id002
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ when: vyos_version is version('1.4.0', '>=', version_type='semver')
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_bgp_global/vars/v1_4.yaml b/tests/integration/targets/vyos_bgp_global/vars/v1_4.yaml
index 1dd462b1..8c023592 100644
--- a/tests/integration/targets/vyos_bgp_global/vars/v1_4.yaml
+++ b/tests/integration/targets/vyos_bgp_global/vars/v1_4.yaml
@@ -1,90 +1,130 @@
---
merged:
commands:
- set protocols bgp system-as 65536
- set protocols bgp parameters bestpath as-path confed
- set protocols bgp parameters bestpath compare-routerid
- set protocols bgp parameters default local-pref 100
- set protocols bgp parameters router-id 192.1.2.9
- set protocols bgp timers keepalive 35
after:
as_number: 65536
bgp_params:
bestpath:
as_path: confed
compare_routerid: true
default:
local_pref: 100
router_id: 192.1.2.9
timers:
keepalive: 35
replaced:
commands:
- delete protocols bgp timers
- delete protocols bgp parameters router-id 192.1.2.9
- delete protocols bgp parameters default
- delete protocols bgp parameters confederation
- delete protocols bgp neighbor 5001::64
- delete protocols bgp neighbor 203.0.113.5
- delete protocols bgp neighbor 192.0.2.25
- set protocols bgp neighbor 192.0.2.43 disable-connected-check
- set protocols bgp neighbor 192.0.2.43 advertisement-interval 72
- set protocols bgp neighbor 192.0.2.43 capability dynamic
- set protocols bgp neighbor 192.0.2.43 timers holdtime 30
- set protocols bgp neighbor 192.0.2.43 timers keepalive 10
- set protocols bgp neighbor 192.0.2.43 remote-as 102
- set protocols bgp neighbor 203.0.113.0 capability dynamic
- set protocols bgp neighbor 203.0.113.0 remote-as 102
- set protocols bgp parameters always-compare-med
- set protocols bgp parameters dampening half-life 33
- set protocols bgp parameters dampening max-suppress-time 20
- set protocols bgp parameters dampening re-use 60
- set protocols bgp parameters dampening start-suppress-time 5
deleted:
commands:
- delete protocols bgp timers
- delete protocols bgp parameters
- delete protocols bgp neighbor 5001::64
- delete protocols bgp neighbor 203.0.113.5
- delete protocols bgp neighbor 192.0.2.25
rendered:
commands:
- set interfaces ethernet eth1 firewall in name 'INBOUND'
- set interfaces ethernet eth1 firewall out name 'OUTBOUND'
- set interfaces ethernet eth1 firewall local name 'LOCAL'
- set interfaces ethernet eth1 firewall local ipv6-name 'V6-LOCAL'
- set interfaces ethernet eth2 firewall in name 'INBOUND'
- set interfaces ethernet eth2 firewall out name 'OUTBOUND'
- set interfaces ethernet eth2 firewall local name 'LOCAL'
- set interfaces ethernet eth2 firewall local ipv6-name 'V6-LOCAL'
populate:
global:
as_number: 65536
bgp_params:
bestpath:
as_path: confed
compare_routerid: true
confederation:
- identifier: 66
- peers: 20
- peers: 55
router_id: 192.1.2.9
neighbor:
- address: 192.0.2.25
disable_connected_check: true
timers:
holdtime: 30
keepalive: 10
remote_as: 102
- address: 203.0.113.5
ebgp_multihop: 2
remote_as: 101
update_source: 192.0.2.25
- address: 5001::64
remote_as: 103
timers:
keepalive: 35
+
+merged_peer_group:
+ commands:
+ - set protocols bgp system-as 65536
+ - set protocols bgp peer-group RR-CLIENTS remote-as 65536
+ - set protocols bgp peer-group RR-CLIENTS update-source lo
+ - set protocols bgp neighbor 192.0.2.1 peer-group RR-CLIENTS
+ after:
+ as_number: 65536
+ neighbor:
+ - address: 192.0.2.1
+ peer_group_name: RR-CLIENTS
+ - address: RR-CLIENTS
+ peer_group: true
+ remote_as: 65536
+ update_source: lo
+
+merged_reflection:
+ commands:
+ - set protocols bgp system-as 65536
+ - set protocols bgp parameters log-neighbor-changes
+ after:
+ as_number: 65536
+ bgp_params:
+ log_neighbor_changes: true
+
+replaced_peer_group:
+ commands:
+ - delete protocols bgp peer-group RR-CLIENTS update-source lo
+
+gathered_peer_group:
+ config:
+ as_number: 65536
+ neighbor:
+ - address: 192.0.2.1
+ peer_group_name: RR-CLIENTS
+ - address: RR-CLIENTS
+ peer_group: true
+ remote_as: 65536
+ update_source: lo
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_peer_group_config_14.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_peer_group_config_14.cfg
new file mode 100644
index 00000000..e492aea5
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_peer_group_config_14.cfg
@@ -0,0 +1,4 @@
+set protocols bgp system-as '65001'
+set protocols bgp peer-group RR-CLIENTS remote-as '65001'
+set protocols bgp peer-group RR-CLIENTS update-source 'lo'
+set protocols bgp neighbor 192.0.2.1 peer-group 'RR-CLIENTS'
diff --git a/tests/unit/modules/network/vyos/test_vyos_bgp_global14.py b/tests/unit/modules/network/vyos/test_vyos_bgp_global14.py
index cf4a377b..d8268504 100644
--- a/tests/unit/modules/network/vyos/test_vyos_bgp_global14.py
+++ b/tests/unit/modules/network/vyos/test_vyos_bgp_global14.py
@@ -1,494 +1,468 @@
# (c) 2016 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_bgp_global
from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args
from .vyos_module import TestVyosModule, load_fixture
class TestVyosBgpglobalModule(TestVyosModule):
module = vyos_bgp_global
def setUp(self):
super(TestVyosBgpglobalModule, 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_execute_show_command_config = patch(
"ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global.Bgp_global._get_config",
)
self.execute_show_command_config = self.mock_execute_show_command_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.bgp_global.bgp_global.Bgp_globalFacts.get_device_data",
)
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.bgp_global.bgp_global.get_os_version",
)
self.test_version = "1.4"
self.get_os_version = self.mock_get_os_version.start()
self.get_os_version.return_value = self.test_version
self.mock_facts_get_os_version = patch(
"ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_global.bgp_global.get_os_version",
)
self.get_facts_os_version = self.mock_facts_get_os_version.start()
self.get_facts_os_version.return_value = self.test_version
self.maxDiff = None
def tearDown(self):
super(TestVyosBgpglobalModule, self).tearDown()
self.mock_get_resource_connection_config.stop()
self.mock_get_resource_connection_facts.stop()
self.mock_execute_show_command.stop()
self.mock_execute_show_command_config.stop()
self.mock_get_os_version.stop()
self.mock_facts_get_os_version.stop()
def load_fixtures(self, commands=None, filename=None):
if filename is None:
filename = "vyos_bgp_global_config_14.cfg"
def load_from_file(*args, **kwargs):
output = load_fixture(filename)
return output
self.execute_show_command.side_effect = load_from_file
self.execute_show_command_config.side_effect = load_from_file
def test_vyos_bgp_global_merged_idempotent(self):
set_module_args(
dict(
config=dict(
as_number="65536",
neighbor=[
dict(
address="10.0.0.4",
disable_connected_check=True,
timers=dict(holdtime=30, keepalive=10),
),
dict(
address="192.168.0.2",
ebgp_multihop=2,
remote_as="65535",
update_source="192.168.0.1",
),
dict(
address="2001:db8::2",
ebgp_multihop=2,
remote_as="65535",
update_source="2001:db8::1",
),
],
- # network=[
- # dict(address="172.16.42.32/27", backdoor=True),
- # dict(address="172.16.42.251/32", route_map="map01"),
- # ],
bgp_params=dict(
bestpath=dict(as_path="confed", compare_routerid=True),
default=dict(no_ipv4_unicast=True),
router_id="10.1.1.1",
),
- # redistribute=[
- # dict(protocol="kernel", route_map="map01"),
- # dict(protocol="static", metric=20),
- # dict(protocol="static", route_map="map01"),
- # ],
),
state="merged",
),
)
self.execute_module(changed=False, commands=[])
def test_vyos_bgp_global_merged(self):
set_module_args(
dict(
config=dict(
as_number="65536",
neighbor=[
dict(
address="2001:db8::2",
ebgp_multihop=2,
remote_as="65535",
update_source="2001:db8::1",
),
],
bgp_params=dict(
confederation=[dict(peers=20), dict(identifier=66)],
router_id="10.1.1.1",
),
),
state="merged",
),
)
commands = [
"set protocols bgp parameters confederation peers 20",
"set protocols bgp parameters confederation identifier 66",
]
self.execute_module(changed=True, commands=commands)
def test_vyos_bgp_global_replaced_idempotent(self):
set_module_args(
dict(
config=dict(
as_number="65536",
neighbor=[
dict(
address="10.0.0.4",
disable_connected_check=True,
timers=dict(holdtime=30, keepalive=10),
),
dict(
address="192.168.0.2",
ebgp_multihop=2,
remote_as="65535",
update_source="192.168.0.1",
),
dict(
address="2001:db8::2",
ebgp_multihop=2,
remote_as="65535",
update_source="2001:db8::1",
),
],
- # network=[
- # dict(address="172.16.42.32/27", backdoor=True),
- # dict(address="172.16.42.251/32", route_map="map01"),
- # ],
bgp_params=dict(
bestpath=dict(as_path="confed", compare_routerid=True),
default=dict(no_ipv4_unicast=True),
router_id="10.1.1.1",
),
- # redistribute=[
- # dict(protocol="kernel", route_map="map01"),
- # dict(protocol="static", metric=20),
- # dict(protocol="static", route_map="map01"),
- # ],
),
state="replaced",
),
)
self.execute_module(changed=False, commands=[])
- #
def test_vyos_bgp_global_replaced(self):
set_module_args(
dict(
config=dict(
as_number="65536",
timers=dict(holdtime=30, keepalive=10),
neighbor=[
dict(
address="200.11.155.3",
),
dict(
address="2001:db8::2",
remote_as="65535",
default_originate="map01",
),
],
bgp_params=dict(
log_neighbor_changes=True,
no_client_to_client_reflection=True,
confederation=[dict(peers=20), dict(identifier=66)],
router_id="10.1.1.1",
),
),
state="replaced",
),
)
commands = [
"delete protocols bgp parameters default",
"delete protocols bgp parameters bestpath compare-routerid",
"delete protocols bgp parameters bestpath as-path confed",
- # "delete protocols bgp network",
- # "delete protocols bgp redistribute",
"delete protocols bgp neighbor 2001:db8::2 update-source 2001:db8::1",
"delete protocols bgp neighbor 2001:db8::2 ebgp-multihop 2",
"delete protocols bgp neighbor 192.168.0.2",
"delete protocols bgp neighbor 10.0.0.4",
"set protocols bgp parameters log-neighbor-changes",
"set protocols bgp parameters no-client-to-client-reflection",
"set protocols bgp parameters confederation peers 20",
"set protocols bgp parameters confederation identifier 66",
"set protocols bgp timers holdtime 30",
"set protocols bgp timers keepalive 10",
]
self.execute_module(changed=True, commands=commands)
#
def test_vyos_bgp_global_purged(self):
set_module_args(dict(config=dict(as_number="65536"), state="purged"))
#
commands = ["delete protocols bgp"]
self.execute_module(changed=True, commands=commands)
- #
- # def test_vyos_bgp_global_incorrect_instance(self):
- # set_module_args(
- # dict(
- # config=dict(
- # as_number="100",
- # timers=dict(holdtime=30, keepalive=10),
- # neighbor=[
- # dict(
- # address="200.11.155.3",
- # allowas_in=10,
- # ),
- # dict(
- # address="2001:db8::2",
- # remote_as="65535",
- # as_override=True,
- # default_originate="map01",
- # route_map=[
- # dict(action="export", route_map="map01"),
- # ],
- # ),
- # ],
- # bgp_params=dict(
- # log_neighbor_changes=True,
- # no_client_to_client_reflection=True,
- # confederation=[dict(peers=20), dict(identifier=66)],
- # router_id="10.1.1.1",
- # ),
- # ),
- # state="replaced",
- # ),
- # )
- # result = self.execute_module(failed=True)
- # self.assertIn("Only one bgp instance is allowed per device", result["msg"])
-
def test_vyos_bgp_global_replaced_af(self):
set_module_args(
dict(
config=dict(
as_number="65536",
timers=dict(holdtime=30, keepalive=10),
neighbor=[
dict(
address="200.11.155.3",
),
dict(
address="2001:db8::2",
remote_as="65535",
default_originate="map01",
),
],
bgp_params=dict(
log_neighbor_changes=True,
no_client_to_client_reflection=True,
confederation=[dict(peers=20), dict(identifier=66)],
router_id="10.1.1.1",
),
),
state="replaced",
),
)
result = self.execute_module(failed=True, filename="vyos_bgp_global_af_config_14.cfg")
self.assertIn(
"Use the _bgp_address_family module to delete the address_family under neighbor 5001::64, before replacing/deleting the neighbor.",
result["msg"],
)
+ def test_vyos_bgp_global_missing_as_number(self):
+ set_module_args(
+ dict(
+ config=dict(neighbor=[dict(address="192.0.2.1", remote_as=65002)]),
+ state="merged",
+ ),
+ )
+ result = self.execute_module(failed=True)
+ self.assertIn("as_number is required", result["msg"])
+
def test_vyos_bgp_global_rendered(self):
set_module_args(
dict(
config=dict(
as_number="65536",
neighbor=[
dict(
address="10.0.0.4",
disable_connected_check=True,
timers=dict(holdtime=30, keepalive=10),
),
dict(
address="192.168.0.2",
ebgp_multihop=2,
remote_as="65535",
update_source="192.168.0.1",
),
dict(
address="2001:db8::2",
ebgp_multihop=2,
remote_as="65535",
update_source="2001:db8::1",
),
],
- # network=[
- # dict(address="172.16.42.32/27", backdoor=True),
- # dict(address="172.16.42.251/32", route_map="map01"),
- # ],
bgp_params=dict(
bestpath=dict(as_path="confed", compare_routerid=True),
default=dict(no_ipv4_unicast=True),
router_id="10.1.1.1",
),
- # redistribute=[
- # dict(protocol="kernel", route_map="map01"),
- # dict(protocol="static", metric=20),
- # dict(protocol="static", route_map="map01"),
- # ],
),
state="rendered",
),
)
rendered_cmds = [
"set protocols bgp system-as 65536",
"set protocols bgp neighbor 10.0.0.4 disable-connected-check",
"set protocols bgp neighbor 10.0.0.4 timers holdtime 30",
"set protocols bgp neighbor 10.0.0.4 timers keepalive 10",
"set protocols bgp neighbor 192.168.0.2 ebgp-multihop 2",
"set protocols bgp neighbor 192.168.0.2 remote-as 65535",
"set protocols bgp neighbor 192.168.0.2 update-source 192.168.0.1",
"set protocols bgp neighbor 2001:db8::2 ebgp-multihop 2",
"set protocols bgp neighbor 2001:db8::2 remote-as 65535",
"set protocols bgp neighbor 2001:db8::2 update-source 2001:db8::1",
- # "set protocols bgp redistribute kernel route-map map01",
- # "set protocols bgp redistribute static route-map map01",
- # "set protocols bgp network 172.16.42.32/27 backdoor",
- # "set protocols bgp network 172.16.42.251/32 route-map map01",
"set protocols bgp parameters bestpath as-path confed",
"set protocols bgp parameters bestpath compare-routerid",
"set protocols bgp parameters default no-ipv4-unicast",
"set protocols bgp parameters router-id 10.1.1.1",
]
result = self.execute_module(changed=False)
self.assertEqual(
sorted(result["rendered"]),
sorted(rendered_cmds),
result["rendered"],
)
def test_vyos_bgp_global_parsed(self):
commands = [
"set protocols bgp system-as 65536",
"set protocols bgp neighbor 10.0.0.4 disable-connected-check",
"set protocols bgp neighbor 10.0.0.4 timers holdtime 30",
"set protocols bgp neighbor 10.0.0.4 timers keepalive 10",
"set protocols bgp neighbor 192.168.0.2 ebgp-multihop 2",
"set protocols bgp neighbor 192.168.0.2 remote-as 65535",
"set protocols bgp neighbor 192.168.0.2 update-source 192.168.0.1",
"set protocols bgp neighbor 2001:db8::2 ebgp-multihop 2",
"set protocols bgp neighbor 2001:db8::2 remote-as 65535",
"set protocols bgp neighbor 2001:db8::2 update-source 2001:db8::1",
- # "set protocols bgp redistribute kernel route-map map01",
- # "set protocols bgp redistribute static route-map map01",
- # "set protocols bgp network 172.16.42.32/27 backdoor",
- # "set protocols bgp network 172.16.42.251/32 route-map map01",
"set protocols bgp parameters bestpath as-path confed",
"set protocols bgp parameters bestpath compare-routerid",
"set protocols bgp parameters default no-ipv4-unicast",
"set protocols bgp parameters router-id 10.1.1.1",
]
parsed_str = "\n".join(commands)
set_module_args(dict(running_config=parsed_str, state="parsed"))
result = self.execute_module(changed=False)
parsed_list = {
"as_number": 65536,
"bgp_params": {
"bestpath": {"as_path": "confed", "compare_routerid": True},
"default": {"no_ipv4_unicast": True},
"router_id": "10.1.1.1",
},
"neighbor": [
{
"address": "10.0.0.4",
"disable_connected_check": True,
"timers": {"holdtime": 30, "keepalive": 10},
},
{
"address": "192.168.0.2",
"ebgp_multihop": 2,
"remote_as": 65535,
"update_source": "192.168.0.1",
},
{
"address": "2001:db8::2",
"ebgp_multihop": 2,
"remote_as": 65535,
"update_source": "2001:db8::1",
},
],
- # "network": [
- # {"address": "172.16.42.32/27", "backdoor": True},
- # {"address": "172.16.42.251/32", "route_map": "map01"},
- # ],
- # "redistribute": [
- # {"protocol": "kernel", "route_map": "map01"},
- # {"protocol": "static", "route_map": "map01"},
- # ],
}
self.assertEqual(sorted(parsed_list), sorted(result["parsed"]))
def test_vyos_bgp_global_gathered(self):
set_module_args(dict(state="gathered"))
result = self.execute_module(changed=False)
gather_list = {
"as_number": 65536,
"bgp_params": {
"bestpath": {"as_path": "confed", "compare_routerid": True},
"default": {"no_ipv4_unicast": True},
"router_id": "10.1.1.1",
},
"neighbor": [
{
"address": "10.0.0.4",
"disable_connected_check": True,
"timers": {"holdtime": 30, "keepalive": 10},
},
{
"address": "192.168.0.2",
"ebgp_multihop": 2,
"remote_as": 65535,
"update_source": "192.168.0.1",
},
{
"address": "2001:db8::2",
"ebgp_multihop": 2,
"remote_as": 65535,
"update_source": "2001:db8::1",
},
],
- # "network": [
- # {"address": "172.16.42.32/27", "backdoor": True},
- # {"address": "172.16.42.251/32", "route_map": "map01"},
- # ],
- # "redistribute": [
- # {"protocol": "kernel", "route_map": "map01"},
- # {"metric": 20, "protocol": "static"},
- # {"protocol": "static", "route_map": "map01"},
- # ],
}
self.assertEqual(sorted(gather_list), sorted(result["gathered"]))
+
+ def test_vyos_bgp_global_reflection_flags_independent(self):
+ self.get_os_version.return_value = "1.5"
+ set_module_args(
+ dict(
+ config=dict(as_number=65001, bgp_params=dict(log_neighbor_changes=True)),
+ state="rendered",
+ ),
+ )
+ cmds = self.execute_module(changed=False)["rendered"]
+ self.assertIn("set protocols bgp parameters log-neighbor-changes", cmds)
+ self.assertFalse(any("no-client-to-client-reflection" in c for c in cmds))
+
+ set_module_args(
+ dict(
+ config=dict(as_number=65001, bgp_params=dict(no_client_to_client_reflection=True)),
+ state="rendered",
+ ),
+ )
+ cmds = self.execute_module(changed=False)["rendered"]
+ self.assertIn("set protocols bgp parameters no-client-to-client-reflection", cmds)
+ self.assertFalse(any("log-neighbor-changes" in c for c in cmds))
+
+ def test_vyos_bgp_global_peer_group_rendered(self):
+ self.get_os_version.return_value = "1.5"
+ group = dict(address="RR-CLIENTS", peer_group=True, remote_as=65001, update_source="lo")
+ member = dict(address="192.0.2.1", peer_group_name="RR-CLIENTS")
+ set_module_args(
+ dict(config=dict(as_number=65001, neighbor=[group, member]), state="rendered"),
+ )
+ self.assertEqual(
+ sorted(self.execute_module(changed=False)["rendered"]),
+ [
+ "set protocols bgp neighbor 192.0.2.1 peer-group RR-CLIENTS",
+ "set protocols bgp peer-group RR-CLIENTS remote-as 65001",
+ "set protocols bgp peer-group RR-CLIENTS update-source lo",
+ "set protocols bgp system-as 65001",
+ ],
+ )
+
+ def test_vyos_bgp_global_peer_group_replaced(self):
+ self.get_os_version.return_value = "1.5"
+ self.get_facts_os_version.return_value = "1.5"
+ group = dict(address="RR-CLIENTS", peer_group=True, remote_as=65001)
+ member = dict(address="192.0.2.1", peer_group_name="RR-CLIENTS")
+ set_module_args(
+ dict(config=dict(as_number=65001, neighbor=[group, member]), state="replaced"),
+ )
+ self.execute_module(
+ changed=True,
+ commands=["delete protocols bgp peer-group RR-CLIENTS update-source lo"],
+ filename="vyos_bgp_global_peer_group_config_14.cfg",
+ )

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 6, 10:16 AM (52 m, 40 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4654183
Default Alt Text
(118 KB)

Event Timeline