summaryrefslogtreecommitdiff
path: root/plugins/modules/vyos_ospfv2.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/modules/vyos_ospfv2.py')
-rw-r--r--plugins/modules/vyos_ospfv2.py487
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()