#!/usr/bin/python3 import pathlib from typing import List, Union try: from ansible_module.generic import SYSTEMD_NETWORK_CONFIG, Types, modspec, systemdbool from ansible_module.module import SystemdUnitModule except ImportError: from ansible.module_utils.sebastian.base.module_utils.generic import SYSTEMD_NETWORK_CONFIG, Types, modspec, systemdbool from ansible.module_utils.sebastian.base.module_utils.module import SystemdUnitModule class Module(SystemdUnitModule): # type: ignore """Sets up the systemd network unit""" name = "network" module_spec = modspec( argument_spec=dict( mac=Types.str(help="The MAC-Address of the device. An ! before the value matches anything but this value."), device=Types.str(help="The name of the network device. An ! before the value matches anything but this value."), virtualization=Types.str(help="The virtualization type. An ! before the value matches anything but this value."), name=Types.str(required=True, help="name of the unit"), dot=Types.bool(help="if DNS-over-TLS should be required or disabled. If it is unset, it will used if the server supports it"), dnssec=Types.bool( help="if the Domainqueries should require DNSSEC or not.\nIf its missing, domains that have DNSSEC enabled will be validated, all others it will be assumed to be okay." ), dns=Types.list(elements=str, help="List of DNS-Servers"), domain=Types.list(elements=str, help="List of domains that are on this device"), defaultdns=Types.bool( help="If the DNS-Server(s) on this device should be used for all domains that are not set on other devices" ), address=Types.list(elements=str, required=True, help="IP-Addresses of this networkdevice"), route=Types.list( elements=str, help="Routes of networks that can be reached with this device", ), masquerade=Types.str( help="how the packets are modified to look like the come from the computer itself.", choices=("true", "false", "both", "ipv4", "ipv6"), ), ), required_if=(("defaultdns", True, ("dns",), False),), required_one_of=(("mac", "device", "virtualization"),), ) def prepare(self): self.unitfile = SYSTEMD_NETWORK_CONFIG.joinpath(self.get("name")).with_suffix(".network") self.__unit = None def unit(self) -> str: if self.__unit is None: self.__unit = "\n".join( ( self.match(), self.network(), self.addresses(), self.routes(), ) ) return self.__unit def match(self) -> str: matches = [] return "[Match]\n" + "".join( self.map_param( mac="MACAddress", device="Name", virtualization="Virtualization", ) ) def network(self) -> str: output = "[Network]\n" options = [] try: options.append("Description={}".format(self.get("description"))) except KeyError: pass try: for server in self.get("dns", []): options.append(f"DNS={server}") options.append("DNSDefaultRoute={}".format(self.get("defaultdns", False))) except KeyError: pass try: domain = self.get("domain") self.set("domainlog", str(domain)) options.append("Domains={}".format(" ".join(domain))) options.append("DNSOverTLS={}".format(systemdbool(self.get("dot", "opportunistic")))) options.append("DNSSEC={}".format(systemdbool(self.get("dnssec", "allow-downgrade")))) except KeyError: pass if self.get("masquerade", -1) != -1: masquerade = self.get("masquerade") if masquerade == "true": masquerade = "both" elif masquerade == "false": masquerade = "no" options.append(f"IPMasquerade={masquerade}") output += "\n".join(options) return output def addresses(self) -> str: output = [] for address in self.get("address"): output.append(f"[Address]\nAddress={address}\n") return "\n".join(output) def routes(self) -> str: output = [] routes = self.get("route", []) self.set("routes", routes) for gw in routes: output.append(f"[Route]\nGateway={gw}\nGatewayOnLink=yes\nQuickAck=yes\n") self.set("routes", output) return "\n".join(output) DOCUMENTATION = """--- description: - Sets up the systemd network unit module: network options: address: description: - IP-Addresses of this networkdevice elements: str required: true type: list after: default: [] description: - list of units that this unit wants to be started after this unit elements: str required: false type: list before: default: [] description: - list of units that this unit needs to be started before this unit. elements: str required: false type: list defaultdns: description: - If the DNS-Server(s) on this device should be used for all domains that are not set on other devices required: false type: bool description: description: - An description for programs that access systemd required: false type: str device: description: - The name of the network device. An ! before the value matches anything but this value. required: false type: str dns: default: [] description: - List of DNS-Servers elements: str required: false type: list dnssec: description: - if the Domainqueries should require DNSSEC or not. - If its missing, domains that have DNSSEC enabled will be validated, all others it will be assumed to be okay. required: false type: bool documentation: default: [] description: - Paths where documentation can be found elements: str required: false type: list domain: default: [] description: - List of domains that are on this device elements: str required: false type: list dot: description: - if DNS-over-TLS should be required or disabled. If it is unset, it will used if the server supports it required: false type: bool mac: description: - The MAC-Address of the device. An ! before the value matches anything but this value. required: false type: str masquerade: choices: - 'true' - 'false' - both - ipv4 - ipv6 description: - how the packets are modified to look like the come from the computer itself. required: false type: str name: description: - name of the unit required: true type: str partof: default: [] description: - list of units that this unit is part of. - If the restart this unit does it too, but if this restarts it does not affect the other units. elements: str required: false type: list requires: default: [] description: - list of units that this unit requires. If it fails or can't be started this unit fails. without before/after this is started at the same time elements: str required: false type: list route: default: [] description: - Routes of networks that can be reached with this device elements: str required: false type: list virtualization: description: - The virtualization type. An ! before the value matches anything but this value. required: false type: str wants: default: [] description: - list of units that this unit wants. If it fails or can't be started it does not affect this unit elements: str required: false type: list short_description: Sets up the systemd network unit """ if __name__ == "__main__": Module()()