diff options
Diffstat (limited to 'plugins/modules/vyos_ospfv2.py')
| -rw-r--r-- | plugins/modules/vyos_ospfv2.py | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/plugins/modules/vyos_ospfv2.py b/plugins/modules/vyos_ospfv2.py new file mode 100644 index 0000000..063d0dc --- /dev/null +++ b/plugins/modules/vyos_ospfv2.py @@ -0,0 +1,487 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# GNU General Public License v3.0+ + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: vyos_ospfv2 +short_description: OSPFv2 resource module via REST API. +description: + - Manages OSPFv2 (OSPF for IPv4) configuration on VyOS via HTTPS REST API. +version_added: "1.0.0" +author: + - VyOS Community (@vyos) +options: + config: + description: OSPFv2 configuration. + type: dict + suboptions: + areas: + type: list + elements: dict + suboptions: + area_id: + type: str + area_type: + type: dict + suboptions: + normal: + type: bool + nssa: + type: dict + suboptions: + set: + type: bool + default_cost: + type: int + no_summary: + type: bool + translate: + type: str + choices: [always, candidate, never] + stub: + type: dict + suboptions: + set: + type: bool + default_cost: + type: int + no_summary: + type: bool + authentication: + type: str + choices: [plaintext-password, md5] + network: + type: list + elements: dict + suboptions: + address: + type: str + range: + type: list + elements: dict + suboptions: + address: + type: str + cost: + type: int + not_advertise: + type: bool + substitute: + type: str + shortcut: + type: str + choices: [default, disable, enable] + auto_cost: + type: dict + suboptions: + reference_bandwidth: + type: int + default_information: + type: dict + suboptions: + originate: + type: dict + suboptions: + always: + type: bool + metric: + type: int + metric_type: + type: int + route_map: + type: str + log_adjacency_changes: + type: str + choices: [detail] + max_metric: + type: dict + suboptions: + router_lsa: + type: dict + suboptions: + administrative: + type: bool + on_shutdown: + type: int + on_startup: + type: int + mpls_te: + type: dict + suboptions: + enabled: + type: bool + router_address: + type: str + neighbor: + type: list + elements: dict + suboptions: + neighbor_id: + type: str + poll_interval: + type: int + priority: + type: int + parameters: + type: dict + suboptions: + router_id: + type: str + opaque_lsa: + type: bool + rfc1583_compatibility: + type: bool + abr_type: + type: str + choices: [cisco, ibm, shortcut, standard] + passive_interface: + type: list + elements: str + redistribute: + type: list + elements: dict + suboptions: + route_type: + type: str + choices: [bgp, connected, kernel, rip, static] + metric: + type: int + metric_type: + type: int + route_map: + type: str + state: + type: str + choices: [merged, replaced, deleted, gathered] + default: merged + hostname: + type: str + required: true + port: + type: int + default: 443 + api_key: + type: str + required: true + no_log: true + timeout: + type: int + default: 30 + verify_ssl: + type: bool + default: false +""" + +RETURN = r""" +before: + returned: always + type: dict +after: + returned: when changed + type: dict +commands: + returned: always + type: list +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.rest.plugins.module_utils.vyos_rest import ( + VYOS_REST_CONNECTION_ARGSPEC, + VyOSRestClient, + VyOSRestError, +) + + +_BASE = ["protocols", "ospf"] + + +def _get(client): + try: + r = client.retrieve_show_config(_BASE) + return r.get("data") or {} + except VyOSRestError: + return {} + + +def _apply(client, config, commands): + params = config.get("parameters") or {} + if params.get("router_id"): + client.configure_set(_BASE + ["parameters", "router-id"], params["router_id"]) + commands.append("set protocols ospf parameters router-id {r}".format(r=params["router_id"])) + if params.get("opaque_lsa"): + client.configure_set(_BASE + ["parameters", "opaque-lsa"]) + if params.get("rfc1583_compatibility"): + client.configure_set(_BASE + ["parameters", "rfc1583-compatibility"]) + if params.get("abr_type"): + client.configure_set(_BASE + ["parameters", "abr-type"], params["abr_type"]) + + ac = config.get("auto_cost") or {} + if ac.get("reference_bandwidth"): + client.configure_set( + _BASE + ["auto-cost", "reference-bandwidth"], + str(ac["reference_bandwidth"]), + ) + commands.append( + "set protocols ospf auto-cost reference-bandwidth {b}".format( + b=ac["reference_bandwidth"], + ), + ) + + if config.get("log_adjacency_changes"): + client.configure_set(_BASE + ["log-adjacency-changes", config["log_adjacency_changes"]]) + + for nbr in config.get("neighbor") or []: + nb = _BASE + ["neighbor", nbr["neighbor_id"]] + client.configure_set(nb) + if nbr.get("poll_interval"): + client.configure_set(nb + ["poll-interval"], str(nbr["poll_interval"])) + if nbr.get("priority"): + client.configure_set(nb + ["priority"], str(nbr["priority"])) + + for pi in config.get("passive_interface") or []: + client.configure_set(_BASE + ["passive-interface"], pi) + commands.append("set protocols ospf passive-interface {i}".format(i=pi)) + + for redist in config.get("redistribute") or []: + rb = _BASE + ["redistribute", redist["route_type"]] + client.configure_set(rb) + commands.append("set protocols ospf redistribute {r}".format(r=redist["route_type"])) + if redist.get("metric"): + client.configure_set(rb + ["metric"], str(redist["metric"])) + if redist.get("metric_type"): + client.configure_set(rb + ["metric-type"], str(redist["metric_type"])) + if redist.get("route_map"): + client.configure_set(rb + ["route-map"], redist["route_map"]) + + di = (config.get("default_information") or {}).get("originate") or {} + if di: + dib = _BASE + ["default-information", "originate"] + client.configure_set(dib) + commands.append("set protocols ospf default-information originate") + if di.get("always"): + client.configure_set(dib + ["always"]) + if di.get("metric"): + client.configure_set(dib + ["metric"], str(di["metric"])) + if di.get("metric_type"): + client.configure_set(dib + ["metric-type"], str(di["metric_type"])) + if di.get("route_map"): + client.configure_set(dib + ["route-map"], di["route_map"]) + + for area in config.get("areas") or []: + aid = area["area_id"] + ab = _BASE + ["area", aid] + client.configure_set(ab) + commands.append("set protocols ospf area {a}".format(a=aid)) + + at = area.get("area_type") or {} + if at.get("normal"): + pass # default + nssa = at.get("nssa") or {} + if nssa.get("set"): + client.configure_set(ab + ["area-type", "nssa"]) + if nssa.get("default_cost"): + client.configure_set( + ab + ["area-type", "nssa", "default-cost"], + str(nssa["default_cost"]), + ) + if nssa.get("no_summary"): + client.configure_set(ab + ["area-type", "nssa", "no-summary"]) + stub = at.get("stub") or {} + if stub.get("set"): + client.configure_set(ab + ["area-type", "stub"]) + if stub.get("default_cost"): + client.configure_set( + ab + ["area-type", "stub", "default-cost"], + str(stub["default_cost"]), + ) + + if area.get("authentication"): + client.configure_set(ab + ["authentication"], area["authentication"]) + + for net in area.get("network") or []: + client.configure_set(ab + ["network"], net["address"]) + commands.append( + "set protocols ospf area {a} network {n}".format( + a=aid, + n=net["address"], + ), + ) + + for rng in area.get("range") or []: + rb2 = ab + ["range", rng["address"]] + client.configure_set(rb2) + if rng.get("cost"): + client.configure_set(rb2 + ["cost"], str(rng["cost"])) + if rng.get("not_advertise"): + client.configure_set(rb2 + ["not-advertise"]) + if rng.get("substitute"): + client.configure_set(rb2 + ["substitute"], rng["substitute"]) + + if area.get("shortcut"): + client.configure_set(ab + ["shortcut"], area["shortcut"]) + + +def main(): + argument_spec = dict( + config=dict( + type="dict", + options=dict( + areas=dict( + type="list", + elements="dict", + options=dict( + area_id=dict(type="str"), + area_type=dict( + type="dict", + options=dict( + normal=dict(type="bool"), + nssa=dict( + type="dict", + options=dict( + set=dict(type="bool"), + default_cost=dict(type="int"), + no_summary=dict(type="bool"), + translate=dict( + type="str", + choices=["always", "candidate", "never"], + ), + ), + ), + stub=dict( + type="dict", + options=dict( + set=dict(type="bool"), + default_cost=dict(type="int"), + no_summary=dict(type="bool"), + ), + ), + ), + ), + authentication=dict(type="str", choices=["plaintext-password", "md5"]), + network=dict( + type="list", + elements="dict", + options=dict(address=dict(type="str")), + ), + range=dict( + type="list", + elements="dict", + options=dict( + address=dict(type="str"), + cost=dict(type="int"), + not_advertise=dict(type="bool"), + substitute=dict(type="str"), + ), + ), + shortcut=dict(type="str", choices=["default", "disable", "enable"]), + ), + ), + auto_cost=dict(type="dict", options=dict(reference_bandwidth=dict(type="int"))), + default_information=dict( + type="dict", + options=dict( + originate=dict( + type="dict", + options=dict( + always=dict(type="bool"), + metric=dict(type="int"), + metric_type=dict(type="int"), + route_map=dict(type="str"), + ), + ), + ), + ), + log_adjacency_changes=dict(type="str", choices=["detail"]), + max_metric=dict(type="dict"), + mpls_te=dict( + type="dict", + options=dict( + enabled=dict(type="bool"), + router_address=dict(type="str"), + ), + ), + neighbor=dict( + type="list", + elements="dict", + options=dict( + neighbor_id=dict(type="str"), + poll_interval=dict(type="int"), + priority=dict(type="int"), + ), + ), + parameters=dict( + type="dict", + options=dict( + router_id=dict(type="str"), + opaque_lsa=dict(type="bool"), + rfc1583_compatibility=dict(type="bool"), + abr_type=dict(type="str", choices=["cisco", "ibm", "shortcut", "standard"]), + ), + ), + passive_interface=dict(type="list", elements="str"), + redistribute=dict( + type="list", + elements="dict", + options=dict( + route_type=dict( + type="str", + choices=["bgp", "connected", "kernel", "rip", "static"], + ), + metric=dict(type="int"), + metric_type=dict(type="int"), + route_map=dict(type="str"), + ), + ), + ), + ), + state=dict( + type="str", + default="merged", + choices=["merged", "replaced", "deleted", "gathered"], + ), + ) + argument_spec.update(VYOS_REST_CONNECTION_ARGSPEC) + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[("state", "merged", ["config"]), ("state", "replaced", ["config"])], + supports_check_mode=True, + ) + client = VyOSRestClient(module) + state = module.params["state"] + config = module.params.get("config") + commands = [] + changed = False + before = _get(client) + + if state == "gathered": + module.exit_json(changed=False, gathered=before, before=before, commands=[]) + if module.check_mode: + module.exit_json(changed=True, before=before, commands=["(check mode)"]) + + try: + if state == "deleted": + if before: + client.configure_delete(_BASE) + commands.append("delete protocols ospf") + changed = True + elif state in ("merged", "replaced"): + if state == "replaced" and before: + client.configure_delete(_BASE) + commands.append("delete protocols ospf") + _apply(client, config, commands) + changed = True + except VyOSRestError as exc: + module.fail_json(msg=str(exc)) + + after = _get(client) if changed else before + module.exit_json(changed=changed, before=before, after=after, commands=commands) + + +if __name__ == "__main__": + main() |
