diff options
35 files changed, 5608 insertions, 2 deletions
diff --git a/changelogs/fragments/bgp_global_resource_module.yaml b/changelogs/fragments/bgp_global_resource_module.yaml new file mode 100644 index 0000000..4d19b12 --- /dev/null +++ b/changelogs/fragments/bgp_global_resource_module.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add vyos BGP global resource module.(https://github.com/ansible-collections/vyos.vyos/pull/125). diff --git a/meta/runtime.yml b/meta/runtime.yml index e68ed60..1f99057 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -6,6 +6,10 @@ plugin_routing: redirect: vyos.vyos.vyos banner: redirect: vyos.vyos.vyos + vyos_bgp_global: + redirect: vyos.vyos.vyos + bgp_global: + redirect: vyos.vyos.vyos vyos_command: redirect: vyos.vyos.vyos command: @@ -113,6 +117,8 @@ plugin_routing: modules: banner: redirect: vyos.vyos.vyos_banner + bgp_global: + redirect: vyos.vyos.vyos_bgp_global command: redirect: vyos.vyos.vyos_command config: diff --git a/plugins/module_utils/network/vyos/argspec/bgp_global/__init__.py b/plugins/module_utils/network/vyos/argspec/bgp_global/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/bgp_global/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/bgp_global/bgp_global.py b/plugins/module_utils/network/vyos/argspec/bgp_global/bgp_global.py new file mode 100644 index 0000000..4192a84 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/bgp_global/bgp_global.py @@ -0,0 +1,290 @@ +# -*- 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_global module +""" + + +class Bgp_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_bgp_global module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {"type": "str"}, + "state": { + "default": "merged", + "type": "str", + "choices": [ + "merged", + "replaced", + "deleted", + "gathered", + "parsed", + "rendered", + "purged", + ], + }, + "config": { + "type": "dict", + "options": { + "redistribute": { + "elements": "dict", + "type": "list", + "options": { + "route_map": {"type": "str"}, + "metric": {"type": "int"}, + "protocol": { + "type": "str", + "choices": [ + "connected", + "kernel", + "ospf", + "rip", + "static", + ], + }, + }, + }, + "network": { + "elements": "dict", + "type": "list", + "options": { + "backdoor": {"type": "bool"}, + "route_map": {"type": "str"}, + "address": {"type": "str"}, + }, + }, + "maximum_paths": { + "type": "list", + "elements": "dict", + "options": { + "path": {"type": "str"}, + "count": {"type": "int"}, + }, + }, + "aggregate_address": { + "elements": "dict", + "type": "list", + "options": { + "summary_only": {"type": "bool"}, + "as_set": {"type": "bool"}, + "prefix": {"type": "str"}, + }, + }, + "timers": { + "type": "dict", + "options": { + "holdtime": {"type": "int"}, + "keepalive": {"type": "int"}, + }, + }, + "neighbor": { + "type": "list", + "elements": "dict", + "options": { + "shutdown": {"type": "bool"}, + "weight": {"type": "int"}, + "default_originate": {"type": "str"}, + "peer_group_name": {"type": "str"}, + "route_reflector_client": {"type": "bool"}, + "strict_capability_match": {"type": "bool"}, + "remove_private_as": {"type": "bool"}, + "as_override": {"type": "bool"}, + "port": {"type": "int"}, + "soft_reconfiguration": {"type": "bool"}, + "nexthop_self": {"type": "bool"}, + "remote_as": {"type": "int"}, + "ebgp_multihop": {"type": "int"}, + "route_map": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "route_map": {"type": "str"}, + }, + }, + "distribute_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "acl": {"type": "int"}, + }, + }, + "allowas_in": {"type": "int"}, + "passive": {"type": "bool"}, + "ttl_security": {"type": "int"}, + "peer_group": {"type": "bool"}, + "maximum_prefix": {"type": "int"}, + "prefix_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "prefix_list": {"type": "str"}, + }, + }, + "update_source": {"type": "str"}, + "description": {"type": "str"}, + "local_as": {"type": "int"}, + "route_server_client": {"type": "bool"}, + "attribute_unchanged": { + "type": "dict", + "options": { + "as_path": {"type": "bool"}, + "med": {"type": "bool"}, + "next_hop": {"type": "bool"}, + }, + }, + "disable_connected_check": {"type": "bool"}, + "address": {"type": "str"}, + "password": {"type": "str"}, + "disable_send_community": { + "type": "str", + "choices": ["extended", "standard"], + }, + "unsuppress_map": {"type": "str"}, + "override_capability": {"type": "bool"}, + "filter_list": { + "elements": "dict", + "type": "list", + "options": { + "action": { + "type": "str", + "choices": ["export", "import"], + }, + "path_list": {"type": "str"}, + }, + }, + "capability": { + "type": "dict", + "options": { + "orf": { + "type": "str", + "choices": ["send", "receive"], + }, + "dynamic": {"type": "bool"}, + }, + }, + "timers": { + "type": "dict", + "options": { + "holdtime": {"type": "int"}, + "connect": {"type": "int"}, + "keepalive": {"type": "int"}, + }, + }, + "disable_capability_negotiation": {"type": "bool"}, + "advertisement_interval": {"type": "int"}, + }, + }, + "bgp_params": { + "type": "dict", + "options": { + "router_id": {"type": "str"}, + "distance": { + "elements": "dict", + "type": "list", + "options": { + "prefix": {"type": "int"}, + "type": { + "type": "str", + "choices": [ + "external", + "internal", + "local", + ], + }, + "value": {"type": "int"}, + }, + }, + "dampening": { + "type": "dict", + "options": { + "half_life": {"type": "int"}, + "start_suppress_time": {"type": "int"}, + "max_suppress_time": {"type": "int"}, + "re_use": {"type": "int"}, + }, + }, + "graceful_restart": {"type": "int"}, + "scan_time": {"type": "int"}, + "always_compare_med": {"type": "bool"}, + "no_fast_external_failover": {"type": "bool"}, + "bestpath": { + "type": "dict", + "options": { + "med": { + "type": "str", + "choices": ["confed", "missing-as-worst"], + }, + "as_path": { + "type": "str", + "choices": ["confed", "ignore"], + }, + "compare_routerid": {"type": "bool"}, + }, + }, + "enforce_first_as": {"type": "bool"}, + "default": { + "type": "dict", + "options": { + "local_pref": {"type": "int"}, + "no_ipv4_unicast": {"type": "bool"}, + }, + }, + "cluster_id": {"type": "str"}, + "no_client_to_client_reflection": {"type": "bool"}, + "deterministic_med": {"type": "bool"}, + "log_neighbor_changes": {"type": "bool"}, + "disable_network_import_check": {"type": "bool"}, + "confederation": { + "type": "list", + "elements": "dict", + "options": { + "peers": {"type": "int"}, + "identifier": {"type": "int"}, + }, + }, + }, + }, + "as_number": {"type": "int"}, + }, + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/bgp_global/__init__.py b/plugins/module_utils/network/vyos/config/bgp_global/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/bgp_global/__init__.py 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 new file mode 100644 index 0000000..0a5f15d --- /dev/null +++ b/plugins/module_utils/network/vyos/config/bgp_global/bgp_global.py @@ -0,0 +1,426 @@ +# +# -*- 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 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_global import ( + Bgp_globalTemplate, +) + + +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 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_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 iteritems(haved): + if k in wantd or not wantd: + h_del.update({k: v}) + for num, entry in iteritems(h_del): + 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 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_global network resource. + """ + parsers = ["maximum_paths", "timers"] + self._compare_neighbor(want, have) + self._compare_lists(want, have) + self._compare_bgp_params(want, have) + for name, entry in iteritems(want): + 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 iteritems(have): + 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", + "network.backdoor", + "network.route_map", + ] + wneigh = want.pop("neighbor", {}) + hneigh = have.pop("neighbor", {}) + self._compare_neigh_lists(wneigh, hneigh) + for name, entry in iteritems(wneigh): + 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 iteritems(hneigh): + 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 " + + str(have["as_number"]) + + " 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}, + }, + ) + + 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 iteritems(wbgp): + 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 " + + str(have["as_number"]) + + " parameters" + ) + hbgp = {} + for name, entry in iteritems(hbgp): + if name == "confederation": + self.commands.append( + "delete protocols bgp " + + str(have["as_number"]) + + " 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_lists(self, want, have): + parsers = [ + "network.backdoor", + "network.route_map", + "redistribute.metric", + "redistribute.route_map", + "aggregate_address", + ] + for attrib in ["redistribute", "network", "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": want["as_number"], attrib: entry}, + have=hdict.pop(key, {}), + ) + hdict.pop(key, {}) + # remove remaining items in have for replaced + if not wdict and hdict: + attrib = re.sub("_", "-", attrib) + self.commands.append( + "delete protocols bgp " + + str(have["as_number"]) + + " " + + attrib + ) + hdict = {} + for key, entry in iteritems(hdict): + self.compare( + parsers=parsers, + want={}, + have={"as_number": have["as_number"], attrib: 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 iteritems(wdict): + 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 iteritems(entry): + 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 _check_af(self, neighbor): + af_present = False + if self._connection: + config_lines = self._get_config(self._connection).splitlines() + for line in config_lines: + 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/__init__.py b/plugins/module_utils/network/vyos/facts/bgp_global/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/bgp_global/__init__.py 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 new file mode 100644 index 0000000..3cfa83c --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/bgp_global/bgp_global.py @@ -0,0 +1,88 @@ +# -*- 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. +""" + +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_global import ( + Bgp_globalTemplate, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.bgp_global.bgp_global import ( + Bgp_globalArgs, +) +import re + + +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) + + for resource in data.splitlines(): + if "address-family" not in resource: + config_lines.append(re.sub("'", "", resource)) + + bgp_global_parser = Bgp_globalTemplate(lines=config_lines) + objs = bgp_global_parser.parse() + + if "neighbor" in objs: + 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( + utils.validate_config(self.argument_spec, {"config": objs}) + ) + + facts["bgp_global"] = 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 c2766de..95eff2e 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -49,6 +49,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospf_interfaces.ospf_interfaces import ( Ospf_interfacesFacts, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_global.bgp_global import ( + Bgp_globalFacts, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import ( Default, Neighbors, @@ -70,6 +73,7 @@ FACT_RESOURCE_SUBSETS = dict( ospfv3=Ospfv3Facts, ospfv2=Ospfv2Facts, ospf_interfaces=Ospf_interfacesFacts, + bgp_global=Bgp_globalFacts, ) diff --git a/plugins/module_utils/network/vyos/rm_templates/bgp_global.py b/plugins/module_utils/network/vyos/rm_templates/bgp_global.py new file mode 100644 index 0000000..aff6258 --- /dev/null +++ b/plugins/module_utils/network/vyos/rm_templates/bgp_global.py @@ -0,0 +1,2043 @@ +# -*- 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.module_utils.six import iteritems + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.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 iteritems(list_el): + command.append( + "protocols bgp {as_number} 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 {as_number} maximum-paths ".format(**config_data) + + list_el["path"] + + " " + + str(list_el["count"]) + ) + return command + + +def _tmplt_bgp_aggregate_address(config_data): + command = "protocols bgp {as_number} aggregate-address".format( + **config_data + ) + if config_data["aggregate_address"].get("as_set"): + command += " {prefix} as-set".format( + **config_data["aggregate_address"] + ) + if config_data["aggregate_address"].get("summary_only"): + command += " {prefix} summary-only".format( + **config_data["aggregate_address"] + ) + return command + + +def _tmplt_delete_bgp_maximum_paths(config_data): + command = "protocols bgp {as_number} maximum-paths".format(**config_data) + return command + + +def _tmplt_bgp_params_default(config_data): + command = "protocols bgp {as_number} 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_delete_redistribute(config_data): + command = ( + "protocols bgp {as_number} redistribute ".format(**config_data) + + config_data["redistribute"]["protocol"] + ) + return command + + +def _tmplt_bgp_neighbor_timers(config_data): + command = [] + for k, v in iteritems(config_data["neighbor"]["timers"]): + command.append( + "protocols bgp {as_number} 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 iteritems(config_data["timers"]): + command.append( + "protocols bgp {as_number} ".format(**config_data) + + "timers " + + k + + " " + + str(v) + ) + + return command + + +def _tmplt_bgp_neighbor_attribute_unchanged_as_path(config_data): + command = "protocols bgp {as_number} ".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 {as_number} ".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 {as_number} ".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 {as_number} ".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 {as_number} ".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 {as_number} ".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 {as_number} ".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 {as_number} parameters distance global ".format( + **config_data + ) + + config_data["bgp_params"]["distance"]["type"] + + " " + + str(config_data["bgp_params"]["distance"]["value"]) + ) + return command + + +class Bgp_globalTemplate(NetworkTemplate): + def __init__(self, lines=None): + prefix = {"set": "set", "remove": "delete"} + super(Bgp_globalTemplate, self).__init__( + lines=lines, tmplt=self, prefix=prefix + ) + + # fmt: off + PARSERS = [ + { + "name": "router", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }}", + "compval": "as_number", + "result": { + "as_number": "{{ as_num }}", + } + }, + { + "name": "aggregate_address", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+aggregate-address + \s+(?P<address>\S+) + \s*(?P<as_set>as-set)* + \s*(?P<summary_only>summary-only)* + $""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_aggregate_address, + "remval": "protocols bgp {{ as_number }} aggregate-address {{ aggregate_address.prefix }}", + "compval": "aggregate_address", + "result": { + "as_number": "{{ as_num }}", + "aggregate_address": [ + { + "prefix": "{{ address }}", + "as_set": "{{ True if as_set is defined }}", + "summary_only": "{{ True if summary_only is defined }}" + } + ] + } + }, + { + "name": "maximum_paths", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+advertisement-interval + \s+(?P<interval>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} advertisement-interval {{ neighbor.advertisement_interval }}", + "remval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+allowas-in + \s+number + \s+(?P<num>\'\d+\') + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+as-override + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \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+(?P<as_num>\d+) + \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+(?P<as_num>\d+) + \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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+capability + \s+(?P<dynamic>dynamic) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+capability + \s+orf + \s+prefix-list + \s+(?P<orf>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+default-originate + \s+route-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+description + \s+(?P<desc>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+disable-capability-negotiation + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+disable-connected-check + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+disable-send-community + \s+(?P<comm>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+ebgp-multihop + \s+(?P<hop>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+filter-list + \s+(?P<action>export|import) + \s+(?P<list>\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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+local-as + \s+(?P<as>\S+) + \s+no-prepend + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+maximum-prefix + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+nexthop-self + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+override-capability + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+passive + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} nexthop-self", + "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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+password + \s+(?P<pwd>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} password {{ neighbor.address }}", + "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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+peer-group + \s+(?P<name>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+port + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+prefix-list + \s+(?P<action>export|import) + \s+(?P<list>\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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+remote-as + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+remote-private-as + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+route-map + \s+(?P<action>export|import) + \s+(?P<map>\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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+route-reflector-client + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+route-server-client + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+shutdown + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+soft-reconfiguration + \s+inbound + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+strict-capability-match + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+unsuppress-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+update-source + \s+(?P<src>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+weight + \s+(?P<num>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+ttl-security + \s+(?P<ttl>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+neighbor + \s+(?P<address>\S+) + \s+timers + \s+(?P<type>connect|holdtime|keepalive) + \s+(?P<sec>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_neighbor_timers, + "remval": "protocols bgp {{ as_number }} neighbor {{ neighbor.address }} timers", + "compval": "neighbor.timers", + "result": { + "as_number": "{{ as_num }}", + "neighbor": { + "{{ address }}": { + "address": "{{ address }}", + "timers": { + "{{ type }}": "{{ sec }}" + } + } + } + } + }, + { + "name": "network.backdoor", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+network + \s+(?P<address>\S+) + \s+backdoor + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} network {{ network.address }} backdoor", + "remval": "protocols bgp {{ as_number }} network {{ network.address }}", + "compval": "network.backdoor", + "result": { + "as_number": "{{ as_num }}", + "network": [ + { + "address": "{{ address }}", + "backdoor": "{{ True }}" + } + ] + } + }, + { + "name": "network.route_map", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+network + \s+(?P<address>\S+) + \s+route-map + \s+(?P<map>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} network {{ network.address }} route-map {{ network.route_map }}", + "remval": "protocols bgp {{ as_number }} network {{ network.address }}", + "compval": "network.route_map", + "result": { + "as_number": "{{ as_num }}", + "network": [ + { + "address": "{{ address }}", + "route_map": "{{ map }}" + } + ] + } + }, + { + "name": "redistribute.metric", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+redistribute + \s+(?P<proto>\S+) + \s+metric + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} redistribute {{ redistribute.protocol }} metric {{ redistribute.metric }}", + "remval": _tmplt_bgp_delete_redistribute, + "compval": "redistribute", + "result": { + "as_number": "{{ as_num }}", + "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+redistribute + \s+(?P<proto>\S+) + \s+route-map + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} redistribute {{ redistribute.protocol }} route-map {{ redistribute.route_map }}", + "remval": _tmplt_bgp_delete_redistribute, + "compval": "redistribute", + "result": { + "as_number": "{{ as_num }}", + "redistribute": [ + { + "protocol": "{{ proto }}", + "route_map": "{{ val }}" + } + ] + } + }, + { + "name": "timers", + "getval": re.compile( + r""" + ^set + \s+protocols + \s+bgp + \s+(?P<as_num>\d+) + \s+timers + \s+(?P<type>\S+) + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_timers, + "remval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+always-compare-med + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+bestpath + \s+as-path + \s+(?P<path>confed|ignore) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+bestpath + \s+compare-routerid + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+bestpath + \s+med + \s+(?P<path>confed|missing-as-worst) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+cluster-id + \s+(?P<id>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+confederation + \s+(?P<type>identifier|peers) + \s+(?P<val>\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+(?P<as_num>\d+) + \s+parameters + \s+dampening + \s+half-life + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+dampening + \s+max-suppress-time + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+dampening + \s+re-use + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+dampening + \s+start-suppress-time + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+default + \s*(?P<no_ipv4_unicast>no-ipv4-unicast)* + \s*(?P<local_pref>local-pref\s\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_params_default, + "remval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+deterministic-med + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+disable-network-import-check + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+distance\sprefix + \s+(?P<prefix>\S+) + \s+distance + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} parameters distance prefix {{ bgp_params.distance.prefix }} distance {{ bgp_params.distance.value }}", + "compval": "bgp_params.distance.prefix", + "remval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+distance\sglobal + \s+(?P<type>\S+) + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_bgp_params_distance, + "remval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+enforce-first-as + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+graceful-restart\s+stalepath-time + \s+(?P<val>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+log-neighbor-changes + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+no-client-to-client-reflection + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} parameters no-client-to-client-reflection", + "compval": "bgp_params.log_neighbor_changes", + "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+(?P<as_num>\d+) + \s+parameters + \s+no-fast-external-failover + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+router-id + \s+(?P<id>\S+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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+(?P<as_num>\d+) + \s+parameters + \s+scan-time + \s+(?P<sec>\d+) + *$""", + re.VERBOSE, + ), + "setval": "protocols bgp {{ as_number }} 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/plugins/modules/vyos_bgp_global.py b/plugins/modules/vyos_bgp_global.py new file mode 100644 index 0000000..aedbae1 --- /dev/null +++ b/plugins/modules/vyos_bgp_global.py @@ -0,0 +1,1440 @@ +#!/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_global +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: vyos_bgp_global +version_added: 2.0.0 +short_description: BGP Global Resource Module. +description: +- This module manages BGP global 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 + 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 + maximum_paths: + description: BGP multipaths + type: list + elements: dict + suboptions: + path: + description: BGP multipaths + type: str + count: + description: No. of paths. + type: int + neighbor: + description: BGP neighbor + type: list + elements: dict + suboptions: + address: + description: BGP neighbor address (v4/v6). + type: str + advertisement_interval: + description: Minimum interval for sending routing updates. + type: int + 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 + type: bool + med: + description: med + type: bool + next_hop: + description: next_hop + 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 + description: + description: description text + type: str + disable_capability_negotiation: + description: Disbale capability negotiation with the neighbor + type: bool + disable_connected_check: + description: Disable check to see if EBGP peer's address is a connected route. + type: bool + disable_send_community: + description: Disable sending community attributes to this neighbor. + type: str + choices: ['extended', 'standard'] + 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 + ebgp_multihop: + description: Allow this EBGP neighbor to not be on a directly connected network. Specify + the number hops. + 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 + local_as: + description: local as number not to be prepended to updates from EBGP peers + type: int + 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_self: + description: Nexthop for routes sent to this neighbor to be the local router. + type: bool + override_capability: + description: Ignore capability negotiation with specified neighbor. + type: bool + passive: + description: Do not initiate a session with this neighbor + type: bool + password: + description: BGP MD5 password + type: str + peer_group_name: + description: IPv4 peer group for this peer + type: str + peer_group: + description: True if all the configs unde this neighbor key is for peer group template. + type: bool + port: + description: Neighbor's BGP port + type: int + 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 + remote_as: + description: Neighbor BGP AS number + type: int + 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 + shutdown: + description: Administratively shut down neighbor + type: bool + soft_reconfiguration: + description: Soft reconfiguration for neighbor + type: bool + strict_capability_match: + description: Enable strict capability negotiation + type: bool + unsuppress_map: + description: Route-map to selectively unsuppress suppressed routes + type: str + update_source: + description: Source IP of routing updates + type: str + weight: + description: Default weight for routes from this neighbor + type: int + ttl_security: + description: Ttl security mechanism for this BGP peer + type: int + timers: + description: Neighbor timers + type: dict + suboptions: + connect: + description: BGP connect timer for this neighbor. + type: int + holdtime: + description: BGP hold timer for this neighbor + type: int + keepalive: + description: BGP keepalive interval for this neighbor + type: int + network: + description: BGP network + type: list + elements: dict + suboptions: + address: + description: BGP network address + type: str + 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', 'rip', 'static'] + route_map: + description: Route map to filter redistributed routes + type: str + metric: + description: Metric for redistributed routes. + type: int + timers: + description: BGP protocol timers + type: dict + suboptions: + keepalive: + description: Keepalive interval + type: int + holdtime: + description: Hold time interval + type: int + bgp_params: + description: BGP parameters + type: dict + suboptions: + always_compare_med: + description: Always compare MEDs from different neighbors + type: bool + bestpath: + description: Default bestpath selection mechanism + type: dict + suboptions: + as_path: + description: AS-path attribute comparison parameters + type: str + choices: ['confed', 'ignore'] + compare_routerid: + description: Compare the router-id for identical EBGP paths + type: bool + med: + description: MED attribute comparison parameters + type: str + choices: ['confed', 'missing-as-worst'] + cluster_id: + description: Route-reflector cluster-id + type: str + confederation: + description: AS confederation parameters + type: list + elements: dict + suboptions: + identifier: + description: Confederation AS identifier + type: int + peers: + description: Peer ASs in the BGP confederation + type: int + dampening: + description: Enable route-flap dampening + type: dict + suboptions: + half_life: + description: Half-life penalty in seconds + type: int + max_suppress_time: + description: Maximum duration to suppress a stable route + type: int + re_use: + description: Time to start reusing a route + type: int + start_suppress_time: + description: When to start suppressing a route + type: int + default: + description: BGP defaults + type: dict + suboptions: + local_pref: + description: Default local preference + type: int + no_ipv4_unicast: + description: Deactivate IPv4 unicast for a peer by default + type: bool + deterministic_med: + description: Compare MEDs between different peers in the same AS + type: bool + disable_network_import_check: + description: Disable IGP route check for network statements + type: bool + distance: + description: Administratives distances for BGP routes + type: list + elements: dict + suboptions: + type: + description: Type of route + type: str + choices: ['external', 'internal', 'local'] + value: + description: distance + type: int + prefix: + description: Administrative distance for a specific BGP prefix + type: int + enforce_first_as: + description: Require first AS in the path to match peer's AS + type: bool + graceful_restart: + description: Maximum time to hold onto restarting peer's stale paths + type: int + log_neighbor_changes: + description: Log neighbor up/down changes and reset reason + type: bool + no_client_to_client_reflection: + description: Disable client to client route reflection + type: bool + no_fast_external_failover: + description: Disable immediate sesison reset if peer's connected link goes down + type: bool + router_id: + description: BGP router-id + type: str + scan_time: + description: BGP route scanner interval + type: int + state: + description: + - The state the configuration should be left in. + - State I(purged) removes all the BGP configurations from the + target device. Use caution with this state.('delete protocols bgp <x>') + - State I(deleted) only removes BGP attributes that this modules + manages and does not negate the BGP process completely. Thereby, preserving + address-family related configurations under BGP context. + - Running states I(deleted) and I(replaced) will result in an error if there + are address-family configuration lines present under neighbor context that is + is to be removed. Please use the M(vyos.vyos.vyos_bgp_address_family) + module for prior cleanup. + - Refer to examples for more details. + type: str + choices: [deleted, merged, purged, replaced, gathered, rendered, parsed] + default: merged + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the EOS device by + executing the command B(show running-config | section 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. + type: str + +""" +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_global: + config: + as_number: "65536" + aggregate_address: + - prefix: "203.0.113.0/24" + as_set: true + - prefix: "192.0.2.0/24" + summary_only: true + network: + - address: "192.1.13.0/24" + backdoor: true + redistribute: + - protocol: "kernel" + metric: 45 + - protocol: "connected" + route_map: "map01" + maximum_paths: + - path: "ebgp" + count: 20 + - path: "ibgp" + count: 55 + timers: + keepalive: 35 + bgp_params: + bestpath: + as_path: "confed" + compare_routerid: true + default: + no_ipv4_unicast: true + router_id: "192.1.2.9" + confederation: + - peers: 20 + - peers: 55 + - identifier: 66 + neighbor: + - address: "192.0.2.25" + disable_connected_check: true + timers: + holdtime: 30 + keepalive: 10 + - address: "203.0.113.5" + attribute_unchanged: + as_path: true + med: true + ebgp_multihop: 2 + remote_as: 101 + update_source: "192.0.2.25" + - address: "5001::64" + maximum_prefix: 34 + distribute_list: + - acl: 20 + action: "export" + - acl: 40 + action: "import" + + state: merged + +# After State +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 aggregate-address 192.0.2.0/24 'summary-only' +# set protocols bgp 65536 aggregate-address 203.0.113.0/24 'as-set' +# set protocols bgp 65536 maximum-paths ebgp '20' +# set protocols bgp 65536 maximum-paths ibgp '55' +# set protocols bgp 65536 neighbor 192.0.2.25 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'as-path' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'med' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'next-hop' +# set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop '2' +# set protocols bgp 65536 neighbor 203.0.113.5 remote-as '101' +# set protocols bgp 65536 neighbor 203.0.113.5 update-source '192.0.2.25' +# set protocols bgp 65536 neighbor 5001::64 distribute-list export '20' +# set protocols bgp 65536 neighbor 5001::64 distribute-list import '40' +# set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' +# set protocols bgp 65536 network 192.1.13.0/24 'backdoor' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters confederation identifier '66' +# set protocols bgp 65536 parameters confederation peers '20' +# set protocols bgp 65536 parameters confederation peers '55' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters router-id '192.1.2.9' +# set protocols bgp 65536 redistribute connected route-map 'map01' +# set protocols bgp 65536 redistribute kernel metric '45' +# set protocols bgp 65536 timers keepalive '35' +# vyos@vyos:~$ +# +# # Module Execution: +# +# "after": { +# "aggregate_address": [ +# { +# "prefix": "192.0.2.0/24", +# "summary_only": true +# }, +# { +# "prefix": "203.0.113.0/24", +# "as_set": true +# } +# ], +# "as_number": 65536, +# "bgp_params": { +# "bestpath": { +# "as_path": "confed", +# "compare_routerid": true +# }, +# "confederation": [ +# { +# "identifier": 66 +# }, +# { +# "peers": 20 +# }, +# { +# "peers": 55 +# } +# ], +# "default": { +# "no_ipv4_unicast": true +# }, +# "router_id": "192.1.2.9" +# }, +# "maximum_paths": [ +# { +# "count": 20, +# "path": "ebgp" +# }, +# { +# "count": 55, +# "path": "ibgp" +# } +# ], +# "neighbor": [ +# { +# "address": "192.0.2.25", +# "disable_connected_check": true, +# "timers": { +# "holdtime": 30, +# "keepalive": 10 +# } +# }, +# { +# "address": "203.0.113.5", +# "attribute_unchanged": { +# "as_path": true, +# "med": true, +# "next_hop": true +# }, +# "ebgp_multihop": 2, +# "remote_as": 101, +# "update_source": "192.0.2.25" +# }, +# { +# "address": "5001::64", +# "distribute_list": [ +# { +# "acl": 20, +# "action": "export" +# }, +# { +# "acl": 40, +# "action": "import" +# } +# ], +# "maximum_prefix": 34 +# } +# ], +# "network": [ +# { +# "address": "192.1.13.0/24", +# "backdoor": true +# } +# ], +# "redistribute": [ +# { +# "protocol": "connected", +# "route_map": "map01" +# }, +# { +# "metric": 45, +# "protocol": "kernel" +# } +# ], +# "timers": { +# "keepalive": 35 +# } +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "set protocols bgp 65536 neighbor 192.0.2.25 disable-connected-check", +# "set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime 30", +# "set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive 10", +# "set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged as-path", +# "set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged med", +# "set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged next-hop", +# "set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop 2", +# "set protocols bgp 65536 neighbor 203.0.113.5 remote-as 101", +# "set protocols bgp 65536 neighbor 203.0.113.5 update-source 192.0.2.25", +# "set protocols bgp 65536 neighbor 5001::64 maximum-prefix 34", +# "set protocols bgp 65536 neighbor 5001::64 distribute-list export 20", +# "set protocols bgp 65536 neighbor 5001::64 distribute-list import 40", +# "set protocols bgp 65536 redistribute kernel metric 45", +# "set protocols bgp 65536 redistribute connected route-map map01", +# "set protocols bgp 65536 network 192.1.13.0/24 backdoor", +# "set protocols bgp 65536 aggregate-address 203.0.113.0/24 as-set", +# "set protocols bgp 65536 aggregate-address 192.0.2.0/24 summary-only", +# "set protocols bgp 65536 parameters bestpath as-path confed", +# "set protocols bgp 65536 parameters bestpath compare-routerid", +# "set protocols bgp 65536 parameters default no-ipv4-unicast", +# "set protocols bgp 65536 parameters router-id 192.1.2.9", +# "set protocols bgp 65536 parameters confederation peers 20", +# "set protocols bgp 65536 parameters confederation peers 55", +# "set protocols bgp 65536 parameters confederation identifier 66", +# "set protocols bgp 65536 maximum-paths ebgp 20", +# "set protocols bgp 65536 maximum-paths ibgp 55", +# "set protocols bgp 65536 timers keepalive 35" +# ], + +# Using replaced: +# -------------- + +# Before state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 aggregate-address 192.0.2.0/24 'summary-only' +# set protocols bgp 65536 aggregate-address 203.0.113.0/24 'as-set' +# set protocols bgp 65536 maximum-paths ebgp '20' +# set protocols bgp 65536 maximum-paths ibgp '55' +# set protocols bgp 65536 neighbor 192.0.2.25 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'as-path' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'med' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'next-hop' +# set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop '2' +# set protocols bgp 65536 neighbor 203.0.113.5 remote-as '101' +# set protocols bgp 65536 neighbor 203.0.113.5 update-source '192.0.2.25' +# set protocols bgp 65536 neighbor 5001::64 distribute-list export '20' +# set protocols bgp 65536 neighbor 5001::64 distribute-list import '40' +# set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' +# set protocols bgp 65536 network 192.1.13.0/24 'backdoor' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters confederation identifier '66' +# set protocols bgp 65536 parameters confederation peers '20' +# set protocols bgp 65536 parameters confederation peers '55' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters router-id '192.1.2.9' +# set protocols bgp 65536 redistribute connected route-map 'map01' +# set protocols bgp 65536 redistribute kernel metric '45' +# set protocols bgp 65536 timers keepalive '35' +# vyos@vyos:~$ + + - name: Replace + vyos.vyos.vyos_bgp_global: + config: + as_number: "65536" + network: + - address: "203.0.113.0/24" + route_map: map01 + redistribute: + - protocol: "static" + route_map: "map01" + neighbor: + - address: "192.0.2.40" + advertisement_interval: 72 + capability: + orf: "receive" + bgp_params: + bestpath: + as_path: "confed" + + state: replaced +# After state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 neighbor 192.0.2.40 advertisement-interval '72' +# set protocols bgp 65536 neighbor 192.0.2.40 capability orf prefix-list 'receive' +# set protocols bgp 65536 network 203.0.113.0/24 route-map 'map01' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 redistribute static route-map 'map01' +# vyos@vyos:~$ +# +# +# Module Execution: +# +# "after": { +# "as_number": 65536, +# "bgp_params": { +# "bestpath": { +# "as_path": "confed" +# } +# }, +# "neighbor": [ +# { +# "address": "192.0.2.40", +# "advertisement_interval": 72, +# "capability": { +# "orf": "receive" +# } +# } +# ], +# "network": [ +# { +# "address": "203.0.113.0/24", +# "route_map": "map01" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map01" +# } +# ] +# }, +# "before": { +# "aggregate_address": [ +# { +# "prefix": "192.0.2.0/24", +# "summary_only": true +# }, +# { +# "prefix": "203.0.113.0/24", +# "as_set": true +# } +# ], +# "as_number": 65536, +# "bgp_params": { +# "bestpath": { +# "as_path": "confed", +# "compare_routerid": true +# }, +# "confederation": [ +# { +# "identifier": 66 +# }, +# { +# "peers": 20 +# }, +# { +# "peers": 55 +# } +# ], +# "default": { +# "no_ipv4_unicast": true +# }, +# "router_id": "192.1.2.9" +# }, +# "maximum_paths": [ +# { +# "count": 20, +# "path": "ebgp" +# }, +# { +# "count": 55, +# "path": "ibgp" +# } +# ], +# "neighbor": [ +# { +# "address": "192.0.2.25", +# "disable_connected_check": true, +# "timers": { +# "holdtime": 30, +# "keepalive": 10 +# } +# }, +# { +# "address": "203.0.113.5", +# "attribute_unchanged": { +# "as_path": true, +# "med": true, +# "next_hop": true +# }, +# "ebgp_multihop": 2, +# "remote_as": 101, +# "update_source": "192.0.2.25" +# }, +# { +# "address": "5001::64", +# "distribute_list": [ +# { +# "acl": 20, +# "action": "export" +# }, +# { +# "acl": 40, +# "action": "import" +# } +# ], +# "maximum_prefix": 34 +# } +# ], +# "network": [ +# { +# "address": "192.1.13.0/24", +# "backdoor": true +# } +# ], +# "redistribute": [ +# { +# "protocol": "connected", +# "route_map": "map01" +# }, +# { +# "metric": 45, +# "protocol": "kernel" +# } +# ], +# "timers": { +# "keepalive": 35 +# } +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 65536 timers", +# "delete protocols bgp 65536 maximum-paths ", +# "delete protocols bgp 65536 maximum-paths ", +# "delete protocols bgp 65536 parameters router-id 192.1.2.9", +# "delete protocols bgp 65536 parameters default", +# "delete protocols bgp 65536 parameters confederation", +# "delete protocols bgp 65536 parameters bestpath compare-routerid", +# "delete protocols bgp 65536 aggregate-address", +# "delete protocols bgp 65536 network 192.1.13.0/24", +# "delete protocols bgp 65536 redistribute kernel", +# "delete protocols bgp 65536 redistribute kernel", +# "delete protocols bgp 65536 redistribute connected", +# "delete protocols bgp 65536 redistribute connected", +# "delete protocols bgp 65536 neighbor 5001::64", +# "delete protocols bgp 65536 neighbor 203.0.113.5", +# "delete protocols bgp 65536 neighbor 192.0.2.25", +# "set protocols bgp 65536 neighbor 192.0.2.40 advertisement-interval 72", +# "set protocols bgp 65536 neighbor 192.0.2.40 capability orf prefix-list receive", +# "set protocols bgp 65536 redistribute static route-map map01", +# "set protocols bgp 65536 network 203.0.113.0/24 route-map map01" +# ], + +# Using deleted: +# ------------- + +# Before state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 neighbor 192.0.2.40 advertisement-interval '72' +# set protocols bgp 65536 neighbor 192.0.2.40 capability orf prefix-list 'receive' +# set protocols bgp 65536 network 203.0.113.0/24 route-map 'map01' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 redistribute static route-map 'map01' +# vyos@vyos:~$ + + - name: Delete configuration + vyos.vyos.vyos_bgp_global: + config: + as_number: "65536" + state: deleted + +# After state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp '65536' +# vyos@vyos:~$ +# +# +# Module Execution: +# +# "after": { +# "as_number": 65536 +# }, +# "before": { +# "as_number": 65536, +# "bgp_params": { +# "bestpath": { +# "as_path": "confed" +# } +# }, +# "neighbor": [ +# { +# "address": "192.0.2.40", +# "advertisement_interval": 72, +# "capability": { +# "orf": "receive" +# } +# } +# ], +# "network": [ +# { +# "address": "203.0.113.0/24", +# "route_map": "map01" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map01" +# } +# ] +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 65536 neighbor 192.0.2.40", +# "delete protocols bgp 65536 redistribute", +# "delete protocols bgp 65536 network", +# "delete protocols bgp 65536 parameters" +# ], + +# Using purged: + +# Before state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 aggregate-address 192.0.2.0/24 'summary-only' +# set protocols bgp 65536 aggregate-address 203.0.113.0/24 'as-set' +# set protocols bgp 65536 maximum-paths ebgp '20' +# set protocols bgp 65536 maximum-paths ibgp '55' +# set protocols bgp 65536 neighbor 192.0.2.25 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'as-path' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'med' +# set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'next-hop' +# set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop '2' +# set protocols bgp 65536 neighbor 203.0.113.5 remote-as '101' +# set protocols bgp 65536 neighbor 203.0.113.5 update-source '192.0.2.25' +# set protocols bgp 65536 neighbor 5001::64 distribute-list export '20' +# set protocols bgp 65536 neighbor 5001::64 distribute-list import '40' +# set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' +# set protocols bgp 65536 network 192.1.13.0/24 'backdoor' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters confederation identifier '66' +# set protocols bgp 65536 parameters confederation peers '20' +# set protocols bgp 65536 parameters confederation peers '55' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters router-id '192.1.2.9' +# set protocols bgp 65536 redistribute connected route-map 'map01' +# set protocols bgp 65536 redistribute kernel metric '45' +# set protocols bgp 65536 timers keepalive '35' +# vyos@vyos:~$ + + + - name: Purge configuration + vyos.vyos.vyos_bgp_global: + config: + as_number: "65536" + state: purged + +# After state: + +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# vyos@vyos:~$ +# +# Module Execution: +# +# "after": {}, +# "before": { +# "aggregate_address": [ +# { +# "prefix": "192.0.2.0/24", +# "summary_only": true +# }, +# { +# "prefix": "203.0.113.0/24", +# "as_set": true +# } +# ], +# "as_number": 65536, +# "bgp_params": { +# "bestpath": { +# "as_path": "confed", +# "compare_routerid": true +# }, +# "confederation": [ +# { +# "identifier": 66 +# }, +# { +# "peers": 20 +# }, +# { +# "peers": 55 +# } +# ], +# "default": { +# "no_ipv4_unicast": true +# }, +# "router_id": "192.1.2.9" +# }, +# "maximum_paths": [ +# { +# "count": 20, +# "path": "ebgp" +# }, +# { +# "count": 55, +# "path": "ibgp" +# } +# ], +# "neighbor": [ +# { +# "address": "192.0.2.25", +# "disable_connected_check": true, +# "timers": { +# "holdtime": 30, +# "keepalive": 10 +# } +# }, +# { +# "address": "203.0.113.5", +# "attribute_unchanged": { +# "as_path": true, +# "med": true, +# "next_hop": true +# }, +# "ebgp_multihop": 2, +# "remote_as": 101, +# "update_source": "192.0.2.25" +# }, +# { +# "address": "5001::64", +# "distribute_list": [ +# { +# "acl": 20, +# "action": "export" +# }, +# { +# "acl": 40, +# "action": "import" +# } +# ], +# "maximum_prefix": 34 +# } +# ], +# "network": [ +# { +# "address": "192.1.13.0/24", +# "backdoor": true +# } +# ], +# "redistribute": [ +# { +# "protocol": "connected", +# "route_map": "map01" +# }, +# { +# "metric": 45, +# "protocol": "kernel" +# } +# ], +# "timers": { +# "keepalive": 35 +# } +# }, +# "changed": true, +# "commands": [ +# "delete protocols bgp 65536" +# ], + + +# Deleted in presence of address family under neighbors: + +# Before state: +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 neighbor 192.0.2.43 advertisement-interval '72' +# set protocols bgp 65536 neighbor 192.0.2.43 capability 'dynamic' +# set protocols bgp 65536 neighbor 192.0.2.43 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.43 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.43 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.0 address-family 'ipv6-unicast' +# set protocols bgp 65536 neighbor 203.0.113.0 capability orf prefix-list 'receive' +# set protocols bgp 65536 network 203.0.113.0/24 route-map 'map01' +# set protocols bgp 65536 parameters 'always-compare-med' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters dampening half-life '33' +# set protocols bgp 65536 parameters dampening max-suppress-time '20' +# set protocols bgp 65536 parameters dampening re-use '60' +# set protocols bgp 65536 parameters dampening start-suppress-time '5' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters distance global external '66' +# set protocols bgp 65536 parameters distance global internal '20' +# set protocols bgp 65536 parameters distance global local '10' +# set protocols bgp 65536 redistribute static route-map 'map01' +# vyos@vyos:~$ ^C +# vyos@vyos:~$ + + + - name: Delete configuration + vyos.vyos.vyos_bgp_global: + config: + as_number: "65536" + state: deleted + +# Module Execution: +# +# "changed": false, +# "invocation": { +# "module_args": { +# "config": { +# "aggregate_address": null, +# "as_number": 65536, +# "bgp_params": null, +# "maximum_paths": null, +# "neighbor": null, +# "network": null, +# "redistribute": null, +# "timers": null +# }, +# "running_config": null, +# "state": "deleted" +# } +# }, +# "msg": "Use the _bgp_address_family module to delete the address_family under neighbor 203.0.113.0, before replacing/deleting the neighbor." +# } + +# using gathered: +# -------------- + +# Before state: +# vyos@vyos:~$ show configuration commands | match "set protocols bgp" +# set protocols bgp 65536 neighbor 192.0.2.43 advertisement-interval '72' +# set protocols bgp 65536 neighbor 192.0.2.43 capability 'dynamic' +# set protocols bgp 65536 neighbor 192.0.2.43 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.43 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.43 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.0 address-family 'ipv6-unicast' +# set protocols bgp 65536 neighbor 203.0.113.0 capability orf prefix-list 'receive' +# set protocols bgp 65536 network 203.0.113.0/24 route-map 'map01' +# set protocols bgp 65536 parameters 'always-compare-med' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters dampening half-life '33' +# set protocols bgp 65536 parameters dampening max-suppress-time '20' +# set protocols bgp 65536 parameters dampening re-use '60' +# set protocols bgp 65536 parameters dampening start-suppress-time '5' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters distance global external '66' +# set protocols bgp 65536 parameters distance global internal '20' +# set protocols bgp 65536 parameters distance global local '10' +# set protocols bgp 65536 redistribute static route-map 'map01' +# vyos@vyos:~$ ^C + + - name: gather configs + vyos.vyos.vyos_bgp_global: + state: gathered + +# Module Execution: +# "gathered": { +# "as_number": 65536, +# "bgp_params": { +# "always_compare_med": true, +# "bestpath": { +# "as_path": "confed", +# "compare_routerid": true +# }, +# "default": { +# "no_ipv4_unicast": true +# }, +# "distance": [ +# { +# "type": "external", +# "value": 66 +# }, +# { +# "type": "internal", +# "value": 20 +# }, +# { +# "type": "local", +# "value": 10 +# } +# ] +# }, +# "neighbor": [ +# { +# "address": "192.0.2.43", +# "advertisement_interval": 72, +# "capability": { +# "dynamic": true +# }, +# "disable_connected_check": true, +# "timers": { +# "holdtime": 30, +# "keepalive": 10 +# } +# }, +# { +# "address": "203.0.113.0", +# "capability": { +# "orf": "receive" +# } +# } +# ], +# "network": [ +# { +# "address": "203.0.113.0/24", +# "route_map": "map01" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map01" +# } +# ] +# }, +# + +# Using parsed: +# ------------ + +# parsed.cfg + +# set protocols bgp 65536 neighbor 192.0.2.43 advertisement-interval '72' +# set protocols bgp 65536 neighbor 192.0.2.43 capability 'dynamic' +# set protocols bgp 65536 neighbor 192.0.2.43 'disable-connected-check' +# set protocols bgp 65536 neighbor 192.0.2.43 timers holdtime '30' +# set protocols bgp 65536 neighbor 192.0.2.43 timers keepalive '10' +# set protocols bgp 65536 neighbor 203.0.113.0 address-family 'ipv6-unicast' +# set protocols bgp 65536 neighbor 203.0.113.0 capability orf prefix-list 'receive' +# set protocols bgp 65536 network 203.0.113.0/24 route-map 'map01' +# set protocols bgp 65536 parameters 'always-compare-med' +# set protocols bgp 65536 parameters bestpath as-path 'confed' +# set protocols bgp 65536 parameters bestpath 'compare-routerid' +# set protocols bgp 65536 parameters dampening half-life '33' +# set protocols bgp 65536 parameters dampening max-suppress-time '20' +# set protocols bgp 65536 parameters dampening re-use '60' +# set protocols bgp 65536 parameters dampening start-suppress-time '5' +# set protocols bgp 65536 parameters default 'no-ipv4-unicast' +# set protocols bgp 65536 parameters distance global external '66' +# set protocols bgp 65536 parameters distance global internal '20' +# set protocols bgp 65536 parameters distance global local '10' +# set protocols bgp 65536 redistribute static route-map 'map01' + + - name: parse configs + vyos.vyos.vyos_bgp_global: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + tags: + - parsed + +# Module execution: +# "parsed": { +# "as_number": 65536, +# "bgp_params": { +# "always_compare_med": true, +# "bestpath": { +# "as_path": "confed", +# "compare_routerid": true +# }, +# "default": { +# "no_ipv4_unicast": true +# }, +# "distance": [ +# { +# "type": "external", +# "value": 66 +# }, +# { +# "type": "internal", +# "value": 20 +# }, +# { +# "type": "local", +# "value": 10 +# } +# ] +# }, +# "neighbor": [ +# { +# "address": "192.0.2.43", +# "advertisement_interval": 72, +# "capability": { +# "dynamic": true +# }, +# "disable_connected_check": true, +# "timers": { +# "holdtime": 30, +# "keepalive": 10 +# } +# }, +# { +# "address": "203.0.113.0", +# "capability": { +# "orf": "receive" +# } +# } +# ], +# "network": [ +# { +# "address": "203.0.113.0/24", +# "route_map": "map01" +# } +# ], +# "redistribute": [ +# { +# "protocol": "static", +# "route_map": "map01" +# } +# ] +# } +# + +# Using rendered: +# -------------- + + - name: Render + vyos.vyos.vyos_bgp_global: + config: + as_number: "65536" + network: + - address: "203.0.113.0/24" + route_map: map01 + redistribute: + - protocol: "static" + route_map: "map01" + bgp_params: + always_compare_med: true + dampening: + start_suppress_time: 5 + max_suppress_time: 20 + half_life: 33 + re_use: 60 + distance: + - type: "internal" + value: 20 + - type: "local" + value: 10 + - type: "external" + value: 66 + bestpath: + as_path: "confed" + compare_routerid: true + default: + no_ipv4_unicast: true + neighbor: + - address: "192.0.2.43" + disable_connected_check: true + advertisement_interval: 72 + capability: + dynamic: true + timers: + holdtime: 30 + keepalive: 10 + - address: "203.0.113.0" + capability: + orf: "receive" + + state: rendered + +# Module Execution: +# "rendered": [ +# "set protocols bgp 65536 neighbor 192.0.2.43 disable-connected-check", +# "set protocols bgp 65536 neighbor 192.0.2.43 advertisement-interval 72", +# "set protocols bgp 65536 neighbor 192.0.2.43 capability dynamic", +# "set protocols bgp 65536 neighbor 192.0.2.43 timers holdtime 30", +# "set protocols bgp 65536 neighbor 192.0.2.43 timers keepalive 10", +# "set protocols bgp 65536 neighbor 203.0.113.0 capability orf prefix-list receive", +# "set protocols bgp 65536 redistribute static route-map map01", +# "set protocols bgp 65536 network 203.0.113.0/24 route-map map01", +# "set protocols bgp 65536 parameters always-compare-med", +# "set protocols bgp 65536 parameters dampening half-life 33", +# "set protocols bgp 65536 parameters dampening max-suppress-time 20", +# "set protocols bgp 65536 parameters dampening re-use 60", +# "set protocols bgp 65536 parameters dampening start-suppress-time 5", +# "set protocols bgp 65536 parameters distance global internal 20", +# "set protocols bgp 65536 parameters distance global local 10", +# "set protocols bgp 65536 parameters distance global external 66", +# "set protocols bgp 65536 parameters bestpath as-path confed", +# "set protocols bgp 65536 parameters bestpath compare-routerid", +# "set protocols bgp 65536 parameters default no-ipv4-unicast" +# ] + + +""" + +from ansible.module_utils.basic import AnsibleModule +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.config.bgp_global.bgp_global import ( + Bgp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_globalArgs.argument_spec, + mutually_exclusive=[], + required_if=[], + supports_check_mode=False, + ) + + result = Bgp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/vyos_bgp_global/defaults/main.yaml b/tests/integration/targets/vyos_bgp_global/defaults/main.yaml new file mode 100644 index 0000000..852a6be --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_bgp_global/meta/main.yaml b/tests/integration/targets/vyos_bgp_global/meta/main.yaml new file mode 100644 index 0000000..7413320 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: + - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_bgp_global/tasks/cli.yaml b/tests/integration/targets/vyos_bgp_global/tasks/cli.yaml new file mode 100644 index 0000000..93eb2fe --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases + find: + paths: '{{ role_path }}/tests/cli' + patterns: '{{ testcase }}.yaml' + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) + include: '{{ test_case_to_run }}' + vars: + ansible_connection: ansible.netcommon.network_cli + with_items: '{{ test_items }}' + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_bgp_global/tasks/main.yaml b/tests/integration/targets/vyos_bgp_global/tasks/main.yaml new file mode 100644 index 0000000..b957d2f --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml + tags: + - network_cli diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_bgp_global/tests/cli/_parsed_config.cfg new file mode 100644 index 0000000..2338b03 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/_parsed_config.cfg @@ -0,0 +1,30 @@ +set policy access-list 20 description 'acl20' +set policy access-list 40 description 'acl40' +set policy route-map map01 description 'map01' +set protocols bgp 65536 aggregate-address 192.0.2.0/24 'summary-only' +set protocols bgp 65536 aggregate-address 203.0.113.0/24 'as-set' +set protocols bgp 65536 maximum-paths ebgp '20' +set protocols bgp 65536 maximum-paths ibgp '55' +set protocols bgp 65536 neighbor 192.0.2.25 'disable-connected-check' +set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime '30' +set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive '10' +set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'as-path' +set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'med' +set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'next-hop' +set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop '2' +set protocols bgp 65536 neighbor 203.0.113.5 remote-as '101' +set protocols bgp 65536 neighbor 203.0.113.5 update-source '192.0.2.25' +set protocols bgp 65536 neighbor 5001::64 distribute-list export '20' +set protocols bgp 65536 neighbor 5001::64 distribute-list import '40' +set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' +set protocols bgp 65536 network 192.1.13.0/24 'backdoor' +set protocols bgp 65536 parameters bestpath as-path 'confed' +set protocols bgp 65536 parameters bestpath 'compare-routerid' +set protocols bgp 65536 parameters confederation identifier '66' +set protocols bgp 65536 parameters confederation peers '20' +set protocols bgp 65536 parameters confederation peers '55' +set protocols bgp 65536 parameters default 'no-ipv4-unicast' +set protocols bgp 65536 parameters router-id '192.1.2.9' +set protocols bgp 65536 redistribute connected route-map 'map01' +set protocols bgp 65536 redistribute kernel metric '45' +set protocols bgp 65536 timers keepalive '35' diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/_populate.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/_populate.yaml new file mode 100644 index 0000000..ec237d9 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/_populate.yaml @@ -0,0 +1,37 @@ +--- +- name: setup + vyos.vyos.vyos_config: + lines: + - set policy access-list 20 description 'acl20' + - set policy access-list 40 description 'acl40' + - set policy route-map map01 description 'map01' + - set protocols bgp 65536 aggregate-address 192.0.2.0/24 'summary-only' + - set protocols bgp 65536 aggregate-address 203.0.113.0/24 'as-set' + - set protocols bgp 65536 maximum-paths ebgp '20' + - set protocols bgp 65536 maximum-paths ibgp '55' + - set protocols bgp 65536 neighbor 192.0.2.25 'disable-connected-check' + - set protocols bgp 65536 neighbor 192.0.2.25 timers holdtime '30' + - set protocols bgp 65536 neighbor 192.0.2.25 timers keepalive '10' + - set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'as-path' + - set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'med' + - set protocols bgp 65536 neighbor 203.0.113.5 attribute-unchanged 'next-hop' + - set protocols bgp 65536 neighbor 203.0.113.5 ebgp-multihop '2' + - set protocols bgp 65536 neighbor 203.0.113.5 remote-as '101' + - set protocols bgp 65536 neighbor 203.0.113.5 update-source '192.0.2.25' + - set protocols bgp 65536 neighbor 5001::64 distribute-list export '20' + - set protocols bgp 65536 neighbor 5001::64 distribute-list import '40' + - set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' + - set protocols bgp 65536 network 192.1.13.0/24 'backdoor' + - set protocols bgp 65536 parameters bestpath as-path 'confed' + - set protocols bgp 65536 parameters bestpath 'compare-routerid' + - set protocols bgp 65536 parameters confederation identifier '66' + - set protocols bgp 65536 parameters confederation peers '20' + - set protocols bgp 65536 parameters confederation peers '55' + - set protocols bgp 65536 parameters default 'no-ipv4-unicast' + - set protocols bgp 65536 parameters router-id '192.1.2.9' + - set protocols bgp 65536 redistribute connected route-map 'map01' + - set protocols bgp 65536 redistribute kernel metric '45' + - set protocols bgp 65536 timers keepalive '35' + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/_populate_af.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/_populate_af.yaml new file mode 100644 index 0000000..59f3d92 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/_populate_af.yaml @@ -0,0 +1,12 @@ +--- +- name: setup + vyos.vyos.vyos_config: + lines: + - set protocols bgp 65536 neighbor 5001::64 address-family 'ipv6-unicast' + - set protocols bgp 65536 neighbor 5001::64 ebgp-multihop '2' + - set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' + - set protocols bgp 65536 neighbor 5001::64 remote-as '65535' + - set protocols bgp 65536 neighbor 5001::64 update-source '2001:db8::1' + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/_preconfig.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/_preconfig.yaml new file mode 100644 index 0000000..8ab69e0 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/_preconfig.yaml @@ -0,0 +1,10 @@ +--- +- name: setup + vyos.vyos.vyos_config: + lines: + - set policy access-list 20 description 'acl20' + - set policy access-list 40 description 'acl40' + - set policy route-map map01 description 'map01' + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/_remove_config.yaml new file mode 100644 index 0000000..07d4aa4 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/_remove_config.yaml @@ -0,0 +1,11 @@ +--- +- name: Remove pre-existing bgp processes + vyos.vyos.vyos_config: + lines: + - delete protocols bgp 65536 + - delete policy access-list 20 + - delete policy access-list 40 + - delete policy route-map map01 + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/deleted.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/deleted.yaml new file mode 100644 index 0000000..e1a7754 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/deleted.yaml @@ -0,0 +1,42 @@ +--- +- debug: + msg: START vyos_bgp_global deleted integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Delete the provided configuration + register: result + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + state: deleted + + - become: true + vyos.vyos.vyos_facts: + gather_network_resources: bgp_global + + - assert: + that: + - result.commands|length == 9 + - result.changed == true + - result.commands|symmetric_difference(deleted.commands) == [] + - result.after == ansible_facts['network_resources']['bgp_global'] + + - name: Delete 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 diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/deleted_af.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/deleted_af.yaml new file mode 100644 index 0000000..9792125 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/deleted_af.yaml @@ -0,0 +1,26 @@ +--- +- debug: + msg: START vyos_bgp_global replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_af.yaml + +- block: + + - name: Delete the existing configuration, in presence of an af under neighbor. + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + state: deleted + + - assert: + that: + - result.msg == 'Use the _bgp_address_family module to delete the address_family under neighbor 5001::64, before replacing/deleting the neighbor.' + + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/empty_config.yaml new file mode 100644 index 0000000..7e52d1c --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/empty_config.yaml @@ -0,0 +1,49 @@ +--- +- debug: + msg: START vyos_bgp_global empty_config integration tests on connection={{ + ansible_connection }} + +- name: Merged with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: + config: + state: merged + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: + config: + state: replaced + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Parsed with empty running_config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: + running_config: + state: parsed + +- assert: + that: + - result.msg == 'value of running_config parameter must not be empty for state + parsed' + +- name: Rendered with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: + config: + state: rendered + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml new file mode 100644 index 0000000..7ec1da8 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/gathered.yaml @@ -0,0 +1,24 @@ +--- +- debug: + msg: START vyos_bgp_global gathered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Gather config from the device in structured format. + register: result + vyos.vyos.vyos_bgp_global: + state: gathered + + - become: true + vyos.vyos.vyos_facts: + gather_network_resources: bgp_global + + - assert: + that: + - result.changed == false + - result.gathered == ansible_facts['network_resources']['bgp_global'] diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml new file mode 100644 index 0000000..8a09c01 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/merged.yaml @@ -0,0 +1,71 @@ +--- +- 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 exisiting running configuration + register: result + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + aggregate_address: + - prefix: "203.0.113.0/24" + as_set: true + - prefix: "192.0.2.0/24" + summary_only: true + network: + - address: "192.1.13.0/24" + backdoor: true + redistribute: + - protocol: "kernel" + metric: 45 + - protocol: "connected" + route_map: "map01" + maximum_paths: + - path: "ebgp" + count: 20 + - path: "ibgp" + count: 55 + timers: + keepalive: 35 + bgp_params: + bestpath: + as_path: "confed" + compare_routerid: true + default: + no_ipv4_unicast: true + router_id: "192.1.2.9" + state: merged + + - become: true + vyos.vyos.vyos_facts: + gather_network_resources: bgp_global + + - assert: + that: + - result.commands|length == 12 + - 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 diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/parsed.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/parsed.yaml new file mode 100644 index 0000000..419df6a --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/parsed.yaml @@ -0,0 +1,16 @@ +--- +- debug: + msg: START vyos_bgp_global parsed integration tests on connection={{ ansible_connection + }} + +- name: Provide the running configuration for parsing (config to be parsed) + become: true + register: result + vyos.vyos.vyos_bgp_global: + running_config: "{{ lookup('file', '_parsed_config.cfg') }}" + state: parsed + +- assert: + that: + - result.changed == false + - result.parsed == populate.global diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/purged.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/purged.yaml new file mode 100644 index 0000000..9588e80 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/purged.yaml @@ -0,0 +1,32 @@ +--- +- debug: + msg: START vyos_bgp_global purged integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Purge the provided configuration + register: result + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + state: purged + + - become: true + vyos.vyos.vyos_facts: + gather_network_resources: bgp_global + + - assert: + that: + - result.commands|length == 1 + - result.changed == true + - "'delete protocols bgp 65536' in result.commands" + - ansible_facts.network_resources.bgp_global == [] + + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/rendered.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/rendered.yaml new file mode 100644 index 0000000..3a44a5e --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/rendered.yaml @@ -0,0 +1,45 @@ +--- +- debug: + msg: START vyos_bgp_global merged integration tests on connection={{ + ansible_connection }} + +- block: + + - name: Render given bgp_global configuration + register: result + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + aggregate_address: + - prefix: "203.0.113.0/24" + as_set: true + - prefix: "192.0.2.0/24" + summary_only: true + network: + - address: "192.1.13.0/24" + backdoor: true + redistribute: + - protocol: "kernel" + metric: 45 + - protocol: "connected" + route_map: "map01" + maximum_paths: + - path: "ebgp" + count: 20 + - path: "ibgp" + count: 55 + timers: + keepalive: 35 + bgp_params: + bestpath: + as_path: "confed" + compare_routerid: true + default: + no_ipv4_unicast: true + router_id: "192.1.2.9" + state: rendered + + - assert: + that: + - result.changed == false + - result.rendered|symmetric_difference(merged.commands) == [] diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml new file mode 100644 index 0000000..2a8b407 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced.yaml @@ -0,0 +1,72 @@ +--- +- debug: + msg: START vyos_bgp_global replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- 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" + network: + - address: "203.0.113.0/24" + route_map: map01 + redistribute: + - protocol: "static" + route_map: "map01" + 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 + default: + no_ipv4_unicast: true + neighbor: + - address: "192.0.2.43" + disable_connected_check: true + advertisement_interval: 72 + capability: + dynamic: true + timers: + holdtime: 30 + keepalive: 10 + - address: "203.0.113.0" + capability: + orf: "receive" + state: replaced + + - become: true + vyos.vyos.vyos_facts: + gather_network_resources: bgp_global + + - assert: + that: + - result.commands|length == 24 + - 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 diff --git a/tests/integration/targets/vyos_bgp_global/tests/cli/replaced_af.yaml b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced_af.yaml new file mode 100644 index 0000000..abcb177 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/tests/cli/replaced_af.yaml @@ -0,0 +1,56 @@ +--- +- debug: + msg: START vyos_bgp_global replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_af.yaml + +- block: + + - name: Replace the existing af configuration with the provided running configuration + register: result + ignore_errors: true + vyos.vyos.vyos_bgp_global: &id001 + config: + as_number: "65536" + network: + - address: "203.0.113.0/24" + route_map: map01 + redistribute: + - protocol: "static" + route_map: "map01" + 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 + default: + no_ipv4_unicast: true + neighbor: + - address: "192.0.2.43" + disable_connected_check: true + advertisement_interval: 72 + capability: + dynamic: true + timers: + holdtime: 30 + keepalive: 10 + - address: "203.0.113.0" + capability: + orf: "receive" + state: replaced + + - assert: + that: + - result.msg == 'Use the _bgp_address_family module to delete the address_family under neighbor 5001::64, before replacing/deleting the neighbor.' + + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_bgp_global/vars/main.yaml b/tests/integration/targets/vyos_bgp_global/vars/main.yaml new file mode 100644 index 0000000..fec5e43 --- /dev/null +++ b/tests/integration/targets/vyos_bgp_global/vars/main.yaml @@ -0,0 +1,150 @@ +--- +merged: + commands: + - set protocols bgp 65536 redistribute kernel metric 45 + - set protocols bgp 65536 redistribute connected route-map map01 + - set protocols bgp 65536 network 192.1.13.0/24 backdoor + - set protocols bgp 65536 aggregate-address 203.0.113.0/24 as-set + - set protocols bgp 65536 aggregate-address 192.0.2.0/24 summary-only + - set protocols bgp 65536 parameters bestpath as-path confed + - set protocols bgp 65536 parameters bestpath compare-routerid + - set protocols bgp 65536 parameters default no-ipv4-unicast + - set protocols bgp 65536 parameters router-id 192.1.2.9 + - set protocols bgp 65536 maximum-paths ebgp 20 + - set protocols bgp 65536 maximum-paths ibgp 55 + - set protocols bgp 65536 timers keepalive 35 + after: + aggregate_address: + - prefix: "192.0.2.0/24" + summary_only: true + - prefix: "203.0.113.0/24" + as_set: true + as_number: 65536 + bgp_params: + bestpath: + as_path: "confed" + compare_routerid: true + default: + no_ipv4_unicast: true + router_id: "192.1.2.9" + maximum_paths: + - count: 20 + path: "ebgp" + - count: 55 + path: "ibgp" + network: + - address: "192.1.13.0/24" + backdoor: true + redistribute: + - protocol: "connected" + route_map: "map01" + - metric: 45 + protocol: "kernel" + timers: + keepalive: 35 + +replaced: + commands: + - delete protocols bgp 65536 timers + - delete protocols bgp 65536 maximum-paths + - delete protocols bgp 65536 parameters router-id 192.1.2.9 + - delete protocols bgp 65536 parameters confederation + - delete protocols bgp 65536 aggregate-address + - delete protocols bgp 65536 network 192.1.13.0/24 + - delete protocols bgp 65536 redistribute kernel + - delete protocols bgp 65536 redistribute connected + - delete protocols bgp 65536 neighbor 5001::64 + - delete protocols bgp 65536 neighbor 203.0.113.5 + - delete protocols bgp 65536 neighbor 192.0.2.25 + - set protocols bgp 65536 neighbor 192.0.2.43 disable-connected-check + - set protocols bgp 65536 neighbor 192.0.2.43 advertisement-interval 72 + - set protocols bgp 65536 neighbor 192.0.2.43 capability dynamic + - set protocols bgp 65536 neighbor 192.0.2.43 timers holdtime 30 + - set protocols bgp 65536 neighbor 192.0.2.43 timers keepalive 10 + - set protocols bgp 65536 neighbor 203.0.113.0 capability orf prefix-list receive + - set protocols bgp 65536 redistribute static route-map map01 + - set protocols bgp 65536 network 203.0.113.0/24 route-map map01 + - set protocols bgp 65536 parameters always-compare-med + - set protocols bgp 65536 parameters dampening half-life 33 + - set protocols bgp 65536 parameters dampening max-suppress-time 20 + - set protocols bgp 65536 parameters dampening re-use 60 + - set protocols bgp 65536 parameters dampening start-suppress-time 5 + +deleted: + commands: + - delete protocols bgp 65536 timers + - delete protocols bgp 65536 maximum-paths + - delete protocols bgp 65536 parameters + - delete protocols bgp 65536 aggregate-address + - delete protocols bgp 65536 network + - delete protocols bgp 65536 redistribute + - delete protocols bgp 65536 neighbor 5001::64 + - delete protocols bgp 65536 neighbor 203.0.113.5 + - delete protocols bgp 65536 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: + aggregate_address: + - prefix: "192.0.2.0/24" + summary_only: true + - prefix: "203.0.113.0/24" + as_set: true + as_number: 65536 + bgp_params: + bestpath: + as_path: "confed" + compare_routerid: true + confederation: + - identifier: 66 + - peers: 20 + - peers: 55 + default: + no_ipv4_unicast: true + router_id: "192.1.2.9" + maximum_paths: + - count: 20 + path: "ebgp" + - count: 55 + path: "ibgp" + neighbor: + - address: "192.0.2.25" + disable_connected_check: true + timers: + holdtime: 30 + keepalive: 10 + - address: "203.0.113.5" + attribute_unchanged: + as_path: true + med: true + next_hop: true + ebgp_multihop: 2 + remote_as: 101 + update_source: "192.0.2.25" + - address: "5001::64" + distribute_list: + - acl: 20 + action: "export" + - acl: 40 + action: "import" + maximum_prefix: 34 + network: + - address: "192.1.13.0/24" + backdoor: true + redistribute: + - protocol: "connected" + route_map: "map01" + - metric: 45 + protocol: "kernel" + timers: + keepalive: 35 diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_af_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_af_config.cfg new file mode 100644 index 0000000..7d990d6 --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_af_config.cfg @@ -0,0 +1,5 @@ +set protocols bgp 65536 neighbor 5001::64 address-family 'ipv6-unicast' +set protocols bgp 65536 neighbor 5001::64 ebgp-multihop '2' +set protocols bgp 65536 neighbor 5001::64 maximum-prefix '34' +set protocols bgp 65536 neighbor 5001::64 remote-as '65535' +set protocols bgp 65536 neighbor 5001::64 update-source '2001:db8::1' diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_config.cfg new file mode 100644 index 0000000..00c615f --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_bgp_global_config.cfg @@ -0,0 +1,23 @@ +set protocols bgp 65536 neighbor 10.0.0.4 'disable-connected-check' +set protocols bgp 65536 neighbor 10.0.0.4 timers holdtime '30' +set protocols bgp 65536 neighbor 10.0.0.4 timers keepalive '10' +set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged 'as-path' +set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged 'med' +set protocols bgp 65536 neighbor 192.168.0.2 ebgp-multihop '2' +set protocols bgp 65536 neighbor 192.168.0.2 remote-as '65535' +set protocols bgp 65536 neighbor 192.168.0.2 soft-reconfiguration 'inbound' +set protocols bgp 65536 neighbor 192.168.0.2 update-source '192.168.0.1' +set protocols bgp 65536 neighbor 2001:db8::2 ebgp-multihop '2' +set protocols bgp 65536 neighbor 2001:db8::2 maximum-prefix '34' +set protocols bgp 65536 neighbor 2001:db8::2 remote-as '65535' +set protocols bgp 65536 neighbor 2001:db8::2 update-source '2001:db8::1' +set protocols bgp 65536 network 172.16.42.32/27 'backdoor' +set protocols bgp 65536 network 172.16.42.251/32 route-map 'map01' +set protocols bgp 65536 parameters bestpath as-path 'confed' +set protocols bgp 65536 parameters bestpath 'compare-routerid' +set protocols bgp 65536 parameters default 'no-ipv4-unicast' +set protocols bgp 65536 parameters router-id '10.1.1.1' +set protocols bgp 65536 neighbor 10.0.0.4 capability orf prefix-list 'receive' +set protocols bgp 65536 redistribute kernel route-map 'map01' +set protocols bgp 65536 redistribute static metric '20' +set protocols bgp 65536 redistribute static route-map 'map01' diff --git a/tests/unit/modules/network/vyos/test_vyos_bgp_global.py b/tests/unit/modules/network/vyos/test_vyos_bgp_global.py new file mode 100644 index 0000000..bdb29c0 --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_bgp_global.py @@ -0,0 +1,562 @@ +# (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 ansible_collections.vyos.vyos.tests.unit.compat.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() + + 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() + + def load_fixtures(self, commands=None, transport="cli", filename=None): + if filename is None: + filename = "vyos_bgp_global_config.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), + capability=dict(orf="receive"), + ), + dict( + address="192.168.0.2", + attribute_unchanged=dict(as_path=True, med=True), + ebgp_multihop=2, + remote_as="65535", + soft_reconfiguration=True, + update_source="192.168.0.1", + ), + dict( + address="2001:db8::2", + ebgp_multihop=2, + remote_as="65535", + maximum_prefix=34, + 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", + maximum_paths=[ + dict(path="ebgp", count=20), + dict(path="ibgp", count=45), + ], + neighbor=[ + dict( + address="2001:db8::2", + ebgp_multihop=2, + remote_as="65535", + maximum_prefix=34, + update_source="2001:db8::1", + distribute_list=[ + dict(action="export", acl=31), + dict(action="import", acl=9), + ], + ) + ], + bgp_params=dict( + confederation=[dict(peers=20), dict(identifier=66)], + router_id="10.1.1.1", + ), + ), + state="merged", + ) + ) + commands = [ + "set protocols bgp 65536 neighbor 2001:db8::2 distribute-list export 31", + "set protocols bgp 65536 neighbor 2001:db8::2 distribute-list import 9", + "set protocols bgp 65536 parameters confederation peers 20", + "set protocols bgp 65536 parameters confederation identifier 66", + "set protocols bgp 65536 maximum-paths ebgp 20", + "set protocols bgp 65536 maximum-paths ibgp 45", + ] + 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), + capability=dict(orf="receive"), + ), + dict( + address="192.168.0.2", + attribute_unchanged=dict(as_path=True, med=True), + ebgp_multihop=2, + remote_as="65535", + soft_reconfiguration=True, + update_source="192.168.0.1", + ), + dict( + address="2001:db8::2", + ebgp_multihop=2, + remote_as="65535", + maximum_prefix=34, + 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", + prefix_list=[ + dict(action="export", prefix_list=10), + ], + 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", + ) + ) + commands = [ + "delete protocols bgp 65536 parameters default", + "delete protocols bgp 65536 parameters bestpath compare-routerid", + "delete protocols bgp 65536 parameters bestpath as-path confed", + "delete protocols bgp 65536 network", + "delete protocols bgp 65536 redistribute", + "delete protocols bgp 65536 neighbor 2001:db8::2 update-source 2001:db8::1", + "delete protocols bgp 65536 neighbor 2001:db8::2 maximum-prefix 34", + "delete protocols bgp 65536 neighbor 2001:db8::2 ebgp-multihop 2", + "delete protocols bgp 65536 neighbor 192.168.0.2", + "delete protocols bgp 65536 neighbor 10.0.0.4", + "set protocols bgp 65536 neighbor 200.11.155.3 prefix-list export 10", + "set protocols bgp 65536 neighbor 200.11.155.3 allowas-in number 10", + "set protocols bgp 65536 neighbor 2001:db8::2 as-override", + "set protocols bgp 65536 neighbor 2001:db8::2 route-map export map01", + "set protocols bgp 65536 parameters log-neighbor-changes", + "set protocols bgp 65536 parameters no-client-to-client-reflection", + "set protocols bgp 65536 parameters confederation peers 20", + "set protocols bgp 65536 parameters confederation identifier 66", + "set protocols bgp 65536 timers holdtime 30", + "set protocols bgp 65536 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 65536"] + 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", + prefix_list=[ + dict(action="export", prefix_list=10), + ], + 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", + prefix_list=[ + dict(action="export", prefix_list=10), + ], + 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, filename="vyos_bgp_global_af_config.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_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), + capability=dict(orf="receive"), + ), + dict( + address="192.168.0.2", + attribute_unchanged=dict(as_path=True, med=True), + ebgp_multihop=2, + remote_as="65535", + soft_reconfiguration=True, + update_source="192.168.0.1", + ), + dict( + address="2001:db8::2", + ebgp_multihop=2, + remote_as="65535", + maximum_prefix=34, + 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 65536 neighbor 10.0.0.4 disable-connected-check", + "set protocols bgp 65536 neighbor 10.0.0.4 timers holdtime 30", + "set protocols bgp 65536 neighbor 10.0.0.4 timers keepalive 10", + "set protocols bgp 65536 neighbor 10.0.0.4 capability orf prefix-list receive", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged as-path", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged med", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged next-hop", + "set protocols bgp 65536 neighbor 192.168.0.2 ebgp-multihop 2", + "set protocols bgp 65536 neighbor 192.168.0.2 remote-as 65535", + "set protocols bgp 65536 neighbor 192.168.0.2 soft-reconfiguration", + "set protocols bgp 65536 neighbor 192.168.0.2 update-source 192.168.0.1", + "set protocols bgp 65536 neighbor 2001:db8::2 ebgp-multihop 2", + "set protocols bgp 65536 neighbor 2001:db8::2 remote-as 65535", + "set protocols bgp 65536 neighbor 2001:db8::2 maximum-prefix 34", + "set protocols bgp 65536 neighbor 2001:db8::2 update-source 2001:db8::1", + "set protocols bgp 65536 redistribute kernel route-map map01", + "set protocols bgp 65536 redistribute static route-map map01", + "set protocols bgp 65536 network 172.16.42.32/27 backdoor", + "set protocols bgp 65536 network 172.16.42.251/32 route-map map01", + "set protocols bgp 65536 parameters bestpath as-path confed", + "set protocols bgp 65536 parameters bestpath compare-routerid", + "set protocols bgp 65536 parameters default no-ipv4-unicast", + "set protocols bgp 65536 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 65536 neighbor 10.0.0.4 disable-connected-check", + "set protocols bgp 65536 neighbor 10.0.0.4 timers holdtime 30", + "set protocols bgp 65536 neighbor 10.0.0.4 timers keepalive 10", + "set protocols bgp 65536 neighbor 10.0.0.4 capability orf prefix-list receive", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged as-path", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged med", + "set protocols bgp 65536 neighbor 192.168.0.2 attribute-unchanged next-hop", + "set protocols bgp 65536 neighbor 192.168.0.2 ebgp-multihop 2", + "set protocols bgp 65536 neighbor 192.168.0.2 remote-as 65535", + "set protocols bgp 65536 neighbor 192.168.0.2 soft-reconfiguration", + "set protocols bgp 65536 neighbor 192.168.0.2 update-source 192.168.0.1", + "set protocols bgp 65536 neighbor 2001:db8::2 ebgp-multihop 2", + "set protocols bgp 65536 neighbor 2001:db8::2 remote-as 65535", + "set protocols bgp 65536 neighbor 2001:db8::2 maximum-prefix 34", + "set protocols bgp 65536 neighbor 2001:db8::2 update-source 2001:db8::1", + "set protocols bgp 65536 redistribute kernel route-map map01", + "set protocols bgp 65536 redistribute static route-map map01", + "set protocols bgp 65536 network 172.16.42.32/27 backdoor", + "set protocols bgp 65536 network 172.16.42.251/32 route-map map01", + "set protocols bgp 65536 parameters bestpath as-path confed", + "set protocols bgp 65536 parameters bestpath compare-routerid", + "set protocols bgp 65536 parameters default no-ipv4-unicast", + "set protocols bgp 65536 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", + "capability": {"orf": "receive"}, + "disable_connected_check": True, + "timers": {"holdtime": 30, "keepalive": 10}, + }, + { + "address": "192.168.0.2", + "attribute_unchanged": { + "as_path": True, + "med": True, + "next_hop": True, + }, + "ebgp_multihop": 2, + "remote_as": 65535, + "update_source": "192.168.0.1", + }, + { + "address": "2001:db8::2", + "ebgp_multihop": 2, + "maximum_prefix": 34, + "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", + "capability": {"orf": "receive"}, + "disable_connected_check": True, + "timers": {"holdtime": 30, "keepalive": 10}, + }, + { + "address": "192.168.0.2", + "attribute_unchanged": {"as_path": True, "med": True}, + "ebgp_multihop": 2, + "remote_as": 65535, + "soft_reconfiguration": True, + "update_source": "192.168.0.1", + }, + { + "address": "2001:db8::2", + "ebgp_multihop": 2, + "maximum_prefix": 34, + "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"])) diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py index 49d4652..cb7874f 100644 --- a/tests/unit/modules/network/vyos/vyos_module.py +++ b/tests/unit/modules/network/vyos/vyos_module.py @@ -62,7 +62,11 @@ class TestVyosModule(ModuleTestCase): defaults=False, filename=None, ): - self.load_fixtures(commands) + + if filename is None: + self.load_fixtures(commands) + else: + self.load_fixtures(commands, filename=filename) if failed: result = self.failed() @@ -101,5 +105,5 @@ class TestVyosModule(ModuleTestCase): self.assertEqual(result["changed"], changed, result) return result - def load_fixtures(self, commands=None): + def load_fixtures(self, commands=None, filename=None): pass |