#!/usr/bin/python3 import pathlib from typing import List, Union try: from ansible_collections.sebastian.systemd.plugins.module_utils.generic import SYSTEMD_NETWORK_CONFIG, Types from ansible_collections.sebastian.systemd.plugins.module_utils.module import SystemdUnitModule except ImportError: from plugins.module_utils.generic import SYSTEMD_NETWORK_CONFIG, Types from plugins.module_utils.module import SystemdUnitModule def boolconvert(b: Union[bool, str]) -> str: if b is True: return "yes" elif b is False: return "no" return b class Module(SystemdUnitModule): """Sets up the systemd network unit""" name = "network" module_spec = dict( argument_spec=dict( mac=Types.str(help="The MAC-Address of the device"), device=Types.str(help="The name of the network device"), 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( "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." ), 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", ), ), required_if=(("defaultdns", True, ("dns",), False),), required_one_of=(("mac", "device"),), ) 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 = [] if self.get("mac", False): matches.append("MACAddress={}\n".format(self.get("mac"))) if self.get("device", False): matches.append("Name={}\n".format(self.get("device"))) return "[Match]\n" + "".join(matches) 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(boolconvert(self.get("dot", "opportunistic")))) options.append("DNSSEC={}".format(boolconvert(self.get("dnssec", "allow-downgrade")))) except KeyError: pass 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 required: false type: str dns: default: [] description: - List of DNS-Servers elements: str required: false type: list dnssec: required: true 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 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 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()()