diff options
| author | omnom62 <omnom62@outlook.com> | 2026-05-06 08:08:27 +1000 |
|---|---|---|
| committer | omnom62 <omnom62@outlook.com> | 2026-05-06 08:08:27 +1000 |
| commit | 9a3fa5777e7203d46faf1185cfb56c4fc121d885 (patch) | |
| tree | 80988400ba3582cfc97ff6445fb8f97c724d3fc6 /plugins/modules/vyos_firewall_interfaces.py | |
| parent | c2493986714604aa992bea28628b74587b3b51bd (diff) | |
| download | rest.vyos-9a3fa5777e7203d46faf1185cfb56c4fc121d885.tar.gz rest.vyos-9a3fa5777e7203d46faf1185cfb56c4fc121d885.zip | |
More modules
Diffstat (limited to 'plugins/modules/vyos_firewall_interfaces.py')
| -rw-r--r-- | plugins/modules/vyos_firewall_interfaces.py | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/plugins/modules/vyos_firewall_interfaces.py b/plugins/modules/vyos_firewall_interfaces.py new file mode 100644 index 0000000..d9085a6 --- /dev/null +++ b/plugins/modules/vyos_firewall_interfaces.py @@ -0,0 +1,244 @@ +#!/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_firewall_interfaces +short_description: Firewall interfaces resource module via REST API. +description: + - Attaches or detaches named firewall rule sets to/from interface + directions (in/out/local) using the VyOS HTTPS REST API. +version_added: "1.0.0" +author: + - VyOS Community (@vyos) +options: + config: + description: List of interface firewall attachment configurations. + type: list + elements: dict + suboptions: + name: + description: Interface name. + type: str + required: true + access_rules: + description: Firewall rule sets per AFI. + type: list + elements: dict + suboptions: + afi: + description: Address family. + type: str + choices: [ipv4, ipv6] + required: true + rules: + description: Rule sets and directions. + type: list + elements: dict + suboptions: + name: + description: Rule set name. + type: str + direction: + description: Traffic direction. + type: str + choices: [in, local, out] + required: true + state: + description: Desired state. + type: str + choices: [merged, replaced, overridden, 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: list +after: + returned: when changed + type: list +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, +) + + +_IFACE_TYPES = { + "eth": "ethernet", + "bond": "bonding", + "vti": "vti", + "vxlan": "vxlan", + "lo": "loopback", + "dummy": "dummy", + "br": "bridge", + "wg": "wireguard", + "tun": "tunnel", +} + + +def _itype(name): + for p, t in _IFACE_TYPES.items(): + if name.startswith(p): + return t + return "ethernet" + + +def _fw_direction_key(afi, direction): + if afi == "ipv4": + return {"in": "in", "out": "out", "local": "local"}[direction] + return {"in": "in", "out": "out", "local": "local"}[direction] + + +def _apply(client, iface_cfg, commands): + name = iface_cfg["name"] + itype = _itype(name) + ibase = ["interfaces", itype, name, "firewall"] + + for ar in iface_cfg.get("access_rules") or []: + afi = ar["afi"] + fw_key = "firewall" if afi == "ipv4" else "ipv6" + for rule in ar.get("rules") or []: + direction = rule["direction"] + rs_name = rule.get("name") + if rs_name: + path = ibase + [direction, fw_key if afi == "ipv6" else "name"] + client.configure_set(path, rs_name) + commands.append( + "set interfaces {t} {n} firewall {d} {k} '{rs}'".format( + t=itype, + n=name, + d=direction, + k="ipv6-name" if afi == "ipv6" else "name", + rs=rs_name, + ), + ) + + +def _delete_iface_fw(client, name, commands): + itype = _itype(name) + path = ["interfaces", itype, name, "firewall"] + try: + client.configure_delete(path) + commands.append("delete interfaces {t} {n} firewall".format(t=itype, n=name)) + except VyOSRestError: + pass + + +def _get(client): + try: + result = client.retrieve_show_config(["interfaces"]) + raw = result.get("data") or {} + out = [] + for itype, itype_data in raw.items(): + if not isinstance(itype_data, dict): + continue + for iname, idata in itype_data.items(): + fw = idata.get("firewall") if isinstance(idata, dict) else None + if fw: + out.append({"name": iname, "firewall": fw}) + return out + except VyOSRestError: + return [] + + +def main(): + argument_spec = dict( + config=dict( + type="list", + elements="dict", + options=dict( + name=dict(type="str", required=True), + access_rules=dict( + type="list", + elements="dict", + options=dict( + afi=dict(type="str", required=True, choices=["ipv4", "ipv6"]), + rules=dict( + type="list", + elements="dict", + options=dict( + name=dict(type="str"), + direction=dict( + type="str", + required=True, + choices=["in", "local", "out"], + ), + ), + ), + ), + ), + ), + ), + state=dict( + type="str", + default="merged", + choices=["merged", "replaced", "overridden", "deleted", "gathered"], + ), + ) + argument_spec.update(VYOS_REST_CONNECTION_ARGSPEC) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + client = VyOSRestClient(module) + state = module.params["state"] + config = module.params.get("config") or [] + 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": + targets = {i["name"] for i in config} if config else {i["name"] for i in before} + for iface in before: + if iface["name"] in targets: + _delete_iface_fw(client, iface["name"], commands) + changed = True + elif state in ("merged", "replaced", "overridden"): + if state in ("replaced", "overridden"): + for cfg in config: + _delete_iface_fw(client, cfg["name"], commands) + for cfg in config: + _apply(client, cfg, 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() |
