feat(topology): extract more service info and add helper functions to define stuff

This commit is contained in:
oddlama 2024-04-01 02:26:52 +02:00
parent cc35dd599a
commit 30579a433e
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
12 changed files with 174 additions and 175 deletions

168
flake.nix
View file

@ -183,151 +183,65 @@
{ {
inherit pkgs; inherit pkgs;
modules = [ modules = [
{ ({config, ...}: let
inherit
(config.lib.helpers)
mkInternet
mkSwitch
mkRouter
mkConnection
mkConnectionRev
;
in {
renderer = "elk"; renderer = "elk";
nixosConfigurations = self.nodes; nixosConfigurations = self.nodes;
nodes.internet = { nodes.internet = mkInternet {};
name = "Internet"; nodes.sentinel.interfaces.wan.physicalConnections = [(mkConnectionRev "internet" "*")];
deviceType = "internet";
hardware.image = ./cloud.svg;
# interfaces.eth0.network = "internet";
interfaces.eth0.physicalConnections = [
{
node = "fritzbox";
interface = "wan0";
}
{
node = "sentinel";
interface = "wan";
}
];
};
nodes.fritzbox = { nodes.fritzbox = mkRouter "FritzBox" {
name = "FritzBox"; info = "FRITZ!Box 7520";
deviceType = "router"; image = ./fritzbox.png;
hardware.info = "FRITZ!Box 7520"; interfaceGroups = [
hardware.image = ./fritzbox.png; ["eth1" "eth2" "eth3" "eth4"]
# interfaces.wan0.network = "internet"; ["wan1"]
interfaces.wan0 = {};
interfaces.eth0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
]; ];
connections.eth1 = mkConnection "ward" "wan";
connections.wan1 = mkConnectionRev "internet" "*";
}; };
# TODO: extract from kea! # TODO: extract from kea!
networks.home-lan = { networks.home-lan = {
name = "Home LAN"; name = "Home LAN";
cidrv4 = "192.168.1.0/24"; cidrv4 = "192.168.1.0/24";
#color = "#78dba9";
}; };
networks.home-fritzbox = { networks.home-fritzbox = {
name = "Home Fritzbox"; name = "Home Fritzbox";
cidrv4 = "192.168.178.0/24"; cidrv4 = "192.168.178.0/24";
#color = "#f1cf8a";
}; };
nodes.switch-attic = mkSwitch "Switch Attic" {
info = "D-Link DGS-1016D";
image = ./dlink-dgs1016d.png;
interfaceGroups = [["eth1" "eth2" "eth3" "eth4" "eth5" "eth6"]];
connections.eth1 = mkConnection "ward" "lan";
connections.eth2 = mkConnection "sire" "lan";
connections.eth3 = [];
};
nodes.switch-bedroom-1 = mkSwitch "Switch Bedroom 1" {
info = "D-Link DGS-105";
image = ./dlink-dgs105.png;
interfaceGroups = [["eth1" "eth2" "eth3" "eth4" "eth5"]];
connections.eth1 = mkConnection "switch-attic" "eth3";
connections.eth2 = mkConnection "kroma" "lan1";
connections.eth3 = mkConnection "nom" "lan1";
};
})
{
nodes.ward.interfaces.lan.network = "home-lan"; nodes.ward.interfaces.lan.network = "home-lan";
nodes.fritzbox.interfaces.eth0.network = "home-fritzbox"; nodes.fritzbox.interfaces.eth1.network = "home-fritzbox";
nodes.switch-attic = {
name = "Switch Attic";
deviceType = "switch";
hardware.info = "D-Link DGS-1016D";
hardware.image = ./dlink-dgs1016d.png;
interfaces.eth0.sharesNetworkWith = _: true;
interfaces.eth1.sharesNetworkWith = _: true;
interfaces.eth2.sharesNetworkWith = _: true;
interfaces.eth0.physicalConnections = [
{
node = "ward";
interface = "lan";
}
];
interfaces.eth1.physicalConnections = [
{
node = "sire";
interface = "lan";
}
];
interfaces.eth2 = {};
};
nodes.switch-bedroom-1 = {
name = "Switch Bedroom 1";
deviceType = "switch";
hardware.info = "D-Link DGS-105";
hardware.image = ./dlink-dgs105.png;
interfaces.eth0.sharesNetworkWith = _: true;
interfaces.eth1.sharesNetworkWith = _: true;
interfaces.eth2.sharesNetworkWith = _: true;
interfaces.eth0.physicalConnections = [
{
node = "switch-attic";
interface = "eth2";
}
];
interfaces.eth1.physicalConnections = [
{
node = "kroma";
interface = "lan1";
}
];
interfaces.eth2.physicalConnections = [
{
node = "nom";
interface = "lan1";
}
];
};
#nodes.fritzbox-no-img = {
# name = "FritzBox No HImg";
# deviceType = "router";
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
#nodes.fritzbox-device-nd = {
# name = "FritzBox No DImg";
# deviceType = "device";
# hardware.image = ./fritzbox.png;
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
#nodes.fritzbox-device = {
# name = "FritzBox No D&HImg";
# deviceType = "device";
# interfaces.wan0.physicalConnections = [
# {
# node = "ward";
# interface = "wan";
# }
# ];
#};
# TODO:
#nodes.fritzbox = config.lib.nodes.mkRouter {};
#nodes.fritzbox = config.lib.nodes.mkSwitch {};
#nodes.fritzbox = config.lib.nodes.mkWifiAP {};
#nodes.printer = config.lib.nodes.mkWifiAP {};
} }
]; ];
}; };

