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;
+ };
+ };
+ }));
};
};
}));