1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 14:50:40 +02:00

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;
modules = [
{
({config, ...}: let
inherit
(config.lib.helpers)
mkInternet
mkSwitch
mkRouter
mkConnection
mkConnectionRev
;
in {
renderer = "elk";
nixosConfigurations = self.nodes;
nodes.internet = {
name = "Internet";
deviceType = "internet";
hardware.image = ./cloud.svg;
# interfaces.eth0.network = "internet";
interfaces.eth0.physicalConnections = [
{
node = "fritzbox";
interface = "wan0";
}
{
node = "sentinel";
interface = "wan";
}
];
};
nodes.internet = mkInternet {};
nodes.sentinel.interfaces.wan.physicalConnections = [(mkConnectionRev "internet" "*")];
nodes.fritzbox = {
name = "FritzBox";
deviceType = "router";
hardware.info = "FRITZ!Box 7520";
hardware.image = ./fritzbox.png;
# interfaces.wan0.network = "internet";
interfaces.wan0 = {};
interfaces.eth0.physicalConnections = [
{
node = "ward";
interface = "wan";
}
nodes.fritzbox = mkRouter "FritzBox" {
info = "FRITZ!Box 7520";
image = ./fritzbox.png;
interfaceGroups = [
["eth1" "eth2" "eth3" "eth4"]
["wan1"]
];
connections.eth1 = mkConnection "ward" "wan";
connections.wan1 = mkConnectionRev "internet" "*";
};
# TODO: extract from kea!
networks.home-lan = {
name = "Home LAN";
cidrv4 = "192.168.1.0/24";
#color = "#78dba9";
};
networks.home-fritzbox = {
name = "Home Fritzbox";
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.fritzbox.interfaces.eth0.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 {};
nodes.fritzbox.interfaces.eth1.network = "home-fritzbox";
}
];
};

View file

@ -20,6 +20,9 @@
./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.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "e1000e" "alx"];
@ -81,6 +84,13 @@
networking.nftables.firewall = {
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
lokiDir = "/var/lib/loki";
in {

View file

@ -23,26 +23,7 @@
topology.self.hardware.image = ../../odroid-h3.png;
topology.self.hardware.info = "ODROID H3, 64GB RAM";
# TODO FIXME topology bogus
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";
}
);
topology.self.interfaces.lan.sharesNetworkWith = x: x == "lan-self";
boot.mode = "efi";
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sdhci_pci" "r8169"];
@ -87,6 +68,13 @@
networking.nftables.firewall = {
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];
};
topology.self.services.adguardhome.info = "https://" + adguardhomeDomain;
services.adguardhome = {
enable = true;
# 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 = {
enable = true;
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;};
config.topology.self.services = mkIf config.topology.extractors.services.enable {
adguardhome = mkIf config.services.adguardhome.enable {
name = "AdGuard Home";
icon = "services.adguardhome";
};
adguardhome = let
address = config.services.adguardhome.settings.bind_host or null;
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 {
name = "Forgejo";
icon = "services.forgejo";
};
forgejo = let
address = config.services.forgejo.settings.server.HTTP_ADDR or null;
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 {
name = "Grafana";
icon = "services.grafana";
};
grafana = let
address = config.services.grafana.settings.server.http_addr or null;
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 {
name = "Kanidm";
icon = "services.kanidm";
info = config.services.kanidm.serverSettings.origin;
details.listen.text = config.services.kanidm.serverSettings.bindaddress;
};
loki = mkIf config.services.loki.enable {
name = "Loki";
icon = "services.loki";
};
loki = let
address = config.services.loki.configuration.server.http_listen_address or null;
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 {
name = "NGINX";
@ -70,6 +97,7 @@ in {
radicale = mkIf config.services.radicale.enable {
name = "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 {

View file

@ -327,6 +327,11 @@ in
icon = mkIf (config.topology.isMainModule && config.icons.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 = {
lib.a.a = connections;
lib.a.b = networkDefiningInterfaces;
lib.a.c = propagatedNetworks;
assertions = flatten (flip map (attrValues config.nodes) (
node:
flip map (attrValues node.interfaces) (

View file

@ -6,14 +6,17 @@ f: {
inherit
(lib)
attrValues
concatMap
elem
flatten
flip
literalExpression
mapAttrsToList
mkDefault
mkIf
mkMerge
mkOption
toList
types
;
in
@ -125,6 +128,56 @@ in
};
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 (
flip map (attrValues config.nodes) (
node: [

View file

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

View file

@ -1,4 +1,5 @@
# TODO:
# - macvtap interface type svg with small link
# - address port label render make newline capable (multiple port labels)
# - NAT indication
# - embed font globally, try removing satori embed?
@ -115,9 +116,9 @@
else net.style.secondaryColor;
in
{
solid = ''<div tw="flex flex-none ${twAttrs} bg-[${net.style.primaryColor}] rounded-md"></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>'';
dotted = ''<div tw="flex flex-none ${twAttrs} rounded-md" style="backgroundImage: radial-gradient(circle, ${net.style.primaryColor} 30%, ${secondaryColor} 30.01%);"></div>'';
solid = ''<div tw="flex flex-none ${twAttrs} bg-[${net.style.primaryColor}]"></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}" style="backgroundImage: radial-gradient(circle, ${net.style.primaryColor} 30%, ${secondaryColor} 30.01%);"></div>'';
}
.${net.style.pattern};
@ -130,7 +131,7 @@
*/
''
<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>
<div tw="flex grow min-w-8"></div>
${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-row items-center">
${html.net.netStylePreview net "w-12 h-6 mr-4"}
<div tw="flex flex-row">
${html.net.netStylePreview net "w-12 h-4 mt-2 mr-4 rounded-md"}
<div tw="flex flex-col grow">
<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.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.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 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>