View file

@ -20,6 +20,9 @@
./net.nix ./net.nix
]; ];
topology.self.hardware.info = "AMD Ryzen Threadripper 1950X, 96GB RAM";
topology.self.interfaces.lan.sharesNetworkWith = x: x == "lan-self";
boot.mode = "efi"; boot.mode = "efi";
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "e1000e" "alx"]; boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "e1000e" "alx"];
@ -81,6 +84,13 @@
networking.nftables.firewall = { networking.nftables.firewall = {
zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName]; zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName];
}; };
topology.self.interfaces.lan.physicalConnections = [
{
node = config.node.name;
interface = "lan-self";
renderer.reverse = true;
}
];
} }
]; ];
}; };

View file

@ -64,6 +64,7 @@ in {
} }
]; ];
topology.self.services.loki.info = "https://" + lokiDomain;
services.loki = let services.loki = let
lokiDir = "/var/lib/loki"; lokiDir = "/var/lib/loki";
in { in {

View file

@ -23,26 +23,7 @@
topology.self.hardware.image = ../../odroid-h3.png; topology.self.hardware.image = ../../odroid-h3.png;
topology.self.hardware.info = "ODROID H3, 64GB RAM"; topology.self.hardware.info = "ODROID H3, 64GB RAM";
# TODO FIXME topology bogus topology.self.interfaces.lan.sharesNetworkWith = x: x == "lan-self";
topology.self.interfaces.lan-self.physicalConnections = [
{
node = config.node.name;
interface = "lan";
}
];
topology.self.interfaces.lan.physicalConnections =
lib.flip map [
"adguardhome"
"forgejo"
"kanidm"
"radicale"
"vaultwarden"
] (
x: {
node = "ward-${x}";
interface = "lan";
}
);
boot.mode = "efi"; boot.mode = "efi";
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sdhci_pci" "r8169"]; boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sdhci_pci" "r8169"];
@ -87,6 +68,13 @@
networking.nftables.firewall = { networking.nftables.firewall = {
zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName]; zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName];
}; };
topology.self.interfaces.lan.physicalConnections = [
{
node = config.node.name;
interface = "lan-self";
renderer.reverse = true;
}
];
} }
]; ];
}; };

