From 1d2e32b8b0ea25e25ab42833d471e57d98ba1f76 Mon Sep 17 00:00:00 2001 From: Patrick Date: Thu, 12 Dec 2024 20:12:36 +0100 Subject: [PATCH] feat: topology --- flake.lock | 13 ++- hosts/desktopnix/default.nix | 1 + hosts/elisabeth/default.nix | 1 + hosts/elisabeth/guests.nix | 10 +- hosts/maddy/default.nix | 1 + hosts/mailnix/default.nix | 1 + hosts/patricknix/default.nix | 1 + nix/topology.nix | 183 +++++++++++++++++++++++++++++- secrets/secrets.nix.age | Bin 8141 -> 8336 bytes users/patrick/Xorg/default.nix | 2 +- users/patrick/programs/direnv.nix | 1 + 11 files changed, 197 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index cac61a9..c0d0c06 100644 --- a/flake.lock +++ b/flake.lock @@ -1522,12 +1522,13 @@ "pre-commit-hooks": "pre-commit-hooks_3" }, "locked": { - "lastModified": 1732192922, - "narHash": "sha256-xQO/3I99TFdiXTN5VoS28NpbNlCQWQUvxmPQHlfkzmU=", - "owner": "oddlama", - "repo": "nix-topology", - "rev": "2b107e98bbde932a363874e0ef5b1739a932bbc5", - "type": "github" + "lastModified": 1733919075, + "narHash": "sha256-qr0HiP+YEuMJWkEsM3KBQkIvfBjA4VFvV6gC43Ize2o=", + "ref": "refs/heads/fix-container-mvlan", + "rev": "f4f7786d315beb8d7c65665b7cfc7260a988d89f", + "revCount": 152, + "type": "git", + "url": "file:///home/patrick/repos/nix/nix-topology/fix-container-mvlan" }, "original": { "owner": "oddlama", diff --git a/hosts/desktopnix/default.nix b/hosts/desktopnix/default.nix index 5942e73..47f97e1 100644 --- a/hosts/desktopnix/default.nix +++ b/hosts/desktopnix/default.nix @@ -69,4 +69,5 @@ programs.streamcontroller.enable = true; hardware.opentabletdriver.enable = true; + topology.self.icon = "devices.desktop"; } diff --git a/hosts/elisabeth/default.nix b/hosts/elisabeth/default.nix index 2b56f16..84fd7c7 100644 --- a/hosts/elisabeth/default.nix +++ b/hosts/elisabeth/default.nix @@ -81,4 +81,5 @@ kexecTime = "1m"; }; }; + topology.self.interfaces.lan.network = "home"; } diff --git a/hosts/elisabeth/guests.nix b/hosts/elisabeth/guests.nix index 4be6160..f0688de 100644 --- a/hosts/elisabeth/guests.nix +++ b/hosts/elisabeth/guests.nix @@ -27,20 +27,13 @@ let actual = "actual"; firefly = "money"; homebox = "homebox"; - octoprint = "print"; invidious = "yt"; blog = "blog"; }; in "${domains.${hostName}}.${config.secrets.secrets.global.domains.web}"; # TODO hard coded elisabeth nicht so schön - ipOf = - hostName: - if hostName == "octoprint" then - #nodes.testienix.config.wireguard.elisabeth.ipv4 - "0.0.0.0" - else - nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4; + ipOf = hostName: nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4; in { services.netbird.server.proxy = @@ -161,7 +154,6 @@ in (blockOf "blog" { port = 80; }) (blockOf "homebox" { }) (proxyProtect "ollama" { } true) - (proxyProtect "octoprint" { } true) (proxyProtect "firefly" { port = 80; } true) (blockOf "apispotify" { port = 3000; diff --git a/hosts/maddy/default.nix b/hosts/maddy/default.nix index e1cd3ce..bb2a61b 100644 --- a/hosts/maddy/default.nix +++ b/hosts/maddy/default.nix @@ -16,4 +16,5 @@ "virtio_blk" ]; nixpkgs.hostPlatform = "x86_64-linux"; + topology.self.icon = "devices.cloud-server"; } diff --git a/hosts/mailnix/default.nix b/hosts/mailnix/default.nix index f142d11..1c387f3 100644 --- a/hosts/mailnix/default.nix +++ b/hosts/mailnix/default.nix @@ -33,4 +33,5 @@ createHome = false; }; users.groups.nix-build = { }; + topology.self.icon = "devices.cloud-server"; } diff --git a/hosts/patricknix/default.nix b/hosts/patricknix/default.nix index 1b3a3f1..7735331 100644 --- a/hosts/patricknix/default.nix +++ b/hosts/patricknix/default.nix @@ -44,4 +44,5 @@ "kvm" "nixos-test" ]; + topology.self.icon = "devices.laptop"; } diff --git a/nix/topology.nix b/nix/topology.nix index ffcd441..b1d7bdb 100644 --- a/nix/topology.nix +++ b/nix/topology.nix @@ -1 +1,182 @@ -{ } +{ config, ... }: +let + inherit (config.lib.topology) + mkInternet + mkRouter + mkConnection + mkSwitch + mkDevice + ; +in +{ + networks = { + home = { + name = "Heimnetz"; + cidrv4 = "192.168.178.0/24"; + }; + }; + nodes = { + internet = mkInternet { + connections = [ + (mkConnection "fritzbox" "wan1") + (mkConnection "mailnix" "lan01") + (mkConnection "maddy" "lan01") + ]; + }; + fritzbox = mkRouter "FritzBox" { + info = "FRITZ!Box 7520"; + interfaceGroups = [ + [ + "wan1" + ] + [ + "eth1" + "eth2" + "eth3" + ] + ]; + interfaces.eth1 = { + addresses = [ "192.168.178.1" ]; + network = "home"; + }; + connections.eth1 = mkConnection "switch-ganzoben" "eth1"; + }; + switch-ganzoben = mkSwitch "Switch Ganzoben" { + info = "TPLink 16 Port"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + "eth7" + "eth8" + "eth9" + "eth10" + "eth11" + "eth12" + "eth13" + "eth14" + "eth15" + "eth16" + ] + ]; + connections = { + eth2 = mkConnection "switch-waschkueche" "eth1"; + eth3 = mkConnection "switch-patrick" "eth5"; + eth4 = mkConnection "docking-station-ganzoben" "lan"; + eth5 = mkConnection "desktop-ganzoben" "lan"; + eth9 = mkConnection "drucker" "lan"; + eth10 = mkConnection "homematic" "lan"; + eth11 = mkConnection "raspberry-pi" "lan"; + eth12 = mkConnection "fernseher" "lan"; + eth16 = mkConnection "devolo" "lan"; + }; + }; + switch-waschkueche = mkSwitch "Switch Waschküche" { + info = "TPLink 8 Port"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + "eth7" + "eth8" + ] + ]; + connections = { + eth2 = mkConnection "switch-server" "eth1"; + eth3 = mkConnection "desktop-david" "lan"; + eth7 = mkConnection "solar-anlage" "lan"; + eth8 = mkConnection "solar-anlage" "lan"; + }; + }; + switch-server = mkSwitch "Switch Server" { + info = "TPLink 5 Port"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + ] + ]; + connections = { + eth2 = mkConnection "elisabeth" "lan01"; + eth3 = mkConnection "homematic-ip" "lan"; + eth4 = mkConnection "dect" "lan"; + eth5 = mkConnection "docking-station-keller" "lan"; + }; + }; + switch-patrick = mkSwitch "Switch Patrick" { + info = "5 Port"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + ] + ]; + connections = { + eth4 = mkConnection "desktopnix" "lan01"; + eth3 = mkConnection "patricknix" "lan01"; + }; + }; + docking-station-ganzoben = mkDevice "Docking Station Ganzoben" { + info = "Docking Station"; + interfaces.lan = { }; + }; + desktop-ganzoben = mkDevice "Desktop Ganzoben" { + info = "Desktop"; + interfaces.lan = { }; + }; + drucker = mkDevice "Drucker" { + info = "HP Drucker"; + interfaces.lan = { }; + }; + homematic = mkDevice "homematic" { + info = "Homematic zentrale"; + interfaces.lan = { }; + }; + raspberry-pi = mkDevice "RaspberryPi" { + info = "Raspberry-Pi 5"; + interfaces.lan = { }; + }; + fernseher = mkDevice "fernseher" { + info = "LG? Fernseher"; + interfaces.lan = { }; + }; + devolo = mkDevice "devolo" { + info = "devolo"; + interfaces.lan = { }; + }; + solar-anlage = mkDevice "solar" { + info = "solar anlage+batterie"; + interfaces.lan = { }; + }; + desktop-david = mkDevice "desktop-david" { + info = "Desktop"; + interfaces.lan = { }; + }; + homematic-ip = mkDevice "homematic-ip" { + info = "homematic-ip point"; + interfaces.lan = { }; + }; + dect = mkDevice "dect" { + info = "Teflon"; + interfaces.lan = { }; + }; + docking-station-keller = mkDevice "Docking-station Keller" { + info = "Für die kellerarbeiter"; + interfaces.lan = { }; + }; + }; +} diff --git a/secrets/secrets.nix.age b/secrets/secrets.nix.age index 2e127042171405dc527aac99310308ebd1a7817c..b6f93bff3c318a6caa6f8eaa9b9878575ca2263e 100644 GIT binary patch literal 8336 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 a98ARyoQEbUcNt@$NZJdOi3ZI2cD;X7)yR|p literal 8141 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