diff --git a/topology/icons/interfaces/ethernet.svg b/topology/icons/interfaces/ethernet.svg new file mode 100644 index 0000000..1d8045a --- /dev/null +++ b/topology/icons/interfaces/ethernet.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/topology/icons/interfaces/wireguard.svg b/topology/icons/interfaces/wireguard.svg new file mode 100644 index 0000000..81823b3 --- /dev/null +++ b/topology/icons/interfaces/wireguard.svg @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/topology/icons/services/wireguard.svg b/topology/icons/services/wireguard.svg new file mode 100644 index 0000000..81823b3 --- /dev/null +++ b/topology/icons/services/wireguard.svg @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/topology/nixos/extractors/services.nix b/topology/nixos/extractors/services.nix index 8a1af3e..1d90542 100644 --- a/topology/nixos/extractors/services.nix +++ b/topology/nixos/extractors/services.nix @@ -1,7 +1,6 @@ { config, lib, - pkgs, ... }: let inherit @@ -12,7 +11,8 @@ in { topology.self.services = { vaultwarden = mkIf config.services.vaultwarden.enable { name = "Vaultwarden"; - icon = "${pkgs.vaultwarden.webvault}/share/vaultwarden/vault/images/safari-pinned-tab.svg"; + info = "https://pw.example.com"; + details.listen.text = "[::]:3000"; }; }; } diff --git a/topology/nixos/extractors/systemd.nix b/topology/nixos/extractors/systemd.nix index b5859ee..d6e2884 100644 --- a/topology/nixos/extractors/systemd.nix +++ b/topology/nixos/extractors/systemd.nix @@ -9,10 +9,12 @@ attrValues concatLists flip + listToAttrs mapAttrsToList mkDefault mkIf mkMerge + nameValuePair optional ; in { @@ -25,6 +27,7 @@ in { optional (netdev ? netdevConfig.Name) { ${netdev.netdevConfig.Name} = { virtual = mkDefault true; + type = mkIf (netdev ? netdevConfig.Kind) netdev.netdevConfig.Kind; }; } ) @@ -34,9 +37,11 @@ in { flip mapAttrsToList config.systemd.network.networks ( _unit: network: let # FIXME: TODO renameInterfacesByMac is not a standard option! + macToName = listToAttrs (mapAttrsToList (k: v: nameValuePair v k) config.networking.renameInterfacesByMac); + nameFromMac = - optional (network ? matchConfig.MACAddress && config.networking.renameInterfacesByMac ? ${network.matchConfig.MACAddress}) - config.networking.renameInterfacesByMac.${network.matchConfig.MACAddress}; + optional (network ? matchConfig.MACAddress && macToName ? ${network.matchConfig.MACAddress}) + macToName.${network.matchConfig.MACAddress}; nameFromNetdev = optional ( diff --git a/topology/options/icons.nix b/topology/options/icons.nix new file mode 100644 index 0000000..4bb94f7 --- /dev/null +++ b/topology/options/icons.nix @@ -0,0 +1,51 @@ +f: { + lib, + config, + ... +}: let + inherit + (lib) + concatStringsSep + filterAttrs + init + mapAttrs' + mkOption + nameValuePair + splitString + types + ; + + removeExtension = filename: concatStringsSep "." (init (splitString "." filename)); + + iconsFromFiles = dir: + mapAttrs' (file: _: nameValuePair (removeExtension file) {file = dir + "/${file}";}) ( + filterAttrs (_: type: type == "regular") (builtins.readDir dir) + ); + + iconType = types.submodule { + options = { + file = mkOption { + description = "The icon file"; + type = types.path; + }; + }; + }; + + mkIcons = name: + mkOption { + description = "Defines icons for ${name}."; + default = {}; + type = types.attrsOf iconType; + }; +in + f { + options.icons = { + interfaces = mkIcons "network interface types"; + services = mkIcons "services"; + }; + + config.icons = { + interfaces = iconsFromFiles ../icons/interfaces; + services = iconsFromFiles ../icons/services; + }; + } diff --git a/topology/options/interfaces.nix b/topology/options/interfaces.nix index 5f00e72..d1d2dd0 100644 --- a/topology/options/interfaces.nix +++ b/topology/options/interfaces.nix @@ -40,6 +40,18 @@ in type = types.nullOr types.str; }; + type = mkOption { + description = "The type of this interface"; + default = "ethernet"; + type = types.str; + }; + + icon = mkOption { + description = "The icon for this interface. If null, an icon will be selected from `icons.interfaces` based on the specified type."; + default = null; + type = types.nullOr types.path; + }; + addresses = mkOption { description = "The configured address(es), or a descriptive string (like DHCP)."; default = []; diff --git a/topology/options/networks.nix b/topology/options/networks.nix index 6ca255b..9b72305 100644 --- a/topology/options/networks.nix +++ b/topology/options/networks.nix @@ -12,8 +12,7 @@ in f { options.networks = mkOption { default = {}; - description = '' - ''; + description = "Defines logical networks that are present in your topology."; type = types.attrsOf (types.submodule (networkSubmod: { options = { id = mkOption { diff --git a/topology/options/nodes.nix b/topology/options/nodes.nix index 73dac08..13c4942 100644 --- a/topology/options/nodes.nix +++ b/topology/options/nodes.nix @@ -14,6 +14,8 @@ in options.nodes = mkOption { default = {}; description = '' + Defines nodes that are shown in the topology graph. + Nodes usually correspond to nixos hosts or other devices in your network. ''; type = types.attrsOf (types.submodule (nodeSubmod: { options = { diff --git a/topology/options/services.nix b/topology/options/services.nix index fa8a421..9d5e65f 100644 --- a/topology/options/services.nix +++ b/topology/options/services.nix @@ -14,7 +14,7 @@ in type = types.attrsOf (types.submodule { options = { services = mkOption { - description = "TODO"; + description = "Defines a service that is running on this node."; default = {}; type = types.attrsOf (types.submodule (submod: { options = { @@ -36,16 +36,34 @@ in default = null; }; - url = mkOption { - description = "The URL under which the service is reachable, if any."; - type = types.nullOr types.str; - default = null; + info = mkOption { + description = "Additional high-profile information about this service, usually the url or listen address. Most likely shown directly below the name."; + type = types.lines; }; - listenAddresses = mkOption { - description = "The addresses on which this service listens."; - type = types.nullOr types.str; - default = null; + details = mkOption { + description = "Additional detail sections that should be shown to the user."; + type = types.attrsOf (types.submodule (detailSubmod: { + options = { + name = mkOption { + description = "The name of this section"; + type = types.str; + readOnly = true; + default = detailSubmod.config._module.args.name; + }; + + order = mkOption { + description = "The order determines how sections are ordered. Lower numbers first, default is 100."; + type = types.int; + default = 100; + }; + + text = mkOption { + description = "The additional information to display"; + type = types.lines; + }; + }; + })); }; }; }));