View file

@ -48,6 +48,7 @@ in {
allowedUDPPorts = [53]; allowedUDPPorts = [53];
}; };
topology.self.services.adguardhome.info = "https://" + adguardhomeDomain;
services.adguardhome = { services.adguardhome = {
enable = true; enable = true;
# TODO allow mutable settings, replace 123.123.123.123 with # TODO allow mutable settings, replace 123.123.123.123 with

View file

@ -43,6 +43,7 @@ in {
} }
]; ];
topology.self.services.radicale.info = "https://" + radicaleDomain;
services.radicale = { services.radicale = {
enable = true; enable = true;
settings = { settings = {

View file

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 929 B

Before After
Before After

View file

@ -21,30 +21,57 @@ in {
options.topology.extractors.services.enable = mkEnableOption "topology service extractor" // {default = true;}; options.topology.extractors.services.enable = mkEnableOption "topology service extractor" // {default = true;};
config.topology.self.services = mkIf config.topology.extractors.services.enable { config.topology.self.services = mkIf config.topology.extractors.services.enable {
adguardhome = mkIf config.services.adguardhome.enable { adguardhome = let
name = "AdGuard Home"; address = config.services.adguardhome.settings.bind_host or null;
icon = "services.adguardhome"; port = config.services.adguardhome.settings.bind_port or null;
}; in
mkIf config.services.adguardhome.enable {
name = "AdGuard Home";
icon = "services.adguardhome";
details.listen = mkIf (address != null && port != null) {text = "${address}:${toString port}";};
};
forgejo = mkIf config.services.forgejo.enable { forgejo = let
name = "Forgejo"; address = config.services.forgejo.settings.server.HTTP_ADDR or null;
icon = "services.forgejo"; port = config.services.forgejo.settings.server.HTTP_PORT or null;
}; in
mkIf config.services.forgejo.enable {
name =
if config.services.forgejo.settings ? DEFAULT.APP_NAME
then "Forgejo (${config.services.forgejo.settings.DEFAULT.APP_NAME})"
else "Forgejo";
icon = "services.forgejo";
info = mkIf (config.services.forgejo.settings ? server.ROOT_URL) config.services.forgejo.settings.server.ROOT_URL;
details.listen = mkIf (address != null && port != null) {text = "${address}:${toString port}";};
};
grafana = mkIf config.services.grafana.enable { grafana = let
name = "Grafana"; address = config.services.grafana.settings.server.http_addr or null;
icon = "services.grafana"; port = config.services.grafana.settings.server.http_port or null;
}; in
mkIf config.services.grafana.enable {
name = "Grafana";
icon = "services.grafana";
info = config.services.grafana.settings.server.root_url;
details.listen = mkIf (address != null && port != null) {text = "${address}:${toString port}";};
};
kanidm = mkIf config.services.kanidm.enableServer { kanidm = mkIf config.services.kanidm.enableServer {
name = "Kanidm"; name = "Kanidm";
icon = "services.kanidm"; icon = "services.kanidm";
info = config.services.kanidm.serverSettings.origin;
details.listen.text = config.services.kanidm.serverSettings.bindaddress;
}; };
loki = mkIf config.services.loki.enable { loki = let
name = "Loki"; address = config.services.loki.configuration.server.http_listen_address or null;
icon = "services.loki"; port = config.services.loki.configuration.server.http_listen_port or null;
}; in
mkIf config.services.loki.enable {
name = "Loki";
icon = "services.loki";
details.listen = mkIf (address != null && port != null) {text = "${address}:${toString port}";};
};
nginx = mkIf config.services.nginx.enable { nginx = mkIf config.services.nginx.enable {
name = "NGINX"; name = "NGINX";
@ -70,6 +97,7 @@ in {
radicale = mkIf config.services.radicale.enable { radicale = mkIf config.services.radicale.enable {
name = "Radicale"; name = "Radicale";
icon = "services.radicale"; icon = "services.radicale";
details.listen = mkIf (config.services.radicale.settings ? server.hosts) {text = toString config.services.radicale.settings.server.hosts;};
}; };
samba = mkIf config.services.samba.enable { samba = mkIf config.services.samba.enable {

View file

@ -327,6 +327,11 @@ in
icon = mkIf (config.topology.isMainModule && config.icons.interfaces ? ${submod.config.type}) ( icon = mkIf (config.topology.isMainModule && config.icons.interfaces ? ${submod.config.type}) (
mkDefault ("interfaces." + submod.config.type) mkDefault ("interfaces." + submod.config.type)
); );
# For switches: Share the network with any other interface by default
sharesNetworkWith = mkIf (config.topology.isMainModule && nodeSubmod.config.deviceType == "switch") (
mkDefault (const true)
);
}; };
})); }));
}; };
@ -335,9 +340,6 @@ in
}; };
config = { config = {
lib.a.a = connections;
lib.a.b = networkDefiningInterfaces;
lib.a.c = propagatedNetworks;
assertions = flatten (flip map (attrValues config.nodes) ( assertions = flatten (flip map (attrValues config.nodes) (
node: node:
flip map (attrValues node.interfaces) ( flip map (attrValues node.interfaces) (

View file

@ -6,14 +6,17 @@ f: {
inherit inherit
(lib) (lib)
attrValues attrValues
concatMap
elem elem
flatten flatten
flip flip
literalExpression literalExpression
mapAttrsToList
mkDefault mkDefault
mkIf mkIf
mkMerge mkMerge
mkOption mkOption
toList
types types
; ;
in in
@ -125,6 +128,56 @@ in
}; };
config = { config = {
lib.helpers = rec {
# Finally we found it, the one-and-only true cloud.
mkInternet = {connections ? [], ...}: {
name = "Internet";
deviceType = "internet";
hardware.image = ../icons/devices/cloud.svg;
interfaces."*".physicalConnections = toList connections;
};
mkConnection = node: interface: {inherit node interface;};
mkConnectionRev = node: interface: {
inherit node interface;
renderer.reverse = true;
};
mkSwitch = name: {
info ? null,
image ? null,
interfaceGroups ? [],
connections ? {},
...
}: {
inherit name;
deviceType = "switch";
hardware = {
info = mkIf (info != null) info;
image = mkIf (image != null) image;
};
interfaces = mkMerge (
flip mapAttrsToList connections (interface: conns: {
${interface}.physicalConnections = toList conns;
})
++ flip concatMap interfaceGroups (
group:
flip map group (
interface: {
${interface}.sharesNetworkWith = x: elem x group;
}
)
)
);
};
mkRouter = name: args:
mkSwitch name args
// {
deviceType = "router";
};
};
assertions = flatten ( assertions = flatten (
flip map (attrValues config.nodes) ( flip map (attrValues config.nodes) (
node: [ node: [

View file

@ -205,7 +205,7 @@
"portLabels.placement" = "OUTSIDE"; "portLabels.placement" = "OUTSIDE";
} }
// optionalAttrs (node.renderer.preferredType == "card") { // optionalAttrs (node.renderer.preferredType == "card") {
"portConstraints" = "FIXED_SIDE"; # "portConstraints" = "FIXED_SIDE";
}; };
}; };
} }

View file

@ -1,4 +1,5 @@
# TODO: # TODO:
# - macvtap interface type svg with small link
# - address port label render make newline capable (multiple port labels) # - address port label render make newline capable (multiple port labels)
# - NAT indication # - NAT indication
# - embed font globally, try removing satori embed? # - embed font globally, try removing satori embed?
@ -115,9 +116,9 @@
else net.style.secondaryColor; else net.style.secondaryColor;
in in
{ {
solid = ''<div tw="flex flex-none ${twAttrs} bg-[${net.style.primaryColor}] rounded-md"></div>''; solid = ''<div tw="flex flex-none ${twAttrs} bg-[${net.style.primaryColor}]"></div>'';
dashed = ''<div tw="flex flex-none ${twAttrs} rounded-md" style="backgroundImage: linear-gradient(90deg, ${net.style.primaryColor} 0%, ${net.style.primaryColor} 50%, ${secondaryColor} 50.01%, ${secondaryColor} 100%);"></div>''; dashed = ''<div tw="flex flex-none ${twAttrs}" style="backgroundImage: linear-gradient(90deg, ${net.style.primaryColor} 0%, ${net.style.primaryColor} 50%, ${secondaryColor} 50.01%, ${secondaryColor} 100%);"></div>'';
dotted = ''<div tw="flex flex-none ${twAttrs} rounded-md" style="backgroundImage: radial-gradient(circle, ${net.style.primaryColor} 30%, ${secondaryColor} 30.01%);"></div>''; dotted = ''<div tw="flex flex-none ${twAttrs}" style="backgroundImage: radial-gradient(circle, ${net.style.primaryColor} 30%, ${secondaryColor} 30.01%);"></div>'';
} }
.${net.style.pattern}; .${net.style.pattern};
@ -130,7 +131,7 @@
*/ */
'' ''
<div tw="flex flex-row mx-6 mt-2 items-center"> <div tw="flex flex-row mx-6 mt-2 items-center">
${html.net.netStylePreview net "w-8 h-4 mr-4"} ${html.net.netStylePreview net "w-12 h-4 mr-4 rounded-md"}
<h2 tw="text-2xl font-bold">${net.name}</h2> <h2 tw="text-2xl font-bold">${net.name}</h2>
<div tw="flex grow min-w-8"></div> <div tw="flex grow min-w-8"></div>
${mkImageMaybe "w-12 h-12 ml-4" (config.lib.icons.get net.icon)} ${mkImageMaybe "w-12 h-12 ml-4" (config.lib.icons.get net.icon)}
@ -160,12 +161,12 @@
*/ */
'' ''
<div tw="flex flex-col mx-4 mt-2 rounded-lg p-2"> <div tw="flex flex-col mx-4 mt-2 rounded-lg p-2">
<div tw="flex flex-row items-center"> <div tw="flex flex-row">
${html.net.netStylePreview net "w-12 h-6 mr-4"} ${html.net.netStylePreview net "w-12 h-4 mt-2 mr-4 rounded-md"}
<div tw="flex flex-col grow"> <div tw="flex flex-col grow">
<h1 tw="text-lg font-bold m-0">${net.name}</h1> <h1 tw="text-lg font-bold m-0">${net.name}</h1>
${optionalString (net.cidrv4 != null) ''<div tw="flex flex-row"><span tw="text-md m-0"><b>CIDRv4</b></span><span tw="text-md text-[${net.style.primaryColor}] m-0 ml-4">${net.cidrv4}</span></div>''} ${optionalString (net.cidrv4 != null) ''<div tw="flex flex-row"><span tw="text-md text-[#7a899f] m-0"><b>CIDRv4</b></span><span tw="text-md text-[${net.style.primaryColor}] m-0 ml-4">${net.cidrv4}</span></div>''}
${optionalString (net.cidrv6 != null) ''<div tw="flex flex-row"><span tw="text-md m-0"><b>CIDRv6</b></span><span tw="text-md text-[${net.style.primaryColor}] m-0 ml-4">${net.cidrv6}</span></div>''} ${optionalString (net.cidrv6 != null) ''<div tw="flex flex-row"><span tw="text-md text-[#7a899f] m-0"><b>CIDRv6</b></span><span tw="text-md text-[${net.style.primaryColor}] m-0 ml-4">${net.cidrv6}</span></div>''}
</div> </div>
</div> </div>
</div> </div>