diff options
Diffstat (limited to 'plugins')
9 files changed, 3287 insertions, 0 deletions
diff --git a/plugins/module_utils/network/vyos/argspec/bgp_address_family/__init__.py b/plugins/module_utils/network/vyos/argspec/bgp_address_family/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/bgp_address_family/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/bgp_address_family/bgp_address_family.py b/plugins/module_utils/network/vyos/argspec/bgp_address_family/bgp_address_family.py new file mode 100644 index 0000000..8cbbc50 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/bgp_address_family/bgp_address_family.py @@ -0,0 +1,200 @@ +# -*- 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 + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The arg spec for the vyos_bgp_address_family module +""" + + +class Bgp_address_familyArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_bgp_address_family module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {}, + "state": { + "default": "merged", + "type": "str", + "choices": [ + "merged", + "replaced", + "deleted", + "gathered", + "parsed", + "rendered", + "purged", + "overridden", + ], + }, + "config": { + "type": "dict", + "options": { + "neighbors": { + "elements": "dict", + "type": "list", + "options": { + "address_family": { + "elements": "dict", + "type": "list", + "options": { + "nexthop_local": {"type": "bool"}, + "soft_reconfiguration": {"type": "bool"}, + "unsupress_map": {"type": "str"}, + "nexthop_self": {"type": "bool"}, + "weight": {"type": "int"}, + "prefix_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "prefix_list": {"type": "str"}, + }, + }, + "default_originate": {"type": "str"}, + "distribute_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "acl": {"type": "int"}, + }, + }, + "allowas_in": {"type": "int"}, + "filter_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "path_list": {"type": "str"}, + }, + }, + "route_server_client": {"type": "bool"}, + "attribute_unchanged": { + "type": "dict", + "options": { + "as_path": {"type": "bool"}, + "med": {"type": "bool"}, + "next_hop": {"type": "bool"}, + }, + }, + "peer_group": {"type": "str"}, + "maximum_prefix": {"type": "int"}, + "route_reflector_client": {"type": "bool"}, + "route_map": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "route_map": {"type": "str"}, + }, + }, + "capability": { + "type": "dict", + "options": { + "orf": { + "type": "str", + "choices": ["send", "receive"], + }, + "dynamic": {"type": "bool"}, + }, + }, + "remove_private_as": {"type": "bool"}, + "as_override": {"type": "bool"}, + "afi": { + "type": "str", + "choices": ["ipv4", "ipv6"], + }, + }, + }, + "neighbor_address": {"type": "str"}, + }, + }, + "as_number": {"type": "int"}, + "address_family": { + "elements": "dict", + "type": "list", + "options": { + "afi": {"type": "str", "choices": ["ipv4", "ipv6"]}, + "redistribute": { + "elements": "dict", + "type": "list", + "options": { + "table": {"type": "str"}, + "metric": {"type": "int"}, + "protocol": { + "type": "str", + "choices": [ + "connected", + "kernel", + "ospf", + "ospfv3", + "rip", + "ripng", + "static", + ], + }, + "route_map": {"type": "str"}, + }, + }, + "networks": { + "elements": "dict", + "type": "list", + "options": { + "backdoor": {"type": "bool"}, + "prefix": {"type": "str"}, + "path_limit": {"type": "int"}, + "route_map": {"type": "str"}, + }, + }, + "aggregate_address": { + "elements": "dict", + "type": "list", + "options": { + "summary_only": {"type": "bool"}, + "prefix": {"type": "str"}, + "as_set": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/bgp_address_family/__init__.py b/plugins/module_utils/network/vyos/config/bgp_address_family/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/bgp_address_family/__init__.py diff --git a/plugins/module_utils/network/vyos/config/bgp_address_family/bgp_address_family.py b/plugins/module_utils/network/vyos/config/bgp_address_family/bgp_address_family.py new file mode 100644 index 0000000..876402f --- /dev/null +++ b/plugins/module_utils/network/vyos/config/bgp_address_family/bgp_address_family.py @@ -0,0 +1,369 @@ +# +# -*- 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_address_family config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +import re + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.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.bgp_address_family import ( + Bgp_address_familyTemplate, +) + + +class Bgp_address_family(ResourceModule): + """ + The vyos_bgp_address_family config class + """ + + def __init__(self, module): + super(Bgp_address_family, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="bgp_address_family", + tmplt=Bgp_address_familyTemplate(), + ) + self.parsers = [] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = {} + haved = {} + + if ( + self.want.get("as_number") == self.have.get("as_number") + or not self.have + ): + 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_af_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 == "deleted": + for k, have in iteritems(haved): + self._delete_af(wantd, have) + wantd = {} + + if self.state == "overridden": + for k, have in iteritems(haved): + if k not in wantd: + self._compare(want={}, have=have) + + for k, want in iteritems(wantd): + 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_address_family network resource. + """ + self._compare_af(want, have) + self._compare_neighbors(want, have) + # 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_af(self, want, have): + waf = want.get("address_family", {}) + haf = have.get("address_family", {}) + for name, entry in iteritems(waf): + self._compare_lists( + entry, + have=haf.get(name, {}), + as_number=want["as_number"], + afi=name, + ) + for name, entry in iteritems(haf): + if name not in waf.keys() and self.state == "replaced": + continue + self._compare_lists( + {}, entry, as_number=have["as_number"], afi=name + ) + + def _delete_af(self, want, have): + for as_num, entry in iteritems(want): + for afi, af_entry in iteritems(entry.get("address_family", {})): + if have.get("address_family"): + for hafi, hentry in iteritems(have["address_family"]): + if hafi == afi: + self.commands.append( + self._tmplt.render( + { + "as_number": as_num, + "address_family": {"afi": afi}, + }, + "address_family", + True, + ) + ) + for neigh, neigh_entry in iteritems(entry.get("neighbors", {})): + if have.get("neighbors"): + for hneigh, hnentry in iteritems(have["neighbors"]): + if hneigh == neigh: + if not neigh_entry.get("address_family"): + self.commands.append( + self._tmplt.render( + { + "as_number": as_num, + "neighbors": { + "neighbor_address": neigh + }, + }, + "neighbors", + True, + ) + ) + else: + for k in neigh_entry["address_family"].keys(): + if ( + hnentry.get("address_family") + and k + in hnentry["address_family"].keys() + ): + self.commands.append( + self._tmplt.render( + { + "as_number": as_num, + "neighbors": { + "neighbor_address": neigh, + "address_family": { + "afi": k + }, + }, + }, + "neighbors.address_family", + True, + ) + ) + + def _compare_neighbors(self, want, have): + parsers = [ + "neighbors.allowas_in", + "neighbors.as_override", + "neighbors.attribute_unchanged.as_path", + "neighbors.attribute_unchanged.med", + "neighbors.attribute_unchanged.next_hop", + "neighbors.capability_dynamic", + "neighbors.capability_orf", + "neighbors.default_originate", + "neighbors.distribute_list", + "neighbors.prefix_list", + "neighbors.filter_list", + "neighbors.maximum_prefix", + "neighbors.nexthop_local", + "neighbors.nexthop_self", + "neighbors.peer_group", + "neighbors.remove_private_as", + "neighbors.route_map", + "neighbors.route_reflector_client", + "neighbors.route_server_client", + "neighbors.soft_reconfiguration", + "neighbors.unsuppress_map", + "neighbors.weight", + ] + wneigh = want.get("neighbors", {}) + hneigh = have.get("neighbors", {}) + for name, entry in iteritems(wneigh): + for afi, af_entry in iteritems(entry.get("address_family")): + for k, val in iteritems(af_entry): + w = { + "as_number": want["as_number"], + "neighbors": { + "neighbor_address": name, + "address_family": {"afi": afi, k: val}, + }, + } + h = {} + if hneigh.get(name): + if hneigh[name]["address_family"].get(afi): + if hneigh[name]["address_family"][afi].get(k): + h = { + "as_number": want["as_number"], + "neighbors": { + "neighbor_address": name, + "address_family": { + "afi": afi, + k: hneigh[name]["address_family"][ + afi + ].pop(k, {}), + }, + }, + } + self.compare( + parsers=parsers, + want=w, + have=h, + ) + for name, entry in iteritems(hneigh): + if name not in wneigh.keys(): + # remove surplus config for overridden and replaced + if self.state != "replaced": + self.commands.append( + self._tmplt.render( + { + "as_number": have["as_number"], + "neighbors": {"neighbor_address": name}, + }, + "neighbors", + True, + ) + ) + continue + + for hafi, haf_entry in iteritems(entry.get("address_family")): + # remove surplus configs for given neighbor - replace and overridden + for k, val in iteritems(haf_entry): + h = { + "as_number": have["as_number"], + "neighbors": { + "neighbor_address": name, + "address_family": {"afi": hafi, k: val}, + }, + } + self.compare(parsers=parsers, want={}, have=h) + + def _compare_lists(self, want, have, as_number, afi): + parsers = [ + "aggregate_address", + "network.backdoor", + "network.path_limit", + "network.route_map", + "redistribute.metric", + "redistribute.route_map", + "redistribute.table", + ] + for attrib in ["redistribute", "networks", "aggregate_address"]: + wdict = want.pop(attrib, {}) + hdict = have.pop(attrib, {}) + for key, entry in iteritems(wdict): + if entry != hdict.get(key, {}): + self.compare( + parsers=parsers, + want={ + "as_number": as_number, + "address_family": {"afi": afi, attrib: entry}, + }, + have={ + "as_number": as_number, + "address_family": { + "afi": afi, + attrib: hdict.pop(key, {}), + }, + }, + ) + hdict.pop(key, {}) + # remove remaining items in have for replaced + if not wdict and hdict: + attrib = re.sub("_", "-", attrib) + attrib = re.sub("networks", "network", attrib) + self.commands.append( + "delete protocols bgp " + + str(as_number) + + " " + + "address-family " + + afi + + " " + + attrib + ) + hdict = {} + for key, entry in iteritems(hdict): + self.compare( + parsers=parsers, + want={}, + have={ + "as_number": as_number, + "address_family": {"afi": afi, attrib: entry}, + }, + ) + + def _bgp_af_list_to_dict(self, entry): + for name, proc in iteritems(entry): + if "address_family" in proc: + af_dict = {} + for entry in proc.get("address_family"): + if "networks" in entry: + network_dict = {} + for n_entry in entry.get("networks", []): + network_dict.update({n_entry["prefix"]: n_entry}) + entry["networks"] = network_dict + + if "aggregate_address" in entry: + agg_dict = {} + for a_entry in entry.get("aggregate_address", []): + agg_dict.update({a_entry["prefix"]: a_entry}) + entry["aggregate_address"] = agg_dict + + if "redistribute" in entry: + redis_dict = {} + for r_entry in entry.get("redistribute", []): + proto_key = r_entry.get("protocol", "table") + redis_dict.update({proto_key: r_entry}) + entry["redistribute"] = redis_dict + + for af in proc.get("address_family"): + af_dict.update({af["afi"]: af}) + proc["address_family"] = af_dict + + if "neighbors" in proc: + neigh_dict = {} + for entry in proc.get("neighbors", []): + neigh_dict.update({entry["neighbor_address"]: entry}) + proc["neighbors"] = neigh_dict + self._bgp_af_list_to_dict(proc["neighbors"]) diff --git a/plugins/module_utils/network/vyos/facts/bgp_address_family/__init__.py b/plugins/module_utils/network/vyos/facts/bgp_address_family/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/bgp_address_family/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py b/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py new file mode 100644 index 0000000..a7296f2 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/bgp_address_family/bgp_address_family.py @@ -0,0 +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_address_family 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.rm_templates.bgp_address_family import ( + Bgp_address_familyTemplate, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.bgp_address_family.bgp_address_family import ( + Bgp_address_familyArgs, +) + + +class Bgp_address_familyFacts(object): + """The vyos bgp_address_family facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Bgp_address_familyArgs.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_address_family 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) + + for resource in data.splitlines(): + if "address-family" in resource: + config_lines.append(re.sub("'", "", resource)) + + # parse native config using the Bgp_address_family template + bgp_address_family_parser = Bgp_address_familyTemplate( + lines=config_lines + ) + objs = bgp_address_family_parser.parse() + if objs: + if "address_family" in objs: + objs["address_family"] = list(objs["address_family"].values()) + for af in objs["address_family"]: + if "networks" in af: + af["networks"] = sorted( + af["networks"], key=lambda k: k["prefix"] + ) + if "aggregate_address" in af: + af["aggregate_address"] = sorted( + af["aggregate_address"], key=lambda k: k["prefix"] + ) + if "neighbors" in objs: + objs["neighbors"] = list(objs["neighbors"].values()) + objs["neighbors"] = sorted( + objs["neighbors"], key=lambda k: k["neighbor_address"] + ) + for neigh in objs["neighbors"]: + if "address_family" in neigh: + neigh["address_family"] = list( + neigh["address_family"].values() + ) + + ansible_facts["ansible_network_resources"].pop( + "bgp_address_family", None + ) + + params = utils.remove_empties( + utils.validate_config(self.argument_spec, {"config": objs}) + ) + + facts["bgp_address_family"] = params.get("config", []) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 95eff2e..1a2d786 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -52,6 +52,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospf_ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_global.bgp_global import ( Bgp_globalFacts, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_address_family.bgp_address_family import ( + Bgp_address_familyFacts, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import ( Default, Neighbors, @@ -74,6 +77,7 @@ FACT_RESOURCE_SUBSETS = dict( ospfv2=Ospfv2Facts, ospf_interfaces=Ospf_interfacesFacts, bgp_global=Bgp_globalFacts, + bgp_address_family=Bgp_address_familyFacts, ) diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py new file mode 100644 index 0000000..55e2200 --- /dev/null +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_address_family.py @@ -0,0 +1,1421 @@ +# -*- 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_address_family 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.network_template import ( + NetworkTemplate, +) + + +def _tmplt_bgp_af_aggregate_address(config_data): + afi = config_data["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} address-family ".format(**config_data) + config_data = config_data["address_family"] + if config_data["aggregate_address"].get("as_set"): + command += afi + " aggregate-address {prefix} as-set".format( + **config_data["aggregate_address"] + ) + if config_data["aggregate_address"].get("summary_only"): + command += afi + " aggregate-address {prefix} summary-only".format( + **config_data["aggregate_address"] + ) + return command + + +def _tmplt_bgp_af_redistribute_metric(config_data): + if config_data["address_family"]["redistribute"].get("metric"): + afi = config_data["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} address-family ".format( + **config_data + ) + if config_data["address_family"]["redistribute"].get("metric"): + command += afi + " redistribute {protocol} metric {metric}".format( + **config_data["address_family"]["redistribute"] + ) + return command + + +def _tmplt_bgp_af_redistribute_route_map(config_data): + if config_data["address_family"]["redistribute"].get("route_map"): + afi = config_data["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} address-family ".format( + **config_data + ) + if config_data["address_family"]["redistribute"].get("route_map"): + command += ( + afi + + " redistribute {protocol} route-map {route_map}".format( + **config_data["address_family"]["redistribute"] + ) + ) + return command + + +def _tmplt_bgp_af_redistribute_table(config_data): + if config_data["address_family"]["redistribute"].get("table"): + afi = config_data["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} address-family ".format( + **config_data + ) + if config_data["address_family"]["redistribute"].get("table"): + command += afi + " table {table}".format( + **config_data["address_family"]["redistribute"] + ) + return command + + +def _tmplt_bgp_af_delete_redistribute(config_data): + afi = config_data["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} address-family ".format(**config_data) + config_data = config_data["address_family"] + command += afi + " redistribute {protocol}".format( + **config_data["redistribute"] + ) + return command + + +def _tmplt_bgp_af_neighbor_distribute_list(config_data): + command = [] + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + cmd = "protocols bgp {as_number} neighbor ".format(**config_data) + cmd += "{neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + config_data = config_data["neighbors"]["address_family"] + for list_el in config_data["distribute_list"]: + command.append( + cmd + + afi + + " distribute-list " + + list_el["action"] + + " " + + str(list_el["acl"]) + ) + return command + + +def _tmplt_bgp_af_neighbor_route_map(config_data): + command = [] + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + cmd = "protocols bgp {as_number} neighbor ".format(**config_data) + cmd += "{neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + config_data = config_data["neighbors"]["address_family"] + for list_el in config_data["route_map"]: + command.append( + cmd + + afi + + " route-map " + + list_el["action"] + + " " + + str(list_el["route_map"]) + ) + return command + + +def _tmplt_bgp_af_neighbor_prefix_list(config_data): + command = [] + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + cmd = "protocols bgp {as_number} neighbor ".format(**config_data) + cmd += "{neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + config_data = config_data["neighbors"]["address_family"] + for list_el in config_data["prefix_list"]: + command.append( + cmd + + afi + + " prefix-list " + + list_el["action"] + + " " + + str(list_el["prefix_list"]) + ) + return command + + +def _tmplt_bgp_af_neighbor_filter_list(config_data): + command = [] + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + cmd = "protocols bgp {as_number} neighbor ".format(**config_data) + cmd += "{neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + config_data = config_data["neighbors"]["address_family"] + for list_el in config_data["filter_list"]: + command.append( + cmd + + afi + + " filter-list " + + list_el["action"] + + " " + + str(list_el["path_list"]) + ) + return command + + +def _tmplt_bgp_af_neighbor_attribute(config_data): + command = [] + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + cmd = "protocols bgp {as_number} neighbor ".format(**config_data) + cmd += "{neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + config_data = config_data["neighbors"]["address_family"] + for k in config_data["attribute_unchanged"].keys(): + if config_data["attribute_unchanged"][k]: + k = re.sub("_", "-", k) + c = cmd + afi + " attribute-unchanged " + k + command.append(c) + return command + + +def _tmplt_bgp_af_neighbor_delete(config_data): + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} ".format(**config_data) + command += ( + "neighbor {neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + + afi + ) + config_data = config_data["neighbors"]["address_family"] + if config_data.get("allowas_in"): + command += " allowas-in" + elif config_data.get("as_override"): + command += " as-override" + elif config_data.get("attribute_unchanged"): + command += " attribute-unchanged" + elif config_data.get("capability"): + command += " capability" + elif config_data.get("default_originate"): + command += " default-originate" + elif config_data.get("maximum_prefix"): + command += " maximum-prefix" + elif config_data.get("nexthop_local"): + command += " nexthop-local" + elif config_data.get("nexthop_self"): + command += " nexthop-self" + elif config_data.get("peer_group"): + command += " peer-group" + elif config_data.get("remote_private_as"): + command += " remote-private-as" + elif config_data.get("route_reflector_client"): + command += " route-reflector-client" + elif config_data.get("route_server_client"): + command += " route-server-client" + elif config_data.get("soft_reconfiguration"): + command += " soft-reconfiguration" + elif config_data.get("unsuppress_map"): + command += " unsuppress-map" + elif config_data.get("weight"): + command += " weight" + elif config_data.get("filter_list"): + command += " filter-list" + elif config_data.get("prefix_list"): + command += " prefix-list" + elif config_data.get("distribute_list"): + command += " distribute-list" + elif config_data.get("route_map"): + command += " route-map" + return command + + +def _tmplt_bgp_af_neighbor(config_data): + afi = config_data["neighbors"]["address_family"]["afi"] + "-unicast" + command = "protocols bgp {as_number} ".format(**config_data) + command += ( + "neighbor {neighbor_address} address-family ".format( + **config_data["neighbors"] + ) + + afi + ) + config_data = config_data["neighbors"]["address_family"] + if config_data.get("allowas_in"): + command += " allowas-in number {allowas_in}".format(**config_data) + elif config_data.get("as_override"): + command += " as-override" + elif config_data.get("capability"): + command += " capability " + if config_data["capability"].get("dynamic"): + command += "dynamic" + elif config_data["capability"].get("orf"): + command += " prefix-list {orf}".format(**config_data["capability"]) + elif config_data.get("default_originate"): + command += " default-originate route-map {default_originate}".format( + **config_data + ) + elif config_data.get("maximum_prefix"): + command += " maximum-prefix {maximum_prefix}".format(**config_data) + elif config_data.get("nexthop_local"): + command += " nexthop-local" + elif config_data.get("nexthop_self"): + command += " nexthop-self" + elif config_data.get("peer_group"): + command += " peer-group {peer_group}".format(**config_data) + elif config_data.get("remote_private_as"): + command += " remote-private-as" + elif config_data.get("route_reflector_client"): + command += " route-reflector-client" + elif config_data.get("route_server_client"): + command += " route-server-client" + elif config_data.get("soft_reconfiguration"): + command += " soft-reconfiguration inbound" + elif config_data.get("unsuppress_map"): + command += " unsuppress-map {unsuppress_map}".format(**config_data) + elif config_data.get("weight"): + command += " weight {weight}".format(**config_data) + return command + + +class Bgp_address_familyTemplate(NetworkTemplate): + def __init__(self, lines=None): + prefix = {"set": "set", "remove": "delete"} + super(Bgp_address_familyTemplate, self).__init__( + lines=lines, tmplt=self, prefix=prefix + ) + + # fmt: off + PARSERS = [ + { + "name": "address_family", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast", + "compval": "as_number", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + } + } + } + }, + { + "name": "aggregate_address", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+aggregate-address + \s+(?P<address>\S+) + \s*(?P<as_set>as-set)* + \s*(?P<summary_only>summary-only)* + $""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_aggregate_address, + "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast aggregate-address" + + " {{ address_family.aggregate_address.prefix }}", + "compval": "address_family.aggregate_address", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "aggregate_address": [ + { + "prefix": "{{ address }}", + "as_set": "{{ True if as_set is defined }}", + "summary_only": "{{ True if summary_only is defined }}" + } + ] + } + } + } + }, + { + "name": "network.backdoor", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+network + \s+(?P<address>\S+) + \s+backdoor + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network {{ address_family.networks.prefix }} backdoor", + "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network {{ address_family.networks.prefix }}", + "compval": "address_family.networks.backdoor", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "networks": [ + { + "prefix": "{{ address }}", + "backdoor": "{{ True }}" + } + ] + } + } + } + }, + { + "name": "network.path_limit", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+network + \s+(?P<address>\S+) + \s+path-limit + \s+(?P<limit>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network" + + "{{ address_family.networks.prefix }} path-limit {{ address_family.networks.path_limit }}", + "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network {{ address_family.networks.address }}", + "compval": "address_family.networks.path_limit", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "networks": [ + { + "prefix": "{{ address }}", + "path_limit": "{{ limit|int }}" + } + ] + } + } + } + }, + { + "name": "network.route_map", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+network + \s+(?P<address>\S+) + \s+route-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network" + + " {{ address_family.networks.prefix }} route-map {{ address_family.networks.route_map }}", + "remval": "protocols bgp {{ as_number }} address-family {{ address_family.afi }}-unicast network {{ address_family.networks.prefix }}", + "compval": "address_family.networks.route_map", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "networks": [ + { + "prefix": "{{ address }}", + "route_map": "{{ map }}" + } + ] + } + } + } + }, + { + "name": "redistribute.metric", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+redistribute + \s+(?P<proto>\S+) + \s+metric + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_redistribute_metric, + "remval": _tmplt_bgp_af_delete_redistribute, + "compval": "address_family.redistribute.metric", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "redistribute": [ + { + "protocol": "{{ proto }}", + "metric": "{{ val|int }}" + } + ] + } + } + } + }, + { + "name": "redistribute.route_map", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+redistribute + \s+(?P<proto>\S+) + \s+route-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_redistribute_route_map, + "remval": _tmplt_bgp_af_delete_redistribute, + "compval": "address_family.redistribute.route_map", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "redistribute": [ + { + "protocol": "{{ proto }}", + "route_map": "{{ map }}" + } + ] + } + } + } + }, + { + "name": "redistribute.table", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+redistribute + \s+table + \s+(?P<tab>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_redistribute_table, + "remval": _tmplt_bgp_af_delete_redistribute, + "compval": "address_family.redistribute.table", + "result": { + "as_number": "{{ as_num }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "redistribute": [ + { + "table": "{{ tab }}" + } + ] + } + } + } + }, + { + "name": "neighbors", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} neighbor {{ neighbors.neighbor_address }} address-family", + "compval": "neighbors", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + } + } + } + }, + { + "name": "neighbors.address_family", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} neighbor {{ neighbors.neighbor_address }} address-family {{ neighbors.address_family.afi }}-unicast", + "compval": "neighbors", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + } + } + } + } + } + }, + { + "name": "neighbors.allowas_in", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+allowas-in + \s+number + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.allowas_in", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "allowas_in": "{{ num }}" + } + } + } + } + } + }, + { + "name": "neighbors.as_override", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+as-override + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.as_override", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "as_override": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.attribute_unchanged.as_path", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+attribute-unchanged + \s+(?P<val>as-path) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_attribute, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.attribute_unchanged.as_path", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "attribute_unchanged": { + "as_path": "{{ True }}" + } + } + } + } + } + } + }, + { + "name": "neighbors.attribute_unchanged.med", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+attribute-unchanged + \s+(?P<val>med) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_attribute, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.attribute_unchanged.med", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "attribute_unchanged": { + "med": "{{ True }}" + } + } + } + } + } + } + }, + { + "name": "neighbors.attribute_unchanged.next_hop", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+attribute-unchanged + \s+(?P<val>next-hop) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_attribute, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.attribute_unchanged.next_hop", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "attribute_unchanged": { + "next_hop": "{{ True }}" + } + } + } + } + } + } + }, + { + "name": "neighbors.capability_dynamic", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+capability + \s+dynamic + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.capability.dynamic", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "capability": { + "dynamic": "{{ true }}" + } + } + } + } + } + } + }, + { + "name": "neighbors.capability_orf", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+capability + \s+prefix-list + \s+(?P<orf>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.capability.orf", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "capability": { + "orf": "{{ orf }}" + } + } + } + } + } + } + }, + { + "name": "neighbors.default_originate", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+default-originate + \s+route-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.default_originate", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "default_originate": "{{ map }}" + } + } + } + } + } + }, + { + "name": "neighbors.distribute_list", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+distribute-list + \s+(?P<action>export|import) + \s+(?P<list>\d+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_distribute_list, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.distribute_list", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "distribute_list": [ + { + "action": "{{ action }}", + "acl": "{{ list }}" + } + ] + } + } + } + } + } + }, + { + "name": "neighbors.prefix_list", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+prefix-list + \s+(?P<action>export|import) + \s+(?P<list>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_prefix_list, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.prefix_list", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "prefix_list": [ + { + "action": "{{ action }}", + "prefix_list": "{{ list }}" + } + ] + } + } + } + } + } + }, + { + "name": "neighbors.filter_list", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+filter-list + \s+(?P<action>export|import) + \s+(?P<list>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_filter_list, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.filter_list", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "filter_list": [ + { + "action": "{{ action }}", + "path_list": "{{ list }}" + } + ] + } + } + } + } + } + }, + { + "name": "neighbors.maximum_prefix", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+maximum-prefix + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.maximum_prefix", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "maximum_prefix": "{{ num }}" + } + } + } + } + } + }, + { + "name": "neighbors.nexthop_local", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+nexthop-local + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.nexthop_local", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "nexthop_local": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.nexthop_self", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+nexthop-self + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.nexthop_self", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "nexthop_self": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.peer_group", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+peer-group + \s+(?P<name>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.peer_group", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "peer_group": "{{ name }}" + } + } + } + } + } + }, + { + "name": "neighbors.remove_private_as", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+remove-private-as + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.remove_private_as", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "remove_private_as": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.route_map", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+route-map + \s+(?P<action>export|import) + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor_route_map, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.route_map", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "route_map": [ + { + "action": "{{ action }}", + "route_map": "{{ map }}" + } + ] + } + } + } + } + } + }, + { + "name": "neighbors.route_reflector_client", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+route-reflector-client + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.route_reflector_client", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "route_reflector_client": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.route_server_client", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+route-server-client + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.route_server_client", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "route_server_client": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.soft_reconfiguration", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+soft-reconfiguration + \s+inbound + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.soft_reconfiguration", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "soft_reconfiguration": "{{ True }}" + } + } + } + } + } + }, + { + "name": "neighbors.unsuppress_map", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+unsuppress-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.unsuppress_map", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "unsuppress_map": "{{ map }}" + } + } + } + } + } + }, + { + "name": "neighbors.weight", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+address-family + \s+(?P<afi>\S+)-unicast + \s+weight + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_af_neighbor, + "remval": _tmplt_bgp_af_neighbor_delete, + "compval": "neighbors.address_family.weight", + "result": { + "as_number": "{{ as_num }}", + "neighbors": { + "{{ address }}": { + "neighbor_address": "{{ address }}", + "address_family": { + "{{ afi }}": { + "afi": "{{ afi }}", + "weight": "{{ num }}" + } + } + } + } + } + }, + ] + # fmt: on diff --git a/plugins/modules/vyos_bgp_address_family.py b/plugins/modules/vyos_bgp_address_family.py new file mode 100644 index 0000000..80c6807 --- /dev/null +++ b/plugins/modules/vyos_bgp_address_family.py @@ -0,0 +1,1192 @@ +#!/usr/bin/python +# -*- 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) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for vyos_bgp_address_family +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: vyos_bgp_address_family +version_added: 2.1.0 +short_description: BGP Address Family Resource Module. +description: +- This module manages BGP address family configuration of interfaces on devices running VYOS. +author: Gomathi Selvi Srinivasan (@GomathiselviS) +options: + config: + description: A dict of BGP global configuration for interfaces. + type: dict + suboptions: + as_number: + description: + - AS number. + type: int + address_family: + description: BGP address-family parameters. + type: list + elements: dict + suboptions: + afi: + description: BGP address family settings. + type: str + choices: ['ipv4', 'ipv6'] + aggregate_address: + description: + - BGP aggregate network. + type: list + elements: dict + suboptions: + prefix: + description: BGP aggregate network. + type: str + as_set: + description: Generate AS-set path information for this aggregate address. + type: bool + summary_only: + description: Announce the aggregate summary network only. + type: bool + networks: + description: BGP network + type: list + elements: dict + suboptions: + prefix: + description: BGP network address + type: str + path_limit: + description: AS path hop count limit + type: int + backdoor: + description: Network as a backdoor route. + type: bool + route_map: + description: Route-map to modify route attributes + type: str + redistribute: + description: Redistribute routes from other protocols into BGP + type: list + elements: dict + suboptions: + protocol: + description: types of routes to be redistributed. + type: str + choices: ['connected', 'kernel', 'ospf', 'ospfv3', 'rip', 'ripng', 'static'] + table: + description: Redistribute non-main Kernel Routing Table. + type: str + route_map: + description: Route map to filter redistributed routes + type: str + metric: + description: Metric for redistributed routes. + type: int + neighbors: + description: BGP neighbor + type: list + elements: dict + suboptions: + neighbor_address: + description: BGP neighbor address (v4/v6). + type: str + address_family: + description: address family. + type: list + elements: dict + suboptions: + afi: + description: BGP neighbor parameters. + type: str + choices: ['ipv4', 'ipv6'] + allowas_in: + description: Number of occurrences of AS number. + type: int + as_override: + description: AS for routes sent to this neighbor to be the local AS. + type: bool + attribute_unchanged: + description: BGP attributes are sent unchanged. + type: dict + suboptions: + as_path: + description: as_path attribute + type: bool + med: + description: med attribute + type: bool + next_hop: + description: next_hop attribute + type: bool + capability: + description: Advertise capabilities to this neighbor. + type: dict + suboptions: + dynamic: + description: Advertise dynamic capability to this neighbor. + type: bool + orf: + description: Advertise ORF capability to this neighbor. + type: str + choices: ['send', 'receive'] + default_originate: + description: Send default route to this neighbor + type: str + distribute_list: + description: Access-list to filter route updates to/from this neighbor. + type: list + elements: dict + suboptions: + action: + description: Access-list to filter outgoing/incoming route updates to this neighbor + type: str + choices: ['export', 'import'] + acl: + description: Acess-list number. + type: int + filter_list: + description: As-path-list to filter route updates to/from this neighbor. + type: list + elements: dict + suboptions: + action: + description: filter outgoing/incoming route updates + type: str + choices: ['export', 'import'] + path_list: + description: As-path-list to filter + type: str + maximum_prefix: + description: Maximum number of prefixes to accept from this neighbor + nexthop-self Nexthop for routes sent to this neighbor to be the local router. + type: int + nexthop_local: + description: Nexthop attributes. + type: bool + nexthop_self: + description: Nexthop for routes sent to this neighbor to be the local router. + type: bool + peer_group: + description: IPv4 peer group for this peer + type: str + prefix_list: + description: Prefix-list to filter route updates to/from this neighbor. + type: list + elements: dict + suboptions: + action: + description: filter outgoing/incoming route updates + type: str + choices: ['export', 'import'] + prefix_list: + description: Prefix-list to filter + type: str + remove_private_as: + description: Remove private AS numbers from AS path in outbound route updates + type: bool + route_map: + description: Route-map to filter route updates to/from this neighbor. + type: list + elements: dict + suboptions: + action: + description: filter outgoing/incoming route updates + type: str + choices: ['export', 'import'] + route_map: + description: route-map to filter + type: str + route_reflector_client: + description: Neighbor as a route reflector client + type: bool + route_server_client: + description: Neighbor is route server client + type: bool + soft_reconfiguration: + description: Soft reconfiguration for neighbor + type: bool + unsupress_map: + description: Route-map to selectively unsuppress suppressed routes + type: str + weight: + description: Default weight for routes from this neighbor + type: int + running_config: + type: str + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show configuration command | match bgp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - deleted + - gathered + - parsed + - rendered + - purged + - overridden + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# vyos@vyos:~$ + + - name: Merge provided configuration with device configuration + vyos.vyos.vyos_bgp_address_family: + config: + as_number: "100" + address_family: + - afi: "ipv4" + redistribute: + - protocol: "static" + metric: 50 + neighbors: + - neighbor_address: "20.33.1.1/24" + address_family: + - afi: "ipv4" + allowas_in: 4 + as_override: True + attribute_unchanged: + med: True + - afi: "ipv6" + default_originate: "map01" + distribute_list: + - action: "export" + acl: 10 + - neighbor_address: "100.11.34.12" + address_family: + - afi: "ipv4" + maximum_prefix: 45 + nexthop_self: True + route_map: + - action: "export" + route_map: "map01" + - action: "import" + route_map: "map01" + weight: 50 + +# After State: +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate route-map 'map01' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list export '10' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map export 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map import 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight '50' +# vyos@vyos:~$ +# +# Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "maximum_prefix": 45, +# "nexthop_self": true, +# "route_map": [ +# { +# "action": "export", +# "route_map": "map01" +# }, +# { +# "action": "import", +# "route_map": "map01" +# } +# ], +# "weight": 50 +# } +# ], +# "neighbor_address": "100.11.34.12" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# }, +# { +# "afi": "ipv6", +# "default_originate": "map01", +# "distribute_list": [ +# { +# "acl": 10, +# "action": "export" +# } +# ] +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "set protocols bgp 100 address-family ipv4-unicast redistribute static metric 50", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number 4", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate route-map map01", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list export 10", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix 45", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map export map01", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map import map01", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight 50" +# ], +# + +# Using replaced: + +# Before state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate route-map 'map01' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list export '10' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map export 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map import 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight '50' +# vyos@vyos:~$ + + - name: Replace provided configuration with device configuration + vyos.vyos.vyos_bgp_address_family: + config: + as_number: "100" + neighbors: + - neighbor_address: "100.11.34.12" + address_family: + - afi: "ipv4" + allowas_in: 4 + as_override: True + attribute_unchanged: + med: True + - afi: "ipv6" + default_originate: "map01" + distribute_list: + - action: "export" + acl: 10 + - neighbor_address: "20.33.1.1/24" + address_family: + - afi: "ipv6" + maximum_prefix: 45 + nexthop_self: True + + state: replaced + +# After State: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast default-originate route-map 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast distribute-list export '10' +# vyos@vyos:~$ +# +# +# # Module Execution: +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# }, +# { +# "afi": "ipv6", +# "default_originate": "map01", +# "distribute_list": [ +# { +# "acl": 10, +# "action": "export" +# } +# ] +# } +# ], +# "neighbor_address": "100.11.34.12" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4" +# }, +# { +# "afi": "ipv6", +# "maximum_prefix": 45, +# "nexthop_self": true +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "maximum_prefix": 45, +# "nexthop_self": true, +# "route_map": [ +# { +# "action": "export", +# "route_map": "map01" +# }, +# { +# "action": "import", +# "route_map": "map01" +# } +# ], +# "weight": 50 +# } +# ], +# "neighbor_address": "100.11.34.12" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# }, +# { +# "afi": "ipv6", +# "default_originate": "map01", +# "distribute_list": [ +# { +# "acl": 10, +# "action": "export" +# } +# ] +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list", +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate", +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged", +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override", +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast allowas-in number 4", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast as-override", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast attribute-unchanged med", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast default-originate route-map map01", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast distribute-list export 10", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast maximum-prefix 45", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast nexthop-self" +# ], + + +# Using overridden +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast network 35.1.1.0/24 backdoor +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 address-family ipv6-unicast aggregate-address 6601:1:1:1::/64 summary-only +# set protocols bgp 100 address-family ipv6-unicast network 5001:1:1:1::/64 route-map 'map01' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast default-originate route-map 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast distribute-list export '10' +# vyos@vyos:~$ + + - name: Override + vyos.vyos.vyos_bgp_address_family: + config: + as_number: "100" + neighbors: + - neighbor_address: "100.11.34.12" + address_family: + - afi: "ipv6" + maximum_prefix: 45 + nexthop_self: True + route_map: + - action: "import" + route_map: "map01" + address_family: + - afi: "ipv4" + aggregate_address: + - prefix: "60.9.2.0/24" + summary_only: True + - afi: "ipv6" + redistribute: + - protocol: "static" + metric: 50 + state: overridden + +# Aft=validate-moduleser State + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast aggregate-address 60.9.2.0/24 summary-only +# set protocols bgp 100 address-family ipv6-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast route-map import 'map01' +# vyos@vyos:~$ + + +# Module Execution: + +# "after": { +# "address_family": [ +# { +# "afi": "ipv4", +# "aggregate_address": [ +# { +# "prefix": "60.9.2.0/24", +# "summary_only": true +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4" +# }, +# { +# "afi": "ipv6", +# "maximum_prefix": 45, +# "nexthop_self": true, +# "route_map": [ +# { +# "action": "import", +# "route_map": "map01" +# } +# ] +# } +# ], +# "neighbor_address": "100.11.34.12" +# } +# ] +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "networks": [ +# { +# "backdoor": true, +# "prefix": "35.1.1.0/24" +# } +# ], +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "aggregate_address": [ +# { +# "prefix": "6601:1:1:1::/64", +# "summary_only": true +# } +# ], +# "networks": [ +# { +# "prefix": "5001:1:1:1::/64", +# "route_map": "map01" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# }, +# { +# "afi": "ipv6", +# "default_originate": "map01", +# "distribute_list": [ +# { +# "acl": 10, +# "action": "export" +# } +# ] +# } +# ], +# "neighbor_address": "100.11.34.12" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4" +# }, +# { +# "afi": "ipv6", +# "maximum_prefix": 45, +# "nexthop_self": true +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast distribute-list", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast default-originate", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast attribute-unchanged", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast as-override", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast allowas-in", +# "delete protocols bgp 100 address-family ipv6 aggregate-address", +# "delete protocols bgp 100 address-family ipv6 network", +# "delete protocols bgp 100 address-family ipv4 network", +# "delete protocols bgp 100 address-family ipv4 redistribute", +# "set protocols bgp 100 address-family ipv4-unicast aggregate-address 60.9.2.0/24 summary-only", +# "set protocols bgp 100 address-family ipv6-unicast redistribute static metric 50", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast maximum-prefix 45", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast nexthop-self", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast route-map import map01" +# ], +# + +# Using deleted: + +# Before State: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast aggregate-address 60.9.2.0/24 summary-only +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 address-family ipv6-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate route-map 'map01' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list export '10' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map export 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map import 'map01' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight '50' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast maximum-prefix '45' +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast nexthop-self +# set protocols bgp 100 neighbor 100.11.34.12 address-family ipv6-unicast route-map import 'map01' +# vyos@vyos:~$ + + - name: Delete + vyos.vyos.vyos_bgp_address_family: + config: + as_number: "100" + neighbors: + - neighbor_address: "20.33.1.1/24" + address_family: + - afi: "ipv6" + - neighbor_address: "100.11.34.12" + address_family: + - afi: "ipv4" + state: deleted + + +# After State: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv6-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 100.11.34.12 +# vyos@vyos:~$ +# +# +# Module Execution: +# +# "after": { +# "address_family": [ +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "before": { +# "address_family": [ +# { +# "afi": "ipv4", +# "aggregate_address": [ +# { +# "prefix": "60.9.2.0/24", +# "summary_only": true +# } +# ], +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "maximum_prefix": 45, +# "nexthop_self": true, +# "route_map": [ +# { +# "action": "export", +# "route_map": "map01" +# }, +# { +# "action": "import", +# "route_map": "map01" +# } +# ], +# "weight": 50 +# }, +# { +# "afi": "ipv6", +# "maximum_prefix": 45, +# "nexthop_self": true, +# "route_map": [ +# { +# "action": "import", +# "route_map": "map01" +# } +# ] +# } +# ], +# "neighbor_address": "100.11.34.12" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# }, +# { +# "afi": "ipv6", +# "default_originate": "map01", +# "distribute_list": [ +# { +# "acl": 10, +# "action": "export" +# } +# ] +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 100 address-family ipv4-unicast", +# "delete protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast", +# "delete protocols bgp 100 neighbor 100.11.34.12 address-family" +# ], +# + +# using parsed: + +# parsed.cfg +# set protocols bgp 65536 address-family ipv4-unicast aggregate-address 192.0.2.0/24 as-set +# set protocols bgp 65536 address-family ipv4-unicast network 192.1.13.0/24 route-map 'map01' +# set protocols bgp 65536 address-family ipv4-unicast network 192.2.13.0/24 backdoor +# set protocols bgp 65536 address-family ipv6-unicast redistribute ripng metric '20' +# set protocols bgp 65536 neighbor 192.0.2.25 address-family ipv4-unicast route-map export 'map01' +# set protocols bgp 65536 neighbor 192.0.2.25 address-family ipv4-unicast soft-reconfiguration inbound +# set protocols bgp 65536 neighbor 203.0.113.5 address-family ipv6-unicast attribute-unchanged next-hop + + + - name: parse configs + vyos.vyos.vyos_bgp_address_family: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# Module Execution: +# "parsed": { +# "address_family": [ +# { +# "afi": "ipv4", +# "aggregate_address": [ +# { +# "as_set": true, +# "prefix": "192.0.2.0/24" +# } +# ], +# "networks": [ +# { +# "prefix": "192.1.13.0/24", +# "route_map": "map01" +# }, +# { +# "backdoor": true, +# "prefix": "192.2.13.0/24" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "redistribute": [ +# { +# "metric": 20, +# "protocol": "ripng" +# } +# ] +# } +# ], +# "as_number": 65536, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "route_map": [ +# { +# "action": "export", +# "route_map": "map01" +# } +# ], +# "soft_reconfiguration": true +# } +# ], +# "neighbor_address": "192.0.2.25" +# }, +# { +# "address_family": [ +# { +# "afi": "ipv6", +# "attribute_unchanged": { +# "next_hop": true +# } +# } +# ], +# "neighbor_address": "203.0.113.5" +# } +# ] +# + +# Using gathered: + +# Native config: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 100 address-family ipv4-unicast network 35.1.1.0/24 backdoor +# set protocols bgp 100 address-family ipv4-unicast redistribute static metric '50' +# set protocols bgp 100 address-family ipv6-unicast aggregate-address 6601:1:1:1::/64 summary-only +# set protocols bgp 100 address-family ipv6-unicast network 5001:1:1:1::/64 route-map 'map01' +# set protocols bgp 100 address-family ipv6-unicast redistribute static metric '50' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number '4' +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override +# set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med +# set protocols bgp 100 neighbor 100.11.34.12 + + - name: gather configs + vyos.vyos.vyos_bgp_address_family: + state: gathered + +# Module Execution: + +# "gathered": { +# "address_family": [ +# { +# "afi": "ipv4", +# "networks": [ +# { +# "backdoor": true, +# "prefix": "35.1.1.0/24" +# } +# ], +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "aggregate_address": [ +# { +# "prefix": "6601:1:1:1::/64", +# "summary_only": true +# } +# ], +# "networks": [ +# { +# "prefix": "5001:1:1:1::/64", +# "route_map": "map01" +# } +# ], +# "redistribute": [ +# { +# "metric": 50, +# "protocol": "static" +# } +# ] +# } +# ], +# "as_number": 100, +# "neighbors": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "allowas_in": 4, +# "as_override": true, +# "attribute_unchanged": { +# "med": true +# } +# } +# ], +# "neighbor_address": "20.33.1.1/24" +# } +# ] + +# Using rendered: + + - name: Render + vyos.vyos.vyos_bgp_address_family: + config: + as_number: "100" + address_family: + - afi: "ipv4" + redistribute: + - protocol: "static" + metric: 50 + neighbors: + - neighbor_address: "20.33.1.1/24" + address_family: + - afi: "ipv4" + allowas_in: 4 + as_override: True + attribute_unchanged: + med: True + - afi: "ipv6" + default_originate: "map01" + distribute_list: + - action: "export" + acl: 10 + - neighbor_address: "100.11.34.12" + address_family: + - afi: "ipv4" + maximum_prefix: 45 + nexthop_self: True + route_map: + - action: "export" + route_map: "map01" + - action: "import" + route_map: "map01" + weight: 50 + state: rendered + +# Module Execution: + +# "rendered": [ +# "set protocols bgp 100 address-family ipv4-unicast redistribute static metric 50", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast allowas-in number 4", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast as-override", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv4-unicast attribute-unchanged med", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast default-originate route-map map01", +# "set protocols bgp 100 neighbor 20.33.1.1/24 address-family ipv6-unicast distribute-list export 10", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast maximum-prefix 45", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast nexthop-self", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map export map01", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast route-map import map01", +# "set protocols bgp 100 neighbor 100.11.34.12 address-family ipv4-unicast weight 50" +# ] + + +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.bgp_address_family.bgp_address_family import ( + Bgp_address_familyArgs, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_address_family.bgp_address_family import ( + Bgp_address_family, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_address_familyArgs.argument_spec, + mutually_exclusive=[], + required_if=[], + supports_check_mode=False, + ) + + result = Bgp_address_family(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() |