From c89209f1df76749ac4669f5ffdbcac6fb67ecd4b Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 10:08:35 +0200 Subject: [PATCH 001/108] Add experimental nix-snapshotter stuff --- container-images.nix | 2 -- container-images/image-definitions.nix | 2 ++ container-images/pulled-images.nix | 13 ++++++++++++ flake-parts/kubenix.nix | 6 ++++-- flake-parts/scripts/default.nix | 9 +++++++- kubenix-modules/all.nix | 20 ------------------ kubenix-modules/cyberchef.nix | 4 ++-- kubenix-modules/inbucket.nix | 2 +- nixos-modules/k3s/default.nix | 29 ++++++++++++++++++++++---- 9 files changed, 55 insertions(+), 32 deletions(-) delete mode 100644 container-images.nix create mode 100644 container-images/image-definitions.nix create mode 100644 container-images/pulled-images.nix diff --git a/container-images.nix b/container-images.nix deleted file mode 100644 index 037defa..0000000 --- a/container-images.nix +++ /dev/null @@ -1,2 +0,0 @@ -{ cyberchef = { cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:5044c72dd8070fb6e0595e720fc4440bf6168493b2433db06a1c966406398ba2"; imageName = "mpepping/cyberchef"; sha256 = "177yjfbz0ijc8lfqfr50fhqqmjk72373c0igyrxv3wwg0pyrgpv4"; }; }; } - diff --git a/container-images/image-definitions.nix b/container-images/image-definitions.nix new file mode 100644 index 0000000..d9faf29 --- /dev/null +++ b/container-images/image-definitions.nix @@ -0,0 +1,2 @@ +{ cyberchef = { cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "v10.18.9"; imageDigest = "sha256:4b06936cbeff92cfebf86fdcfbb4bad7807d6a5f99b8affa114bd84f81461fe3"; imageName = "mpepping/cyberchef"; sha256 = "019wr9vrpjg6kq4sqkf9d9xr5w86hn4d93pkk57sliqwyjjn13x8"; }; }; inbucket = { inbucket = { finalImageName = "inbucket/inbucket"; finalImageTag = "edge"; imageDigest = "sha256:e39238af6ac485c406ead9cf411ca7d6bad5dd6e1bca2a02af87273db5f53c8e"; imageName = "inbucket/inbucket"; sha256 = "1z9gywpr3i5048k39dflqlp9k6227b7kdipwk790x711iga2jqpk"; }; }; } + diff --git a/container-images/pulled-images.nix b/container-images/pulled-images.nix new file mode 100644 index 0000000..8e8d40c --- /dev/null +++ b/container-images/pulled-images.nix @@ -0,0 +1,13 @@ +pkgs: lib: +let + imageDefs = import ./image-definitions.nix; +in +lib.attrsets.mapAttrs + (projectName: project: + lib.attrsets.mapAttrs + (imageName: imageDef: + pkgs.dockerTools.pullImage imageDef + ) + project + ) + imageDefs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index d3774a3..33c90ed 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -1,9 +1,11 @@ -{ self, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem +{ self, nixpkgs, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; + pulledImages = (import "${self}/container-images/pulled-images.nix") pkgs pkgs.lib; mkKubenixPackage = module: kubenix.packages.${system}.default.override { - specialArgs = { inherit myLib kubenix nixhelm system dns blog-pim machines; }; + specialArgs = { inherit myLib kubenix nixhelm system dns blog-pim machines pulledImages; }; module = { imports = [ module ]; }; }; in diff --git a/flake-parts/scripts/default.nix b/flake-parts/scripts/default.nix index 451e575..2e4aa4d 100644 --- a/flake-parts/scripts/default.nix +++ b/flake-parts/scripts/default.nix @@ -32,7 +32,14 @@ in cyberchef = { cyberchef = { image-name = "mpepping/cyberchef"; - image-tag = "latest"; + image-tag = "v10.18.9"; + }; + }; + + inbucket = { + inbucket = { + image-name = "inbucket/inbucket"; + image-tag = "edge"; }; }; }; diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index fe91bc5..eb470c4 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -24,26 +24,6 @@ let ]; in { - kubernetes.resources.pods.testje.spec = { - containers.redis = { - image = "nix:0/nix/store/5nmh9qawhbwinzxidafjlfw68wfkh0pj-nix-image-redis.tar"; - args = [ "--protected-mode" "no" ]; - - ports = [{ - name = "redis"; - containerPort = 6379; - }]; - }; - - affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms = [{ - matchExpressions = [{ - key = "kubernetes.io/hostname"; - operator = "In"; - values = [ "atlas" ]; - }]; - }]; - }; - imports = [ ./base.nix ./longhorn.nix diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 19c2578..6691687 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,4 +1,4 @@ -{ +{ pulledImages, ... }: { kubernetes.resources = { deployments.cyberchef.spec = { replicas = 3; @@ -8,7 +8,7 @@ metadata.labels.app = "cyberchef"; spec.containers.cyberchef = { - image = "mpepping/cyberchef"; + image = "mpepping/cyberchef:latest"; ports.web.containerPort = 8000; }; }; diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index ba4edbd..83d2987 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -1,4 +1,4 @@ -{ lib, myLib, ... }: { +{ pulledImages, myLib, ... }: { kubernetes.resources = { deployments.inbucket = { metadata.labels.app = "inbucket"; diff --git a/nixos-modules/k3s/default.nix b/nixos-modules/k3s/default.nix index 4c902d9..6800efb 100644 --- a/nixos-modules/k3s/default.nix +++ b/nixos-modules/k3s/default.nix @@ -1,4 +1,4 @@ -{ inputs, pkgs, lib, config, ... }: +{ self, inputs, pkgs, lib, config, ... }: let cfg = config.lab.k3s; @@ -167,9 +167,30 @@ in cp -f ${./k3s-ca/etcd/server-ca.crt} /var/lib/rancher/k3s/server/tls/etcd/server-ca.crt ''; - nix-snapshotter-image = '' - ln -sf ${image} /root/image.tar - ''; + docker-images = + let + pulledImages = (import "${self}/container-images/pulled-images.nix") pkgs lib; + basePath = "/var/docker_images"; + linesForImage = projectName: imageName: pulledImage: + let + projectPath = "${basePath}/${projectName}"; + in + '' + mkdir -p ${projectPath} + ln -sf ${pulledImage} ${projectPath}/${imageName}.tar + ''; + linesForProject = projectName: project: + let + lines = lib.attrsets.mapAttrsToList (linesForImage projectName) project; + in + builtins.concatStringsSep "\n" lines; + generateLines = projects: + let + lines = lib.attrsets.mapAttrsToList linesForProject projects; + in + builtins.concatStringsSep "\n" lines; + in + generateLines pulledImages; }; }; From 8091664f11f09ca00ced35c0e63c46f75e65d279 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 11:07:51 +0200 Subject: [PATCH 002/108] Expose NFS shares on 10.0.0.0/8 --- nixos-modules/data-sharing.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos-modules/data-sharing.nix b/nixos-modules/data-sharing.nix index b5e7440..ac6c456 100644 --- a/nixos-modules/data-sharing.nix +++ b/nixos-modules/data-sharing.nix @@ -14,7 +14,7 @@ let nfsExports = lib.strings.concatLines ( builtins.map (share: - "${share} 192.168.30.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1/8(rw,sync,no_subtree_check,no_root_squash)" + "${share} 192.168.30.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1/8(rw,sync,no_subtree_check,no_root_squash) 10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)" ) nfsShares ); From 0af78c23e6f15f152baa96cef3592cf73d72acdf Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 11:28:29 +0200 Subject: [PATCH 003/108] Resize atuin volumes --- kubenix-modules/all.nix | 20 -------------------- kubenix-modules/volumes.nix | 12 ++++++------ 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index fe91bc5..eb470c4 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -24,26 +24,6 @@ let ]; in { - kubernetes.resources.pods.testje.spec = { - containers.redis = { - image = "nix:0/nix/store/5nmh9qawhbwinzxidafjlfw68wfkh0pj-nix-image-redis.tar"; - args = [ "--protected-mode" "no" ]; - - ports = [{ - name = "redis"; - containerPort = 6379; - }]; - }; - - affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms = [{ - matchExpressions = [{ - key = "kubernetes.io/hostname"; - operator = "In"; - values = [ "atlas" ]; - }]; - }]; - }; - imports = [ ./base.nix ./longhorn.nix diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 8f9952f..57ec8ac 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -5,13 +5,13 @@ # volumeMounts = [ - # { name = "immich"; mountPath = "/immich"; } - # { name = "immich-db"; mountPath = "/immich-db"; } + # { name = "atuin"; mountPath = "/atuin"; } + # { name = "atuin-db"; mountPath = "/atuin-db"; } # ]; # }; - # volumes.immich.persistentVolumeClaim.claimName = "immich"; - # volumes.immich-db.persistentVolumeClaim.claimName = "immich-db"; + # volumes.atuin.persistentVolumeClaim.claimName = "atuin"; + # volumes.atuin-db.persistentVolumeClaim.claimName = "atuin-db"; # }; lab = { @@ -40,8 +40,8 @@ bazarr.storage = "25Mi"; attic.storage = "15Gi"; attic-db.storage = "150Mi"; - atuin.storage = "600Mi"; - atuin-db.storage = "100Mi"; + atuin.storage = "300Mi"; + atuin-db.storage = "300Mi"; immich.storage = "50Gi"; immich-db.storage = "5Gi"; }; From 04474ec7df9ea1f7099874ba66e9e30bede55519 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 11:44:13 +0200 Subject: [PATCH 004/108] Resize freshrss volume --- kubenix-modules/volumes.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 57ec8ac..f4592e7 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -18,7 +18,7 @@ longhornVolumes = { hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; - freshrss.storage = "400Mi"; + freshrss.storage = "1Gi"; radicale.storage = "200Mi"; minecraft.storage = "1Gi"; nextcloud.storage = "50Gi"; From a9dc926c9c975fae1348fb98548a28044d77ca06 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 12:08:24 +0200 Subject: [PATCH 005/108] chore(immich): Update to v1.108.0 --- kubenix-modules/immich.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 9e30ea3..b5ebfc2 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -32,7 +32,7 @@ volumes.data.persistentVolumeClaim.claimName = "immich"; containers.immich = { - image = "ghcr.io/immich-app/immich-server:v1.106.4"; + image = "ghcr.io/immich-app/immich-server:v1.108.0"; imagePullPolicy = "Always"; ports.web.containerPort = 3001; @@ -78,7 +78,7 @@ volumes.cache.persistentVolumeClaim.claimName = "immich-cache"; containers.machine-learning = { - image = "ghcr.io/immich-app/immich-machine-learning:v1.106.4"; + image = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; imagePullPolicy = "Always"; ports.ml.containerPort = 3003; env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; From e578de7fe99208345959cb19a56e4362e38a2139 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 13:37:16 +0200 Subject: [PATCH 006/108] chore(radicale): Update to 3.2.2.0 --- kubenix-modules/radicale.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix index 9f6f621..171714a 100644 --- a/kubenix-modules/radicale.nix +++ b/kubenix-modules/radicale.nix @@ -39,13 +39,23 @@ spec = { selector.matchLabels.app = "radicale"; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels.app = "radicale"; spec = { containers.radicale = { - image = "tomsquest/docker-radicale:3.2.0.0"; + image = "tomsquest/docker-radicale:3.2.2.0"; ports.web.containerPort = 5232; + imagePullPolicy = "Always"; volumeMounts = [ { From dff11e742b6f24ba9bc8de959ce4b8c6076550f0 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 14:00:11 +0200 Subject: [PATCH 007/108] chore(forgejo): Update to 7.0.5 --- kubenix-modules/forgejo/config.nix | 5 +- kubenix-modules/forgejo/default.nix | 88 ++++++++++++++--------------- secrets/kubernetes.yaml | 5 +- 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/kubenix-modules/forgejo/config.nix b/kubenix-modules/forgejo/config.nix index 8bebdba..7247cf2 100644 --- a/kubenix-modules/forgejo/config.nix +++ b/kubenix-modules/forgejo/config.nix @@ -7,7 +7,10 @@ "repository.pull-request".DEFAULT_MERGE_STYLE = "merge"; "repository.signing".DEFAULT_TRUST_MODEL = "committer"; ui.DEFAULT_THEME = "forgejo-light"; - oauth2.ENABLED = false; + oauth2 = { + ENABLED = false; + JWT_SECRET = "ref+sops://secrets/kubernetes.yaml#/forgejo/jwtSecret"; + }; DEFAULT = { APP_NAME = "Forgejo: Beyond coding. We forge."; diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix index 6b25875..0fca6d7 100644 --- a/kubenix-modules/forgejo/default.nix +++ b/kubenix-modules/forgejo/default.nix @@ -11,52 +11,53 @@ }; }; - deployments = { - forgejo = { - metadata.labels = { - app = "forgejo"; - component = "forgejo"; + deployments.forgejo = { + metadata.labels = { + app = "forgejo"; + component = "forgejo"; + }; + + spec = { + selector.matchLabels.app = "forgejo"; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; }; - spec = { - selector.matchLabels = { - app = "forgejo"; - component = "forgejo"; - }; + template = { + metadata.labels.app = "forgejo"; - template = { - metadata.labels = { - app = "forgejo"; - component = "forgejo"; + spec = { + containers.forgejo = { + image = "codeberg.org/forgejo/forgejo:7.0.5"; + envFrom = [{ configMapRef.name = "forgejo-env"; }]; + + ports = { + web.containerPort = 3000; + ssh.containerPort = 22; + }; + + volumeMounts = [ + { + name = "data"; + mountPath = "/data"; + } + { + name = "config"; + mountPath = "/data/gitea/conf/app.ini"; + subPath = "config"; + } + ]; }; - spec = { - containers.forgejo = { - image = "codeberg.org/forgejo/forgejo:7.0.1"; - envFrom = [{ configMapRef.name = "forgejo-env"; }]; - - ports = { - web.containerPort = 3000; - ssh.containerPort = 22; - }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/data"; - } - { - name = "config"; - mountPath = "/data/gitea/conf/app.ini"; - subPath = "config"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "forgejo"; - config.configMap.name = "forgejo-config"; - }; + volumes = { + data.persistentVolumeClaim.claimName = "forgejo"; + config.configMap.name = "forgejo-config"; }; }; }; @@ -65,10 +66,7 @@ services = { forgejo-web.spec = { - selector = { - app = "forgejo"; - component = "forgejo"; - }; + selector.app = "forgejo"; ports.web = { port = 80; diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index 21c0773..43d6d90 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -16,6 +16,7 @@ kitchenowl: forgejo: lfsJwtSecret: ENC[AES256_GCM,data:VWyUDUKZ6km0YPZLejnISBI3wkmOi26CS55NZm+eWbiymGDN9Z9xUQ4FTA==,iv:gGhNGtEEOJnsmq9GMIAImkVOPWMwYq+kDQeWoHVU860=,tag:63z/7PJKI0ePXbJ94radpw==,type:str] internalToken: ENC[AES256_GCM,data:nKLE/Ir8Ewm3GuRzUNZZTShnMMx6avxYu40PvMEti14Be0YmQhJ0IZruRdpktyW1Jj4n5ksXhk+qsO/vEIzQaJmPU1RxN6vsGGk6EBIwMP0kuUNmp25lPefafoJvxoQpXdJvkLy8f8MC,iv:dUki8hCTOF1O5fmwDqZAkaE1OCH3IL/SFPBDSJ/GMiU=,tag:HUpkVqJg53H8uEmHFqJ7+w==,type:str] + jwtSecret: ENC[AES256_GCM,data:ZIGOR53XCE1kGPQIpaY6ImbLMISbTpmC8R1oRFbjQGxHDG9dQuBigyjs5w==,iv:14WHd/RwniA7+YFGGrs+oyHx5Cc9G+D/IV9aBqn3KOI=,tag:+3LiFnV3Emx4i4efSRmthw==,type:str] attic: jwtToken: ENC[AES256_GCM,data:nAuryLY1xD9ur3qDcsJXPJPLFcPwssPKv+/BoivZ4aO6ec6rmOaYAkSRsBjgANyKhssbn0fhGsdyhMBwdHTXDnnIo67amFdxxSe+jJlGtcBXcekaOfD0Ug==,iv:h+h7CD8oI8u2ItzD/KKM16FKaG2xuVqIKh4r1TGjYtw=,tag:Er141FCK8usfzRRtrawHOw==,type:str] databaseURL: ENC[AES256_GCM,data:F2XyCgXRuebQgvkHGz8DVM2z53sC0/8GzVN6P6iJjrVxB522BJnGlw0YdFBg5K9xMWRhuzxRgDJ+ySfIb8HTtFvlF8Ifx41vFZV1zSpmDMzo4/0=,iv:wp3sg+Y9kgGH5GZZDxAE2CpzDvJeV1mH8mfHRPB17Ys=,tag:IhGRIq/qPT0vSbv/L1ODYg==,type:str] @@ -49,8 +50,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-06-16T14:30:15Z" - mac: ENC[AES256_GCM,data:dGFqNLSfoWvQ88l9ZEchJkRGmKyE0Ullactg+45t6gT9qzS9Y6crV1VOZEkfv6CabDrXWsq8cgadW9bD1z+vmpnRGdnsFIzYycw36y+ibiJ7ItCkT5KO86W8EsalzSxdy+Ac89Jp3Fv1xWzWcxKAO6jz0zluv6CrUl3kk5wTfBI=,iv:tdWY4pjE6ux5rbsYG5qTqnRDjspsIXAuWXqEnR6j4qI=,tag:Sw6fdDVKB8L1Me6Sa67O6Q==,type:str] + lastmodified: "2024-07-12T11:55:18Z" + mac: ENC[AES256_GCM,data:X2uCQfFmVkRq2OSClVlLO9zzmY/jj/B8Qo4dln93KJLRr4g2wdTQVbJWBtLDUMotlHs6b27nJc8T1wTR9/4Q1xqh92DjGeWZQmA5VbBgWuOmCB1xOE8eAFY1rVCT7e2uAFuHknxKhOS2KfOxZyGc4AJ7weXs9bLJWe5i0PSesvA=,iv:KWii9fvWUECng8Nb82nV87HR+BPIyYEfJKZHOrGPjiw=,tag:89xRQre8WahRSt1I6AweYg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 411e3b6e2d986e20f29ea213234d0c6c1e3e0bce Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 15:20:39 +0200 Subject: [PATCH 008/108] Add documentation about Media stack --- docs/media.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/media.md diff --git a/docs/media.md b/docs/media.md new file mode 100644 index 0000000..34f0fc7 --- /dev/null +++ b/docs/media.md @@ -0,0 +1,11 @@ +# Media + +[profilarr](https://github.com/Dictionarry-Hub/profilarr) was used to import the "1080p Transparent" quality profile to both Radarr and Sonarr. +Profilarr has some neat tools that magically applies custom formats and quality definitions. +As far as I understand, these are used to indentify files that are high quality. +Profilarr can then also import a quality profile, which uses the aforementioned definitions to select torrents in my desired format. +In my case, I have chosen "1080p Transparent." +According to the [docs](https://selectarr.pages.dev/): +> Projected Size: 10 - 15gb +> +> Description: Prioritizes 1080p transparent releases. Lossy audio is allowed, and all upgrades are allowed. HDR is banned. From 39dd06b97eafcce686f0191b808fc417a2e1825f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 15:53:01 +0200 Subject: [PATCH 009/108] chore(jellyseerr): Update to 1.9.2 --- kubenix-modules/media.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index f3d5e52..96016ae 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -182,6 +182,15 @@ component = "jellyseerr"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -192,9 +201,10 @@ volumes.config.persistentVolumeClaim.claimName = "jellyseerr"; containers.jellyseerr = { - image = "fallenbagel/jellyseerr:1.7.0"; + image = "fallenbagel/jellyseerr:1.9.2"; envFrom = [{ configMapRef.name = "jellyseerr-env"; }]; ports.web.containerPort = 5055; + imagePullPolicy = "Always"; volumeMounts = [{ name = "config"; From 4928a65bb1a8fa97f43f0cd064d25e466cd13d89 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 16:08:15 +0200 Subject: [PATCH 010/108] chore(jellyfin): Update to 10.9.7 chore(transmission): Pin version to 4.0.6 chore(radarr): Pin version to 5.7.0 chore(prowlarr): Pin version to 1.20.1 chore(sonarr): Pin version to 4.0.6 chore(bazarr): Pin version to 1.4.3 --- kubenix-modules/media.nix | 62 +++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index 96016ae..6aad73e 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -68,7 +68,7 @@ spec = { containers.jellyfin = { - image = "jellyfin/jellyfin:10.9.6"; + image = "jellyfin/jellyfin:10.9.7"; envFrom = [{ configMapRef.name = "jellyfin-env"; }]; ports.web.containerPort = 8096; imagePullPolicy = "Always"; @@ -128,6 +128,15 @@ component = "transmission"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -136,8 +145,9 @@ spec = { containers.transmission = { - image = "lscr.io/linuxserver/transmission:latest"; + image = "lscr.io/linuxserver/transmission:4.0.6"; envFrom = [{ configMapRef.name = "transmission-env"; }]; + imagePullPolicy = "Always"; ports = { web.containerPort = 9091; @@ -233,6 +243,15 @@ component = "radarr"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -241,9 +260,10 @@ spec = { containers.radarr = { - image = "lscr.io/linuxserver/radarr:latest"; + image = "lscr.io/linuxserver/radarr:5.7.0"; envFrom = [{ configMapRef.name = "radarr-env"; }]; ports.web.containerPort = 7878; + imagePullPolicy = "Always"; volumeMounts = [ { @@ -283,6 +303,15 @@ component = "prowlarr"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -293,9 +322,10 @@ volumes.config.persistentVolumeClaim.claimName = "prowlarr"; containers.prowlarr = { - image = "lscr.io/linuxserver/prowlarr:latest"; + image = "lscr.io/linuxserver/prowlarr:1.20.1"; envFrom = [{ configMapRef.name = "prowlarr-env"; }]; ports.web.containerPort = 9696; + imagePullPolicy = "Always"; volumeMounts = [{ name = "config"; @@ -324,6 +354,15 @@ component = "sonarr"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -332,9 +371,10 @@ spec = { containers.sonarr = { - image = "lscr.io/linuxserver/sonarr:latest"; + image = "lscr.io/linuxserver/sonarr:4.0.6"; envFrom = [{ configMapRef.name = "sonarr-env"; }]; ports.web.containerPort = 8989; + imagePullPolicy = "Always"; volumeMounts = [ { @@ -374,6 +414,15 @@ component = "bazarr"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "media"; @@ -382,9 +431,10 @@ spec = { containers.bazarr = { - image = "lscr.io/linuxserver/bazarr:latest"; + image = "lscr.io/linuxserver/bazarr:1.4.3"; envFrom = [{ configMapRef.name = "bazarr-env"; }]; ports.web.containerPort = 6767; + imagePullPolicy = "Always"; volumeMounts = [ { From 572d788c767dd44a7ad31c69f3d30c848a27efe0 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 16:44:30 +0200 Subject: [PATCH 011/108] chore(nix): Update Nix flake inputs --- flake.lock | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/flake.lock b/flake.lock index 68221e4..ba99541 100644 --- a/flake.lock +++ b/flake.lock @@ -29,11 +29,11 @@ "utils": "utils" }, "locked": { - "lastModified": 1715699772, - "narHash": "sha256-sKhqIgucN5sI/7UQgBwsonzR4fONjfMr9OcHK/vPits=", + "lastModified": 1718194053, + "narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=", "owner": "serokell", "repo": "deploy-rs", - "rev": "b3ea6f333f9057b77efd9091119ba67089399ced", + "rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a", "type": "github" }, "original": { @@ -49,11 +49,11 @@ ] }, "locked": { - "lastModified": 1717770040, - "narHash": "sha256-eq9gP060TqWqRf2k4WO5FrG49rVq5Jy3Ptusg0CFdds=", + "lastModified": 1720661479, + "narHash": "sha256-nsGgA14vVn0GGiqEfomtVgviRJCuSR3UEopfP8ixW1I=", "owner": "nix-community", "repo": "disko", - "rev": "398acc470f7c2d68621db01900f053e6000129c4", + "rev": "786965e1b1ed3fd2018d78399984f461e2a44689", "type": "github" }, "original": { @@ -70,11 +70,11 @@ ] }, "locked": { - "lastModified": 1715873341, - "narHash": "sha256-vOTcr7KXhNDvYPwGotjxcLBrrUq/Nt3sfKRtFwGdHGo=", + "lastModified": 1719459426, + "narHash": "sha256-4Kn9Pb3lvsik/VYsEAYgXpkcmLhrr0tTE6oIT2PMSPA=", "owner": "kirelagin", "repo": "dns.nix", - "rev": "9ebfa9158290de09fafcc759211e48bda48329ee", + "rev": "e6693931023206f1f3c2bfc57d2c98b5f27f52e6", "type": "github" }, "original": { @@ -361,11 +361,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1717574423, - "narHash": "sha256-cz3P5MZffAHwL2IQaNzsqUBsJS+u0J/AAwArHMAcCa0=", + "lastModified": 1720737798, + "narHash": "sha256-G/OtEAts7ZUvW5lrGMXSb8HqRp2Jr9I7reBuvCOL54w=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "d6c6cf6f5fead4057d8fb2d5f30aa8ac1727f177", + "rev": "c5013aa7ce2c7ec90acee5d965d950c8348db751", "type": "github" }, "original": { @@ -393,27 +393,27 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1717880976, - "narHash": "sha256-BRvSCsKtDUr83NEtbGfHLUOdDK0Cgbezj2PtcHnz+sQ=", + "lastModified": 1720282526, + "narHash": "sha256-dudRkHPRivMNOhd04YI+v4sWvn2SnN5ODSPIu5IVbco=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4913a7c3d8b8d00cb9476a6bd730ff57777f740c", + "rev": "550ac3e955c30fe96dd8b2223e37e0f5d225c927", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-23.11", + "ref": "release-24.05", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1717646450, - "narHash": "sha256-KE+UmfSVk5PG8jdKdclPVcMrUB8yVZHbsjo7ZT1Bm3c=", + "lastModified": 1720687749, + "narHash": "sha256-nqJ+iK/zyqCJ/YShqCpZ2cJKE1UtjZIEUWLUFZqvxcA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "818dbe2f96df233d2041739d6079bb616d3e5597", + "rev": "6af55cb91ca2005516b9562f707bb99c8f79bf77", "type": "github" }, "original": { @@ -425,11 +425,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1717555607, - "narHash": "sha256-WZ1s48OODmRJ3DHC+I/DtM3tDRuRJlNqMvxvAPTD7ec=", + "lastModified": 1720691131, + "narHash": "sha256-CWT+KN8aTPyMIx8P303gsVxUnkinIz0a/Cmasz1jyIM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0b8e7a1ae5a94da2e1ee3f3030a32020f6254105", + "rev": "a046c1202e11b62cbede5385ba64908feb7bfac4", "type": "github" }, "original": { @@ -488,11 +488,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1718137936, - "narHash": "sha256-psA+1Q5fPaK6yI3vzlLINNtb6EeXj111zQWnZYyJS9c=", + "lastModified": 1720479166, + "narHash": "sha256-jqvhLDXzTLTHq9ZviFOpcTmXXmnbLfz7mWhgMNipMN4=", "owner": "Mic92", "repo": "sops-nix", - "rev": "c279dec105dd53df13a5e57525da97905cc0f0d6", + "rev": "67035a355b1d52d2d238501f8cc1a18706979760", "type": "github" }, "original": { From b33c3a0b82d495148b33a114a1da31cf048df020 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 12 Jul 2024 16:48:17 +0200 Subject: [PATCH 012/108] chore(kubernetes): Update helm charts --- flake.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index ba99541..fcf039e 100644 --- a/flake.lock +++ b/flake.lock @@ -190,11 +190,11 @@ "systems": "systems_5" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -207,11 +207,11 @@ "systems": "systems_6" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -286,11 +286,11 @@ ] }, "locked": { - "lastModified": 1698974481, - "narHash": "sha256-yPncV9Ohdz1zPZxYHQf47S8S0VrnhV7nNhCawY46hDA=", + "lastModified": 1703863825, + "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=", "owner": "nix-community", "repo": "nix-github-actions", - "rev": "4bb5e752616262457bc7ca5882192a564c0472d2", + "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547", "type": "github" }, "original": { @@ -301,11 +301,11 @@ }, "nix-kube-generators": { "locked": { - "lastModified": 1702548734, - "narHash": "sha256-2pREm/iZ1FyyFuukt/B3nud2NYTUImy5vqc2tESoP9g=", + "lastModified": 1708155396, + "narHash": "sha256-A/BIeJjiRS7sBYP6tFJa/WHDPHe7DGTCkSEKXttYeAQ=", "owner": "farcaller", "repo": "nix-kube-generators", - "rev": "fb7a70a8cd76aa76fdf3281123582693aec486a7", + "rev": "14dbd5e5b40615937900f71d9a9851b59b4d9a88", "type": "github" }, "original": { @@ -346,11 +346,11 @@ "poetry2nix": "poetry2nix" }, "locked": { - "lastModified": 1717722458, - "narHash": "sha256-D9DSHU68yifGrrwX9VARYs3BrWk1pmjULMVW0SaXPdQ=", + "lastModified": 1720746402, + "narHash": "sha256-+dGh0ruRbwZLymQQkvK1iqgg7J6gRp4wHxa8OqsNUlU=", "owner": "farcaller", "repo": "nixhelm", - "rev": "a592d7672cfd0ee2c7dda33b8fc8fe75b6442f77", + "rev": "6fbf227d6b6b17e14a50c84ae66e9541306d4c98", "type": "github" }, "original": { @@ -451,11 +451,11 @@ "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1702365004, - "narHash": "sha256-IRFvmyP1uk1hchRVxaXTqu6YoZCvMM/NVtUf2hD2Tag=", + "lastModified": 1718285706, + "narHash": "sha256-DScsBM+kZvxOva7QegfdtleebMXh30XPxDQr/1IGKYo=", "owner": "nix-community", "repo": "poetry2nix", - "rev": "c12ac880114d52a3cad5fa02b00f2e2090e89982", + "rev": "a5be1bbbe0af0266147a88e0ec43b18c722f2bb9", "type": "github" }, "original": { @@ -634,11 +634,11 @@ ] }, "locked": { - "lastModified": 1699786194, - "narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=", + "lastModified": 1717850719, + "narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1", + "rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed", "type": "github" }, "original": { From ada288674a622304dfe4c467e91afb50a0cde7cd Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 13 Jul 2024 20:18:17 +0200 Subject: [PATCH 013/108] feat(kubernetes): Deploy Cyberchef using applyset --- flake-parts/kubenix-deploy.sh | 7 ++++ flake-parts/kubenix.nix | 55 +++++++++++++++++++++++++++-- kubenix-modules/all.nix | 6 ++-- kubenix-modules/base.nix | 20 ++++++----- kubenix-modules/custom/default.nix | 7 ++++ kubenix-modules/cyberchef.nix | 56 ++++++++++++++++++------------ 6 files changed, 112 insertions(+), 39 deletions(-) create mode 100755 flake-parts/kubenix-deploy.sh create mode 100644 kubenix-modules/custom/default.nix diff --git a/flake-parts/kubenix-deploy.sh b/flake-parts/kubenix-deploy.sh new file mode 100755 index 0000000..d6cf7b9 --- /dev/null +++ b/flake-parts/kubenix-deploy.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + +export KUBECTL_APPLYSET=true +vals eval -fail-on-missing-key-in-map <$MANIFEST | kubectl apply -f - --prune --applyset $APPLYSET --namespace $NAMESPACE diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index d3774a3..8cbc485 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -1,4 +1,4 @@ -{ self, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem +{ self, pkgs, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem (system: let mkKubenixPackage = module: kubenix.packages.${system}.default.override @@ -6,8 +6,57 @@ specialArgs = { inherit myLib kubenix nixhelm system dns blog-pim machines; }; module = { imports = [ module ]; }; }; + + deployScript = (pkgs.writeScriptBin "kubenix" (builtins.readFile ./kubenix-deploy.sh)).overrideAttrs (old: { + buildCommand = "${old.buildCommand}\npatchShebangs $out"; + }); + + mkDeployScript = kubernetes: applyset: namespace: + let + kubeconfig = kubernetes.kubeconfig or ""; + result = kubernetes.result or ""; + + wrappedDeployScript = pkgs.symlinkJoin + { + name = "kubenix"; + paths = [ deployScript pkgs.vals pkgs.kubectl ]; + buildInputs = [ pkgs.makeWrapper ]; + passthru.manifest = result; + + postBuild = '' + wrapProgram $out/bin/kubenix \ + --suffix PATH : "$out/bin" \ + --run 'export KUBECONFIG=''${KUBECONFIG:-${toString kubeconfig}}' \ + --set MANIFEST '${result}' \ + --set APPLYSET '${applyset}' \ + --set NAMESPACE '${namespace}' + ''; + }; + in + wrappedDeployScript; + + mkDeployScriptAndManifest = module: applyset: namespace: + let + kubernetes = (kubenix.evalModules.${system} { + module = { kubenix, ... }: + { + imports = [ + kubenix.modules.k8s + "${self}/kubenix-modules/custom" + module + ]; + }; + }).config.kubernetes; + in + { + manifest = kubernetes.result; + deploy = mkDeployScript kubernetes applyset namespace; + }; in { - kubenix = mkKubenixPackage "${self}/kubenix-modules/all.nix"; - kubenix-bootstrap = mkKubenixPackage "${self}/kubenix-modules/base.nix"; + kubenix.all.deploy = mkKubenixPackage "${self}/kubenix-modules/all.nix"; + kubenix.bootstrap.deploy = mkKubenixPackage "${self}/kubenix-modules/base.nix"; + + kubenix.cyberchef = mkDeployScriptAndManifest + "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "cyberchef"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index eb470c4..98a05a4 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,7 +1,7 @@ let applications = [ ./freshrss.nix - ./cyberchef.nix + # ./cyberchef.nix ./kms.nix ./inbucket.nix ./radicale.nix @@ -31,9 +31,7 @@ in ./ek2024.nix ./metallb.nix ./cert-manager.nix - ./custom/ingress.nix - ./custom/nfs-volume.nix - ./custom/longhorn-volume.nix + ./custom ./traefik.nix ./volumes.nix ./custom-types.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 018f126..7f422f4 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -59,15 +59,17 @@ }; }; - resources.nodes = - let - machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; - in - builtins.mapAttrs - (name: machine: { - metadata.labels = machine.kubernetesNodeLabels; - }) - machinesWithKubernetesLabels; + resources = { + nodes = + let + machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; + in + builtins.mapAttrs + (name: machine: { + metadata.labels = machine.kubernetesNodeLabels; + }) + machinesWithKubernetesLabels; + }; }; }; } diff --git a/kubenix-modules/custom/default.nix b/kubenix-modules/custom/default.nix new file mode 100644 index 0000000..d21b916 --- /dev/null +++ b/kubenix-modules/custom/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./ingress.nix + ./longhorn-volume.nix + ./nfs-volume.nix + ]; +} diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 19c2578..2e25d32 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,35 +1,45 @@ { - kubernetes.resources = { - deployments.cyberchef.spec = { - replicas = 3; - selector.matchLabels.app = "cyberchef"; + config = { + kubenix.project = "cyberchef"; - template = { - metadata.labels.app = "cyberchef"; + kubernetes = { + namespace = "cyberchef"; - spec.containers.cyberchef = { - image = "mpepping/cyberchef"; - ports.web.containerPort = 8000; + resources = { + namespaces.cyberchef = { }; + + deployments.cyberchef.spec = { + replicas = 3; + selector.matchLabels.app = "cyberchef"; + + template = { + metadata.labels.app = "cyberchef"; + + spec.containers.cyberchef = { + image = "mpepping/cyberchef"; + ports.web.containerPort = 8000; + }; + }; + }; + + services.cyberchef.spec = { + selector.app = "cyberchef"; + + ports.web = { + port = 80; + targetPort = "web"; + }; }; }; }; - services.cyberchef.spec = { - selector.app = "cyberchef"; + lab.ingresses.cyberchef = { + host = "cyberchef.kun.is"; - ports.web = { - port = 80; - targetPort = "web"; + service = { + name = "cyberchef"; + portName = "web"; }; }; }; - - lab.ingresses.cyberchef = { - host = "cyberchef.kun.is"; - - service = { - name = "cyberchef"; - portName = "web"; - }; - }; } From 07bd2e1e0179e2e22ffec7f6869a85369cf4e5b3 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 11:47:46 +0200 Subject: [PATCH 014/108] feat(freshrss): Move to its own namespace feat(longhorn): Add ability to specify PVC namespace refactor(freshrss): Simplify env variable declaration --- flake-parts/kubenix.nix | 11 ++++- kubenix-modules/all.nix | 2 +- kubenix-modules/base.nix | 5 ++ kubenix-modules/custom/longhorn-volume.nix | 7 ++- kubenix-modules/cyberchef.nix | 56 +++++++++------------- kubenix-modules/freshrss.nix | 23 +++++---- kubenix-modules/volumes.nix | 8 ++-- 7 files changed, 62 insertions(+), 50 deletions(-) diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 8cbc485..bbd2ace 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -28,7 +28,7 @@ --suffix PATH : "$out/bin" \ --run 'export KUBECONFIG=''${KUBECONFIG:-${toString kubeconfig}}' \ --set MANIFEST '${result}' \ - --set APPLYSET '${applyset}' \ + --set APPLYSET 'applyset-${applyset}' \ --set NAMESPACE '${namespace}' ''; }; @@ -38,6 +38,8 @@ mkDeployScriptAndManifest = module: applyset: namespace: let kubernetes = (kubenix.evalModules.${system} { + specialArgs = { inherit namespace; }; + module = { kubenix, ... }: { imports = [ @@ -45,6 +47,11 @@ "${self}/kubenix-modules/custom" module ]; + + config = { + kubenix.project = applyset; + kubernetes.namespace = namespace; + }; }; }).config.kubernetes; in @@ -59,4 +66,6 @@ kubenix.cyberchef = mkDeployScriptAndManifest "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "cyberchef"; + kubenix.freshrss = mkDeployScriptAndManifest + "${self}/kubenix-modules/freshrss.nix" "freshrss" "freshrss"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 98a05a4..ddf15ed 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,6 +1,6 @@ let applications = [ - ./freshrss.nix + # ./freshrss.nix # ./cyberchef.nix ./kms.nix ./inbucket.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 7f422f4..4ba88ef 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -60,6 +60,11 @@ }; resources = { + namespaces = { + cyberchef = { }; + freshrss = { }; + }; + nodes = let machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; diff --git a/kubenix-modules/custom/longhorn-volume.nix b/kubenix-modules/custom/longhorn-volume.nix index 8f3cb76..e261cab 100644 --- a/kubenix-modules/custom/longhorn-volume.nix +++ b/kubenix-modules/custom/longhorn-volume.nix @@ -5,6 +5,11 @@ let storage = lib.mkOption { type = lib.types.str; }; + + namespace = lib.mkOption { + type = lib.types.str; + default = "default"; + }; }; }; in @@ -28,7 +33,7 @@ in claimRef = { inherit name; - namespace = "default"; + namespace = longhornVolume.namespace; }; csi = { diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 2e25d32..19c2578 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,45 +1,35 @@ { - config = { - kubenix.project = "cyberchef"; + kubernetes.resources = { + deployments.cyberchef.spec = { + replicas = 3; + selector.matchLabels.app = "cyberchef"; - kubernetes = { - namespace = "cyberchef"; + template = { + metadata.labels.app = "cyberchef"; - resources = { - namespaces.cyberchef = { }; - - deployments.cyberchef.spec = { - replicas = 3; - selector.matchLabels.app = "cyberchef"; - - template = { - metadata.labels.app = "cyberchef"; - - spec.containers.cyberchef = { - image = "mpepping/cyberchef"; - ports.web.containerPort = 8000; - }; - }; - }; - - services.cyberchef.spec = { - selector.app = "cyberchef"; - - ports.web = { - port = 80; - targetPort = "web"; - }; + spec.containers.cyberchef = { + image = "mpepping/cyberchef"; + ports.web.containerPort = 8000; }; }; }; - lab.ingresses.cyberchef = { - host = "cyberchef.kun.is"; + services.cyberchef.spec = { + selector.app = "cyberchef"; - service = { - name = "cyberchef"; - portName = "web"; + ports.web = { + port = 80; + targetPort = "web"; }; }; }; + + lab.ingresses.cyberchef = { + host = "cyberchef.kun.is"; + + service = { + name = "cyberchef"; + portName = "web"; + }; + }; } diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 6567b36..0f62a40 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -1,12 +1,5 @@ -{ +{ namespace, ... }: { kubernetes.resources = { - configMaps.freshrss.data = { - TZ = "Europe/Amsterdam"; - CRON_MIN = "2,32"; - ADMIN_EMAIL = "pim@kunis.nl"; - PUBLISHED_PORT = "443"; - }; - secrets.freshrss.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; deployments.freshrss = { @@ -31,10 +24,14 @@ containers.freshrss = { image = "freshrss/freshrss:1.24.1"; imagePullPolicy = "Always"; - envFrom = [{ configMapRef.name = "freshrss"; }]; ports.web.containerPort = 80; env = { + TZ.value = "Europe/Amsterdam"; + CRON_MIN.value = "2,32"; + ADMIN_EMAIL.value = "pim@kunis.nl"; + PUBLISHED_PORT.value = "443"; + ADMIN_PASSWORD.valueFrom.secretKeyRef = { name = "freshrss"; key = "adminPassword"; @@ -82,5 +79,13 @@ portName = "web"; }; }; + + # TODO: Maybe we should revisit this architecture? + # The PVs are cluster-wide and should probably be defined elsewhere. + # Then the PVC should reference the PV probably. + longhornVolumes.freshrss = { + storage = "1Gi"; + inherit namespace; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index f4592e7..ecd3d09 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -5,20 +5,18 @@ # volumeMounts = [ - # { name = "atuin"; mountPath = "/atuin"; } - # { name = "atuin-db"; mountPath = "/atuin-db"; } + # { name = "freshrss"; mountPath = "/freshrss"; } # ]; # }; - # volumes.atuin.persistentVolumeClaim.claimName = "atuin"; - # volumes.atuin-db.persistentVolumeClaim.claimName = "atuin-db"; + # volumes.freshrss.persistentVolumeClaim.claimName = "freshrss"; # }; lab = { longhornVolumes = { hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; - freshrss.storage = "1Gi"; + # freshrss.storage = "1Gi"; radicale.storage = "200Mi"; minecraft.storage = "1Gi"; nextcloud.storage = "50Gi"; From e724ff94a9ece83ffc4e5067cc31621462cac76c Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 12:25:20 +0200 Subject: [PATCH 015/108] feat(longhorn): Reference PV from PVC refactor(freshrss): Rename k8s resources --- kubenix-modules/custom/longhorn-volume.nix | 152 +++++++++++++++------ kubenix-modules/freshrss.nix | 25 ++-- kubenix-modules/volumes.nix | 5 +- 3 files changed, 129 insertions(+), 53 deletions(-) diff --git a/kubenix-modules/custom/longhorn-volume.nix b/kubenix-modules/custom/longhorn-volume.nix index e261cab..868e16f 100644 --- a/kubenix-modules/custom/longhorn-volume.nix +++ b/kubenix-modules/custom/longhorn-volume.nix @@ -12,6 +12,28 @@ let }; }; }; + + longhornPVOpts = { name, ... }: { + options = { + storage = lib.mkOption { + type = lib.types.str; + }; + }; + }; + + longhornPVCOpts = { name, ... }: { + options = { + volumeName = lib.mkOption { + type = lib.types.str; + default = name; + }; + + # TODO: ideally we take this from the longhornPV so we don't duplicate this information. + storage = lib.mkOption { + type = lib.types.str; + }; + }; + }; in { options = { @@ -19,55 +41,109 @@ in type = with lib.types; attrsOf (submodule longhornVolumeOpts); default = { }; }; + + lab.longhorn = { + persistentVolume = lib.mkOption { + type = with lib.types; attrsOf (submodule longhornPVOpts); + default = { }; + }; + + persistentVolumeClaim = lib.mkOption { + type = with lib.types; attrsOf (submodule longhornPVCOpts); + default = { }; + }; + }; }; config = { kubernetes.resources = { - persistentVolumes = builtins.mapAttrs - (name: longhornVolume: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - capacity.storage = longhornVolume.storage; - persistentVolumeReclaimPolicy = "Delete"; - volumeMode = "Filesystem"; + persistentVolumes = lib.mergeAttrs + (builtins.mapAttrs + (name: longhornVolume: { + spec = { + accessModes = [ "ReadWriteOnce" ]; + capacity.storage = longhornVolume.storage; + persistentVolumeReclaimPolicy = "Delete"; + volumeMode = "Filesystem"; - claimRef = { - inherit name; - namespace = longhornVolume.namespace; - }; + claimRef = { + inherit name; + namespace = longhornVolume.namespace; + }; - csi = { - driver = "driver.longhorn.io"; - fsType = "ext4"; - volumeHandle = name; - - volumeAttributes = { - dataLocality = "disabled"; - fromBackup = ""; + csi = { + driver = "driver.longhorn.io"; fsType = "ext4"; - numberOfReplicas = "2"; - staleReplicaTimeout = "30"; - unmapMarkSnapChainRemoved = "ignored"; + volumeHandle = name; - recurringJobSelector = lib.generators.toYAML { } [{ - name = "backup-nfs"; - isGroup = false; - }]; + volumeAttributes = { + dataLocality = "disabled"; + fromBackup = ""; + fsType = "ext4"; + numberOfReplicas = "2"; + staleReplicaTimeout = "30"; + unmapMarkSnapChainRemoved = "ignored"; + + recurringJobSelector = lib.generators.toYAML { } [{ + name = "backup-nfs"; + isGroup = false; + }]; + }; }; }; - }; - }) - config.lab.longhornVolumes; + }) + config.lab.longhornVolumes) + (builtins.mapAttrs + (name: longhornPV: { + spec = { + accessModes = [ "ReadWriteOnce" ]; + capacity.storage = longhornPV.storage; + persistentVolumeReclaimPolicy = "Delete"; + volumeMode = "Filesystem"; - persistentVolumeClaims = builtins.mapAttrs - (name: longhornVolume: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = longhornVolume.storage; - storageClassName = ""; - }; - }) - config.lab.longhornVolumes; + csi = { + driver = "driver.longhorn.io"; + fsType = "ext4"; + volumeHandle = name; + + volumeAttributes = { + dataLocality = "disabled"; + fromBackup = ""; + fsType = "ext4"; + numberOfReplicas = "2"; + staleReplicaTimeout = "30"; + unmapMarkSnapChainRemoved = "ignored"; + + recurringJobSelector = lib.generators.toYAML { } [{ + name = "backup-nfs"; + isGroup = false; + }]; + }; + }; + }; + }) + config.lab.longhorn.persistentVolume); + + persistentVolumeClaims = lib.mergeAttrs + (builtins.mapAttrs + (name: longhornVolume: { + spec = { + accessModes = [ "ReadWriteOnce" ]; + resources.requests.storage = longhornVolume.storage; + storageClassName = ""; + }; + }) + config.lab.longhornVolumes) + (builtins.mapAttrs + (name: longhornPVC: { + spec = { + accessModes = [ "ReadWriteOnce" ]; + resources.requests.storage = longhornPVC.storage; + storageClassName = ""; + volumeName = longhornPVC.volumeName; + }; + }) + config.lab.longhorn.persistentVolumeClaim); }; }; } diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 0f62a40..200b46c 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -1,8 +1,8 @@ -{ namespace, ... }: { +{ kubernetes.resources = { - secrets.freshrss.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; + secrets.server.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; - deployments.freshrss = { + deployments.server = { metadata.labels.app = "freshrss"; spec = { @@ -33,12 +33,12 @@ PUBLISHED_PORT.value = "443"; ADMIN_PASSWORD.valueFrom.secretKeyRef = { - name = "freshrss"; + name = "server"; key = "adminPassword"; }; ADMIN_API_PASSWORD.valueFrom.secretKeyRef = { - name = "freshrss"; + name = "server"; key = "adminPassword"; }; }; @@ -49,7 +49,7 @@ }]; }; - volumes.data.persistentVolumeClaim.claimName = "freshrss"; + volumes.data.persistentVolumeClaim.claimName = "data"; securityContext = { fsGroup = 33; @@ -60,7 +60,7 @@ }; }; - services.freshrss.spec = { + services.web.spec = { selector.app = "freshrss"; ports.web = { @@ -71,21 +71,18 @@ }; lab = { - ingresses.freshrss = { + ingresses.web = { host = "rss.kun.is"; service = { - name = "freshrss"; + name = "web"; portName = "web"; }; }; - # TODO: Maybe we should revisit this architecture? - # The PVs are cluster-wide and should probably be defined elsewhere. - # Then the PVC should reference the PV probably. - longhornVolumes.freshrss = { + longhorn.persistentVolumeClaim.data = { + volumeName = "freshrss"; storage = "1Gi"; - inherit namespace; }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index ecd3d09..f279db7 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -16,7 +16,6 @@ longhornVolumes = { hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; - # freshrss.storage = "1Gi"; radicale.storage = "200Mi"; minecraft.storage = "1Gi"; nextcloud.storage = "50Gi"; @@ -44,6 +43,10 @@ immich-db.storage = "5Gi"; }; + longhorn.persistentVolume = { + freshrss.storage = "1Gi"; + }; + nfsVolumes = { media.path = "media"; music.path = "media/music"; From cf804ac260ec4113011ad4758ce2bb488f628415 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 12:29:36 +0200 Subject: [PATCH 016/108] refactor(cyberchef): Rename k8s resources refactor(freshrss): Remove useless deployment label --- kubenix-modules/cyberchef.nix | 8 ++-- kubenix-modules/freshrss.nix | 80 +++++++++++++++++------------------ 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 19c2578..94301c8 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,6 +1,6 @@ { kubernetes.resources = { - deployments.cyberchef.spec = { + deployments.server.spec = { replicas = 3; selector.matchLabels.app = "cyberchef"; @@ -14,7 +14,7 @@ }; }; - services.cyberchef.spec = { + services.server.spec = { selector.app = "cyberchef"; ports.web = { @@ -24,11 +24,11 @@ }; }; - lab.ingresses.cyberchef = { + lab.ingresses.server = { host = "cyberchef.kun.is"; service = { - name = "cyberchef"; + name = "server"; portName = "web"; }; }; diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 200b46c..c186cf5 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -2,65 +2,61 @@ kubernetes.resources = { secrets.server.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; - deployments.server = { - metadata.labels.app = "freshrss"; + deployments.server.spec = { + selector.matchLabels.app = "freshrss"; - spec = { - selector.matchLabels.app = "freshrss"; + strategy = { + type = "RollingUpdate"; - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; }; + }; - template = { - metadata.labels.app = "freshrss"; + template = { + metadata.labels.app = "freshrss"; - spec = { - containers.freshrss = { - image = "freshrss/freshrss:1.24.1"; - imagePullPolicy = "Always"; - ports.web.containerPort = 80; + spec = { + containers.freshrss = { + image = "freshrss/freshrss:1.24.1"; + imagePullPolicy = "Always"; + ports.web.containerPort = 80; - env = { - TZ.value = "Europe/Amsterdam"; - CRON_MIN.value = "2,32"; - ADMIN_EMAIL.value = "pim@kunis.nl"; - PUBLISHED_PORT.value = "443"; + env = { + TZ.value = "Europe/Amsterdam"; + CRON_MIN.value = "2,32"; + ADMIN_EMAIL.value = "pim@kunis.nl"; + PUBLISHED_PORT.value = "443"; - ADMIN_PASSWORD.valueFrom.secretKeyRef = { - name = "server"; - key = "adminPassword"; - }; - - ADMIN_API_PASSWORD.valueFrom.secretKeyRef = { - name = "server"; - key = "adminPassword"; - }; + ADMIN_PASSWORD.valueFrom.secretKeyRef = { + name = "server"; + key = "adminPassword"; }; - volumeMounts = [{ - name = "data"; - mountPath = "/var/www/FreshRSS/data"; - }]; + ADMIN_API_PASSWORD.valueFrom.secretKeyRef = { + name = "server"; + key = "adminPassword"; + }; }; - volumes.data.persistentVolumeClaim.claimName = "data"; + volumeMounts = [{ + name = "data"; + mountPath = "/var/www/FreshRSS/data"; + }]; + }; - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumes.data.persistentVolumeClaim.claimName = "data"; + + securityContext = { + fsGroup = 33; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - services.web.spec = { + services.server.spec = { selector.app = "freshrss"; ports.web = { From eeef91333b10c8ff12c53f09e6e8fe5ff1da0f30 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 13:31:18 +0200 Subject: [PATCH 017/108] docs(readme): Update deployment instructions docs(readme): Fix commands for ZSH --- README.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 72bde6c..fc3d3f3 100644 --- a/README.md +++ b/README.md @@ -30,22 +30,32 @@ Additionally, it deploys an age identity, which is later used for decrypting sec 1. Make sure your have a [Secret service](https://www.gnu.org/software/emacs/manual/html_node/auth/Secret-Service-API.html) running (such as Keepassxc) that provides the age identity. 2. Ensure you have root SSH access to the server. -3. Run nixos-anywhere: `nix run .#bootstrap ` +3. Run nixos-anywhere: `nix run '.#bootstrap' ` ### Deployment -To deploy all servers at once: `nix run nixpkgs#deploy-rs -- .# -k` -To deploy only one server: `nix run nixpkgs#deploy-rs -- -k --targets .#` +To deploy all servers at once: `nix run 'nixpkgs#deploy-rs' -- '.#' -k` +To deploy only one server: `nix run 'nixpkgs#deploy-rs' -- -k --targets '.#'` ## Deploying to Kubernetes To deploy to the Kubernetes cluster, first make sure you have an admin account on the cluster. -You can generate this using `nix run .#gen-k3s-cert ~/.kube`, assuming you have SSH access to the master node. +You can generate this using `nix run '.#gen-k3s-cert' ~/.kube`, assuming you have SSH access to the master node. This puts a private key, signed certificate and a kubeconfig in the kubeconfig directory -If the cluster has not been initialized yet, next run `nix run .#kubenix-bootstrap.x86_64-linux`. +If the cluster has not been initialized yet, next run `nix run '.#kubenix.x86_64-linux.bootstrap.deploy'`. -Lastly, deploy everything to the cluster using `nix run .#kubenix.x86_64-linux`. +Applications are currently deployed in two method: + - A single big deployment of many applications (which I am trying to move away from) + - A separate deployment for each application using [ApplySets](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-delete-objects) + +The first method: `nix run '.#kubenix.x86_64-linux.all.deploy'` +The second method: `nix run '.#kubenix.x86_64-linux..deploy'` +Currently, the applications being deployed like this are: +- `cyberchef` +- `freshrss` + +Lastly, deploy everything to the cluster using `nix run '.#kubenix.x86_64-linux'`. ## Known bugs From 6dc3bef386c58ed7bee4ad638cdb02f51f3276e3 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 13:32:45 +0200 Subject: [PATCH 018/108] docs(readme): Fix deployment instructions --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index fc3d3f3..88c4fe8 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,6 @@ Currently, the applications being deployed like this are: - `cyberchef` - `freshrss` -Lastly, deploy everything to the cluster using `nix run '.#kubenix.x86_64-linux'`. - ## Known bugs ### Rsync not available during bootstrap From 3223347964cc27b473a1f55fe690dbaa98cacc66 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 13:48:17 +0200 Subject: [PATCH 019/108] feat(radicale): Move to separate k8s namespace fix(freshrss): Use correct service name --- flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 3 -- kubenix-modules/base.nix | 1 + kubenix-modules/freshrss.nix | 2 +- kubenix-modules/radicale.nix | 95 ++++++++++++++++++------------------ kubenix-modules/volumes.nix | 2 +- 6 files changed, 53 insertions(+), 52 deletions(-) diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index bbd2ace..cfecd91 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -68,4 +68,6 @@ "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "cyberchef"; kubenix.freshrss = mkDeployScriptAndManifest "${self}/kubenix-modules/freshrss.nix" "freshrss" "freshrss"; + kubenix.radicale = mkDeployScriptAndManifest + "${self}/kubenix-modules/radicale.nix" "radicale" "radicale"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index ddf15ed..0b4ad20 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,10 +1,7 @@ let applications = [ - # ./freshrss.nix - # ./cyberchef.nix ./kms.nix ./inbucket.nix - ./radicale.nix ./syncthing.nix ./nextcloud.nix ./pihole.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 4ba88ef..e6595b2 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -63,6 +63,7 @@ namespaces = { cyberchef = { }; freshrss = { }; + radicale = { }; }; nodes = diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index c186cf5..0da1ce0 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -71,7 +71,7 @@ host = "rss.kun.is"; service = { - name = "web"; + name = "server"; portName = "web"; }; }; diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix index 171714a..ab2301d 100644 --- a/kubenix-modules/radicale.nix +++ b/kubenix-modules/radicale.nix @@ -1,6 +1,6 @@ { lib, ... }: { kubernetes.resources = { - configMaps.radicale.data = { + configMaps.server.data = { users = "pim:$apr1$GUiTihkS$dDCkaUxFx/O86m6NCy/yQ."; config = lib.generators.toINI { } { @@ -33,63 +33,59 @@ }; }; - deployments.radicale = { - metadata.labels.app = "radicale"; + deployments.server.spec = { + selector.matchLabels.app = "radicale"; - spec = { - selector.matchLabels.app = "radicale"; + strategy = { + type = "RollingUpdate"; - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; }; + }; - template = { - metadata.labels.app = "radicale"; + template = { + metadata.labels.app = "radicale"; - spec = { - containers.radicale = { - image = "tomsquest/docker-radicale:3.2.2.0"; - ports.web.containerPort = 5232; - imagePullPolicy = "Always"; + spec = { + containers.radicale = { + image = "tomsquest/docker-radicale:3.2.2.0"; + ports.web.containerPort = 5232; + imagePullPolicy = "Always"; - volumeMounts = [ - { - name = "data"; - mountPath = "/data"; - } - { - name = "config"; - mountPath = "/config/config"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/config/users"; - subPath = "users"; - } - ]; - }; + volumeMounts = [ + { + name = "data"; + mountPath = "/data"; + } + { + name = "config"; + mountPath = "/config/config"; + subPath = "config"; + } + { + name = "config"; + mountPath = "/config/users"; + subPath = "users"; + } + ]; + }; - volumes = { - data.persistentVolumeClaim.claimName = "radicale"; - config.configMap.name = "radicale"; - }; + volumes = { + data.persistentVolumeClaim.claimName = "data"; + config.configMap.name = "server"; + }; - securityContext = { - fsGroup = 2999; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 2999; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - services.radicale.spec = { + services.server.spec = { selector.app = "radicale"; ports.web = { @@ -100,13 +96,18 @@ }; lab = { - ingresses.radicale = { + ingresses.web = { host = "dav.kun.is"; service = { - name = "radicale"; + name = "server"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim.data = { + volumeName = "radicale"; + storage = "200Mi"; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index f279db7..7ff68f0 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -16,7 +16,6 @@ longhornVolumes = { hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; - radicale.storage = "200Mi"; minecraft.storage = "1Gi"; nextcloud.storage = "50Gi"; nextcloud-db.storage = "400Mi"; @@ -45,6 +44,7 @@ longhorn.persistentVolume = { freshrss.storage = "1Gi"; + radicale.storage = "200Mi"; }; nfsVolumes = { From e4b7b69bbb74c673242dd4da8bfef506e146c8f3 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 13:58:08 +0200 Subject: [PATCH 020/108] feat(kms): Move to separate namespace --- README.md | 2 ++ flake-parts/kubenix.nix | 4 +++- kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/kms.nix | 20 ++++++++------------ 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 88c4fe8..e6264ae 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ The second method: `nix run '.#kubenix.x86_64-linux..deploy'` Currently, the applications being deployed like this are: - `cyberchef` - `freshrss` +- `radicale` +- `kms` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index cfecd91..2e47c61 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -38,7 +38,7 @@ mkDeployScriptAndManifest = module: applyset: namespace: let kubernetes = (kubenix.evalModules.${system} { - specialArgs = { inherit namespace; }; + specialArgs = { inherit namespace myLib; }; module = { kubenix, ... }: { @@ -70,4 +70,6 @@ "${self}/kubenix-modules/freshrss.nix" "freshrss" "freshrss"; kubenix.radicale = mkDeployScriptAndManifest "${self}/kubenix-modules/radicale.nix" "radicale" "radicale"; + kubenix.kms = mkDeployScriptAndManifest + "${self}/kubenix-modules/kms.nix" "kms" "kms"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 0b4ad20..5b99c5d 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,6 +1,5 @@ let applications = [ - ./kms.nix ./inbucket.nix ./syncthing.nix ./nextcloud.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index e6595b2..b44bbf7 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -64,6 +64,7 @@ cyberchef = { }; freshrss = { }; radicale = { }; + kms = { }; }; nodes = diff --git a/kubenix-modules/kms.nix b/kubenix-modules/kms.nix index 48169c8..151c8df 100644 --- a/kubenix-modules/kms.nix +++ b/kubenix-modules/kms.nix @@ -1,23 +1,19 @@ { myLib, ... }: { kubernetes.resources = { - deployments.kms = { - metadata.labels.app = "kms"; + deployments.server.spec = { + selector.matchLabels.app = "kms"; - spec = { - selector.matchLabels.app = "kms"; + template = { + metadata.labels.app = "kms"; - template = { - metadata.labels.app = "kms"; - - spec.containers.kms = { - image = "teddysun/kms"; - ports.kms.containerPort = 1688; - }; + spec.containers.kms = { + image = "teddysun/kms"; + ports.kms.containerPort = 1688; }; }; }; - services.kms.spec = { + services.server.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.kmsIPv4; selector.app = "kms"; From 3fcbbfa8c28bca82bde152ee9709570bcf9afea2 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 14:14:08 +0200 Subject: [PATCH 021/108] feat(atuin): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/atuin.nix | 134 +++++++++++++++++++----------------- kubenix-modules/base.nix | 1 + kubenix-modules/volumes.nix | 4 +- 6 files changed, 78 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index e6264ae..fcf617c 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Currently, the applications being deployed like this are: - `freshrss` - `radicale` - `kms` +- `atuin` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 2e47c61..470fbb7 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -72,4 +72,6 @@ "${self}/kubenix-modules/radicale.nix" "radicale" "radicale"; kubenix.kms = mkDeployScriptAndManifest "${self}/kubenix-modules/kms.nix" "kms" "kms"; + kubenix.atuin = mkDeployScriptAndManifest + "${self}/kubenix-modules/atuin.nix" "atuin" "atuin"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 5b99c5d..67a3363 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -13,7 +13,6 @@ let ./dnsmasq.nix ./blog.nix ./attic.nix - ./atuin.nix ./immich.nix # ./argo.nix # ./minecraft.nix diff --git a/kubenix-modules/atuin.nix b/kubenix-modules/atuin.nix index ccbaea8..cea3eb6 100644 --- a/kubenix-modules/atuin.nix +++ b/kubenix-modules/atuin.nix @@ -1,84 +1,80 @@ { kubernetes.resources = { - secrets.atuin.stringData = { + secrets.database.stringData = { databasePassword = "ref+sops://secrets/kubernetes.yaml#/atuin/databasePassword"; databaseURL = "ref+sops://secrets/kubernetes.yaml#/atuin/databaseURL"; }; - deployments.atuin = { - metadata.labels.app = "atuin"; + deployments.server.spec = { + selector.matchLabels.app = "atuin"; - spec = { - selector.matchLabels.app = "atuin"; + strategy = { + type = "RollingUpdate"; - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; }; + }; - template = { - metadata.labels.app = "atuin"; + template = { + metadata.labels.app = "atuin"; - spec = { - volumes = { - data.persistentVolumeClaim.claimName = "atuin"; - db.persistentVolumeClaim.claimName = "atuin-db"; + spec = { + volumes = { + data.persistentVolumeClaim.claimName = "data"; + database.persistentVolumeClaim.claimName = "database"; + }; + + containers = { + atuin = { + image = "ghcr.io/atuinsh/atuin:18.3.0"; + imagePullPolicy = "Always"; + ports.web.containerPort = 8888; + args = [ "server" "start" ]; + + env = { + ATUIN_HOST.value = "0.0.0.0"; + ATUIN_PORT.value = "8888"; + ATUIN_OPEN_REGISTRATION.value = "false"; + + ATUIN_DB_URI.valueFrom.secretKeyRef = { + name = "database"; + key = "databaseURL"; + }; + }; + + volumeMounts = [{ + name = "data"; + mountPath = "/config"; + }]; }; - containers = { - atuin = { - image = "ghcr.io/atuinsh/atuin:18.3.0"; - imagePullPolicy = "Always"; - ports.web.containerPort = 8888; - args = [ "server" "start" ]; + database = { + image = "postgres:14"; + ports.web.containerPort = 5432; - env = { - ATUIN_HOST.value = "0.0.0.0"; - ATUIN_PORT.value = "8888"; - ATUIN_OPEN_REGISTRATION.value = "false"; + env = { + POSTGRES_DB.value = "atuin"; + POSTGRES_USER.value = "atuin"; - ATUIN_DB_URI.valueFrom.secretKeyRef = { - name = "atuin"; - key = "databaseURL"; - }; + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "database"; + key = "databasePassword"; }; - - volumeMounts = [{ - name = "data"; - mountPath = "/config"; - }]; }; - database = { - image = "postgres:14"; - ports.web.containerPort = 5432; - - env = { - POSTGRES_DB.value = "atuin"; - POSTGRES_USER.value = "atuin"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "atuin"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "db"; - mountPath = "/var/lib/postgresql/data"; - }]; - }; + volumeMounts = [{ + name = "database"; + mountPath = "/var/lib/postgresql/data"; + }]; }; }; }; }; }; - services.atuin.spec = { + services.server.spec = { selector.app = "atuin"; ports.web = { @@ -88,12 +84,26 @@ }; }; - lab.ingresses.atuin = { - host = "atuin.kun.is"; + lab = { + ingresses.server = { + host = "atuin.kun.is"; - service = { - name = "atuin"; - portName = "web"; + service = { + name = "server"; + portName = "web"; + }; + }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "atuin"; + storage = "300Mi"; + }; + + database = { + volumeName = "atuin-db"; + storage = "300Mi"; + }; }; }; } diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index b44bbf7..a94ef8a 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -65,6 +65,7 @@ freshrss = { }; radicale = { }; kms = { }; + atuin = { }; }; nodes = diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 7ff68f0..cae1e1a 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -36,8 +36,6 @@ bazarr.storage = "25Mi"; attic.storage = "15Gi"; attic-db.storage = "150Mi"; - atuin.storage = "300Mi"; - atuin-db.storage = "300Mi"; immich.storage = "50Gi"; immich-db.storage = "5Gi"; }; @@ -45,6 +43,8 @@ longhorn.persistentVolume = { freshrss.storage = "1Gi"; radicale.storage = "200Mi"; + atuin.storage = "300Mi"; + atuin-db.storage = "300Mi"; }; nfsVolumes = { From 0d2b2b90f7eb83ecf03614b0ed501d97e7a7bd89 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 15:31:58 +0200 Subject: [PATCH 022/108] feat(blog): Move to static-websites k8s namespace refactor(cyberchef): Move to static-websites k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 6 ++++-- flake.lock | 9 +++++---- flake.nix | 3 ++- kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 2 +- kubenix-modules/blog.nix | 21 +++++++++------------ kubenix-modules/cyberchef.nix | 8 ++++---- 8 files changed, 26 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index fcf617c..c4a6222 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Currently, the applications being deployed like this are: - `radicale` - `kms` - `atuin` +- `blog` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 470fbb7..b4caeed 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -38,7 +38,7 @@ mkDeployScriptAndManifest = module: applyset: namespace: let kubernetes = (kubenix.evalModules.${system} { - specialArgs = { inherit namespace myLib; }; + specialArgs = { inherit namespace myLib blog-pim; }; module = { kubenix, ... }: { @@ -65,7 +65,7 @@ kubenix.bootstrap.deploy = mkKubenixPackage "${self}/kubenix-modules/base.nix"; kubenix.cyberchef = mkDeployScriptAndManifest - "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "cyberchef"; + "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "static-websites"; kubenix.freshrss = mkDeployScriptAndManifest "${self}/kubenix-modules/freshrss.nix" "freshrss" "freshrss"; kubenix.radicale = mkDeployScriptAndManifest @@ -74,4 +74,6 @@ "${self}/kubenix-modules/kms.nix" "kms" "kms"; kubenix.atuin = mkDeployScriptAndManifest "${self}/kubenix-modules/atuin.nix" "atuin" "atuin"; + kubenix.blog = mkDeployScriptAndManifest + "${self}/kubenix-modules/blog.nix" "blog" "static-websites"; }) diff --git a/flake.lock b/flake.lock index fcf039e..68aecb0 100644 --- a/flake.lock +++ b/flake.lock @@ -9,15 +9,16 @@ ] }, "locked": { - "lastModified": 1716491160, - "narHash": "sha256-dA6+BRp3ptxdgsysrVE5i+asQA8Yk5TTLnr+8hPNzrg=", + "lastModified": 1715503080, + "narHash": "sha256-/VnzHTpTq3u0z2Vgu/vKU0SHwOUIu8olHDORWT0IofM=", "ref": "refs/heads/master", - "rev": "e82fb4539d51da22b6a01e50416ef6ecb548c681", - "revCount": 22, + "rev": "7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5", + "revCount": 21, "type": "git", "url": "https://git.kun.is/home/blog-pim" }, "original": { + "rev": "7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5", "type": "git", "url": "https://git.kun.is/home/blog-pim" } diff --git a/flake.nix b/flake.nix index 23f85a8..f3add24 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,8 @@ }; blog-pim = { - url = "git+https://git.kun.is/home/blog-pim"; + # HACK: pinning this to a specific revision, as my automation is broken. + url = "git+https://git.kun.is/home/blog-pim?rev=7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5"; inputs.nixpkgs.follows = "nixpkgs"; }; diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 67a3363..3dd9a49 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -11,7 +11,6 @@ let ./media.nix ./bind9 ./dnsmasq.nix - ./blog.nix ./attic.nix ./immich.nix # ./argo.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index a94ef8a..c06e2b2 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -61,7 +61,7 @@ resources = { namespaces = { - cyberchef = { }; + static-websites = { }; freshrss = { }; radicale = { }; kms = { }; diff --git a/kubenix-modules/blog.nix b/kubenix-modules/blog.nix index bd1e2c4..3dd65ab 100644 --- a/kubenix-modules/blog.nix +++ b/kubenix-modules/blog.nix @@ -1,19 +1,16 @@ { blog-pim, ... }: { kubernetes.resources = { - deployments.blog = { - metadata.labels.app = "blog"; + deployments.blog.spec = { + replicas = 3; + selector.matchLabels.app = "blog"; - spec = { - selector.matchLabels.app = "blog"; + template = { + metadata.labels.app = "blog"; - template = { - metadata.labels.app = "blog"; - - spec = { - containers.blog = { - image = "git.kun.is/home/blog-pim:${blog-pim.rev}"; - ports.web.containerPort = 80; - }; + spec = { + containers.blog = { + image = "git.kun.is/home/blog-pim:${blog-pim.rev}"; + ports.web.containerPort = 80; }; }; }; diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 94301c8..19c2578 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,6 +1,6 @@ { kubernetes.resources = { - deployments.server.spec = { + deployments.cyberchef.spec = { replicas = 3; selector.matchLabels.app = "cyberchef"; @@ -14,7 +14,7 @@ }; }; - services.server.spec = { + services.cyberchef.spec = { selector.app = "cyberchef"; ports.web = { @@ -24,11 +24,11 @@ }; }; - lab.ingresses.server = { + lab.ingresses.cyberchef = { host = "cyberchef.kun.is"; service = { - name = "server"; + name = "cyberchef"; portName = "web"; }; }; From 2fbc15091288e8deddecaeb8c19411e7609c52e1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 15:56:38 +0200 Subject: [PATCH 023/108] feat(nextcloud): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/nextcloud.nix | 170 +++++++++++++++++----------------- kubenix-modules/volumes.nix | 4 +- 6 files changed, 90 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index c4a6222..1291374 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Currently, the applications being deployed like this are: - `kms` - `atuin` - `blog` +- `nextcloud` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index b4caeed..2796651 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -76,4 +76,6 @@ "${self}/kubenix-modules/atuin.nix" "atuin" "atuin"; kubenix.blog = mkDeployScriptAndManifest "${self}/kubenix-modules/blog.nix" "blog" "static-websites"; + kubenix.nextcloud = mkDeployScriptAndManifest + "${self}/kubenix-modules/nextcloud.nix" "nextcloud" "nextcloud"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 3dd9a49..c2e6deb 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -2,7 +2,6 @@ let applications = [ ./inbucket.nix ./syncthing.nix - ./nextcloud.nix ./pihole.nix ./hedgedoc.nix ./paperless.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index c06e2b2..a351cee 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -66,6 +66,7 @@ radicale = { }; kms = { }; atuin = { }; + nextcloud = { }; }; nodes = diff --git a/kubenix-modules/nextcloud.nix b/kubenix-modules/nextcloud.nix index 13fbe2b..07fda6d 100644 --- a/kubenix-modules/nextcloud.nix +++ b/kubenix-modules/nextcloud.nix @@ -1,130 +1,116 @@ { kubernetes.resources = { - configMaps = { - nextcloud.data = { - POSTGRES_USER = "nextcloud"; - POSTGRES_DB = "nextcloud"; - POSTGRES_HOST = "lewis.dmz"; - }; - - nextcloud-db-env.data = { - POSTGRES_DB = "nextcloud"; - POSTGRES_USER = "nextcloud"; - POSTGRES_PASSWORD = "ref+sops://secrets/kubernetes.yaml#/nextcloud/databasePassword"; - PGDATA = "/pgdata/data"; - }; - }; - - secrets.nextcloud.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/nextcloud/databasePassword"; + secrets.database.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/nextcloud/databasePassword"; deployments = { - nextcloud = { - metadata.labels = { + server.spec = { + selector.matchLabels = { app = "nextcloud"; - component = "website"; + component = "server"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "nextcloud"; - component = "website"; + component = "server"; }; - strategy = { - type = "RollingUpdate"; + spec = { + volumes.data.persistentVolumeClaim.claimName = "data"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + containers.nextcloud = { + image = "nextcloud:28"; + ports.web.containerPort = 80; - template = { - metadata.labels = { - app = "nextcloud"; - component = "website"; - }; + env = { + POSTGRES_USER.value = "nextcloud"; + POSTGRES_DB.value = "nextcloud"; + POSTGRES_HOST.value = "lewis.dmz"; - spec = { - volumes.data.persistentVolumeClaim.claimName = "nextcloud"; - - containers.nextcloud = { - image = "nextcloud:28"; - envFrom = [{ configMapRef.name = "nextcloud"; }]; - ports.web.containerPort = 80; - - env.POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "nextcloud"; + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "database"; key = "databasePassword"; }; - - volumeMounts = [{ - name = "data"; - mountPath = "/var/www/html"; - }]; }; - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; - - affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution = [{ - weight = 1; - preference.matchExpressions = [{ - key = "storageType"; - operator = "In"; - values = [ "fast" ]; - }]; + volumeMounts = [{ + name = "data"; + mountPath = "/var/www/html"; }]; }; + + securityContext = { + fsGroup = 33; + fsGroupChangePolicy = "OnRootMismatch"; + }; + + affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution = [{ + weight = 1; + preference.matchExpressions = [{ + key = "storageType"; + operator = "In"; + values = [ "fast" ]; + }]; + }]; }; }; }; - nextcloud-db = { - metadata.labels = { + database.spec = { + selector.matchLabels = { app = "nextcloud"; component = "database"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "nextcloud"; component = "database"; }; - template = { - metadata.labels = { - app = "nextcloud"; - component = "database"; - }; + spec = { + containers.postgres = { + image = "postgres:15"; + imagePullPolicy = "IfNotPresent"; + ports.postgres.containerPort = 5432; - spec = { - containers.postgres = { - image = "postgres:15"; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - envFrom = [{ configMapRef.name = "nextcloud-db-env"; }]; + env = { + POSTGRES_DB.value = "nextcloud"; + POSTGRES_USER.value = "nextcloud"; + PGDATA.value = "/pgdata/data"; - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "database"; + key = "databasePassword"; + }; }; - volumes.data.persistentVolumeClaim.claimName = "nextcloud-db"; + volumeMounts = [{ + name = "database"; + mountPath = "/pgdata"; + }]; }; + + volumes.database.persistentVolumeClaim.claimName = "database"; }; }; }; }; services = { - nextcloud.spec = { + server.spec = { selector = { app = "nextcloud"; - component = "website"; + component = "server"; }; ports.web = { @@ -133,7 +119,7 @@ }; }; - nextcloud-db.spec = { + database.spec = { selector = { app = "nextcloud"; component = "database"; @@ -148,13 +134,25 @@ }; lab = { - ingresses.nextcloud = { + ingresses.web = { host = "cloud.kun.is"; service = { - name = "nextcloud"; + name = "server"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "nextcloud"; + storage = "50Gi"; + }; + + database = { + volumeName = "nextcloud-db"; + storage = "400Mi"; + }; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index cae1e1a..90097d0 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -17,8 +17,6 @@ hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; minecraft.storage = "1Gi"; - nextcloud.storage = "50Gi"; - nextcloud-db.storage = "400Mi"; pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; forgejo.storage = "20Gi"; @@ -45,6 +43,8 @@ radicale.storage = "200Mi"; atuin.storage = "300Mi"; atuin-db.storage = "300Mi"; + nextcloud.storage = "50Gi"; + nextcloud-db.storage = "400Mi"; }; nfsVolumes = { From cfb9f1bb127b69689005ed36a37e470fe79ef632 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 16:20:24 +0200 Subject: [PATCH 024/108] feat(hedgedoc): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/hedgedoc.nix | 170 +++++++++++++++++------------------ kubenix-modules/volumes.nix | 4 +- secrets/kubernetes.yaml | 6 +- 7 files changed, 90 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 1291374..94d4fd1 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Currently, the applications being deployed like this are: - `atuin` - `blog` - `nextcloud` +- `hedgedoc` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 2796651..e19bfb6 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -78,4 +78,6 @@ "${self}/kubenix-modules/blog.nix" "blog" "static-websites"; kubenix.nextcloud = mkDeployScriptAndManifest "${self}/kubenix-modules/nextcloud.nix" "nextcloud" "nextcloud"; + kubenix.hedgedoc = mkDeployScriptAndManifest + "${self}/kubenix-modules/hedgedoc.nix" "hedgedoc" "hedgedoc"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index c2e6deb..6a722aa 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -3,7 +3,6 @@ let ./inbucket.nix ./syncthing.nix ./pihole.nix - ./hedgedoc.nix ./paperless.nix ./kitchenowl.nix ./forgejo diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index a351cee..5210af5 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -67,6 +67,7 @@ kms = { }; atuin = { }; nextcloud = { }; + hedgedoc = { }; }; nodes = diff --git a/kubenix-modules/hedgedoc.nix b/kubenix-modules/hedgedoc.nix index 2ee7e30..1ba013b 100644 --- a/kubenix-modules/hedgedoc.nix +++ b/kubenix-modules/hedgedoc.nix @@ -1,26 +1,7 @@ { lib, ... }: { kubernetes.resources = { - configMaps = { - hedgedoc-env.data = { - CMD_DOMAIN = "md.kun.is"; - CMD_PORT = "3000"; - CMD_URL_ADDPORT = "false"; - CMD_ALLOW_ANONYMOUS = "true"; - CMD_ALLOW_EMAIL_REGISTER = "false"; - CMD_PROTOCOL_USESSL = "true"; - CMD_CSP_ENABLE = "false"; - }; - - hedgedoc-config.data.config = lib.generators.toJSON { } { - useSSL = false; - }; - - hedgedoc-db-env.data = { - POSTGRES_DB = "hedgedoc"; - POSTGRES_USER = "hedgedoc"; - POSTGRES_PASSWORD = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databasePassword"; - PGDATA = "/pgdata/data"; - }; + configMaps.hedgedoc-config.data.config = lib.generators.toJSON { } { + useSSL = false; }; secrets.hedgedoc.stringData = { @@ -29,109 +10,108 @@ }; deployments = { - hedgedoc = { - metadata.labels = { + server.spec = { + selector.matchLabels = { app = "hedgedoc"; component = "website"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "hedgedoc"; component = "website"; }; - template = { - metadata.labels = { - app = "hedgedoc"; - component = "website"; - }; + spec = { + containers.hedgedoc = { + image = "quay.io/hedgedoc/hedgedoc:1.9.9"; + ports.web.containerPort = 3000; - spec = { - containers.hedgedoc = { - image = "quay.io/hedgedoc/hedgedoc:1.9.9"; - envFrom = [{ configMapRef.name = "hedgedoc-env"; }]; - ports.web.containerPort = 3000; + env = { + CMD_DOMAIN.value = "md.kun.is"; + CMD_PORT.value = "3000"; + CMD_URL_ADDPORT.value = "false"; + CMD_ALLOW_ANONYMOUS.value = "true"; + CMD_ALLOW_EMAIL_REGISTER.value = "false"; + CMD_PROTOCOL_USESSL.value = "true"; + CMD_CSP_ENABLE.value = "false"; - env = { - CMD_DB_URL.valueFrom.secretKeyRef = { - name = "hedgedoc"; - key = "databaseURL"; - }; - - CMD_SESSION_SECRET.valueFrom.secretKeyRef = { - name = "hedgedoc"; - key = "sessionSecret"; - }; + CMD_DB_URL.valueFrom.secretKeyRef = { + name = "hedgedoc"; + key = "databaseURL"; }; - volumeMounts = [ - { - name = "uploads"; - mountPath = "/hedgedoc/public/uploads"; - } - { - name = "config"; - mountPath = "/hedgedoc/config.json"; - subPath = "config"; - } - ]; + CMD_SESSION_SECRET.valueFrom.secretKeyRef = { + name = "hedgedoc"; + key = "sessionSecret"; + }; }; - volumes = { - uploads.persistentVolumeClaim.claimName = "hedgedoc-uploads"; - config.configMap.name = "hedgedoc-config"; - }; + volumeMounts = [ + { + name = "uploads"; + mountPath = "/hedgedoc/public/uploads"; + } + { + name = "config"; + mountPath = "/hedgedoc/config.json"; + subPath = "config"; + } + ]; + }; - securityContext = { - fsGroup = 65534; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumes = { + uploads.persistentVolumeClaim.claimName = "uploads"; + config.configMap.name = "hedgedoc-config"; + }; + + securityContext = { + fsGroup = 65534; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - hedgedoc-db = { - metadata.labels = { + database.spec = { + selector.matchLabels = { app = "hedgedoc"; component = "database"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "hedgedoc"; component = "database"; }; - template = { - metadata.labels = { - app = "hedgedoc"; - component = "database"; - }; + spec = { + containers.postgres = { + image = "postgres:15"; + imagePullPolicy = "IfNotPresent"; + ports.postgres.containerPort = 5432; - spec = { - containers.postgres = { - image = "postgres:15"; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - envFrom = [{ configMapRef.name = "hedgedoc-db-env"; }]; - - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; + env = { + POSTGRES_DB.value = "hedgedoc"; + POSTGRES_USER.value = "hedgedoc"; + POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databasePassword"; + PGDATA.value = "/pgdata/data"; }; - volumes.data.persistentVolumeClaim.claimName = "hedgedoc-db"; + volumeMounts = [{ + name = "database"; + mountPath = "/pgdata"; + }]; }; + + volumes.database.persistentVolumeClaim.claimName = "database"; }; }; }; }; services = { - hedgedoc.spec = { + server.spec = { selector = { app = "hedgedoc"; component = "website"; @@ -143,7 +123,7 @@ }; }; - hedgedoc-db.spec = { + database.spec = { selector = { app = "hedgedoc"; component = "database"; @@ -158,13 +138,25 @@ }; lab = { - ingresses.hedgedoc = { + ingresses.web = { host = "md.kun.is"; service = { - name = "hedgedoc"; + name = "server"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim = { + uploads = { + volumeName = "hedgedoc-uploads"; + storage = "50Mi"; + }; + + database = { + volumeName = "hedgedoc-db"; + storage = "100Mi"; + }; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 90097d0..a09a69d 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -14,8 +14,6 @@ lab = { longhornVolumes = { - hedgedoc-uploads.storage = "50Mi"; - hedgedoc-db.storage = "100Mi"; minecraft.storage = "1Gi"; pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; @@ -45,6 +43,8 @@ atuin-db.storage = "300Mi"; nextcloud.storage = "50Gi"; nextcloud-db.storage = "400Mi"; + hedgedoc-uploads.storage = "50Mi"; + hedgedoc-db.storage = "100Mi"; }; nfsVolumes = { diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index 43d6d90..fcb81ee 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -3,7 +3,7 @@ freshrss: pihole: password: ENC[AES256_GCM,data:yqPpovQKmP7NgUMI3w1p8t7RjbxNsMMHZbsNEaleyLJTqnDzNqONsQ==,iv:i+ys/EZelT4a4Sr0RpDto8udk/9yYC6pzl3FiUZQxrQ=,tag:FlvbMN6fuo+VV50YyuMeGg==,type:str] hedgedoc: - databaseURL: ENC[AES256_GCM,data:dmaXh8wnECBOeEtM00Nc6kpVc3NiJbP5gepToAxLrpmpEEH1vs5SdE90Z3+T3qeXrsTQVr/Q6EOocNKMsTe1pcZoEirECk0dwZ3k6s/bUmUJdZgOf0ir6Iy5J8RZYvJz3AnwuFIsIJ79x0+WfEfACQ==,iv:C7D1zY/vu4zc687XA2mwuYEOFtSFDV+/po4tyNw3ks8=,tag:GQGj4TbP7Mcrm+auuaplnw==,type:str] + databaseURL: ENC[AES256_GCM,data:VVz5meJM/SWC9+gWvorSj4ymLRux0vQPbI0kQLFrUGz2bocaRFzDqHAKbF4sd5iSzc6y5LQqwUfOgNoVrKhIROzKxStOmaQAWTLAJvfdReAqQoEaLVuLcZeML9QIhqvdAvPV5kVMznJ1u5YczSA=,iv:wU/GrAYSF2y0JWl0Nz6UuYmII0kCPIZ+UfAGI/1mUsE=,tag:xVOUwd5T6VHZ7vrpj9FMxg==,type:str] sessionSecret: ENC[AES256_GCM,data:FhYr4rFNHmtk9jUcjM4UthepS/5Z4x7WPAE5lTB94WmHrALbzZl2M3JcmibR6/z1FtAJhCsaPZ7Xeg8nOZtU2g==,iv:7soqcd8A+yNfXEZg0qDjOZgfsUIFHfflxByuf7nZk3Y=,tag:x/rmaXo4nTdA080Zl/0MiQ==,type:str] databasePassword: ENC[AES256_GCM,data:Fv1qeGvXZ93KvdFCCz9t9Dzhe7wKGOfR0lj64lzRM3s48E5FYdrH0w==,iv:cqhIOUKiSSkBpf95Eza9C9l8PX6YmTBpvBAR4+ibgeA=,tag:r8ZvF6l8oNeOt3d5UCA7Ww==,type:str] nextcloud: @@ -50,8 +50,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-12T11:55:18Z" - mac: ENC[AES256_GCM,data:X2uCQfFmVkRq2OSClVlLO9zzmY/jj/B8Qo4dln93KJLRr4g2wdTQVbJWBtLDUMotlHs6b27nJc8T1wTR9/4Q1xqh92DjGeWZQmA5VbBgWuOmCB1xOE8eAFY1rVCT7e2uAFuHknxKhOS2KfOxZyGc4AJ7weXs9bLJWe5i0PSesvA=,iv:KWii9fvWUECng8Nb82nV87HR+BPIyYEfJKZHOrGPjiw=,tag:89xRQre8WahRSt1I6AweYg==,type:str] + lastmodified: "2024-07-14T14:19:35Z" + mac: ENC[AES256_GCM,data:JDlXC7OACi6h78yEMOrJa8Nt/yOlV5es/vhq53UfjlCWEW3Q7haf9eeeTtfRbZ5fubp41M31zkW8fX0vBs7ynq78/3ZY4NDvQqkm6uw4OjDhebfpjqDt4FimUijZM+6GooR12ejWULCLm5oIfR7jsOJKaD7xWTQf+585MBQSIIk=,iv:lTz1X4Dr3B052mjtKaAA/UPJ7myd571INxn6j3oII7I=,tag:AfKcTAY+wPvQUwQrfSNsxA==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 17f507d2770365af855696b789d65e148e82f712 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 19:59:49 +0200 Subject: [PATCH 025/108] feat(kitchenowl): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 ++ kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/kitchenowl.nix | 65 ++++++++++++++++++++-------------- kubenix-modules/volumes.nix | 2 +- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 94d4fd1..578cf99 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Currently, the applications being deployed like this are: - `blog` - `nextcloud` - `hedgedoc` +- `kitchenowl` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index e19bfb6..9906434 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -80,4 +80,6 @@ "${self}/kubenix-modules/nextcloud.nix" "nextcloud" "nextcloud"; kubenix.hedgedoc = mkDeployScriptAndManifest "${self}/kubenix-modules/hedgedoc.nix" "hedgedoc" "hedgedoc"; + kubenix.kitchenowl = mkDeployScriptAndManifest + "${self}/kubenix-modules/kitchenowl.nix" "kitchenowl" "kitchenowl"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 6a722aa..033e366 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -4,7 +4,6 @@ let ./syncthing.nix ./pihole.nix ./paperless.nix - ./kitchenowl.nix ./forgejo ./media.nix ./bind9 diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 5210af5..968a3a6 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -68,6 +68,7 @@ atuin = { }; nextcloud = { }; hedgedoc = { }; + kitchenowl = { }; }; nodes = diff --git a/kubenix-modules/kitchenowl.nix b/kubenix-modules/kitchenowl.nix index c65ae29..611279c 100644 --- a/kubenix-modules/kitchenowl.nix +++ b/kubenix-modules/kitchenowl.nix @@ -1,44 +1,50 @@ { kubernetes.resources = { - secrets.kitchenowl.stringData.jwtSecretKey = "ref+sops://secrets/kubernetes.yaml#/kitchenowl/jwtSecretKey"; + secrets.server.stringData.jwtSecretKey = "ref+sops://secrets/kubernetes.yaml#/kitchenowl/jwtSecretKey"; - deployments.kitchenowl = { - metadata.labels.app = "kitchenowl"; + deployments.server.spec = { + selector.matchLabels.app = "kitchenowl"; - spec = { - selector.matchLabels.app = "kitchenowl"; + strategy = { + type = "RollingUpdate"; - template = { - metadata.labels.app = "kitchenowl"; + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; - spec = { - volumes.data.persistentVolumeClaim.claimName = "kitchenowl"; + template = { + metadata.labels.app = "kitchenowl"; - containers.kitchenowl = { - image = "tombursch/kitchenowl:v0.5.1"; - ports.web.containerPort = 8080; + spec = { + volumes.data.persistentVolumeClaim.claimName = "data"; - env.JWT_SECRET_KEY.valueFrom.secretKeyRef = { - name = "kitchenowl"; - key = "jwtSecretKey"; - }; + containers.kitchenowl = { + image = "tombursch/kitchenowl:v0.5.1"; + ports.web.containerPort = 8080; + imagePullPolicy = "Always"; - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; + env.JWT_SECRET_KEY.valueFrom.secretKeyRef = { + name = "server"; + key = "jwtSecretKey"; }; - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumeMounts = [{ + name = "data"; + mountPath = "/data"; + }]; + }; + + securityContext = { + fsGroup = 0; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - services.kitchenowl.spec = { + services.server.spec = { selector.app = "kitchenowl"; ports.web = { @@ -49,13 +55,18 @@ }; lab = { - ingresses.kitchenowl = { + ingresses.web = { host = "boodschappen.kun.is"; service = { - name = "kitchenowl"; + name = "server"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim.data = { + volumeName = "kitchenowl"; + storage = "100Mi"; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index a09a69d..1747d59 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -18,7 +18,6 @@ pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; forgejo.storage = "20Gi"; - kitchenowl.storage = "100Mi"; syncthing.storage = "400Mi"; paperless-data.storage = "10Gi"; paperless-redisdata.storage = "20Mi"; @@ -45,6 +44,7 @@ nextcloud-db.storage = "400Mi"; hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; + kitchenowl.storage = "100Mi"; }; nfsVolumes = { From f606cb2f1c7d21c43181ea7e64edb97a9ab92091 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 20:14:48 +0200 Subject: [PATCH 026/108] feat(forgejo): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/forgejo/default.nix | 106 ++++++++++++++-------------- kubenix-modules/volumes.nix | 2 +- 6 files changed, 59 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 578cf99..b513cc6 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Currently, the applications being deployed like this are: - `nextcloud` - `hedgedoc` - `kitchenowl` +- `forgejo` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 9906434..967fa02 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -82,4 +82,6 @@ "${self}/kubenix-modules/hedgedoc.nix" "hedgedoc" "hedgedoc"; kubenix.kitchenowl = mkDeployScriptAndManifest "${self}/kubenix-modules/kitchenowl.nix" "kitchenowl" "kitchenowl"; + kubenix.forgejo = mkDeployScriptAndManifest + "${self}/kubenix-modules/forgejo" "forgejo" "forgejo"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 033e366..d090f6c 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -4,7 +4,6 @@ let ./syncthing.nix ./pihole.nix ./paperless.nix - ./forgejo ./media.nix ./bind9 ./dnsmasq.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 968a3a6..a26bf78 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -69,6 +69,7 @@ nextcloud = { }; hedgedoc = { }; kitchenowl = { }; + forgejo = { }; }; nodes = diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix index 0fca6d7..2dc1cf8 100644 --- a/kubenix-modules/forgejo/default.nix +++ b/kubenix-modules/forgejo/default.nix @@ -1,71 +1,68 @@ { lib, myLib, ... }: { kubernetes.resources = { configMaps = { - forgejo-config.data = { + config.data = { config = lib.generators.toINI { } (import ./config.nix); }; - - forgejo-env.data = { - USER_UID = "1000"; - USER_GID = "1000"; - }; }; - deployments.forgejo = { - metadata.labels = { - app = "forgejo"; - component = "forgejo"; + deployments.server.spec = { + selector.matchLabels.app = "forgejo"; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; }; - spec = { - selector.matchLabels.app = "forgejo"; + template = { + metadata.labels.app = "forgejo"; - strategy = { - type = "RollingUpdate"; + spec = { + # This disables services from becoming environmental variables + # to prevent SSH_PORT clashing with Forgejo config. + enableServiceLinks = false; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; + containers.forgejo = { + image = "codeberg.org/forgejo/forgejo:7.0.5"; + imagePullPolicy = "Always"; + + env = { + USER_UID.value = "1000"; + USER_GID.value = "1000"; + }; + + ports = { + web.containerPort = 3000; + ssh.containerPort = 22; + }; + + volumeMounts = [ + { + name = "data"; + mountPath = "/data"; + } + { + name = "config"; + mountPath = "/data/gitea/conf/app.ini"; + subPath = "config"; + } + ]; }; - }; - template = { - metadata.labels.app = "forgejo"; - - spec = { - containers.forgejo = { - image = "codeberg.org/forgejo/forgejo:7.0.5"; - envFrom = [{ configMapRef.name = "forgejo-env"; }]; - - ports = { - web.containerPort = 3000; - ssh.containerPort = 22; - }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/data"; - } - { - name = "config"; - mountPath = "/data/gitea/conf/app.ini"; - subPath = "config"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "forgejo"; - config.configMap.name = "forgejo-config"; - }; + volumes = { + data.persistentVolumeClaim.claimName = "data"; + config.configMap.name = "config"; }; }; }; }; services = { - forgejo-web.spec = { + web.spec = { selector.app = "forgejo"; ports.web = { @@ -74,7 +71,7 @@ }; }; - forgejo-ssh.spec = { + ssh.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.gitIPv4; selector.app = "forgejo"; @@ -88,13 +85,18 @@ }; lab = { - ingresses.forgejo = { + ingresses.web = { host = "git.kun.is"; service = { - name = "forgejo-web"; + name = "web"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim.data = { + volumeName = "forgejo"; + storage = "20Gi"; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 1747d59..f178c5c 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -17,7 +17,6 @@ minecraft.storage = "1Gi"; pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; - forgejo.storage = "20Gi"; syncthing.storage = "400Mi"; paperless-data.storage = "10Gi"; paperless-redisdata.storage = "20Mi"; @@ -45,6 +44,7 @@ hedgedoc-uploads.storage = "50Mi"; hedgedoc-db.storage = "100Mi"; kitchenowl.storage = "100Mi"; + forgejo.storage = "20Gi"; }; nfsVolumes = { From a8d9e4f6345b30338f53b876bb8f50932494f706 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 14 Jul 2024 22:58:06 +0200 Subject: [PATCH 027/108] feat(paperless-ngx): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/paperless.nix | 244 +++++++++++++++++++--------------- kubenix-modules/volumes.nix | 6 +- 6 files changed, 141 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index b513cc6..3ce0544 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Currently, the applications being deployed like this are: - `hedgedoc` - `kitchenowl` - `forgejo` +- `paperless-ngx` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 967fa02..3558332 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -84,4 +84,6 @@ "${self}/kubenix-modules/kitchenowl.nix" "kitchenowl" "kitchenowl"; kubenix.forgejo = mkDeployScriptAndManifest "${self}/kubenix-modules/forgejo" "forgejo" "forgejo"; + kubenix.paperless = mkDeployScriptAndManifest + "${self}/kubenix-modules/paperless.nix" "paperless" "paperless"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index d090f6c..0f2bf41 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -3,7 +3,6 @@ let ./inbucket.nix ./syncthing.nix ./pihole.nix - ./paperless.nix ./media.nix ./bind9 ./dnsmasq.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index a26bf78..7634b80 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -70,6 +70,7 @@ hedgedoc = { }; kitchenowl = { }; forgejo = { }; + paperless = { }; }; nodes = diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index 52f3989..35caecd 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -1,168 +1,175 @@ { kubernetes.resources = { - configMaps = { - paperless.data = { - PAPERLESS_REDIS = "redis://paperless-redis.default.svc.cluster.local:6379"; - PAPERLESS_DBENGINE = "postgresql"; - PAPERLESS_DBHOST = "paperless-db.default.svc.cluster.local"; - PAPERLESS_DBNAME = "paperless"; - PAPERLESS_DBUSER = "paperless"; - PAPERLESS_DATA_DIR = "/data/"; - PAPERLESS_MEDIA_ROOT = "/data/"; - PAPERLESS_OCR_LANGUAGES = "nld eng"; - PAPERLESS_URL = "https://paperless.kun.is"; - PAPERLESS_TIME_ZONE = "Europe/Amsterdam"; - PAPERLESS_OCR_LANGUAGE = "nld"; - USERMAP_UID = "33"; - USERMAP_GID = "33"; - }; - - paperless-db-env.data = { - POSTGRES_DB = "paperless"; - POSTGRES_USER = "paperless"; - POSTGRES_PASSWORD = "ref+sops://secrets/kubernetes.yaml#/paperless/databasePassword"; - PGDATA = "/pgdata/data"; - }; - }; - - secrets.paperless.stringData = { - databasePassword = "ref+sops://secrets/kubernetes.yaml#/paperless/databasePassword"; - secretKey = "ref+sops://secrets/kubernetes.yaml#/paperless/secretKey"; + secrets = { + database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/paperless/databasePassword"; + server.stringData.secretKey = "ref+sops://secrets/kubernetes.yaml#/paperless/secretKey"; }; deployments = { - paperless-web = { - metadata.labels = { + server.spec = { + selector.matchLabels = { app = "paperless"; component = "web"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "paperless"; component = "web"; }; - template = { - metadata.labels = { - app = "paperless"; - component = "web"; - }; + spec = { + volumes.data.persistentVolumeClaim.claimName = "data"; - spec = { - volumes.data.persistentVolumeClaim.claimName = "paperless-data"; + containers.paperless = { + image = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; + imagePullPolicy = "Always"; + ports.web.containerPort = 8000; - containers.paperless = { - image = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; - envFrom = [{ configMapRef.name = "paperless"; }]; - ports.web.containerPort = 8000; + env = { + PAPERLESS_REDIS.value = "redis://redis.paperless.svc.cluster.local:6379"; + PAPERLESS_DBENGINE.value = "postgresql"; + PAPERLESS_DBHOST.value = "database.paperless.svc.cluster.local"; + PAPERLESS_DBNAME.value = "paperless"; + PAPERLESS_DBUSER.value = "paperless"; + PAPERLESS_DATA_DIR.value = "/data/"; + PAPERLESS_MEDIA_ROOT.value = "/data/"; + PAPERLESS_OCR_LANGUAGES.value = "nld eng"; + PAPERLESS_URL.value = "https://paperless.kun.is"; + PAPERLESS_TIME_ZONE.value = "Europe/Amsterdam"; + PAPERLESS_OCR_LANGUAGE.value = "nld"; + USERMAP_UID.value = "33"; + USERMAP_GID.value = "33"; - env = { - PAPERLESS_DBPASS.valueFrom.secretKeyRef = { - name = "paperless"; - key = "databasePassword"; - }; - PAPERLESS_SECRET_KEY.valueFrom.secretKeyRef = { - name = "paperless"; - key = "secretKey"; - }; + PAPERLESS_DBPASS.valueFrom.secretKeyRef = { + name = "database"; + key = "password"; }; - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; + PAPERLESS_SECRET_KEY.valueFrom.secretKeyRef = { + name = "server"; + key = "secretKey"; + }; }; - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumeMounts = [{ + name = "data"; + mountPath = "/data"; + }]; + }; + + securityContext = { + fsGroup = 33; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - paperless-redis = { - metadata.labels = { + redis.spec = { + selector.matchLabels = { app = "paperless"; component = "redis"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "paperless"; component = "redis"; }; - template = { - metadata.labels = { - app = "paperless"; - component = "redis"; + spec = { + volumes.data.persistentVolumeClaim.claimName = "redisdata"; + + containers.redis = { + image = "docker.io/library/redis:7"; + ports.redis.containerPort = 6379; + imagePullPolicy = "Always"; + + volumeMounts = [{ + name = "data"; + mountPath = "/data"; + }]; }; - spec = { - volumes.data.persistentVolumeClaim.claimName = "paperless-redisdata"; - - containers.redis = { - image = "docker.io/library/redis:7"; - ports.redis.containerPort = 6379; - - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; - }; - - securityContext = { - fsGroup = 999; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 999; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - paperless-db = { - metadata.labels = { + database.spec = { + selector.matchLabels = { app = "paperless"; component = "database"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "paperless"; component = "database"; }; - template = { - metadata.labels = { - app = "paperless"; - component = "database"; - }; + spec = { + containers.postgres = { + image = "postgres:15"; + ports.postgres.containerPort = 5432; + imagePullPolicy = "Always"; - spec = { - containers.postgres = { - image = "postgres:15"; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - envFrom = [{ configMapRef.name = "paperless-db-env"; }]; + env = { + POSTGRES_DB.value = "paperless"; + POSTGRES_USER.value = "paperless"; + PGDATA.value = "/pgdata/data"; - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "database"; + key = "password"; + }; }; - volumes.data.persistentVolumeClaim.claimName = "paperless-db"; + volumeMounts = [{ + name = "data"; + mountPath = "/pgdata"; + }]; }; + + volumes.data.persistentVolumeClaim.claimName = "database"; }; }; }; }; services = { - paperless-web.spec = { + web.spec = { selector = { app = "paperless"; component = "web"; @@ -174,7 +181,7 @@ }; }; - paperless-redis.spec = { + redis.spec = { selector = { app = "paperless"; component = "redis"; @@ -186,7 +193,7 @@ }; }; - paperless-db.spec = { + database.spec = { selector = { app = "paperless"; component = "database"; @@ -201,13 +208,30 @@ }; lab = { - ingresses.paperless = { + ingresses.web = { host = "paperless.kun.is"; service = { - name = "paperless-web"; + name = "web"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "paperless-data"; + storage = "10Gi"; + }; + + redisdata = { + volumeName = "paperless-redisdata"; + storage = "20Mi"; + }; + + database = { + volumeName = "paperless-db"; + storage = "150Mi"; + }; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index f178c5c..bdfd8de 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -18,9 +18,6 @@ pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; syncthing.storage = "400Mi"; - paperless-data.storage = "10Gi"; - paperless-redisdata.storage = "20Mi"; - paperless-db.storage = "150Mi"; jellyfin.storage = "5Gi"; transmission.storage = "25Mi"; jellyseerr.storage = "75Mi"; @@ -45,6 +42,9 @@ hedgedoc-db.storage = "100Mi"; kitchenowl.storage = "100Mi"; forgejo.storage = "20Gi"; + paperless-data.storage = "10Gi"; + paperless-redisdata.storage = "20Mi"; + paperless-db.storage = "150Mi"; }; nfsVolumes = { From c8ddbb6aeb34f108e54877789e217dd642717042 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 16 Jul 2024 15:31:47 +0200 Subject: [PATCH 028/108] feat(syncthing): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/syncthing.nix | 79 +++++++++++++++++++---------------- kubenix-modules/volumes.nix | 14 ++++++- 6 files changed, 59 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 3ce0544..9254a9e 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ Currently, the applications being deployed like this are: - `kitchenowl` - `forgejo` - `paperless-ngx` +- `syncthing` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 3558332..79af1d6 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -86,4 +86,6 @@ "${self}/kubenix-modules/forgejo" "forgejo" "forgejo"; kubenix.paperless = mkDeployScriptAndManifest "${self}/kubenix-modules/paperless.nix" "paperless" "paperless"; + kubenix.syncthing = mkDeployScriptAndManifest + "${self}/kubenix-modules/syncthing.nix" "syncthing" "syncthing"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 0f2bf41..fc671de 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,7 +1,6 @@ let applications = [ ./inbucket.nix - ./syncthing.nix ./pihole.nix ./media.nix ./bind9 diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 7634b80..3d281da 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -71,6 +71,7 @@ kitchenowl = { }; forgejo = { }; paperless = { }; + syncthing = { }; }; nodes = diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index a152cac..4d46388 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -1,47 +1,42 @@ { kubernetes.resources = { - configMaps.syncthing.data = { - PUID = "33"; - PGID = "33"; - TZ = "Europe/Amsterdam"; - }; + deployments.syncthing.spec = { + selector.matchLabels.app = "syncthing"; - deployments.syncthing = { - metadata.labels.app = "syncthing"; + template = { + metadata.labels.app = "syncthing"; - spec = { - selector.matchLabels.app = "syncthing"; + spec = { + containers.syncthing = { + image = "lscr.io/linuxserver/syncthing:1.23.6"; + ports.web.containerPort = 8384; - template = { - metadata.labels.app = "syncthing"; - - spec = { - containers.syncthing = { - image = "lscr.io/linuxserver/syncthing:1.23.6"; - envFrom = [{ configMapRef.name = "syncthing"; }]; - ports.web.containerPort = 8384; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "music"; - mountPath = "/music"; - } - ]; + env = { + PUID.value = "33"; + PGID.value = "33"; + TZ.value = "Europe/Amsterdam"; }; - volumes = { - config.persistentVolumeClaim.claimName = "syncthing"; - music.persistentVolumeClaim.claimName = "music"; - }; + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "music"; + mountPath = "/music"; + } + ]; + }; - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumes = { + config.persistentVolumeClaim.claimName = "config"; + music.persistentVolumeClaim.claimName = "music"; + }; + + securityContext = { + fsGroup = 33; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; @@ -55,6 +50,13 @@ targetPort = "web"; }; }; + + persistentVolumeClaims.music.spec = { + accessModes = [ "ReadWriteMany" ]; + storageClassName = ""; + resources.requests.storage = "1Mi"; + volumeName = "music-syncthing"; + }; }; lab = { @@ -67,5 +69,10 @@ portName = "web"; }; }; + + longhorn.persistentVolumeClaim.config = { + volumeName = "syncthing"; + storage = "400Mi"; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index bdfd8de..5431a25 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -12,12 +12,21 @@ # volumes.freshrss.persistentVolumeClaim.claimName = "freshrss"; # }; + kubernetes.resources.persistentVolumes.music-syncthing.spec = { + capacity.storage = "1Gi"; + accessModes = [ "ReadWriteMany" ]; + + nfs = { + server = "lewis.dmz"; + path = "/mnt/longhorn/persistent/media/music"; + }; + }; + lab = { longhornVolumes = { minecraft.storage = "1Gi"; pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; - syncthing.storage = "400Mi"; jellyfin.storage = "5Gi"; transmission.storage = "25Mi"; jellyseerr.storage = "75Mi"; @@ -45,11 +54,12 @@ paperless-data.storage = "10Gi"; paperless-redisdata.storage = "20Mi"; paperless-db.storage = "150Mi"; + syncthing.storage = "400Mi"; }; nfsVolumes = { media.path = "media"; - music.path = "media/music"; + # music.path = "media/music"; }; }; } From 2853429dc4f6af26f487207b26d720043308e4c1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 16 Jul 2024 15:46:13 +0200 Subject: [PATCH 029/108] feat(pihole): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/pihole.nix | 99 ++++++++++++++++++++----------------- kubenix-modules/volumes.nix | 4 +- 6 files changed, 59 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 9254a9e..cddc9e6 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Currently, the applications being deployed like this are: - `forgejo` - `paperless-ngx` - `syncthing` +- `pihole` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 79af1d6..e844af8 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -88,4 +88,6 @@ "${self}/kubenix-modules/paperless.nix" "paperless" "paperless"; kubenix.syncthing = mkDeployScriptAndManifest "${self}/kubenix-modules/syncthing.nix" "syncthing" "syncthing"; + kubenix.pihole = mkDeployScriptAndManifest + "${self}/kubenix-modules/pihole.nix" "pihole" "pihole"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index fc671de..716cbd7 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,7 +1,6 @@ let applications = [ ./inbucket.nix - ./pihole.nix ./media.nix ./bind9 ./dnsmasq.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 3d281da..f226da6 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -72,6 +72,7 @@ forgejo = { }; paperless = { }; syncthing = { }; + pihole = { }; }; nodes = diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix index 3a61246..52f4ec7 100644 --- a/kubenix-modules/pihole.nix +++ b/kubenix-modules/pihole.nix @@ -1,68 +1,63 @@ { myLib, ... }: { kubernetes.resources = { - configMaps.pihole.data = { - TZ = "Europe/Amsterdam"; - PIHOLE_DNS_ = "192.168.30.1"; - }; - secrets.pihole.stringData.webPassword = "ref+sops://secrets/kubernetes.yaml#/pihole/password"; - deployments.pihole = { - metadata.labels.app = "pihole"; + deployments.pihole.spec = { + selector.matchLabels.app = "pihole"; - spec = { - selector.matchLabels.app = "pihole"; + template = { + metadata.labels.app = "pihole"; - template = { - metadata.labels.app = "pihole"; + spec = { + containers.pihole = { + image = "pihole/pihole:latest"; - spec = { - containers.pihole = { - image = "pihole/pihole:latest"; - envFrom = [{ configMapRef.name = "pihole"; }]; + env = { + TZ.value = "Europe/Amsterdam"; + PIHOLE_DNS_.value = "192.168.30.1"; - ports = { - web.containerPort = 80; - - dns = { - containerPort = 53; - protocol = "UDP"; - }; - }; - - env.WEBPASSWORD.valueFrom.secretKeyRef = { + WEBPASSWORD.valueFrom.secretKeyRef = { name = "pihole"; key = "webPassword"; }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/etc/pihole"; - } - { - name = "dnsmasq"; - mountPath = "/etc/dnsmasq.d"; - } - ]; }; - volumes = { - data.persistentVolumeClaim.claimName = "pihole-data"; - dnsmasq.persistentVolumeClaim.claimName = "pihole-dnsmasq"; + ports = { + web.containerPort = 80; + + dns = { + containerPort = 53; + protocol = "UDP"; + }; }; - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumeMounts = [ + { + name = "data"; + mountPath = "/etc/pihole"; + } + { + name = "dnsmasq"; + mountPath = "/etc/dnsmasq.d"; + } + ]; + }; + + volumes = { + data.persistentVolumeClaim.claimName = "data"; + dnsmasq.persistentVolumeClaim.claimName = "dnsmasq"; + }; + + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; services = { - pihole-web.spec = { + web.spec = { selector.app = "pihole"; ports.web = { @@ -71,7 +66,7 @@ }; }; - pihole-dns.spec = { + dns.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.piholeIPv4; selector.app = "pihole"; @@ -91,9 +86,21 @@ entrypoint = "localsecure"; service = { - name = "pihole-web"; + name = "web"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "pihole-data"; + storage = "750Mi"; + }; + + dnsmasq = { + volumeName = "pihole-dnsmasq"; + storage = "16Mi"; + }; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 5431a25..9ee626d 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -25,8 +25,6 @@ lab = { longhornVolumes = { minecraft.storage = "1Gi"; - pihole-data.storage = "750Mi"; - pihole-dnsmasq.storage = "16Mi"; jellyfin.storage = "5Gi"; transmission.storage = "25Mi"; jellyseerr.storage = "75Mi"; @@ -55,6 +53,8 @@ paperless-redisdata.storage = "20Mi"; paperless-db.storage = "150Mi"; syncthing.storage = "400Mi"; + pihole-data.storage = "750Mi"; + pihole-dnsmasq.storage = "16Mi"; }; nfsVolumes = { From d1d09da3d3c2962a3e96f34532f9463d0e388f0a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 16 Jul 2024 16:13:29 +0200 Subject: [PATCH 030/108] feat(immich): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/immich.nix | 260 +++++++++++++++++------------------- kubenix-modules/volumes.nix | 4 +- 6 files changed, 130 insertions(+), 139 deletions(-) diff --git a/README.md b/README.md index cddc9e6..8ff5002 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Currently, the applications being deployed like this are: - `paperless-ngx` - `syncthing` - `pihole` +- `immich` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index e844af8..f47fbf6 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -90,4 +90,6 @@ "${self}/kubenix-modules/syncthing.nix" "syncthing" "syncthing"; kubenix.pihole = mkDeployScriptAndManifest "${self}/kubenix-modules/pihole.nix" "pihole" "pihole"; + kubenix.immich = mkDeployScriptAndManifest + "${self}/kubenix-modules/immich.nix" "immich" "immich"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 716cbd7..ca94a07 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -5,7 +5,6 @@ let ./bind9 ./dnsmasq.nix ./attic.nix - ./immich.nix # ./argo.nix # ./minecraft.nix ]; diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index f226da6..f19a1e3 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -73,6 +73,7 @@ paperless = { }; syncthing = { }; pihole = { }; + immich = { }; }; nodes = diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index b5ebfc2..87f7c5e 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -1,188 +1,162 @@ { kubernetes.resources = { deployments = { - immich-server = { - metadata.labels = { + immich.spec = { + selector.matchLabels = { app = "immich"; component = "server"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "immich"; component = "server"; }; - strategy = { - type = "RollingUpdate"; + spec = { + volumes.data.persistentVolumeClaim.claimName = "data"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + enableServiceLinks = false; - template = { - metadata.labels = { - app = "immich"; - component = "server"; - }; + containers.immich = { + image = "ghcr.io/immich-app/immich-server:v1.108.0"; + imagePullPolicy = "Always"; + ports.web.containerPort = 3001; - spec = { - volumes.data.persistentVolumeClaim.claimName = "immich"; - - containers.immich = { - image = "ghcr.io/immich-app/immich-server:v1.108.0"; - imagePullPolicy = "Always"; - ports.web.containerPort = 3001; - - env = { - TZ.value = "Europe/Amsterdam"; - REDIS_HOSTNAME.value = "immich-redis.default.svc.cluster.local"; - DB_HOSTNAME.value = "immich-postgres.default.svc.cluster.local"; - DB_USERNAME.value = "postgres"; - DB_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; - DB_DATABASE_NAME.value = "immich"; - IMMICH_MACHINE_LEARNING_URL.value = "http://immich-ml.default.svc.cluster.local"; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/usr/src/app/upload"; - }]; + env = { + TZ.value = "Europe/Amsterdam"; + REDIS_HOSTNAME.value = "redis.immich.svc.cluster.local"; + DB_HOSTNAME.value = "postgres.immich.svc.cluster.local"; + DB_USERNAME.value = "postgres"; + DB_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; + DB_DATABASE_NAME.value = "immich"; + IMMICH_MACHINE_LEARNING_URL.value = "http://ml.immich.svc.cluster.local"; }; + + volumeMounts = [{ + name = "data"; + mountPath = "/usr/src/app/upload"; + }]; }; }; }; }; - immich-ml = { - metadata.labels = { + ml.spec = { + selector.matchLabels = { app = "immich"; component = "machine-learning"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "immich"; component = "machine-learning"; }; - template = { - metadata.labels = { - app = "immich"; - component = "machine-learning"; - }; + spec = { + volumes.cache.persistentVolumeClaim.claimName = "cache"; - spec = { - volumes.cache.persistentVolumeClaim.claimName = "immich-cache"; + containers.machine-learning = { + image = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; + imagePullPolicy = "Always"; + ports.ml.containerPort = 3003; + env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; - containers.machine-learning = { - image = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; - imagePullPolicy = "Always"; - ports.ml.containerPort = 3003; - env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; - - volumeMounts = [{ - name = "cache"; - mountPath = "/cache"; - }]; - }; + volumeMounts = [{ + name = "cache"; + mountPath = "/cache"; + }]; }; }; }; }; - immich-redis = { - metadata.labels = { + redis.spec = { + selector.matchLabels = { app = "immich"; component = "redis"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "immich"; component = "redis"; }; - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "immich"; - component = "redis"; - }; - - spec = { - containers.redis = { - image = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; - ports.redis.containerPort = 6379; - imagePullPolicy = "Always"; - }; + spec = { + containers.redis = { + image = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; + ports.redis.containerPort = 6379; + imagePullPolicy = "Always"; }; }; }; }; - immich-database = { - metadata.labels = { + database.spec = { + selector.matchLabels = { app = "immich"; component = "database"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "immich"; component = "database"; }; - strategy = { - type = "RollingUpdate"; + spec = { + volumes.data.persistentVolumeClaim.claimName = "database"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + containers.postgres = { + image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + imagePullPolicy = "Always"; + command = [ "postgres" ]; + args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; + ports.postgres.containerPort = 5432; + securityContext.runAsUser = 999; + securityContext.runAsGroup = 999; - template = { - metadata.labels = { - app = "immich"; - component = "database"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "immich-db"; - - containers.postgres = { - image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; - imagePullPolicy = "Always"; - command = [ "postgres" ]; - args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; - ports.postgres.containerPort = 5432; - securityContext.runAsUser = 999; - securityContext.runAsGroup = 999; - - env = { - POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; - POSTGRES_USER.value = "postgres"; - POSTGRES_DB.value = "immich"; - POSTGRES_INITDB_ARGS.value = "--data-checksums"; - PGDATA.value = "/pgdata/data"; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; + env = { + POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; + POSTGRES_USER.value = "postgres"; + POSTGRES_DB.value = "immich"; + POSTGRES_INITDB_ARGS.value = "--data-checksums"; + PGDATA.value = "/pgdata/data"; }; + + volumeMounts = [{ + name = "data"; + mountPath = "/pgdata"; + }]; }; }; }; @@ -190,7 +164,7 @@ }; services = { - immich-server.spec = { + server.spec = { selector = { app = "immich"; component = "server"; @@ -202,7 +176,7 @@ }; }; - immich-redis.spec = { + redis.spec = { selector = { app = "immich"; component = "redis"; @@ -214,7 +188,7 @@ }; }; - immich-ml.spec = { + ml.spec = { selector = { app = "immich"; component = "machine-learning"; @@ -226,7 +200,7 @@ }; }; - immich-postgres.spec = { + postgres.spec = { selector = { app = "immich"; component = "database"; @@ -239,18 +213,32 @@ }; }; - persistentVolumeClaims.immich-cache.spec = { + persistentVolumeClaims.cache.spec = { accessModes = [ "ReadWriteOnce" ]; resources.requests.storage = "5Gi"; }; }; - lab.ingresses.immich-test = { - host = "immich.kun.is"; + lab = { + ingresses.immich = { + host = "immich.kun.is"; - service = { - name = "immich-server"; - portName = "web"; + service = { + name = "server"; + portName = "web"; + }; + }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "immich"; + storage = "50Gi"; + }; + + database = { + volumeName = "immich-db"; + storage = "5Gi"; + }; }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 9ee626d..b1bedb3 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -34,8 +34,6 @@ bazarr.storage = "25Mi"; attic.storage = "15Gi"; attic-db.storage = "150Mi"; - immich.storage = "50Gi"; - immich-db.storage = "5Gi"; }; longhorn.persistentVolume = { @@ -55,6 +53,8 @@ syncthing.storage = "400Mi"; pihole-data.storage = "750Mi"; pihole-dnsmasq.storage = "16Mi"; + immich.storage = "50Gi"; + immich-db.storage = "5Gi"; }; nfsVolumes = { From af9f72b76a20d75aa5e4fa0554ebc9829fe872a7 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 16 Jul 2024 18:38:47 +0200 Subject: [PATCH 031/108] feat(attic): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/attic.nix | 145 +++++++++++++++++++----------------- kubenix-modules/base.nix | 1 + kubenix-modules/volumes.nix | 4 +- secrets/kubernetes.yaml | 6 +- 7 files changed, 86 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 8ff5002..915f974 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Currently, the applications being deployed like this are: - `syncthing` - `pihole` - `immich` +- `attic` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index f47fbf6..2844ede 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -92,4 +92,6 @@ "${self}/kubenix-modules/pihole.nix" "pihole" "pihole"; kubenix.immich = mkDeployScriptAndManifest "${self}/kubenix-modules/immich.nix" "immich" "immich"; + kubenix.attic = mkDeployScriptAndManifest + "${self}/kubenix-modules/attic.nix" "attic" "attic"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index ca94a07..b07e1a4 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -4,7 +4,6 @@ let ./media.nix ./bind9 ./dnsmasq.nix - ./attic.nix # ./argo.nix # ./minecraft.nix ]; diff --git a/kubenix-modules/attic.nix b/kubenix-modules/attic.nix index ea74001..b8fe530 100644 --- a/kubenix-modules/attic.nix +++ b/kubenix-modules/attic.nix @@ -2,7 +2,10 @@ kubernetes.resources = let atticSettings = { - database.url = "ref+sops://secrets/kubernetes.yaml#attic/databaseURL"; + # The '+" is to explicitly denote the end of the Vals expression. + # This is done because we quote the template for the INI file. + # See: https://github.com/helmfile/vals?tab=readme-ov-file#expression-syntax + database.url = "ref+sops://secrets/kubernetes.yaml#attic/databaseURL+"; storage = { type = "local"; @@ -37,104 +40,99 @@ generatedConfig = (pkgs.formats.toml { }).generate "attic.toml" atticSettings; in { - configMaps = { - attic-env.data.ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64 = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; - attic-config.data.config = builtins.readFile generatedConfig; + configMaps.config.data.config = builtins.readFile generatedConfig; - attic-db-env.data = { - POSTGRES_DB = "attic"; - POSTGRES_USER = "attic"; - POSTGRES_PASSWORD = "ref+sops://secrets/kubernetes.yaml#/attic/databasePassword"; - PGDATA = "/pgdata/data"; - }; + secrets = { + server.stringData.token = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; + database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/attic/databasePassword"; }; deployments = { - attic = { - metadata.labels = { + attic.spec = { + selector.matchLabels = { app = "attic"; component = "website"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "attic"; component = "website"; }; - template = { - metadata.labels = { - app = "attic"; - component = "website"; + spec = { + containers.attic = { + image = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; + ports.web.containerPort = 8080; + args = [ "-f" "/etc/atticd/config.toml" ]; + + env.ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64.valueFrom.secretKeyRef = { + name = "server"; + key = "token"; + }; + + volumeMounts = [ + { + name = "data"; + mountPath = "/var/lib/atticd/storage"; + } + { + name = "config"; + mountPath = "/etc/atticd/config.toml"; + subPath = "config"; + } + ]; }; - spec = { - containers.attic = { - image = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; - envFrom = [{ configMapRef.name = "attic-env"; }]; - ports.web.containerPort = 8080; - args = [ "-f" "/etc/atticd/config.toml" ]; + volumes = { + data.persistentVolumeClaim.claimName = "data"; + config.configMap.name = "config"; + }; - volumeMounts = [ - { - name = "data"; - mountPath = "/var/lib/atticd/storage"; - } - { - name = "config"; - mountPath = "/etc/atticd/config.toml"; - subPath = "config"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "attic"; - config.configMap.name = "attic-config"; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 0; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - attic-db = { - metadata.labels = { + attic-db.spec = { + selector.matchLabels = { app = "attic"; component = "database"; }; - spec = { - selector.matchLabels = { + template = { + metadata.labels = { app = "attic"; component = "database"; }; - template = { - metadata.labels = { - app = "attic"; - component = "database"; - }; + spec = { + containers.postgres = { + image = "postgres:15"; + imagePullPolicy = "IfNotPresent"; + ports.postgres.containerPort = 5432; - spec = { - containers.postgres = { - image = "postgres:15"; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - envFrom = [{ configMapRef.name = "attic-db-env"; }]; + env = { + POSTGRES_DB.value = "attic"; + POSTGRES_USER.value = "attic"; + PGDATA.value = "/pgdata/data"; - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "database"; + key = "password"; + }; }; - volumes.data.persistentVolumeClaim.claimName = "attic-db"; + volumeMounts = [{ + name = "data"; + mountPath = "/pgdata"; + }]; }; + + volumes.data.persistentVolumeClaim.claimName = "database"; }; }; }; @@ -153,7 +151,7 @@ }; }; - attic-db.spec = { + database.spec = { selector = { app = "attic"; component = "database"; @@ -170,12 +168,23 @@ lab = { ingresses.attic = { host = "attic.kun.is"; - # entrypoint = "localsecure"; service = { name = "attic"; portName = "web"; }; }; + + longhorn.persistentVolumeClaim = { + data = { + volumeName = "attic"; + storage = "15Gi"; + }; + + database = { + volumeName = "attic-db"; + storage = "150Mi"; + }; + }; }; } diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index f19a1e3..b9d05b6 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -74,6 +74,7 @@ syncthing = { }; pihole = { }; immich = { }; + attic = { }; }; nodes = diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index b1bedb3..0890cd7 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -32,8 +32,6 @@ prowlarr.storage = "150Mi"; sonarr.storage = "150Mi"; bazarr.storage = "25Mi"; - attic.storage = "15Gi"; - attic-db.storage = "150Mi"; }; longhorn.persistentVolume = { @@ -55,6 +53,8 @@ pihole-dnsmasq.storage = "16Mi"; immich.storage = "50Gi"; immich-db.storage = "5Gi"; + attic.storage = "15Gi"; + attic-db.storage = "150Mi"; }; nfsVolumes = { diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index fcb81ee..6fa7adf 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -19,7 +19,7 @@ forgejo: jwtSecret: ENC[AES256_GCM,data:ZIGOR53XCE1kGPQIpaY6ImbLMISbTpmC8R1oRFbjQGxHDG9dQuBigyjs5w==,iv:14WHd/RwniA7+YFGGrs+oyHx5Cc9G+D/IV9aBqn3KOI=,tag:+3LiFnV3Emx4i4efSRmthw==,type:str] attic: jwtToken: ENC[AES256_GCM,data:nAuryLY1xD9ur3qDcsJXPJPLFcPwssPKv+/BoivZ4aO6ec6rmOaYAkSRsBjgANyKhssbn0fhGsdyhMBwdHTXDnnIo67amFdxxSe+jJlGtcBXcekaOfD0Ug==,iv:h+h7CD8oI8u2ItzD/KKM16FKaG2xuVqIKh4r1TGjYtw=,tag:Er141FCK8usfzRRtrawHOw==,type:str] - databaseURL: ENC[AES256_GCM,data:F2XyCgXRuebQgvkHGz8DVM2z53sC0/8GzVN6P6iJjrVxB522BJnGlw0YdFBg5K9xMWRhuzxRgDJ+ySfIb8HTtFvlF8Ifx41vFZV1zSpmDMzo4/0=,iv:wp3sg+Y9kgGH5GZZDxAE2CpzDvJeV1mH8mfHRPB17Ys=,tag:IhGRIq/qPT0vSbv/L1ODYg==,type:str] + databaseURL: ENC[AES256_GCM,data:caKIXEAOIqWl1tjZItabbdYjotKjMwrPYJKR8mj/Zs0LkrUhOzOlyybNIhHAR/5rqHZlAhimVnVIxh/95g6AJOCNNukbForHUbj/PxkVUG8E,iv:9uh9FyN7n7M+FMLe5G/Z3NmbCgqc3t2SRocc4xL/Qbc=,tag:4JAb3qJUMIkBrAIAuKhjWQ==,type:str] databasePassword: ENC[AES256_GCM,data:Zwv5DKkihOUU/yL1tvbZl1+bPtI=,iv:C+6n6RHo1zTUJ/g0DWCWNxtLbusoYmDHMySsea5Jpz0=,tag:+pyw0WqnX5rMQxSl/48L5A==,type:str] atuin: databaseURL: ENC[AES256_GCM,data:IBmND/J2Pzz+CDCeNBRtErxSQIi8PeUuLGN4rIXKSLwZ6TGJKcNmbuxQDvWkCnI1crx3oak=,iv:wc3G/00oIuaiGF4mA2vIm35wFGxT0a3Ox3k1C9YBAx4=,tag:MQPcsR+vrD85DttYYi6jUw==,type:str] @@ -50,8 +50,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-14T14:19:35Z" - mac: ENC[AES256_GCM,data:JDlXC7OACi6h78yEMOrJa8Nt/yOlV5es/vhq53UfjlCWEW3Q7haf9eeeTtfRbZ5fubp41M31zkW8fX0vBs7ynq78/3ZY4NDvQqkm6uw4OjDhebfpjqDt4FimUijZM+6GooR12ejWULCLm5oIfR7jsOJKaD7xWTQf+585MBQSIIk=,iv:lTz1X4Dr3B052mjtKaAA/UPJ7myd571INxn6j3oII7I=,tag:AfKcTAY+wPvQUwQrfSNsxA==,type:str] + lastmodified: "2024-07-16T16:10:38Z" + mac: ENC[AES256_GCM,data:VL8fsI2LWvXttPJDi+3TVBec/Ot4CFSM8MWVWu81YJAkG0V7FpUcmJ44PaaknzyISpZGo5hmpJOx8c/ad3CO5Mq1ZIGCf/vyN6iGHFD3tEOsxlp4puJcsoNgM2my5tQ7mRjNZrvgrmoDYinsFRHT+u0DWOcL8A8g8fLOOd/T5KA=,iv:KRW+aFyyYd/S9SMA19GiTQqDyk4b9CdgL5fNqvG9Kew=,tag:8sCbi0s4SJa38sX00qKb8g==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From e9307da90d78453c123b8c344ac5d2932f059d58 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 16 Jul 2024 19:56:18 +0200 Subject: [PATCH 032/108] feat(inbucket): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 ++ kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 1 + kubenix-modules/inbucket.nix | 32 ++++++++++++++------------------ 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 915f974..bbfccb6 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Currently, the applications being deployed like this are: - `pihole` - `immich` - `attic` +- `inbucket` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 2844ede..4a197cc 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -94,4 +94,6 @@ "${self}/kubenix-modules/immich.nix" "immich" "immich"; kubenix.attic = mkDeployScriptAndManifest "${self}/kubenix-modules/attic.nix" "attic" "attic"; + kubenix.inbucket = mkDeployScriptAndManifest + "${self}/kubenix-modules/inbucket.nix" "inbucket" "inbucket"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index b07e1a4..fd78044 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,6 +1,5 @@ let applications = [ - ./inbucket.nix ./media.nix ./bind9 ./dnsmasq.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index b9d05b6..8cf6974 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -75,6 +75,7 @@ pihole = { }; immich = { }; attic = { }; + inbucket = { }; }; nodes = diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index ba4edbd..80033f8 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -1,22 +1,18 @@ -{ lib, myLib, ... }: { +{ myLib, ... }: { kubernetes.resources = { - deployments.inbucket = { - metadata.labels.app = "inbucket"; + deployments.inbucket.spec = { + selector.matchLabels.app = "inbucket"; - spec = { - selector.matchLabels.app = "inbucket"; + template = { + metadata.labels.app = "inbucket"; - template = { - metadata.labels.app = "inbucket"; + spec = { + containers.inbucket = { + image = "inbucket/inbucket:edge"; - spec = { - containers.inbucket = { - image = "inbucket/inbucket:edge"; - - ports = { - web.containerPort = 9000; - smtp.containerPort = 2500; - }; + ports = { + web.containerPort = 9000; + smtp.containerPort = 2500; }; }; }; @@ -24,7 +20,7 @@ }; services = { - inbucket-web.spec = { + web.spec = { selector.app = "inbucket"; ports.web = { @@ -33,7 +29,7 @@ }; }; - inbucket-email.spec = { + email.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.inbucketIPv4; selector.app = "inbucket"; @@ -51,7 +47,7 @@ entrypoint = "localsecure"; service = { - name = "inbucket-web"; + name = "web"; portName = "web"; }; }; From 342ba2baeb00cc0c9e41faa7035f95c439768d5b Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 10:25:23 +0200 Subject: [PATCH 033/108] feat(dnsmasq): Move to dns k8s namespace refactor(pihole): Move to dns k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 4 +++- kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 2 +- kubenix-modules/dnsmasq.nix | 39 ++++++++++++++++--------------------- kubenix-modules/pihole.nix | 14 ++++++------- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index bbfccb6..836d3a4 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Currently, the applications being deployed like this are: - `immich` - `attic` - `inbucket` +- `dnsmasq` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 4a197cc..d6f45ca 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -89,11 +89,13 @@ kubenix.syncthing = mkDeployScriptAndManifest "${self}/kubenix-modules/syncthing.nix" "syncthing" "syncthing"; kubenix.pihole = mkDeployScriptAndManifest - "${self}/kubenix-modules/pihole.nix" "pihole" "pihole"; + "${self}/kubenix-modules/pihole.nix" "pihole" "dns"; kubenix.immich = mkDeployScriptAndManifest "${self}/kubenix-modules/immich.nix" "immich" "immich"; kubenix.attic = mkDeployScriptAndManifest "${self}/kubenix-modules/attic.nix" "attic" "attic"; kubenix.inbucket = mkDeployScriptAndManifest "${self}/kubenix-modules/inbucket.nix" "inbucket" "inbucket"; + kubenix.dnsmasq = mkDeployScriptAndManifest + "${self}/kubenix-modules/dnsmasq.nix" "dnsmasq" "dns"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index fd78044..95eaf8e 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -2,7 +2,6 @@ let applications = [ ./media.nix ./bind9 - ./dnsmasq.nix # ./argo.nix # ./minecraft.nix ]; diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 8cf6974..ebef733 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -72,10 +72,10 @@ forgejo = { }; paperless = { }; syncthing = { }; - pihole = { }; immich = { }; attic = { }; inbucket = { }; + dns = { }; }; nodes = diff --git a/kubenix-modules/dnsmasq.nix b/kubenix-modules/dnsmasq.nix index 27b761b..bc29d61 100644 --- a/kubenix-modules/dnsmasq.nix +++ b/kubenix-modules/dnsmasq.nix @@ -1,6 +1,5 @@ { myLib, ... }: { kubernetes.resources = { - # TODO: generate this with nix? configMaps.dnsmasq-config.data.config = '' address=/kms.kun.is/${myLib.globals.kmsIPv4} address=/ssh.git.kun.is/${myLib.globals.gitIPv4} @@ -16,33 +15,29 @@ server=/kun.is/${myLib.globals.bind9IPv4} ''; - deployments.dnsmasq = { - metadata.labels.app = "dnsmasq"; + deployments.dnsmasq.spec = { + selector.matchLabels.app = "dnsmasq"; - spec = { - selector.matchLabels.app = "dnsmasq"; + template = { + metadata.labels.app = "dnsmasq"; - template = { - metadata.labels.app = "dnsmasq"; + spec = { + containers.dnsmasq = { + image = "dockurr/dnsmasq:2.90"; - spec = { - containers.dnsmasq = { - image = "dockurr/dnsmasq:2.90"; - - ports.dns = { - containerPort = 53; - protocol = "UDP"; - }; - - volumeMounts = [{ - name = "config"; - mountPath = "/etc/dnsmasq.conf"; - subPath = "config"; - }]; + ports.dns = { + containerPort = 53; + protocol = "UDP"; }; - volumes.config.configMap.name = "dnsmasq-config"; + volumeMounts = [{ + name = "config"; + mountPath = "/etc/dnsmasq.conf"; + subPath = "config"; + }]; }; + + volumes.config.configMap.name = "dnsmasq-config"; }; }; }; diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix index 52f4ec7..b5540b9 100644 --- a/kubenix-modules/pihole.nix +++ b/kubenix-modules/pihole.nix @@ -44,8 +44,8 @@ }; volumes = { - data.persistentVolumeClaim.claimName = "data"; - dnsmasq.persistentVolumeClaim.claimName = "dnsmasq"; + data.persistentVolumeClaim.claimName = "pihole-data"; + dnsmasq.persistentVolumeClaim.claimName = "pihole-dnsmasq"; }; securityContext = { @@ -57,7 +57,7 @@ }; services = { - web.spec = { + pihole-web.spec = { selector.app = "pihole"; ports.web = { @@ -66,7 +66,7 @@ }; }; - dns.spec = { + pihole-dns.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.piholeIPv4; selector.app = "pihole"; @@ -86,18 +86,18 @@ entrypoint = "localsecure"; service = { - name = "web"; + name = "pihole-web"; portName = "web"; }; }; longhorn.persistentVolumeClaim = { - data = { + pihole-data = { volumeName = "pihole-data"; storage = "750Mi"; }; - dnsmasq = { + pihole-dnsmasq = { volumeName = "pihole-dnsmasq"; storage = "16Mi"; }; From 7b1958e5c5cf2e0a1ec10d3d5db9f0352bd28b32 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 10:30:50 +0200 Subject: [PATCH 034/108] feat(bind9): Move to dns k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 4 +- kubenix-modules/all.nix | 1 - kubenix-modules/bind9/default.nix | 106 ++++++++++++++---------------- 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 836d3a4..f1bd22f 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Currently, the applications being deployed like this are: - `attic` - `inbucket` - `dnsmasq` +- `bind9` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index d6f45ca..fdf4418 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -38,7 +38,7 @@ mkDeployScriptAndManifest = module: applyset: namespace: let kubernetes = (kubenix.evalModules.${system} { - specialArgs = { inherit namespace myLib blog-pim; }; + specialArgs = { inherit namespace myLib blog-pim dns; }; module = { kubenix, ... }: { @@ -98,4 +98,6 @@ "${self}/kubenix-modules/inbucket.nix" "inbucket" "inbucket"; kubenix.dnsmasq = mkDeployScriptAndManifest "${self}/kubenix-modules/dnsmasq.nix" "dnsmasq" "dns"; + kubenix.bind9 = mkDeployScriptAndManifest + "${self}/kubenix-modules/bind9" "bind9" "dns"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 95eaf8e..8e77fc0 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,7 +1,6 @@ let applications = [ ./media.nix - ./bind9 # ./argo.nix # ./minecraft.nix ]; diff --git a/kubenix-modules/bind9/default.nix b/kubenix-modules/bind9/default.nix index 7ce9a08..50aaefc 100644 --- a/kubenix-modules/bind9/default.nix +++ b/kubenix-modules/bind9/default.nix @@ -41,69 +41,65 @@ in }; }; - deployments.bind9 = { - metadata.labels.app = "bind9"; + deployments.bind9.spec = { + selector.matchLabels.app = "bind9"; - spec = { - selector.matchLabels.app = "bind9"; + template = { + metadata.labels.app = "bind9"; - template = { - metadata.labels.app = "bind9"; + spec = { + containers = { + bind9-udp = { + image = "ubuntu/bind9:9.18-22.04_beta"; + envFrom = [{ configMapRef.name = "bind9-env"; }]; - spec = { - containers = { - bind9-udp = { - image = "ubuntu/bind9:9.18-22.04_beta"; - envFrom = [{ configMapRef.name = "bind9-env"; }]; - - ports.dns-udp = { - containerPort = 53; - protocol = "UDP"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/etc/bind/named.conf"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/etc/bind/kun.is.zone"; - subPath = "kunis-zone"; - } - ]; + ports.dns-udp = { + containerPort = 53; + protocol = "UDP"; }; - bind9-tcp = { - image = "ubuntu/bind9:9.18-22.04_beta"; - envFrom = [{ configMapRef.name = "bind9-env"; }]; - - ports.dns-tcp = { - containerPort = 53; - protocol = "TCP"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/etc/bind/named.conf"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/etc/bind/kun.is.zone"; - subPath = "kunis-zone"; - } - ]; - }; + volumeMounts = [ + { + name = "config"; + mountPath = "/etc/bind/named.conf"; + subPath = "config"; + } + { + name = "config"; + mountPath = "/etc/bind/kun.is.zone"; + subPath = "kunis-zone"; + } + ]; }; - volumes = [{ - name = "config"; - configMap.name = "bind9-config"; - }]; + bind9-tcp = { + image = "ubuntu/bind9:9.18-22.04_beta"; + envFrom = [{ configMapRef.name = "bind9-env"; }]; + + ports.dns-tcp = { + containerPort = 53; + protocol = "TCP"; + }; + + volumeMounts = [ + { + name = "config"; + mountPath = "/etc/bind/named.conf"; + subPath = "config"; + } + { + name = "config"; + mountPath = "/etc/bind/kun.is.zone"; + subPath = "kunis-zone"; + } + ]; + }; }; + + volumes = [{ + name = "config"; + configMap.name = "bind9-config"; + }]; }; }; }; From c7624baa78147ed9af59fe5913f2ef412bbf4919 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 11:59:48 +0200 Subject: [PATCH 035/108] feat(media): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 11 +- kubenix-modules/base.nix | 8 +- kubenix-modules/media.nix | 663 ++++++++++++++++++------------------ kubenix-modules/volumes.nix | 47 +-- 6 files changed, 362 insertions(+), 370 deletions(-) diff --git a/README.md b/README.md index f1bd22f..e91a270 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Currently, the applications being deployed like this are: - `inbucket` - `dnsmasq` - `bind9` +- `media` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index fdf4418..ff873cb 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -100,4 +100,6 @@ "${self}/kubenix-modules/dnsmasq.nix" "dnsmasq" "dns"; kubenix.bind9 = mkDeployScriptAndManifest "${self}/kubenix-modules/bind9" "bind9" "dns"; + kubenix.media = mkDeployScriptAndManifest + "${self}/kubenix-modules/media.nix" "media" "media"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 8e77fc0..83a1e2c 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,12 +1,7 @@ -let - applications = [ - ./media.nix - # ./argo.nix - # ./minecraft.nix - ]; -in { imports = [ + # ./argo.nix + # ./minecraft.nix ./base.nix ./longhorn.nix ./esrom.nix @@ -17,5 +12,5 @@ in ./traefik.nix ./volumes.nix ./custom-types.nix - ] ++ applications; + ]; } diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index ebef733..dfff269 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -44,17 +44,16 @@ longhorn = { chart = nixhelm.chartsDerivations.${system}.longhorn.longhorn; includeCRDs = true; + values = { + persistence.defaultClassReplicaCount = 2; + defaultSettings = { defaultDataPath = "/mnt/longhorn"; storageMinimalAvailablePercentage = 0; allowRecurringJobWhileVolumeDetached = true; backupTarget = "nfs://lewis.dmz:/mnt/longhorn/persistent/longhorn-backup"; }; - - persistence = { - defaultClassReplicaCount = 2; - }; }; }; }; @@ -76,6 +75,7 @@ attic = { }; inbucket = { }; dns = { }; + media = { }; }; nodes = diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index 6aad73e..f921ebe 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -1,462 +1,405 @@ { myLib, ... }: { kubernetes.resources = { - configMaps = { - jellyfin-env.data.JELLYFIN_PublishedServerUrl = "https://media.kun.is"; - transmission-env.data = { - PUID = "1000"; - PGID = "1000"; - TZ = "Europe/Amsterdam"; - }; - - jellyseerr-env.data = { - LOG_LEVEL = "debug"; - TZ = "Europe/Amsterdam"; - }; - - radarr-env.data = { - PUID = "1000"; - PGID = "1000"; - TZ = "Europe/Amsterdam"; - }; - - prowlarr-env.data = { - PUID = "1000"; - PGID = "1000"; - TZ = "Europe/Amsterdam"; - }; - - sonarr-env.data = { - PUID = "1000"; - PGID = "1000"; - TZ = "Europe/Amsterdam"; - }; - - bazarr-env.data = { - PUID = "1000"; - PGID = "1000"; - TZ = "Europe/Amsterdam"; - }; - }; - deployments = { - jellyfin = { - metadata.labels = { + jellyfin.spec = { + selector.matchLabels = { app = "media"; component = "jellyfin"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "jellyfin"; }; - strategy = { - type = "RollingUpdate"; + spec = { + containers.jellyfin = { + image = "jellyfin/jellyfin:10.9.7"; + ports.web.containerPort = 8096; + imagePullPolicy = "Always"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + env.JELLYFIN_PublishedServerUrl.value = "https://media.kun.is"; - template = { - metadata.labels = { - app = "media"; - component = "jellyfin"; + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + { + name = "cache"; + mountPath = "/config/transcodes"; + } + ]; }; - spec = { - containers.jellyfin = { - image = "jellyfin/jellyfin:10.9.7"; - envFrom = [{ configMapRef.name = "jellyfin-env"; }]; - ports.web.containerPort = 8096; - imagePullPolicy = "Always"; + volumes = { + config.persistentVolumeClaim.claimName = "jellyfin"; + cache.persistentVolumeClaim.claimName = "jellyfin-cache"; - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - { - name = "cache"; - mountPath = "/config/transcodes"; - } - ]; + media.hostPath = { + path = "/mnt/longhorn/persistent/media"; + type = "Directory"; }; + }; - volumes = { - config.persistentVolumeClaim.claimName = "jellyfin"; - cache.persistentVolumeClaim.claimName = "jellyfin-cache"; + securityContext = { + fsGroup = 0; + fsGroupChangePolicy = "OnRootMismatch"; + }; - media.hostPath = { - path = "/mnt/longhorn/persistent/media"; - type = "Directory"; - }; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; - - affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms = [{ - matchExpressions = [{ - key = "hasMedia"; - operator = "In"; - values = [ "true" ]; - }]; + affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms = [{ + matchExpressions = [{ + key = "hasMedia"; + operator = "In"; + values = [ "true" ]; }]; - }; + }]; }; }; }; - transmission = { - metadata.labels = { + transmission.spec = { + selector.matchLabels = { app = "media"; component = "transmission"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "transmission"; }; - strategy = { - type = "RollingUpdate"; + spec = { + containers.transmission = { + image = "lscr.io/linuxserver/transmission:4.0.6"; + imagePullPolicy = "Always"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + ports = { + web.containerPort = 9091; + bittorrent.containerPort = 31780; + }; - template = { - metadata.labels = { - app = "media"; - component = "transmission"; + env = { + PUID.value = "1000"; + PGID.value = "1000"; + TZ.value = "Europe/Amsterdam"; + }; + + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; }; - spec = { - containers.transmission = { - image = "lscr.io/linuxserver/transmission:4.0.6"; - envFrom = [{ configMapRef.name = "transmission-env"; }]; - imagePullPolicy = "Always"; + volumes = { + config.persistentVolumeClaim.claimName = "transmission"; + media.persistentVolumeClaim.claimName = "media"; + }; - ports = { - web.containerPort = 9091; - bittorrent.containerPort = 31780; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "transmission"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - jellyseerr = { - metadata.labels = { + jellyseerr.spec = { + selector.matchLabels = { app = "media"; component = "jellyseerr"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "jellyseerr"; }; - strategy = { - type = "RollingUpdate"; + spec = { + volumes.config.persistentVolumeClaim.claimName = "jellyseerr"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + containers.jellyseerr = { + image = "fallenbagel/jellyseerr:1.9.2"; + ports.web.containerPort = 5055; + imagePullPolicy = "Always"; - template = { - metadata.labels = { - app = "media"; - component = "jellyseerr"; - }; - - spec = { - volumes.config.persistentVolumeClaim.claimName = "jellyseerr"; - - containers.jellyseerr = { - image = "fallenbagel/jellyseerr:1.9.2"; - envFrom = [{ configMapRef.name = "jellyseerr-env"; }]; - ports.web.containerPort = 5055; - imagePullPolicy = "Always"; - - volumeMounts = [{ - name = "config"; - mountPath = "/app/config"; - }]; + env = { + LOG_LEVEL.value = "debug"; + TZ.value = "Europe/Amsterdam"; }; - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumeMounts = [{ + name = "config"; + mountPath = "/app/config"; + }]; + }; + + securityContext = { + fsGroup = 0; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - radarr = { - metadata.labels = { + radarr.spec = { + selector.matchLabels = { app = "media"; component = "radarr"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "radarr"; }; - strategy = { - type = "RollingUpdate"; + spec = { + containers.radarr = { + image = "lscr.io/linuxserver/radarr:5.7.0"; + ports.web.containerPort = 7878; + imagePullPolicy = "Always"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + env = { + PUID.value = "1000"; + PGID.value = "1000"; + TZ.value = "Europe/Amsterdam"; + }; - template = { - metadata.labels = { - app = "media"; - component = "radarr"; + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; }; - spec = { - containers.radarr = { - image = "lscr.io/linuxserver/radarr:5.7.0"; - envFrom = [{ configMapRef.name = "radarr-env"; }]; - ports.web.containerPort = 7878; - imagePullPolicy = "Always"; + volumes = { + config.persistentVolumeClaim.claimName = "radarr"; + media.persistentVolumeClaim.claimName = "media"; + }; - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "radarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - prowlarr = { - metadata.labels = { + prowlarr.spec = { + selector.matchLabels = { app = "media"; component = "prowlarr"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "prowlarr"; }; - strategy = { - type = "RollingUpdate"; + spec = { + volumes.config.persistentVolumeClaim.claimName = "prowlarr"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + containers.prowlarr = { + image = "lscr.io/linuxserver/prowlarr:1.20.1"; + ports.web.containerPort = 9696; + imagePullPolicy = "Always"; - template = { - metadata.labels = { - app = "media"; - component = "prowlarr"; - }; - - spec = { - volumes.config.persistentVolumeClaim.claimName = "prowlarr"; - - containers.prowlarr = { - image = "lscr.io/linuxserver/prowlarr:1.20.1"; - envFrom = [{ configMapRef.name = "prowlarr-env"; }]; - ports.web.containerPort = 9696; - imagePullPolicy = "Always"; - - volumeMounts = [{ - name = "config"; - mountPath = "/config"; - }]; + env = { + PUID.value = "1000"; + PGID.value = "1000"; + TZ.value = "Europe/Amsterdam"; }; - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + volumeMounts = [{ + name = "config"; + mountPath = "/config"; + }]; + }; + + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - sonarr = { - metadata.labels = { + sonarr.spec = { + selector.matchLabels = { app = "media"; component = "sonarr"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "sonarr"; }; - strategy = { - type = "RollingUpdate"; + spec = { + containers.sonarr = { + image = "lscr.io/linuxserver/sonarr:4.0.6"; + ports.web.containerPort = 8989; + imagePullPolicy = "Always"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + env = { + PUID.value = "1000"; + PGID.value = "1000"; + TZ.value = "Europe/Amsterdam"; + }; - template = { - metadata.labels = { - app = "media"; - component = "sonarr"; + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; }; - spec = { - containers.sonarr = { - image = "lscr.io/linuxserver/sonarr:4.0.6"; - envFrom = [{ configMapRef.name = "sonarr-env"; }]; - ports.web.containerPort = 8989; - imagePullPolicy = "Always"; + volumes = { + config.persistentVolumeClaim.claimName = "sonarr"; + media.persistentVolumeClaim.claimName = "media"; + }; - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "sonarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; - bazarr = { - metadata.labels = { + bazarr.spec = { + selector.matchLabels = { app = "media"; component = "bazarr"; }; - spec = { - selector.matchLabels = { + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { app = "media"; component = "bazarr"; }; - strategy = { - type = "RollingUpdate"; + spec = { + containers.bazarr = { + image = "lscr.io/linuxserver/bazarr:1.4.3"; + ports.web.containerPort = 6767; + imagePullPolicy = "Always"; - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; + env = { + PUID.value = "1000"; + PGID.value = "1000"; + TZ.value = "Europe/Amsterdam"; + }; - template = { - metadata.labels = { - app = "media"; - component = "bazarr"; + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; }; - spec = { - containers.bazarr = { - image = "lscr.io/linuxserver/bazarr:1.4.3"; - envFrom = [{ configMapRef.name = "bazarr-env"; }]; - ports.web.containerPort = 6767; - imagePullPolicy = "Always"; + volumes = { + config.persistentVolumeClaim.claimName = "bazarr"; + media.persistentVolumeClaim.claimName = "media"; + }; - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "bazarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; + securityContext = { + fsGroup = 1000; + fsGroupChangePolicy = "OnRootMismatch"; }; }; }; @@ -564,9 +507,18 @@ }; }; - persistentVolumeClaims.jellyfin-cache.spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = "20Gi"; + persistentVolumeClaims = { + jellyfin-cache.spec = { + accessModes = [ "ReadWriteOnce" ]; + resources.requests.storage = "20Gi"; + }; + + media.spec = { + accessModes = [ "ReadWriteMany" ]; + storageClassName = ""; + resources.requests.storage = "1Mi"; + volumeName = "media-media"; + }; }; }; @@ -641,5 +593,42 @@ }; }; }; + + longhorn.persistentVolumeClaim = { + jellyfin = { + volumeName = "jellyfin"; + storage = "5Gi"; + }; + + transmission = { + volumeName = "transmission"; + storage = "25Mi"; + }; + + jellyseerr = { + volumeName = "jellyseerr"; + storage = "75Mi"; + }; + + radarr = { + volumeName = "radarr"; + storage = "300Mi"; + }; + + prowlarr = { + volumeName = "prowlarr"; + storage = "150Mi"; + }; + + sonarr = { + volumeName = "sonarr"; + storage = "150Mi"; + }; + + bazarr = { + volumeName = "bazarr"; + storage = "25Mi"; + }; + }; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 0890cd7..8a1b88c 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -12,27 +12,30 @@ # volumes.freshrss.persistentVolumeClaim.claimName = "freshrss"; # }; - kubernetes.resources.persistentVolumes.music-syncthing.spec = { - capacity.storage = "1Gi"; - accessModes = [ "ReadWriteMany" ]; + kubernetes.resources.persistentVolumes = { + music-syncthing.spec = { + capacity.storage = "1Gi"; + accessModes = [ "ReadWriteMany" ]; - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/media/music"; + nfs = { + server = "lewis.dmz"; + path = "/mnt/longhorn/persistent/media/music"; + }; + }; + + media-media.spec = { + capacity.storage = "1Gi"; + accessModes = [ "ReadWriteMany" ]; + + nfs = { + server = "lewis.dmz"; + path = "/mnt/longhorn/persistent/media"; + }; }; }; lab = { - longhornVolumes = { - minecraft.storage = "1Gi"; - jellyfin.storage = "5Gi"; - transmission.storage = "25Mi"; - jellyseerr.storage = "75Mi"; - radarr.storage = "300Mi"; - prowlarr.storage = "150Mi"; - sonarr.storage = "150Mi"; - bazarr.storage = "25Mi"; - }; + longhornVolumes.minecraft.storage = "1Gi"; longhorn.persistentVolume = { freshrss.storage = "1Gi"; @@ -55,11 +58,13 @@ immich-db.storage = "5Gi"; attic.storage = "15Gi"; attic-db.storage = "150Mi"; - }; - - nfsVolumes = { - media.path = "media"; - # music.path = "media/music"; + jellyfin.storage = "5Gi"; + transmission.storage = "25Mi"; + jellyseerr.storage = "75Mi"; + radarr.storage = "300Mi"; + prowlarr.storage = "150Mi"; + sonarr.storage = "150Mi"; + bazarr.storage = "25Mi"; }; }; } From dfe457c894cafff62112338eb9b5ca599fddf7b1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 14:26:17 +0200 Subject: [PATCH 036/108] refactor(traefik): Deploy resources in kube-system namespace --- README.md | 1 + flake-parts/kubenix.nix | 4 ++ kubenix-modules/all.nix | 3 -- kubenix-modules/base.nix | 9 ++-- kubenix-modules/ek2024.nix | 22 --------- kubenix-modules/esrom.nix | 22 --------- kubenix-modules/traefik.nix | 90 +++++++++++++++++++++++++++---------- 7 files changed, 77 insertions(+), 74 deletions(-) delete mode 100644 kubenix-modules/ek2024.nix delete mode 100644 kubenix-modules/esrom.nix diff --git a/README.md b/README.md index e91a270..29b2186 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ Currently, the applications being deployed like this are: - `dnsmasq` - `bind9` - `media` +- `traefik` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index ff873cb..f253f48 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -44,7 +44,9 @@ { imports = [ kubenix.modules.k8s + kubenix.modules.helm "${self}/kubenix-modules/custom" + "${self}/kubenix-modules/custom-types.nix" module ]; @@ -102,4 +104,6 @@ "${self}/kubenix-modules/bind9" "bind9" "dns"; kubenix.media = mkDeployScriptAndManifest "${self}/kubenix-modules/media.nix" "media" "media"; + kubenix.traefik = mkDeployScriptAndManifest + "${self}/kubenix-modules/traefik.nix" "traefik" "kube-system"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 83a1e2c..4aea28d 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -4,12 +4,9 @@ # ./minecraft.nix ./base.nix ./longhorn.nix - ./esrom.nix - ./ek2024.nix ./metallb.nix ./cert-manager.nix ./custom - ./traefik.nix ./volumes.nix ./custom-types.nix ]; diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index dfff269..8e601e3 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -36,10 +36,10 @@ includeCRDs = false; }; - argo-workflows = { - chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; - includeCRDs = true; - }; + # argo-workflows = { + # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; + # includeCRDs = true; + # }; longhorn = { chart = nixhelm.chartsDerivations.${system}.longhorn.longhorn; @@ -76,6 +76,7 @@ inbucket = { }; dns = { }; media = { }; + traefik = { }; }; nodes = diff --git a/kubenix-modules/ek2024.nix b/kubenix-modules/ek2024.nix deleted file mode 100644 index 89b83ea..0000000 --- a/kubenix-modules/ek2024.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - kubernetes.resources = { - services.ek2024.spec = { - type = "ExternalName"; - externalName = "ek2024.dmz"; - - ports.web = { - port = 80; - targetPort = 80; - }; - }; - }; - - lab.ingresses.ek2024 = { - host = "ek2024.kun.is"; - - service = { - name = "ek2024"; - portName = "web"; - }; - }; -} diff --git a/kubenix-modules/esrom.nix b/kubenix-modules/esrom.nix deleted file mode 100644 index 5c30a71..0000000 --- a/kubenix-modules/esrom.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - kubernetes.resources = { - services.esrom.spec = { - type = "ExternalName"; - externalName = "esrom.dmz"; - - ports.web = { - port = 80; - targetPort = 80; - }; - }; - }; - - lab.ingresses.esrom = { - host = "esrom.kun.is"; - - service = { - name = "esrom"; - portName = "web"; - }; - }; -} diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index 8cf58ec..293ac24 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -1,34 +1,78 @@ { lib, myLib, ... }: { - kubernetes.resources.helmChartConfigs = { - traefik = { - metadata.namespace = "kube-system"; + kubernetes.resources = { + helmChartConfigs = { + traefik = { + metadata.namespace = lib.mkForce "kube-system"; - # Override Traefik's service with a static load balancer IP. - # Create endpoint for HTTPS on port 444. - # Allow external name services for esrom. - spec.valuesContent = lib.generators.toYAML { } { - # service.annotations."metallb.universe.tf/loadBalancerIPs" = myLib.globals.traefikIPv4; - providers.kubernetesIngress.allowExternalNameServices = true; - service.loadBalancerIP = myLib.globals.traefikIPv4; + # Override Traefik's service with a static load balancer IP. + # Create endpoint for HTTPS on port 444. + # Allow external name services for servers in LAN. + spec.valuesContent = lib.generators.toYAML { } { + # service.annotations."metallb.universe.tf/loadBalancerIPs" = myLib.globals.traefikIPv4; + providers.kubernetesIngress.allowExternalNameServices = true; + service.loadBalancerIP = myLib.globals.traefikIPv4; - ports = { - localsecure = { - port = 8444; - expose = true; - exposedPort = 444; - protocol = "TCP"; + ports = { + localsecure = { + port = 8444; + expose = true; + exposedPort = 444; + protocol = "TCP"; - tls = { - enabled = true; - options = ""; - certResolver = ""; - domains = [ ]; + tls = { + enabled = true; + options = ""; + certResolver = ""; + domains = [ ]; + }; }; - }; - web.redirectTo = "websecure"; + web.redirectTo = "websecure"; + }; + }; + }; + }; + + services = { + ek2024.spec = { + type = "ExternalName"; + externalName = "ek2024.dmz"; + + ports.web = { + port = 80; + targetPort = 80; + }; + }; + + esrom.spec = { + type = "ExternalName"; + externalName = "esrom.dmz"; + + ports.web = { + port = 80; + targetPort = 80; }; }; }; }; + + lab.ingresses = { + ek2024 = { + host = "ek2024.kun.is"; + + service = { + name = "ek2024"; + portName = "web"; + }; + }; + + esrom = { + host = "esrom.kun.is"; + + service = { + name = "esrom"; + portName = "web"; + }; + }; + }; } From 5a4376f699a7107a1b13c5ed0dc9e3f20fa2dca2 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 14:48:06 +0200 Subject: [PATCH 037/108] feat(minecraft): Move to separate k8s namespace --- README.md | 1 + flake-parts/kubenix.nix | 2 + kubenix-modules/all.nix | 1 - kubenix-modules/base.nix | 2 +- kubenix-modules/minecraft.nix | 72 +++++++++++++++++------------------ kubenix-modules/volumes.nix | 3 +- 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 29b2186..93c190c 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Currently, the applications being deployed like this are: - `bind9` - `media` - `traefik` +- `minecraft` ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index f253f48..2eefec0 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -106,4 +106,6 @@ "${self}/kubenix-modules/media.nix" "media" "media"; kubenix.traefik = mkDeployScriptAndManifest "${self}/kubenix-modules/traefik.nix" "traefik" "kube-system"; + kubenix.minecraft = mkDeployScriptAndManifest + "${self}/kubenix-modules/minecraft.nix" "minecraft" "minecraft"; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 4aea28d..055de68 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -1,7 +1,6 @@ { imports = [ # ./argo.nix - # ./minecraft.nix ./base.nix ./longhorn.nix ./metallb.nix diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 8e601e3..cb21e91 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -76,7 +76,7 @@ inbucket = { }; dns = { }; media = { }; - traefik = { }; + minecraft = { }; }; nodes = diff --git a/kubenix-modules/minecraft.nix b/kubenix-modules/minecraft.nix index a103db6..a3157eb 100644 --- a/kubenix-modules/minecraft.nix +++ b/kubenix-modules/minecraft.nix @@ -1,48 +1,48 @@ { myLib, ... }: { - kubernetes.resources = { - configMaps.minecraft-env.data.EULA = "TRUE"; + # kubernetes.resources = { + # deployments.minecraft.spec = { + # selector.matchLabels.app = "minecraft"; - deployments.minecraft = { - metadata.labels.app = "minecraft"; + # template = { + # metadata.labels.app = "minecraft"; - spec = { - selector.matchLabels.app = "minecraft"; + # spec = { + # volumes.data.persistentVolumeClaim.claimName = "data"; - template = { - metadata.labels.app = "minecraft"; + # containers.minecraft = { + # image = "itzg/minecraft-server"; + # ports.minecraft.containerPort = 25565; - spec = { - volumes.data.persistentVolumeClaim.claimName = "minecraft"; + # env.EULA.value = "TRUE"; - containers.minecraft = { - image = "itzg/minecraft-server"; - envFrom = [{ configMapRef.name = "minecraft-env"; }]; - ports.minecraft.containerPort = 25565; + # volumeMounts = [{ + # name = "data"; + # mountPath = "/data"; + # }]; + # }; - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; - }; + # securityContext = { + # fsGroup = 1000; + # fsGroupChangePolicy = "OnRootMismatch"; + # }; + # }; + # }; + # }; - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - }; + # services.minecraft.spec = { + # type = "LoadBalancer"; + # loadBalancerIP = myLib.globals.minecraftIPv4; + # selector.app = "minecraft"; - services.minecraft.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.minecraftIPv4; - selector.app = "minecraft"; + # ports.minecraft = { + # port = 25565; + # targetPort = "minecraft"; + # }; + # }; + # }; - ports.minecraft = { - port = 25565; - targetPort = "minecraft"; - }; - }; + lab.longhorn.persistentVolumeClaim.data = { + volumeName = "minecraft"; + storage = "1Gi"; }; } diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 8a1b88c..8623b1a 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -35,8 +35,6 @@ }; lab = { - longhornVolumes.minecraft.storage = "1Gi"; - longhorn.persistentVolume = { freshrss.storage = "1Gi"; radicale.storage = "200Mi"; @@ -65,6 +63,7 @@ prowlarr.storage = "150Mi"; sonarr.storage = "150Mi"; bazarr.storage = "25Mi"; + minecraft.storage = "1Gi"; }; }; } From 7a915f09287633be9eec042be8d15798c0d64964 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 16:25:41 +0200 Subject: [PATCH 038/108] refactor(kubenix): DRY deployment creation feat(kubenix): Create applysets for remaining resources --- flake-parts/kubenix.nix | 181 ++++++++++++++++-------- kubenix-modules/all.nix | 12 -- kubenix-modules/base.nix | 94 ------------ kubenix-modules/bootstrapDefault.nix | 164 +++++++++++++++++++++ kubenix-modules/bootstrapKubeSystem.nix | 36 +++++ kubenix-modules/cert-manager.nix | 15 -- kubenix-modules/longhorn.nix | 44 ------ kubenix-modules/metallb.nix | 7 - kubenix-modules/traefik.nix | 3 - kubenix-modules/volumes.nix | 69 --------- 10 files changed, 324 insertions(+), 301 deletions(-) delete mode 100644 kubenix-modules/all.nix delete mode 100644 kubenix-modules/base.nix create mode 100644 kubenix-modules/bootstrapDefault.nix create mode 100644 kubenix-modules/bootstrapKubeSystem.nix delete mode 100644 kubenix-modules/cert-manager.nix delete mode 100644 kubenix-modules/longhorn.nix delete mode 100644 kubenix-modules/metallb.nix delete mode 100644 kubenix-modules/volumes.nix diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 2eefec0..320731b 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -1,17 +1,11 @@ { self, pkgs, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem (system: let - mkKubenixPackage = module: kubenix.packages.${system}.default.override - { - specialArgs = { inherit myLib kubenix nixhelm system dns blog-pim machines; }; - module = { imports = [ module ]; }; - }; - deployScript = (pkgs.writeScriptBin "kubenix" (builtins.readFile ./kubenix-deploy.sh)).overrideAttrs (old: { buildCommand = "${old.buildCommand}\npatchShebangs $out"; }); - mkDeployScript = kubernetes: applyset: namespace: + mkDeployScript = kubernetes: applysetName: namespace: let kubeconfig = kubernetes.kubeconfig or ""; result = kubernetes.result or ""; @@ -28,17 +22,17 @@ --suffix PATH : "$out/bin" \ --run 'export KUBECONFIG=''${KUBECONFIG:-${toString kubeconfig}}' \ --set MANIFEST '${result}' \ - --set APPLYSET 'applyset-${applyset}' \ + --set APPLYSET 'applyset-${applysetName}' \ --set NAMESPACE '${namespace}' ''; }; in wrappedDeployScript; - mkDeployScriptAndManifest = module: applyset: namespace: + mkDeployScriptAndManifest = name: { module, namespace }: let kubernetes = (kubenix.evalModules.${system} { - specialArgs = { inherit namespace myLib blog-pim dns; }; + specialArgs = { inherit namespace myLib blog-pim dns nixhelm system machines; }; module = { kubenix, ... }: { @@ -51,7 +45,7 @@ ]; config = { - kubenix.project = applyset; + kubenix.project = name; kubernetes.namespace = namespace; }; }; @@ -59,53 +53,126 @@ in { manifest = kubernetes.result; - deploy = mkDeployScript kubernetes applyset namespace; + deploy = mkDeployScript kubernetes name namespace; }; + + deployers = { + bootstrap-default = { + module = "${self}/kubenix-modules/bootstrapDefault.nix"; + namespace = "default"; + }; + + bootstrap-kube-system = { + module = "${self}/kubenix-modules/bootstrapKubeSystem.nix"; + namespace = "kube-system"; + }; + + cyberchef = { + module = "${self}/kubenix-modules/cyberchef.nix"; + namespace = "static-websites"; + }; + + freshrss = { + module = "${self}/kubenix-modules/freshrss.nix"; + namespace = "freshrss"; + }; + + radicale = { + module = "${self}/kubenix-modules/radicale.nix"; + namespace = "radicale"; + }; + + kms = { + module = "${self}/kubenix-modules/kms.nix"; + namespace = "kms"; + }; + + atuin = { + module = "${self}/kubenix-modules/atuin.nix"; + namespace = "atuin"; + }; + + blog = { + module = "${self}/kubenix-modules/blog.nix"; + namespace = "static-websites"; + }; + + nextcloud = { + module = "${self}/kubenix-modules/nextcloud.nix"; + namespace = "nextcloud"; + }; + + hedgedoc = { + module = "${self}/kubenix-modules/hedgedoc.nix"; + namespace = "hedgedoc"; + }; + + kitchenowl = { + module = "${self}/kubenix-modules/kitchenowl.nix"; + namespace = "kitchenowl"; + }; + + forgejo = { + module = "${self}/kubenix-modules/forgejo"; + namespace = "forgejo"; + }; + + paperless = { + module = "${self}/kubenix-modules/paperless.nix"; + namespace = "paperless"; + }; + + syncthing = { + module = "${self}/kubenix-modules/syncthing.nix"; + namespace = "syncthing"; + }; + + pihole = { + module = "${self}/kubenix-modules/pihole.nix"; + namespace = "dns"; + }; + + immich = { + module = "${self}/kubenix-modules/immich.nix"; + namespace = "immich"; + }; + + attic = { + module = "${self}/kubenix-modules/attic.nix"; + namespace = "attic"; + }; + + inbucket = { + module = "${self}/kubenix-modules/inbucket.nix"; + namespace = "inbucket"; + }; + + dnsmasq = { + module = "${self}/kubenix-modules/dnsmasq.nix"; + namespace = "dns"; + }; + + bind9 = { + module = "${self}/kubenix-modules/bind9"; + namespace = "dns"; + }; + + media = { + module = "${self}/kubenix-modules/media.nix"; + namespace = "media"; + }; + + traefik = { + module = "${self}/kubenix-modules/traefik.nix"; + namespace = "kube-system"; + }; + + minecraft = { + module = "${self}/kubenix-modules/minecraft.nix"; + namespace = "minecraft"; + }; + }; in { - kubenix.all.deploy = mkKubenixPackage "${self}/kubenix-modules/all.nix"; - kubenix.bootstrap.deploy = mkKubenixPackage "${self}/kubenix-modules/base.nix"; - - kubenix.cyberchef = mkDeployScriptAndManifest - "${self}/kubenix-modules/cyberchef.nix" "cyberchef" "static-websites"; - kubenix.freshrss = mkDeployScriptAndManifest - "${self}/kubenix-modules/freshrss.nix" "freshrss" "freshrss"; - kubenix.radicale = mkDeployScriptAndManifest - "${self}/kubenix-modules/radicale.nix" "radicale" "radicale"; - kubenix.kms = mkDeployScriptAndManifest - "${self}/kubenix-modules/kms.nix" "kms" "kms"; - kubenix.atuin = mkDeployScriptAndManifest - "${self}/kubenix-modules/atuin.nix" "atuin" "atuin"; - kubenix.blog = mkDeployScriptAndManifest - "${self}/kubenix-modules/blog.nix" "blog" "static-websites"; - kubenix.nextcloud = mkDeployScriptAndManifest - "${self}/kubenix-modules/nextcloud.nix" "nextcloud" "nextcloud"; - kubenix.hedgedoc = mkDeployScriptAndManifest - "${self}/kubenix-modules/hedgedoc.nix" "hedgedoc" "hedgedoc"; - kubenix.kitchenowl = mkDeployScriptAndManifest - "${self}/kubenix-modules/kitchenowl.nix" "kitchenowl" "kitchenowl"; - kubenix.forgejo = mkDeployScriptAndManifest - "${self}/kubenix-modules/forgejo" "forgejo" "forgejo"; - kubenix.paperless = mkDeployScriptAndManifest - "${self}/kubenix-modules/paperless.nix" "paperless" "paperless"; - kubenix.syncthing = mkDeployScriptAndManifest - "${self}/kubenix-modules/syncthing.nix" "syncthing" "syncthing"; - kubenix.pihole = mkDeployScriptAndManifest - "${self}/kubenix-modules/pihole.nix" "pihole" "dns"; - kubenix.immich = mkDeployScriptAndManifest - "${self}/kubenix-modules/immich.nix" "immich" "immich"; - kubenix.attic = mkDeployScriptAndManifest - "${self}/kubenix-modules/attic.nix" "attic" "attic"; - kubenix.inbucket = mkDeployScriptAndManifest - "${self}/kubenix-modules/inbucket.nix" "inbucket" "inbucket"; - kubenix.dnsmasq = mkDeployScriptAndManifest - "${self}/kubenix-modules/dnsmasq.nix" "dnsmasq" "dns"; - kubenix.bind9 = mkDeployScriptAndManifest - "${self}/kubenix-modules/bind9" "bind9" "dns"; - kubenix.media = mkDeployScriptAndManifest - "${self}/kubenix-modules/media.nix" "media" "media"; - kubenix.traefik = mkDeployScriptAndManifest - "${self}/kubenix-modules/traefik.nix" "traefik" "kube-system"; - kubenix.minecraft = mkDeployScriptAndManifest - "${self}/kubenix-modules/minecraft.nix" "minecraft" "minecraft"; + kubenix = builtins.mapAttrs mkDeployScriptAndManifest deployers; }) diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix deleted file mode 100644 index 055de68..0000000 --- a/kubenix-modules/all.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ - imports = [ - # ./argo.nix - ./base.nix - ./longhorn.nix - ./metallb.nix - ./cert-manager.nix - ./custom - ./volumes.nix - ./custom-types.nix - ]; -} diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix deleted file mode 100644 index cb21e91..0000000 --- a/kubenix-modules/base.nix +++ /dev/null @@ -1,94 +0,0 @@ -# We deploy several resources that rely on "custom resource definitions". -# We must first import these resources definitions, before deploying resources that depend on them. -{ lib, kubenix, nixhelm, system, machines, ... }: { - imports = [ - kubenix.modules.k8s - kubenix.modules.helm - ]; - - config = { - kubenix.project = "home"; - - kubernetes = { - kubeconfig = "~/.kube/config"; - - # TODO: These were copied from https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.crds.yaml - # See https://cert-manager.io/docs/installation/helm/ - # Seems kubenix cannot import a list of resources, but only individual resources. - # Might be good to create a PR for this. - imports = [ - ./cert-manager-manifests/certificaterequest.yaml - ./cert-manager-manifests/certificate.yaml - ./cert-manager-manifests/challenge.yaml - ./cert-manager-manifests/clusterissuer.yaml - ./cert-manager-manifests/issuer.yaml - ./cert-manager-manifests/order.yaml - ]; - - helm.releases = { - metallb = { - chart = nixhelm.chartsDerivations.${system}.metallb.metallb; - includeCRDs = true; - }; - - cert-manager = { - chart = nixhelm.chartsDerivations.${system}.jetstack.cert-manager; - includeCRDs = false; - }; - - # argo-workflows = { - # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; - # includeCRDs = true; - # }; - - longhorn = { - chart = nixhelm.chartsDerivations.${system}.longhorn.longhorn; - includeCRDs = true; - - values = { - persistence.defaultClassReplicaCount = 2; - - defaultSettings = { - defaultDataPath = "/mnt/longhorn"; - storageMinimalAvailablePercentage = 0; - allowRecurringJobWhileVolumeDetached = true; - backupTarget = "nfs://lewis.dmz:/mnt/longhorn/persistent/longhorn-backup"; - }; - }; - }; - }; - - resources = { - namespaces = { - static-websites = { }; - freshrss = { }; - radicale = { }; - kms = { }; - atuin = { }; - nextcloud = { }; - hedgedoc = { }; - kitchenowl = { }; - forgejo = { }; - paperless = { }; - syncthing = { }; - immich = { }; - attic = { }; - inbucket = { }; - dns = { }; - media = { }; - minecraft = { }; - }; - - nodes = - let - machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; - in - builtins.mapAttrs - (name: machine: { - metadata.labels = machine.kubernetesNodeLabels; - }) - machinesWithKubernetesLabels; - }; - }; - }; -} diff --git a/kubenix-modules/bootstrapDefault.nix b/kubenix-modules/bootstrapDefault.nix new file mode 100644 index 0000000..e581c96 --- /dev/null +++ b/kubenix-modules/bootstrapDefault.nix @@ -0,0 +1,164 @@ +{ lib, nixhelm, system, machines, ... }: { + kubernetes = { + + helm.releases = { + metallb = { + chart = nixhelm.chartsDerivations.${system}.metallb.metallb; + includeCRDs = true; + }; + + # argo-workflows = { + # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; + # includeCRDs = true; + # }; + + longhorn = { + chart = nixhelm.chartsDerivations.${system}.longhorn.longhorn; + includeCRDs = true; + + values = { + persistence.defaultClassReplicaCount = 2; + + defaultSettings = { + defaultDataPath = "/mnt/longhorn"; + storageMinimalAvailablePercentage = 0; + allowRecurringJobWhileVolumeDetached = true; + backupTarget = "nfs://lewis.dmz:/mnt/longhorn/persistent/longhorn-backup"; + }; + }; + }; + + # argo-workflows = { + # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; + # includeCRDs = true; + # }; + }; + + resources = { + namespaces = { + static-websites = { }; + freshrss = { }; + radicale = { }; + kms = { }; + atuin = { }; + nextcloud = { }; + hedgedoc = { }; + kitchenowl = { }; + forgejo = { }; + paperless = { }; + syncthing = { }; + immich = { }; + attic = { }; + inbucket = { }; + dns = { }; + media = { }; + minecraft = { }; + }; + + nodes = + let + machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; + in + builtins.mapAttrs + (name: machine: { + metadata.labels = machine.kubernetesNodeLabels; + }) + machinesWithKubernetesLabels; + + ingresses.longhorn = { + metadata.annotations = { + "cert-manager.io/cluster-issuer" = "letsencrypt"; + "traefik.ingress.kubernetes.io/router.entrypoints" = "localsecure"; + }; + + spec = { + ingressClassName = "traefik"; + + rules = [{ + host = "longhorn.kun.is"; + + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = "longhorn-frontend"; + port.number = 80; + }; + }]; + }]; + + tls = [{ + secretName = "longhorn-tls"; + hosts = [ "longhorn.kun.is" ]; + }]; + }; + }; + + recurringJobs.backup-nfs.spec = { + cron = "0 1 * * *"; # One o'clock at night + task = "backup"; + retain = 2; # We don't need many, as we also make Borg backups. + concurrency = 1; + }; + + ipAddressPools.main.spec.addresses = [ "192.168.30.128-192.168.30.200" "2a0d:6e00:1a77:30::2-2a0d:6e00:1a77:30:ffff:ffff:ffff:fffe" ]; + l2Advertisements.main.metadata = { }; + + persistentVolumes = { + music-syncthing.spec = { + capacity.storage = "1Gi"; + accessModes = [ "ReadWriteMany" ]; + + nfs = { + server = "lewis.dmz"; + path = "/mnt/longhorn/persistent/media/music"; + }; + }; + + media-media.spec = { + capacity.storage = "1Gi"; + accessModes = [ "ReadWriteMany" ]; + + nfs = { + server = "lewis.dmz"; + path = "/mnt/longhorn/persistent/media"; + }; + }; + }; + }; + }; + + lab = { + longhorn.persistentVolume = { + freshrss.storage = "1Gi"; + radicale.storage = "200Mi"; + atuin.storage = "300Mi"; + atuin-db.storage = "300Mi"; + nextcloud.storage = "50Gi"; + nextcloud-db.storage = "400Mi"; + hedgedoc-uploads.storage = "50Mi"; + hedgedoc-db.storage = "100Mi"; + kitchenowl.storage = "100Mi"; + forgejo.storage = "20Gi"; + paperless-data.storage = "10Gi"; + paperless-redisdata.storage = "20Mi"; + paperless-db.storage = "150Mi"; + syncthing.storage = "400Mi"; + pihole-data.storage = "750Mi"; + pihole-dnsmasq.storage = "16Mi"; + immich.storage = "50Gi"; + immich-db.storage = "5Gi"; + attic.storage = "15Gi"; + attic-db.storage = "150Mi"; + jellyfin.storage = "5Gi"; + transmission.storage = "25Mi"; + jellyseerr.storage = "75Mi"; + radarr.storage = "300Mi"; + prowlarr.storage = "150Mi"; + sonarr.storage = "150Mi"; + bazarr.storage = "25Mi"; + minecraft.storage = "1Gi"; + }; + }; +} diff --git a/kubenix-modules/bootstrapKubeSystem.nix b/kubenix-modules/bootstrapKubeSystem.nix new file mode 100644 index 0000000..43db164 --- /dev/null +++ b/kubenix-modules/bootstrapKubeSystem.nix @@ -0,0 +1,36 @@ +{ nixhelm, system, ... }: { + kubernetes = { + # TODO: These were copied from https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.crds.yaml + # See https://cert-manager.io/docs/installation/helm/ + # Seems kubenix cannot import a list of resources, only individual resources. + # Might be good to create a PR for this. + imports = [ + ./cert-manager-manifests/certificaterequest.yaml + ./cert-manager-manifests/certificate.yaml + ./cert-manager-manifests/challenge.yaml + ./cert-manager-manifests/clusterissuer.yaml + ./cert-manager-manifests/issuer.yaml + ./cert-manager-manifests/order.yaml + ]; + + helm.releases = { + cert-manager = { + chart = nixhelm.chartsDerivations.${system}.jetstack.cert-manager; + includeCRDs = false; + namespace = "kube-system"; + }; + }; + + resources.clusterIssuers.letsencrypt = { + spec.acme = { + server = "https://acme-v02.api.letsencrypt.org/directory"; + email = "pim@kunis.nl"; + privateKeySecretRef.name = "letsencrypt-private-key"; + solvers = [{ + selector = { }; + http01.ingress.class = "traefik"; + }]; + }; + }; + }; +} diff --git a/kubenix-modules/cert-manager.nix b/kubenix-modules/cert-manager.nix deleted file mode 100644 index ff3dbd1..0000000 --- a/kubenix-modules/cert-manager.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ - kubernetes.resources.clusterIssuers.letsencrypt = { - metadata.namespace = "kube-system"; - - spec.acme = { - server = "https://acme-v02.api.letsencrypt.org/directory"; - email = "pim@kunis.nl"; - privateKeySecretRef.name = "letsencrypt-private-key"; - solvers = [{ - selector = { }; - http01.ingress.class = "traefik"; - }]; - }; - }; -} diff --git a/kubenix-modules/longhorn.nix b/kubenix-modules/longhorn.nix deleted file mode 100644 index 48cb659..0000000 --- a/kubenix-modules/longhorn.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ lib, nixhelm, system, ... }: { - config = { - kubernetes = { - resources = { - ingresses.longhorn = { - metadata.annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt"; - "traefik.ingress.kubernetes.io/router.entrypoints" = "localsecure"; - }; - - spec = { - ingressClassName = "traefik"; - - rules = [{ - host = "longhorn.kun.is"; - - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = "longhorn-frontend"; - port.number = 80; - }; - }]; - }]; - - tls = [{ - secretName = "longhorn-tls"; - hosts = [ "longhorn.kun.is" ]; - }]; - }; - }; - - recurringJobs.backup-nfs.spec = { - cron = "0 1 * * *"; # One o'clock at night - task = "backup"; - retain = 2; # We don't need many, as we also make Borg backups. - concurrency = 1; - }; - }; - }; - }; -} diff --git a/kubenix-modules/metallb.nix b/kubenix-modules/metallb.nix deleted file mode 100644 index 4adc926..0000000 --- a/kubenix-modules/metallb.nix +++ /dev/null @@ -1,7 +0,0 @@ -# TODO: These resources should probably exist within the kube-system namespace. -{ - kubernetes.resources = { - ipAddressPools.main.spec.addresses = [ "192.168.30.128-192.168.30.200" "2a0d:6e00:1a77:30::2-2a0d:6e00:1a77:30:ffff:ffff:ffff:fffe" ]; - l2Advertisements.main.metadata = { }; - }; -} diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index 293ac24..36f49ec 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -2,13 +2,10 @@ kubernetes.resources = { helmChartConfigs = { traefik = { - metadata.namespace = lib.mkForce "kube-system"; - # Override Traefik's service with a static load balancer IP. # Create endpoint for HTTPS on port 444. # Allow external name services for servers in LAN. spec.valuesContent = lib.generators.toYAML { } { - # service.annotations."metallb.universe.tf/loadBalancerIPs" = myLib.globals.traefikIPv4; providers.kubernetesIngress.allowExternalNameServices = true; service.loadBalancerIP = myLib.globals.traefikIPv4; diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix deleted file mode 100644 index 8623b1a..0000000 --- a/kubenix-modules/volumes.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ - # kubernetes.resources.pods.testje.spec = { - # containers.testje = { - # image = "nginx"; - - # volumeMounts = [ - - # { name = "freshrss"; mountPath = "/freshrss"; } - # ]; - # }; - - # volumes.freshrss.persistentVolumeClaim.claimName = "freshrss"; - # }; - - kubernetes.resources.persistentVolumes = { - music-syncthing.spec = { - capacity.storage = "1Gi"; - accessModes = [ "ReadWriteMany" ]; - - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/media/music"; - }; - }; - - media-media.spec = { - capacity.storage = "1Gi"; - accessModes = [ "ReadWriteMany" ]; - - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/media"; - }; - }; - }; - - lab = { - longhorn.persistentVolume = { - freshrss.storage = "1Gi"; - radicale.storage = "200Mi"; - atuin.storage = "300Mi"; - atuin-db.storage = "300Mi"; - nextcloud.storage = "50Gi"; - nextcloud-db.storage = "400Mi"; - hedgedoc-uploads.storage = "50Mi"; - hedgedoc-db.storage = "100Mi"; - kitchenowl.storage = "100Mi"; - forgejo.storage = "20Gi"; - paperless-data.storage = "10Gi"; - paperless-redisdata.storage = "20Mi"; - paperless-db.storage = "150Mi"; - syncthing.storage = "400Mi"; - pihole-data.storage = "750Mi"; - pihole-dnsmasq.storage = "16Mi"; - immich.storage = "50Gi"; - immich-db.storage = "5Gi"; - attic.storage = "15Gi"; - attic-db.storage = "150Mi"; - jellyfin.storage = "5Gi"; - transmission.storage = "25Mi"; - jellyseerr.storage = "75Mi"; - radarr.storage = "300Mi"; - prowlarr.storage = "150Mi"; - sonarr.storage = "150Mi"; - bazarr.storage = "25Mi"; - minecraft.storage = "1Gi"; - }; - }; -} From 7a407389891921f8cc0fd9c0218e0560a5028dec Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 17:20:39 +0200 Subject: [PATCH 039/108] refactor(cert-manager): Consolidate NixOS module --- flake-parts/kubenix.nix | 4 ++-- .../{bootstrapDefault.nix => bootstrap-default.nix} | 0 kubenix-modules/bootstrap-kube-system.nix | 5 +++++ .../default.nix} | 12 ++++++------ .../manifests}/certificate.yaml | 0 .../manifests}/certificaterequest.yaml | 0 .../manifests}/challenge.yaml | 0 .../manifests}/clusterissuer.yaml | 0 .../manifests}/issuer.yaml | 0 .../manifests}/order.yaml | 0 10 files changed, 13 insertions(+), 8 deletions(-) rename kubenix-modules/{bootstrapDefault.nix => bootstrap-default.nix} (100%) create mode 100644 kubenix-modules/bootstrap-kube-system.nix rename kubenix-modules/{bootstrapKubeSystem.nix => cert-manager/default.nix} (76%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/certificate.yaml (100%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/certificaterequest.yaml (100%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/challenge.yaml (100%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/clusterissuer.yaml (100%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/issuer.yaml (100%) rename kubenix-modules/{cert-manager-manifests => cert-manager/manifests}/order.yaml (100%) diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 320731b..6645ca3 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -58,12 +58,12 @@ deployers = { bootstrap-default = { - module = "${self}/kubenix-modules/bootstrapDefault.nix"; + module = "${self}/kubenix-modules/bootstrap-default.nix"; namespace = "default"; }; bootstrap-kube-system = { - module = "${self}/kubenix-modules/bootstrapKubeSystem.nix"; + module = "${self}/kubenix-modules/bootstrap-kube-system.nix"; namespace = "kube-system"; }; diff --git a/kubenix-modules/bootstrapDefault.nix b/kubenix-modules/bootstrap-default.nix similarity index 100% rename from kubenix-modules/bootstrapDefault.nix rename to kubenix-modules/bootstrap-default.nix diff --git a/kubenix-modules/bootstrap-kube-system.nix b/kubenix-modules/bootstrap-kube-system.nix new file mode 100644 index 0000000..1e2ed59 --- /dev/null +++ b/kubenix-modules/bootstrap-kube-system.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./cert-manager + ]; +} diff --git a/kubenix-modules/bootstrapKubeSystem.nix b/kubenix-modules/cert-manager/default.nix similarity index 76% rename from kubenix-modules/bootstrapKubeSystem.nix rename to kubenix-modules/cert-manager/default.nix index 43db164..81570a6 100644 --- a/kubenix-modules/bootstrapKubeSystem.nix +++ b/kubenix-modules/cert-manager/default.nix @@ -5,12 +5,12 @@ # Seems kubenix cannot import a list of resources, only individual resources. # Might be good to create a PR for this. imports = [ - ./cert-manager-manifests/certificaterequest.yaml - ./cert-manager-manifests/certificate.yaml - ./cert-manager-manifests/challenge.yaml - ./cert-manager-manifests/clusterissuer.yaml - ./cert-manager-manifests/issuer.yaml - ./cert-manager-manifests/order.yaml + ./manifests/certificaterequest.yaml + ./manifests/certificate.yaml + ./manifests/challenge.yaml + ./manifests/clusterissuer.yaml + ./manifests/issuer.yaml + ./manifests/order.yaml ]; helm.releases = { diff --git a/kubenix-modules/cert-manager-manifests/certificate.yaml b/kubenix-modules/cert-manager/manifests/certificate.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/certificate.yaml rename to kubenix-modules/cert-manager/manifests/certificate.yaml diff --git a/kubenix-modules/cert-manager-manifests/certificaterequest.yaml b/kubenix-modules/cert-manager/manifests/certificaterequest.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/certificaterequest.yaml rename to kubenix-modules/cert-manager/manifests/certificaterequest.yaml diff --git a/kubenix-modules/cert-manager-manifests/challenge.yaml b/kubenix-modules/cert-manager/manifests/challenge.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/challenge.yaml rename to kubenix-modules/cert-manager/manifests/challenge.yaml diff --git a/kubenix-modules/cert-manager-manifests/clusterissuer.yaml b/kubenix-modules/cert-manager/manifests/clusterissuer.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/clusterissuer.yaml rename to kubenix-modules/cert-manager/manifests/clusterissuer.yaml diff --git a/kubenix-modules/cert-manager-manifests/issuer.yaml b/kubenix-modules/cert-manager/manifests/issuer.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/issuer.yaml rename to kubenix-modules/cert-manager/manifests/issuer.yaml diff --git a/kubenix-modules/cert-manager-manifests/order.yaml b/kubenix-modules/cert-manager/manifests/order.yaml similarity index 100% rename from kubenix-modules/cert-manager-manifests/order.yaml rename to kubenix-modules/cert-manager/manifests/order.yaml From 835aea667c900ab2f9c4f31510b7c4905cf9a9f8 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 17 Jul 2024 18:20:49 +0200 Subject: [PATCH 040/108] refactor(flake): Improve flake outputs for k8s scripts and manifests docs(readme): Update k8s deployment instructions --- README.md | 38 +++------- .../{kubenix-deploy.sh => applyset-deploy.sh} | 0 flake-parts/kubenix.nix | 70 ++++++++++--------- 3 files changed, 48 insertions(+), 60 deletions(-) rename flake-parts/{kubenix-deploy.sh => applyset-deploy.sh} (100%) diff --git a/README.md b/README.md index 93c190c..6b74f72 100644 --- a/README.md +++ b/README.md @@ -43,36 +43,18 @@ To deploy to the Kubernetes cluster, first make sure you have an admin account o You can generate this using `nix run '.#gen-k3s-cert' ~/.kube`, assuming you have SSH access to the master node. This puts a private key, signed certificate and a kubeconfig in the kubeconfig directory -If the cluster has not been initialized yet, next run `nix run '.#kubenix.x86_64-linux.bootstrap.deploy'`. +We are now ready to deploy to the Kubernetes cluster. +Deployments are done through an experimental Kubernetes feature called [ApplySets](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-delete-objects). +Each applyset is responsible for a set number of resources within a namespace. -Applications are currently deployed in two method: - - A single big deployment of many applications (which I am trying to move away from) - - A separate deployment for each application using [ApplySets](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-delete-objects) +If the cluster has not been initialized yet, we must bootstrap it first. +Run these deployments: +- `nix run '.#bootstrap-default.deploy'` +- `nix run '.#bootstrap-kube-system.deploy'` -The first method: `nix run '.#kubenix.x86_64-linux.all.deploy'` -The second method: `nix run '.#kubenix.x86_64-linux..deploy'` -Currently, the applications being deployed like this are: -- `cyberchef` -- `freshrss` -- `radicale` -- `kms` -- `atuin` -- `blog` -- `nextcloud` -- `hedgedoc` -- `kitchenowl` -- `forgejo` -- `paperless-ngx` -- `syncthing` -- `pihole` -- `immich` -- `attic` -- `inbucket` -- `dnsmasq` -- `bind9` -- `media` -- `traefik` -- `minecraft` +Now the cluster has been initialized and we can deploy applications. +To explore which applications we can deploy, run `nix flake show`. +Then, for each application, run `nix run '.#.deploy'`. ## Known bugs diff --git a/flake-parts/kubenix-deploy.sh b/flake-parts/applyset-deploy.sh similarity index 100% rename from flake-parts/kubenix-deploy.sh rename to flake-parts/applyset-deploy.sh diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 6645ca3..81223c5 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -1,59 +1,64 @@ { self, pkgs, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem (system: let - deployScript = (pkgs.writeScriptBin "kubenix" (builtins.readFile ./kubenix-deploy.sh)).overrideAttrs (old: { + deployScript = (pkgs.writeScriptBin "applyset-deploy.sh" (builtins.readFile ./applyset-deploy.sh)).overrideAttrs (old: { buildCommand = "${old.buildCommand}\npatchShebangs $out"; }); - mkDeployScript = kubernetes: applysetName: namespace: + mkKubernetes = name: module: namespace: (kubenix.evalModules.${system} { + specialArgs = { inherit namespace myLib blog-pim dns nixhelm system machines; }; + + module = { kubenix, ... }: + { + imports = [ + kubenix.modules.k8s + kubenix.modules.helm + "${self}/kubenix-modules/custom" + "${self}/kubenix-modules/custom-types.nix" + module + ]; + + config = { + kubenix.project = name; + kubernetes.namespace = namespace; + }; + }; + }).config.kubernetes; + + mkManifest = name: { module, namespace }: + { + manifest = (mkKubernetes name module namespace).result; + }; + + mkDeployApp = name: { module, namespace }: let + kubernetes = mkKubernetes name module namespace; kubeconfig = kubernetes.kubeconfig or ""; result = kubernetes.result or ""; wrappedDeployScript = pkgs.symlinkJoin { - name = "kubenix"; + name = "applyset-deploy.sh"; paths = [ deployScript pkgs.vals pkgs.kubectl ]; buildInputs = [ pkgs.makeWrapper ]; passthru.manifest = result; + meta.mainProgram = "applyset-deploy.sh"; postBuild = '' - wrapProgram $out/bin/kubenix \ + wrapProgram $out/bin/applyset-deploy.sh \ --suffix PATH : "$out/bin" \ --run 'export KUBECONFIG=''${KUBECONFIG:-${toString kubeconfig}}' \ --set MANIFEST '${result}' \ - --set APPLYSET 'applyset-${applysetName}' \ + --set APPLYSET 'applyset-${name}' \ --set NAMESPACE '${namespace}' ''; }; in - wrappedDeployScript; - - mkDeployScriptAndManifest = name: { module, namespace }: - let - kubernetes = (kubenix.evalModules.${system} { - specialArgs = { inherit namespace myLib blog-pim dns nixhelm system machines; }; - - module = { kubenix, ... }: - { - imports = [ - kubenix.modules.k8s - kubenix.modules.helm - "${self}/kubenix-modules/custom" - "${self}/kubenix-modules/custom-types.nix" - module - ]; - - config = { - kubenix.project = name; - kubernetes.namespace = namespace; - }; - }; - }).config.kubernetes; - in { - manifest = kubernetes.result; - deploy = mkDeployScript kubernetes name namespace; + deploy = { + type = "app"; + program = "${pkgs.lib.getExe wrappedDeployScript}"; + }; }; deployers = { @@ -174,5 +179,6 @@ }; in { - kubenix = builtins.mapAttrs mkDeployScriptAndManifest deployers; + apps = builtins.mapAttrs mkDeployApp deployers; + packages = builtins.mapAttrs mkManifest deployers; }) From 0f2a90ec8aa203ef6de7af3e66a84925da5747e2 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 15:05:27 +0200 Subject: [PATCH 041/108] feat(inbucket): Expose on tailnet --- kubenix-modules/bootstrap-default.nix | 5 -- kubenix-modules/custom/default.nix | 1 - kubenix-modules/custom/nfs-volume.nix | 47 -------------- kubenix-modules/inbucket.nix | 88 +++++++++++++++++++++------ my-lib/globals.nix | 3 +- secrets/kubernetes.yaml | 6 +- 6 files changed, 77 insertions(+), 73 deletions(-) delete mode 100644 kubenix-modules/custom/nfs-volume.nix diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index e581c96..f1828b2 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -27,11 +27,6 @@ }; }; }; - - # argo-workflows = { - # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; - # includeCRDs = true; - # }; }; resources = { diff --git a/kubenix-modules/custom/default.nix b/kubenix-modules/custom/default.nix index d21b916..a1dc536 100644 --- a/kubenix-modules/custom/default.nix +++ b/kubenix-modules/custom/default.nix @@ -2,6 +2,5 @@ imports = [ ./ingress.nix ./longhorn-volume.nix - ./nfs-volume.nix ]; } diff --git a/kubenix-modules/custom/nfs-volume.nix b/kubenix-modules/custom/nfs-volume.nix deleted file mode 100644 index 804cc7e..0000000 --- a/kubenix-modules/custom/nfs-volume.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ lib, config, ... }: -let - nfsVolumeOpts = { name, ... }: { - options = { - path = lib.mkOption { - type = lib.types.str; - }; - }; - }; -in -{ - options = { - lab.nfsVolumes = lib.mkOption { - type = with lib.types; attrsOf (submodule nfsVolumeOpts); - default = { }; - }; - }; - - config = { - kubernetes.resources = { - persistentVolumes = builtins.mapAttrs - (name: nfsVolume: { - spec = { - capacity.storage = "1Mi"; - accessModes = [ "ReadWriteMany" ]; - - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/${nfsVolume.path}"; - }; - }; - }) - config.lab.nfsVolumes; - - persistentVolumeClaims = builtins.mapAttrs - (name: nfsVolume: { - spec = { - accessModes = [ "ReadWriteMany" ]; - storageClassName = ""; - resources.requests.storage = "1Mi"; - volumeName = name; - }; - }) - config.lab.nfsVolumes; - }; - }; -} diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 80033f8..5e5b2b3 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -1,5 +1,42 @@ -{ myLib, ... }: { +{ myLib, ... }: +let + # TODO: make module of this. + tailscaleSecretName = "tailscale-auth"; + inbucketSAName = "inbucket"; +in +{ kubernetes.resources = { + secrets.${tailscaleSecretName}.stringData.TS_AUTHKEY = "ref+sops://secrets/kubernetes.yaml#/tailscale/authKey"; + + roles.tailscale.rules = [ + { + apiGroups = [ "" ]; + resources = [ "secrets" ]; + verbs = [ "create" ]; + } + { + apiGroups = [ "" ]; + resourceNames = [ tailscaleSecretName ]; + resources = [ "secrets" ]; + verbs = [ "get" "update" "patch" ]; + } + ]; + + roleBindings.inbucket-tailscale = { + subjects = [{ + kind = "ServiceAccount"; + name = inbucketSAName; + }]; + + roleRef = { + kind = "Role"; + name = "tailscale"; + apiGroup = "rbac.authorization.k8s.io"; + }; + }; + + serviceAccounts.${inbucketSAName} = { }; + deployments.inbucket.spec = { selector.matchLabels.app = "inbucket"; @@ -7,12 +44,37 @@ metadata.labels.app = "inbucket"; spec = { - containers.inbucket = { - image = "inbucket/inbucket:edge"; + serviceAccountName = inbucketSAName; - ports = { - web.containerPort = 9000; - smtp.containerPort = 2500; + containers = { + inbucket = { + image = "inbucket/inbucket:edge"; + + env.INBUCKET_WEB_ADDR.value = "0.0.0.0:80"; + + ports = { + web.containerPort = 80; + smtp.containerPort = 2500; + }; + }; + + tailscale-sidecar = { + imagePullPolicy = "Always"; + image = "ghcr.io/tailscale/tailscale:latest"; + + env = { + TS_HOSTNAME.value = "inbucket"; + TS_KUBE_SECRET.value = tailscaleSecretName; + TS_USERSPACE.value = "false"; + TS_DEBUG_FIREWALL_MODE.value = "auto"; + TS_AUTHKEY.valueFrom.secretKeyRef = { + name = tailscaleSecretName; + key = "TS_AUTHKEY"; + optional = true; + }; + }; + + securityContext.capabilities.add = [ "NET_ADMIN" ]; }; }; }; @@ -21,6 +83,8 @@ services = { web.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.inbucketWebIPv4; selector.app = "inbucket"; ports.web = { @@ -31,7 +95,7 @@ email.spec = { type = "LoadBalancer"; - loadBalancerIP = myLib.globals.inbucketIPv4; + loadBalancerIP = myLib.globals.inbucketEmailIPv4; selector.app = "inbucket"; ports = [{ @@ -41,14 +105,4 @@ }; }; }; - - lab.ingresses.inbucket = { - host = "inbucket.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "web"; - portName = "web"; - }; - }; } diff --git a/my-lib/globals.nix b/my-lib/globals.nix index e070cc1..049c883 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -8,7 +8,8 @@ bittorrentIPv4 = "192.168.30.133"; gitIPv4 = "192.168.30.132"; piholeIPv4 = "192.168.30.131"; - inbucketIPv4 = "192.168.30.130"; + inbucketEmailIPv4 = "192.168.30.130"; kmsIPv4 = "192.168.30.129"; traefikIPv4 = "192.168.30.128"; + inbucketWebIPv4 = "192.168.30.137"; } diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index 6fa7adf..a3847d3 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -26,6 +26,8 @@ atuin: databasePassword: ENC[AES256_GCM,data:qfWOmFfBOuguOfb1Z51F527ic3o=,iv:4Yx5rpzZHzRlfvZydcBNFRStEO0P4uIcjDqxgRgQmHE=,tag:pbJXcUdvul7nCrXQ9ylAdQ==,type:str] immich: databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] +tailscale: + authKey: ENC[AES256_GCM,data:pBbrL6/HVxDgvEeVHdnH6O3YsUB4tpRCO7SacYxSunDcMg8xcIXWWx1Zt65z9hcMcW/2AZbXC8mh+UPBRw==,iv:tTXdEAgCAHL46nN6yO0QNwJ0DUltAmQ/359TzuqXrpI=,tag:F7DtCigCRhdPBgMK3ZzV7g==,type:str] sops: kms: [] gcp_kms: [] @@ -50,8 +52,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-16T16:10:38Z" - mac: ENC[AES256_GCM,data:VL8fsI2LWvXttPJDi+3TVBec/Ot4CFSM8MWVWu81YJAkG0V7FpUcmJ44PaaknzyISpZGo5hmpJOx8c/ad3CO5Mq1ZIGCf/vyN6iGHFD3tEOsxlp4puJcsoNgM2my5tQ7mRjNZrvgrmoDYinsFRHT+u0DWOcL8A8g8fLOOd/T5KA=,iv:KRW+aFyyYd/S9SMA19GiTQqDyk4b9CdgL5fNqvG9Kew=,tag:8sCbi0s4SJa38sX00qKb8g==,type:str] + lastmodified: "2024-07-18T09:03:54Z" + mac: ENC[AES256_GCM,data:BEgztutw7barzGcbx5hkfAnauPv2H4nvwZM5iUfPJcjOkPsKTVwYAcdDdJE8wL2Nc9b4iIGSRwf9fwizyaerPR6SFt1zNHgbQz0DbUz+j/bUIXwKBSQNgK0KjiX8ONyFK62OxAhEa600OUV0cqWURUwRl+F8fRQSqQCvKuREVyE=,iv:ZMj4NAVI94bM/HwYSkZIN9hRPXWR1miIld57EeC+ckk=,tag:wy2ENtExu2mtpFPc/jy+nw==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 6f3a7a3c44183dc1033282e9e9acc16718a1c0a1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 16:26:21 +0200 Subject: [PATCH 042/108] refactor(tailscale): Modularize Tailscale k8s config --- kubenix-modules/custom/default.nix | 1 + kubenix-modules/custom/tailscale.nix | 91 ++++++++++++++++++++++++++++ kubenix-modules/inbucket.nix | 66 +++----------------- 3 files changed, 101 insertions(+), 57 deletions(-) create mode 100644 kubenix-modules/custom/tailscale.nix diff --git a/kubenix-modules/custom/default.nix b/kubenix-modules/custom/default.nix index a1dc536..f5cc500 100644 --- a/kubenix-modules/custom/default.nix +++ b/kubenix-modules/custom/default.nix @@ -2,5 +2,6 @@ imports = [ ./ingress.nix ./longhorn-volume.nix + ./tailscale.nix ]; } diff --git a/kubenix-modules/custom/tailscale.nix b/kubenix-modules/custom/tailscale.nix new file mode 100644 index 0000000..e5b1142 --- /dev/null +++ b/kubenix-modules/custom/tailscale.nix @@ -0,0 +1,91 @@ +{ lib, config, ... }: +let + cfg = config.lab.tailscale; + secretName = "tailscale-auth"; + roleName = "tailscale"; + sidecarContainername = "tailscale-sidecar"; +in +{ + options = with lib.types; { + lab.tailscale = { + enable = lib.mkEnableOption "tailscale"; + + allowedServiceAccounts = lib.mkOption { + type = listOf str; + + description = '' + Allow specified service accounts to manage Tailscale authentication. + ''; + }; + + deploymentsWithSidecarContainers = lib.mkOption { + type = attrsOf (submodule ({ name, ... }: { + options.hostName = lib.mkOption { type = str; }; + })); + }; + }; + }; + + config = + let + mkRoleBinding = name: { + name = "${name}-${roleName}"; + value = { + subjects = [{ + inherit name; + kind = "ServiceAccount"; + }]; + + roleRef = { + kind = "Role"; + name = roleName; + apiGroup = "rbac.authorization.k8s.io"; + }; + }; + }; + + mkSidecarContainer = name: { hostName, ... }: { + spec.template.spec.containers.${sidecarContainername} = { + imagePullPolicy = "Always"; + image = "ghcr.io/tailscale/tailscale:latest"; + + env = { + TS_HOSTNAME.value = hostName; + TS_KUBE_SECRET.value = secretName; + TS_USERSPACE.value = "false"; + TS_DEBUG_FIREWALL_MODE.value = "auto"; + TS_AUTHKEY.valueFrom.secretKeyRef = { + name = secretName; + key = "TS_AUTHKEY"; + optional = true; + }; + }; + + securityContext.capabilities.add = [ "NET_ADMIN" ]; + }; + }; + in + { + kubernetes.resources = lib.mkIf cfg.enable { + secrets.${secretName}.stringData.TS_AUTHKEY = "ref+sops://secrets/kubernetes.yaml#/tailscale/authKey"; + + roles.${roleName}.rules = [ + { + apiGroups = [ "" ]; + resources = [ "secrets" ]; + verbs = [ "create" ]; + } + { + apiGroups = [ "" ]; + resourceNames = [ secretName ]; + resources = [ "secrets" ]; + verbs = [ "get" "update" "patch" ]; + } + ]; + + roleBindings = builtins.listToAttrs (map mkRoleBinding cfg.allowedServiceAccounts); + + deployments = builtins.mapAttrs mkSidecarContainer cfg.deploymentsWithSidecarContainers; + }; + }; +} diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 5e5b2b3..26676ea 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -1,41 +1,6 @@ -{ myLib, ... }: -let - # TODO: make module of this. - tailscaleSecretName = "tailscale-auth"; - inbucketSAName = "inbucket"; -in -{ +{ myLib, ... }: { kubernetes.resources = { - secrets.${tailscaleSecretName}.stringData.TS_AUTHKEY = "ref+sops://secrets/kubernetes.yaml#/tailscale/authKey"; - - roles.tailscale.rules = [ - { - apiGroups = [ "" ]; - resources = [ "secrets" ]; - verbs = [ "create" ]; - } - { - apiGroups = [ "" ]; - resourceNames = [ tailscaleSecretName ]; - resources = [ "secrets" ]; - verbs = [ "get" "update" "patch" ]; - } - ]; - - roleBindings.inbucket-tailscale = { - subjects = [{ - kind = "ServiceAccount"; - name = inbucketSAName; - }]; - - roleRef = { - kind = "Role"; - name = "tailscale"; - apiGroup = "rbac.authorization.k8s.io"; - }; - }; - - serviceAccounts.${inbucketSAName} = { }; + serviceAccounts.inbucket = { }; deployments.inbucket.spec = { selector.matchLabels.app = "inbucket"; @@ -44,7 +9,7 @@ in metadata.labels.app = "inbucket"; spec = { - serviceAccountName = inbucketSAName; + serviceAccountName = "inbucket"; containers = { inbucket = { @@ -57,25 +22,6 @@ in smtp.containerPort = 2500; }; }; - - tailscale-sidecar = { - imagePullPolicy = "Always"; - image = "ghcr.io/tailscale/tailscale:latest"; - - env = { - TS_HOSTNAME.value = "inbucket"; - TS_KUBE_SECRET.value = tailscaleSecretName; - TS_USERSPACE.value = "false"; - TS_DEBUG_FIREWALL_MODE.value = "auto"; - TS_AUTHKEY.valueFrom.secretKeyRef = { - name = tailscaleSecretName; - key = "TS_AUTHKEY"; - optional = true; - }; - }; - - securityContext.capabilities.add = [ "NET_ADMIN" ]; - }; }; }; }; @@ -105,4 +51,10 @@ in }; }; }; + + lab.tailscale = { + enable = true; + allowedServiceAccounts = [ "inbucket" ]; + deploymentsWithSidecarContainers.inbucket.hostName = "inbucket"; + }; } From 8fc6961362a73fd31633e28b0c42608c0181a11f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 16:50:52 +0200 Subject: [PATCH 043/108] feat(syncthing): Only expose on tailnet --- kubenix-modules/syncthing.nix | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index 4d46388..472cfdf 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -1,15 +1,29 @@ { kubernetes.resources = { + serviceAccounts.syncthing = { }; + deployments.syncthing.spec = { selector.matchLabels.app = "syncthing"; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels.app = "syncthing"; spec = { + serviceAccountName = "syncthing"; + containers.syncthing = { image = "lscr.io/linuxserver/syncthing:1.23.6"; ports.web.containerPort = 8384; + imagePullPolicy = "Always"; env = { PUID.value = "33"; @@ -60,19 +74,15 @@ }; lab = { - ingresses.syncthing = { - host = "sync.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "syncthing"; - portName = "web"; - }; - }; - longhorn.persistentVolumeClaim.config = { volumeName = "syncthing"; storage = "400Mi"; }; + + tailscale = { + enable = true; + allowedServiceAccounts = [ "syncthing" ]; + deploymentsWithSidecarContainers.syncthing.hostName = "syncthing"; + }; }; } From cb6b883f6e48d90b80d5c75a37db1aca41261e62 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 19:47:22 +0200 Subject: [PATCH 044/108] feat(tailscale): Install k8s operator --- flake-parts/kubenix.nix | 5 ++ kubenix-modules/bootstrap-default.nix | 2 +- kubenix-modules/custom/tailscale.nix | 109 ++++++++------------------ kubenix-modules/inbucket.nix | 11 +-- kubenix-modules/syncthing.nix | 7 +- kubenix-modules/tailscale.nix | 14 ++++ secrets/kubernetes.yaml | 7 +- 7 files changed, 66 insertions(+), 89 deletions(-) create mode 100644 kubenix-modules/tailscale.nix diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 81223c5..76cfa53 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -176,6 +176,11 @@ module = "${self}/kubenix-modules/minecraft.nix"; namespace = "minecraft"; }; + + tailscale = { + module = "${self}/kubenix-modules/tailscale.nix"; + namespace = "tailscale"; + }; }; in { diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index f1828b2..4f5d9ba 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -1,6 +1,5 @@ { lib, nixhelm, system, machines, ... }: { kubernetes = { - helm.releases = { metallb = { chart = nixhelm.chartsDerivations.${system}.metallb.metallb; @@ -48,6 +47,7 @@ dns = { }; media = { }; minecraft = { }; + tailscale = { }; }; nodes = diff --git a/kubenix-modules/custom/tailscale.nix b/kubenix-modules/custom/tailscale.nix index e5b1142..0789c6c 100644 --- a/kubenix-modules/custom/tailscale.nix +++ b/kubenix-modules/custom/tailscale.nix @@ -1,91 +1,50 @@ -{ lib, config, ... }: -let - cfg = config.lab.tailscale; - secretName = "tailscale-auth"; - roleName = "tailscale"; - sidecarContainername = "tailscale-sidecar"; -in -{ +{ lib, config, ... }: { options = with lib.types; { - lab.tailscale = { - enable = lib.mkEnableOption "tailscale"; + lab.tailscaleIngresses = lib.mkOption { + type = attrsOf (submodule { + options = { + host = lib.mkOption { type = str; }; - allowedServiceAccounts = lib.mkOption { - type = listOf str; + service = { + name = lib.mkOption { type = str; }; - description = '' - Allow specified service accounts to manage Tailscale authentication. - ''; - }; - - deploymentsWithSidecarContainers = lib.mkOption { - type = attrsOf (submodule ({ name, ... }: { - options.hostName = lib.mkOption { type = str; }; - })); - }; + portName = lib.mkOption { + type = str; + default = "web"; + }; + }; + }; + }); }; }; config = let - mkRoleBinding = name: { - name = "${name}-${roleName}"; - value = { - subjects = [{ - inherit name; - kind = "ServiceAccount"; + cfg = config.lab.tailscaleIngresses; + + mkTailscaleIngress = name: { host, service }: { + spec = { + ingressClassName = "tailscale"; + + rules = [{ + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = service.name; + port.name = service.portName; + }; + }]; }]; - roleRef = { - kind = "Role"; - name = roleName; - apiGroup = "rbac.authorization.k8s.io"; - }; - }; - }; - - mkSidecarContainer = name: { hostName, ... }: { - spec.template.spec.containers.${sidecarContainername} = { - imagePullPolicy = "Always"; - image = "ghcr.io/tailscale/tailscale:latest"; - - env = { - TS_HOSTNAME.value = hostName; - TS_KUBE_SECRET.value = secretName; - TS_USERSPACE.value = "false"; - TS_DEBUG_FIREWALL_MODE.value = "auto"; - TS_AUTHKEY.valueFrom.secretKeyRef = { - name = secretName; - key = "TS_AUTHKEY"; - optional = true; - }; - }; - - securityContext.capabilities.add = [ "NET_ADMIN" ]; + tls = [{ + hosts = [ host ]; + }]; }; }; in { - kubernetes.resources = lib.mkIf cfg.enable { - secrets.${secretName}.stringData.TS_AUTHKEY = "ref+sops://secrets/kubernetes.yaml#/tailscale/authKey"; - - roles.${roleName}.rules = [ - { - apiGroups = [ "" ]; - resources = [ "secrets" ]; - verbs = [ "create" ]; - } - { - apiGroups = [ "" ]; - resourceNames = [ secretName ]; - resources = [ "secrets" ]; - verbs = [ "get" "update" "patch" ]; - } - ]; - - roleBindings = builtins.listToAttrs (map mkRoleBinding cfg.allowedServiceAccounts); - - deployments = builtins.mapAttrs mkSidecarContainer cfg.deploymentsWithSidecarContainers; - }; + kubernetes.resources.ingresses = builtins.mapAttrs mkTailscaleIngress cfg; }; } diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 26676ea..aed9bac 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -15,10 +15,8 @@ inbucket = { image = "inbucket/inbucket:edge"; - env.INBUCKET_WEB_ADDR.value = "0.0.0.0:80"; - ports = { - web.containerPort = 80; + web.containerPort = 9000; smtp.containerPort = 2500; }; }; @@ -52,9 +50,8 @@ }; }; - lab.tailscale = { - enable = true; - allowedServiceAccounts = [ "inbucket" ]; - deploymentsWithSidecarContainers.inbucket.hostName = "inbucket"; + lab.tailscaleIngresses.tailscale = { + host = "inbucket"; + service.name = "web"; }; } diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index 472cfdf..de132c0 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -79,10 +79,9 @@ storage = "400Mi"; }; - tailscale = { - enable = true; - allowedServiceAccounts = [ "syncthing" ]; - deploymentsWithSidecarContainers.syncthing.hostName = "syncthing"; + tailscaleIngresses.tailscale = { + host = "sync"; + service.name = "syncthing"; }; }; } diff --git a/kubenix-modules/tailscale.nix b/kubenix-modules/tailscale.nix new file mode 100644 index 0000000..58a61fe --- /dev/null +++ b/kubenix-modules/tailscale.nix @@ -0,0 +1,14 @@ +{ nixhelm, system, ... }: { + kubernetes = { + helm.releases.tailscale = { + chart = nixhelm.chartsDerivations.${system}.tailscale.tailscale-operator; + includeCRDs = true; + namespace = "tailscale"; + }; + + resources.secrets.operator-oauth.stringData = { + client_id = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientID"; + client_secret = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientSecret"; + }; + }; +} diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index a3847d3..41de328 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -28,6 +28,9 @@ immich: databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] tailscale: authKey: ENC[AES256_GCM,data:pBbrL6/HVxDgvEeVHdnH6O3YsUB4tpRCO7SacYxSunDcMg8xcIXWWx1Zt65z9hcMcW/2AZbXC8mh+UPBRw==,iv:tTXdEAgCAHL46nN6yO0QNwJ0DUltAmQ/359TzuqXrpI=,tag:F7DtCigCRhdPBgMK3ZzV7g==,type:str] + oauth: + clientID: ENC[AES256_GCM,data:HLkgZ2q79LSBDCrwgzErNVE=,iv:/877rL2F/r4yxhGXaZW/TsbaU0arBKJiH9arTqfStrk=,tag:lVLJJ/D19FoSJXLu7S3ByQ==,type:str] + clientSecret: ENC[AES256_GCM,data:AsgE6KYXP8Z/2c4WdxWOou62txjz/TNarlQn6osebPB3czVVlGky4d4KcDE2cMgXqIEY3E/LNxbjMnfxIC9s,iv:EQDN/ECzIkKXtfj2DE0JtgXEpRMMEbYbfYDMxwXkx5E=,tag:NXwbzQv38njh+a5O8kQOag==,type:str] sops: kms: [] gcp_kms: [] @@ -52,8 +55,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-18T09:03:54Z" - mac: ENC[AES256_GCM,data:BEgztutw7barzGcbx5hkfAnauPv2H4nvwZM5iUfPJcjOkPsKTVwYAcdDdJE8wL2Nc9b4iIGSRwf9fwizyaerPR6SFt1zNHgbQz0DbUz+j/bUIXwKBSQNgK0KjiX8ONyFK62OxAhEa600OUV0cqWURUwRl+F8fRQSqQCvKuREVyE=,iv:ZMj4NAVI94bM/HwYSkZIN9hRPXWR1miIld57EeC+ckk=,tag:wy2ENtExu2mtpFPc/jy+nw==,type:str] + lastmodified: "2024-07-21T16:43:44Z" + mac: ENC[AES256_GCM,data:Gx9Zpdt/HzeYRj2ksmCGLaIJTcsfzxJklGdVNbtMIU888A32B72lAHfv0MbU5OBX0ZRt+VYDRncARSeTKPI3CGZu0qLtJwkDcVFGv+y+sea63DN8mmvNpYLQeif0daqE1GGMPVWukzV/2aBmfWbYBtHhm3C2v4f7KXobE83v3K0=,iv:bd+U7zyGOeH2Wq+y4RRv7kGfDkUGq1Kkfj4LOFdMJkY=,tag:5JkuFvY8kFfguBJoZfOnvg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 1ee68fc2a6461b0610a6ed214fb28b2bc8cd0001 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 19:48:42 +0200 Subject: [PATCH 045/108] refactor: Rename tailscale sops secrets --- kubenix-modules/tailscale.nix | 4 ++-- secrets/kubernetes.yaml | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/kubenix-modules/tailscale.nix b/kubenix-modules/tailscale.nix index 58a61fe..6181417 100644 --- a/kubenix-modules/tailscale.nix +++ b/kubenix-modules/tailscale.nix @@ -7,8 +7,8 @@ }; resources.secrets.operator-oauth.stringData = { - client_id = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientID"; - client_secret = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientSecret"; + client_id = "ref+sops://secrets/kubernetes.yaml#/tailscale/clientID"; + client_secret = "ref+sops://secrets/kubernetes.yaml#/tailscale/clientSecret"; }; }; } diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index 41de328..e38b0d3 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -27,10 +27,8 @@ atuin: immich: databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] tailscale: - authKey: ENC[AES256_GCM,data:pBbrL6/HVxDgvEeVHdnH6O3YsUB4tpRCO7SacYxSunDcMg8xcIXWWx1Zt65z9hcMcW/2AZbXC8mh+UPBRw==,iv:tTXdEAgCAHL46nN6yO0QNwJ0DUltAmQ/359TzuqXrpI=,tag:F7DtCigCRhdPBgMK3ZzV7g==,type:str] - oauth: - clientID: ENC[AES256_GCM,data:HLkgZ2q79LSBDCrwgzErNVE=,iv:/877rL2F/r4yxhGXaZW/TsbaU0arBKJiH9arTqfStrk=,tag:lVLJJ/D19FoSJXLu7S3ByQ==,type:str] - clientSecret: ENC[AES256_GCM,data:AsgE6KYXP8Z/2c4WdxWOou62txjz/TNarlQn6osebPB3czVVlGky4d4KcDE2cMgXqIEY3E/LNxbjMnfxIC9s,iv:EQDN/ECzIkKXtfj2DE0JtgXEpRMMEbYbfYDMxwXkx5E=,tag:NXwbzQv38njh+a5O8kQOag==,type:str] + clientID: ENC[AES256_GCM,data:p5gGizzxAsRpW/a9GAkFZnc=,iv:DBJbEy2GbYUxvsY1MlvlVsLR+/DH/FYlQJIyxbt457c=,tag:Glm3/25WLO1VwKHWCm8wMw==,type:str] + clientSecret: ENC[AES256_GCM,data:/rB7WGmo0uyszwtMR1yAFzJ8F8USw1P7Cx5rKwOWXxPFTWZ88EaKOnDcDo5mwJVpe4OobGe+L83qwkq4lOPi,iv:QZ0dBSyYaWMD9+c2Mgmel2/3warW1f2fmeijm/HMTOE=,tag:VUxij/19MVpPhQ3SK4vvHw==,type:str] sops: kms: [] gcp_kms: [] @@ -55,8 +53,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-21T16:43:44Z" - mac: ENC[AES256_GCM,data:Gx9Zpdt/HzeYRj2ksmCGLaIJTcsfzxJklGdVNbtMIU888A32B72lAHfv0MbU5OBX0ZRt+VYDRncARSeTKPI3CGZu0qLtJwkDcVFGv+y+sea63DN8mmvNpYLQeif0daqE1GGMPVWukzV/2aBmfWbYBtHhm3C2v4f7KXobE83v3K0=,iv:bd+U7zyGOeH2Wq+y4RRv7kGfDkUGq1Kkfj4LOFdMJkY=,tag:5JkuFvY8kFfguBJoZfOnvg==,type:str] + lastmodified: "2024-07-21T17:48:17Z" + mac: ENC[AES256_GCM,data:iseLH9pFaZ65lwf0wT386TN/ysscGBuSrJ+8aYI+3YzxHzPjcySaTcnvZ9gBB5ZF8tD15CkwlegNl7P2atx0jvigpKouE1n6Xvv2gKHjDvtqF/gCpdu1EmQOC/krfhRVJm0CtYTGKM7OHjb+dxuwrfeyiftjkXnNsgnl4sg57jM=,iv:QdrzTIRFZgCPSrIKiczLKgXMvd1QoPztYFowj/5GHtc=,tag:gUgzbV4yrstl+caasAlzAg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From e129d5cf8d92ca3087e0ad1ef946be84fcdb4fc5 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 20:02:40 +0200 Subject: [PATCH 046/108] feat: Expose Pihole on tailnet --- kubenix-modules/pihole.nix | 41 +++++++++++++++-------------------- kubenix-modules/syncthing.nix | 4 +++- my-lib/globals.nix | 1 + 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix index b5540b9..a465d7e 100644 --- a/kubenix-modules/pihole.nix +++ b/kubenix-modules/pihole.nix @@ -57,40 +57,28 @@ }; services = { - pihole-web.spec = { - selector.app = "pihole"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - pihole-dns.spec = { + pihole.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.piholeIPv4; selector.app = "pihole"; - ports.dns = { - protocol = "UDP"; - port = 53; - targetPort = "dns"; + ports = { + dns = { + protocol = "UDP"; + port = 53; + targetPort = "dns"; + }; + + web = { + port = 80; + targetPort = "web"; + }; }; }; }; }; lab = { - ingresses.pihole = { - host = "pihole.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "pihole-web"; - portName = "web"; - }; - }; - longhorn.persistentVolumeClaim = { pihole-data = { volumeName = "pihole-data"; @@ -102,5 +90,10 @@ storage = "16Mi"; }; }; + + tailscaleIngresses.tailscale-pihole = { + host = "pihole"; + service.name = "pihole"; + }; }; } diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index de132c0..afae1ed 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { serviceAccounts.syncthing = { }; @@ -57,6 +57,8 @@ }; services.syncthing.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.syncthingWebIPv4; selector.app = "syncthing"; ports.web = { diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 049c883..3df3b46 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -12,4 +12,5 @@ kmsIPv4 = "192.168.30.129"; traefikIPv4 = "192.168.30.128"; inbucketWebIPv4 = "192.168.30.137"; + syncthingWebIPv4 = "192.168.30.138"; } From 6152ce4577186fc68c4856e7d9f688009d255796 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 20:30:47 +0200 Subject: [PATCH 047/108] feat: Expose longhorn UI on tailnet refactor: Merge inbucket services --- kubenix-modules/bootstrap-default.nix | 44 ++++++++------------------- kubenix-modules/inbucket.nix | 30 ++++++++---------- kubenix-modules/syncthing.nix | 2 +- my-lib/globals.nix | 6 ++-- 4 files changed, 30 insertions(+), 52 deletions(-) diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index 4f5d9ba..81dbb8f 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -1,4 +1,4 @@ -{ lib, nixhelm, system, machines, ... }: { +{ lib, nixhelm, system, machines, myLib, ... }: { kubernetes = { helm.releases = { metallb = { @@ -17,6 +17,7 @@ values = { persistence.defaultClassReplicaCount = 2; + service.ui.type = "LoadBalancer"; defaultSettings = { defaultDataPath = "/mnt/longhorn"; @@ -29,6 +30,8 @@ }; resources = { + services.longhorn-frontend.spec.loadBalancerIP = myLib.globals.longhornIPv4; + namespaces = { static-websites = { }; freshrss = { }; @@ -60,36 +63,6 @@ }) machinesWithKubernetesLabels; - ingresses.longhorn = { - metadata.annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt"; - "traefik.ingress.kubernetes.io/router.entrypoints" = "localsecure"; - }; - - spec = { - ingressClassName = "traefik"; - - rules = [{ - host = "longhorn.kun.is"; - - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = "longhorn-frontend"; - port.number = 80; - }; - }]; - }]; - - tls = [{ - secretName = "longhorn-tls"; - hosts = [ "longhorn.kun.is" ]; - }]; - }; - }; - recurringJobs.backup-nfs.spec = { cron = "0 1 * * *"; # One o'clock at night task = "backup"; @@ -155,5 +128,14 @@ bazarr.storage = "25Mi"; minecraft.storage = "1Gi"; }; + + tailscaleIngresses.tailscale-longhorn = { + host = "longhorn"; + + service = { + name = "longhorn-frontend"; + portName = "http"; + }; + }; }; } diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index aed9bac..743cd5a 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -26,32 +26,28 @@ }; services = { - web.spec = { + inbucket.spec = { type = "LoadBalancer"; - loadBalancerIP = myLib.globals.inbucketWebIPv4; + loadBalancerIP = myLib.globals.inbucketIPv4; selector.app = "inbucket"; - ports.web = { - port = 80; - targetPort = "web"; + ports = { + smtp = { + port = 25; + targetPort = "smtp"; + }; + + web = { + port = 80; + targetPort = "web"; + }; }; }; - - email.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.inbucketEmailIPv4; - selector.app = "inbucket"; - - ports = [{ - port = 25; - targetPort = "smtp"; - }]; - }; }; }; lab.tailscaleIngresses.tailscale = { host = "inbucket"; - service.name = "web"; + service.name = "inbucket"; }; } diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index afae1ed..42e53b1 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -58,7 +58,7 @@ services.syncthing.spec = { type = "LoadBalancer"; - loadBalancerIP = myLib.globals.syncthingWebIPv4; + loadBalancerIP = myLib.globals.syncthingIPv4; selector.app = "syncthing"; ports.web = { diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 3df3b46..602a1b8 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -8,9 +8,9 @@ bittorrentIPv4 = "192.168.30.133"; gitIPv4 = "192.168.30.132"; piholeIPv4 = "192.168.30.131"; - inbucketEmailIPv4 = "192.168.30.130"; + inbucketIPv4 = "192.168.30.130"; kmsIPv4 = "192.168.30.129"; traefikIPv4 = "192.168.30.128"; - inbucketWebIPv4 = "192.168.30.137"; - syncthingWebIPv4 = "192.168.30.138"; + syncthingIPv4 = "192.168.30.138"; + longhornIPv4 = "192.168.30.139"; } From d3d6abdde810822ef316a7620ea5a6a4f36bbaa9 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 21:00:32 +0200 Subject: [PATCH 048/108] feat: Rollout tailscale for media stack fix: Add default for tailscale ingress option --- kubenix-modules/custom/tailscale.nix | 2 + kubenix-modules/media.nix | 128 +++++++++++---------------- my-lib/globals.nix | 23 +++-- 3 files changed, 71 insertions(+), 82 deletions(-) diff --git a/kubenix-modules/custom/tailscale.nix b/kubenix-modules/custom/tailscale.nix index 0789c6c..29ad04f 100644 --- a/kubenix-modules/custom/tailscale.nix +++ b/kubenix-modules/custom/tailscale.nix @@ -15,6 +15,8 @@ }; }; }); + + default = { }; }; }; diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index f921ebe..52b525c 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -419,34 +419,32 @@ }; }; - transmission-web.spec = { - selector = { - app = "media"; - component = "transmission"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - transmission-bittorrent.spec = { + transmission.spec = { type = "LoadBalancer"; - loadBalancerIP = myLib.globals.bittorrentIPv4; + loadBalancerIP = myLib.globals.transmissionIPv4; selector = { app = "media"; component = "transmission"; }; - ports.bittorrent = { - port = 31780; - targetPort = "bittorrent"; + ports = { + bittorrent = { + port = 31780; + targetPort = "bittorrent"; + }; + + web = { + port = 80; + targetPort = "web"; + }; }; }; jellyseerr.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.jellyseerrIPv4; + selector = { app = "media"; component = "jellyseerr"; @@ -459,6 +457,9 @@ }; radarr.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.radarrIPv4; + selector = { app = "media"; component = "radarr"; @@ -471,6 +472,9 @@ }; prowlarr.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.prowlarrIPv4; + selector = { app = "media"; component = "prowlarr"; @@ -483,6 +487,9 @@ }; sonarr.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.sonarrIPv4; + selector = { app = "media"; component = "sonarr"; @@ -495,6 +502,9 @@ }; bazarr.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.bazarrIPv4; + selector = { app = "media"; component = "bazarr"; @@ -523,74 +533,44 @@ }; lab = { - ingresses = { - jellyfin = { - host = "media.kun.is"; + ingresses.jellyfin = { + host = "media.kun.is"; - service = { - name = "jellyfin"; - portName = "web"; - }; + service = { + name = "jellyfin"; + portName = "web"; + }; + }; + + tailscaleIngresses = { + tailscale-jellyseerr = { + host = "jellyseerr"; + service.name = "jellyseerr"; }; - transmission = { - host = "transmission.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "transmission-web"; - portName = "web"; - }; + tailscale-radarr = { + host = "radarr"; + service.name = "radarr"; }; - jellyseerr = { - host = "jellyseerr.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "jellyseerr"; - portName = "web"; - }; + tailscale-sonarr = { + host = "sonarr"; + service.name = "sonarr"; }; - radarr = { - host = "radarr.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "radarr"; - portName = "web"; - }; + tailscale-bazarr = { + host = "bazarr"; + service.name = "bazarr"; }; - prowlarr = { - host = "prowlarr.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "prowlarr"; - portName = "web"; - }; + tailscale-prowlarr = { + host = "prowlarr"; + service.name = "prowlarr"; }; - sonarr = { - host = "sonarr.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "sonarr"; - portName = "web"; - }; - }; - - bazarr = { - host = "bazarr.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "bazarr"; - portName = "web"; - }; + tailscale-transmission = { + host = "transmission"; + service.name = "transmission"; }; }; diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 602a1b8..e9a5806 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -1,16 +1,23 @@ { routerPublicIPv4 = "192.145.57.90"; routerPublicIPv6 = "2a0d:6e00:1a77::1"; - minecraftIPv4 = "192.168.30.136"; - dnsmasqIPv4 = "192.168.30.135"; - bind9IPv4 = "192.168.30.134"; bind9Ipv6 = "2a0d:6e00:1a77:30::134"; - bittorrentIPv4 = "192.168.30.133"; - gitIPv4 = "192.168.30.132"; - piholeIPv4 = "192.168.30.131"; - inbucketIPv4 = "192.168.30.130"; - kmsIPv4 = "192.168.30.129"; + + # Load balancer IPv4 traefikIPv4 = "192.168.30.128"; + kmsIPv4 = "192.168.30.129"; + inbucketIPv4 = "192.168.30.130"; + piholeIPv4 = "192.168.30.131"; + gitIPv4 = "192.168.30.132"; + transmissionIPv4 = "192.168.30.133"; + bind9IPv4 = "192.168.30.134"; + dnsmasqIPv4 = "192.168.30.135"; + minecraftIPv4 = "192.168.30.136"; + jellyseerrIPv4 = "192.168.30.137"; syncthingIPv4 = "192.168.30.138"; longhornIPv4 = "192.168.30.139"; + radarrIPv4 = "192.168.30.140"; + prowlarrIPv4 = "192.168.30.141"; + sonarrIPv4 = "192.168.30.142"; + bazarrIPv4 = "192.168.30.143"; } From 052c75849d06d198fc93977fc7d37feb3fbc21ae Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 21:26:20 +0200 Subject: [PATCH 049/108] refactor: Remove support for port 444 --- kubenix-modules/traefik.nix | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index 36f49ec..b369f4b 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -9,23 +9,7 @@ providers.kubernetesIngress.allowExternalNameServices = true; service.loadBalancerIP = myLib.globals.traefikIPv4; - ports = { - localsecure = { - port = 8444; - expose = true; - exposedPort = 444; - protocol = "TCP"; - - tls = { - enabled = true; - options = ""; - certResolver = ""; - domains = [ ]; - }; - }; - - web.redirectTo = "websecure"; - }; + ports.web.redirectTo = "websecure"; }; }; }; From 92b096608ff20eb22334f57b53f70ad998710ded Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 22 Jul 2024 20:36:28 +0200 Subject: [PATCH 050/108] Revert "refactor: Remove support for port 444" This reverts commit 052c75849d06d198fc93977fc7d37feb3fbc21ae. --- kubenix-modules/traefik.nix | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index b369f4b..36f49ec 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -9,7 +9,23 @@ providers.kubernetesIngress.allowExternalNameServices = true; service.loadBalancerIP = myLib.globals.traefikIPv4; - ports.web.redirectTo = "websecure"; + ports = { + localsecure = { + port = 8444; + expose = true; + exposedPort = 444; + protocol = "TCP"; + + tls = { + enabled = true; + options = ""; + certResolver = ""; + domains = [ ]; + }; + }; + + web.redirectTo = "websecure"; + }; }; }; }; From c22d356191374c6922cb71aaf8035d3fda5c3e9a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 22 Jul 2024 20:44:51 +0200 Subject: [PATCH 051/108] Re-enable port 444 for inbucket @pizzaniels --- kubenix-modules/inbucket.nix | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 743cd5a..d9c2087 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -46,8 +46,21 @@ }; }; - lab.tailscaleIngresses.tailscale = { - host = "inbucket"; - service.name = "inbucket"; + lab = { + tailscaleIngresses.tailscale = { + host = "inbucket"; + service.name = "inbucket"; + }; + + + ingresses.inbucket = { + host = "inbucket.kun.is"; + entrypoint = "localsecure"; + + service = { + name = "inbucket"; + portName = "web"; + }; + }; }; } From 15e0dce041377f2adf1856fb48d1a66920c98e72 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 22 Jul 2024 22:54:08 +0200 Subject: [PATCH 052/108] feat: Enable tailscale on physical servers fix: Fix Nix flake checks --- flake-parts/kubenix.nix | 3 +-- nixos-modules/default.nix | 1 + nixos-modules/k3s/default.nix | 1 + nixos-modules/tailscale.nix | 14 ++++++++++++++ secrets/nixos.yaml | 6 ++++-- 5 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 nixos-modules/tailscale.nix diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 76cfa53..8893c62 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -184,6 +184,5 @@ }; in { - apps = builtins.mapAttrs mkDeployApp deployers; - packages = builtins.mapAttrs mkManifest deployers; + apps = pkgs.lib.mergeAttrs (builtins.mapAttrs mkDeployApp deployers) (builtins.mapAttrs mkManifest deployers); }) diff --git a/nixos-modules/default.nix b/nixos-modules/default.nix index 8d3c5d2..4ee9a8b 100644 --- a/nixos-modules/default.nix +++ b/nixos-modules/default.nix @@ -6,5 +6,6 @@ ./data-sharing.nix ./monitoring ./k3s + ./tailscale.nix ]; } diff --git a/nixos-modules/k3s/default.nix b/nixos-modules/k3s/default.nix index 4c902d9..d47f182 100644 --- a/nixos-modules/k3s/default.nix +++ b/nixos-modules/k3s/default.nix @@ -61,6 +61,7 @@ in nfs-utils # Required for Longhorn ]; + # TODO!!!!! networking = { nftables.enable = lib.mkForce false; firewall.enable = lib.mkForce false; diff --git a/nixos-modules/tailscale.nix b/nixos-modules/tailscale.nix new file mode 100644 index 0000000..0edd968 --- /dev/null +++ b/nixos-modules/tailscale.nix @@ -0,0 +1,14 @@ +{ config, ... }: { + config = { + services.tailscale = { + enable = true; + authKeyFile = config.sops.secrets."tailscale/authKey".path; + + extraUpFlags = [ + "--hostname=${config.networking.hostName}" + ]; + }; + + sops.secrets."tailscale/authKey" = { }; + }; +} diff --git a/secrets/nixos.yaml b/secrets/nixos.yaml index 6386cd8..6bbc8e8 100644 --- a/secrets/nixos.yaml +++ b/secrets/nixos.yaml @@ -11,6 +11,8 @@ k3s: etcd: peerCAKey: ENC[AES256_GCM,data:hr/Q9UqzA5IKK4o+mxyYQyXjTl1/guRLcjeBBaErxlvtQ0QarNWBMV0SuekCTiv0aGEUiXrY4u/39n6/VdVsxCdCDFDSuEJE5iEklpReKkW0gIvW3wIk98PC8xhNKjwRNnPwgE6TmOi8RSR9jdL9A3VKUXXo4XDkKPWrK6yHOJHKWgGOKX8+TP8HHwGGG6JvcMgOfbLJIvstsB9C17bOHt0KNaPKIpGN3gRkY7rJE/ORIJaOFxQB9WrcmweB2B7K3tlnVyLsY/wZsturZDJtK4CtVPEba7jXlpI4xnr0EANhRxs=,iv:gy8/RAxOxMrzFbPynQw1iDbXYEM4iYXJ+OfvQE9MAfU=,tag:vlnfHLzOm9ztsnaSIbL14w==,type:str] serverCAKey: ENC[AES256_GCM,data:bn4BLlUSOHBOzjxO7oCmnWY3+yc/+J149QFfHOxrrFFblCkY3MEtXg9ogFsU+CYhZg6HZtOiecbo3V1fTe6dbSdWlUW7mHVoFP75aRuLjeEwX9Crgu/BVce7tcL0nFXvaBfaPngz3irzE2t2Dt+p1rVFWsMa2Ms2Wfzx9ZfVUbD0mOBgKmR+fGCHQBuUk4F9kzXA//J6iuk2VNh0+6YXBfTWCEsBllg8CvLgD9aU3DE7nS/xcbZcbpR3nWp8nQvezA5/cAEVTyuQfUO2u/tnYAoEE7t1Qo4RJrWlY30xTvXdq44=,iv:kXjH9JPjix64b+nWWIF/TBlZH9DsOYGTq5okQB3HKYs=,tag:MYM0xdi8AjaR0I/ZcpELAQ==,type:str] +tailscale: + authKey: ENC[AES256_GCM,data:nOxCntC28235lk47BRpIPuNRwmp87DbEY8c3QHIZLXfLvS+U1neoNNlAZ8ThQd4addLoPrJRH0LgDiWAUQ==,iv:7ymbpb78mdXm1/MaGe/ZrsJv8zYQNGm3//Hud7lCgPY=,tag:Wuwf2EKz2RBsaEbrxyNQ0w==,type:str] sops: kms: [] gcp_kms: [] @@ -71,8 +73,8 @@ sops: Q0VudEFzRUFGWlNJcHc0VzZJUVRwbHMKjTMUFFbHhDeP7QLmR64yqDEh4naazL9f etbOvYUkgj4IaB9UgDerG4MjyyHiVVY9Md8Jqe3dOQN0rqXRxNOW1g== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-06-15T19:11:54Z" - mac: ENC[AES256_GCM,data:OR2ibRtOtUwIuQ27c5PHRzdvKoTGMl4Ll7/hmuIB40amBqs54Cku/SEOqw2kHG31ii3cK5XbyaR6tC8Lvu07tn1iutbU8WjN8Ww+txr0FgdbeTYRIWr9aClAKmR3Ek1Ky2NsA2OaTm02Um6W0xX78Ran04Gjuf8vpaXSRYVsPbA=,iv:w9M3O5DHlm7Jq9vjfxaq34petJtgMeEUHZ0fZKycOjs=,tag:ShLvjfZJV3FARa4An+YfQA==,type:str] + lastmodified: "2024-07-22T20:27:25Z" + mac: ENC[AES256_GCM,data:zIY2DotoqnJmz/aBRHq+4ZLi/Smi1Bn4phmFsngMY1w0LVauKX95jwKwOhE0PfvIyd8E54N+BoCQ3QmRMv3uvBddScPNSGJgdgDRn8LDWol4/8avDoPFISpNvdS32Ac00UDnMeBEkW4S/oo9CwYHCpEsiwjL6FgjCX/KOK++kzA=,iv:sGCFNJ6gsEOskMlLWUnR9Gnsp8Emc0vdBAl4WN2A1f8=,tag:fHi4CR+exp1roW7UOzhMmQ==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 4e619eb0c46452ed2f64e977b68e2f8150b44e4c Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 23 Jul 2024 22:50:11 +0200 Subject: [PATCH 053/108] feat(tailscale): Enable warwick as exit node and subnet router --- machines/warwick.nix | 7 +++++-- nixos-modules/networking/default.nix | 6 ++---- nixos-modules/tailscale.nix | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/machines/warwick.nix b/machines/warwick.nix index a53159c..f8c2af6 100644 --- a/machines/warwick.nix +++ b/machines/warwick.nix @@ -3,8 +3,11 @@ arch = "aarch64-linux"; isRaspberryPi = true; - nixosModule = { - lab.monitoring.server.enable = true; + nixosModule = { lib, ... }: { + lab = { + monitoring.server.enable = true; + tailscale.advertiseExitNode = true; + }; services.bird2 = { enable = false; diff --git a/nixos-modules/networking/default.nix b/nixos-modules/networking/default.nix index e07f8c5..df36440 100644 --- a/nixos-modules/networking/default.nix +++ b/nixos-modules/networking/default.nix @@ -2,12 +2,10 @@ config = { networking = { domain = "dmz"; - nftables.enable = true; + nftables.enable = lib.mkDefault true; useDHCP = false; - firewall = { - enable = true; - }; + firewall.enable = lib.mkDefault true; }; systemd.network = { diff --git a/nixos-modules/tailscale.nix b/nixos-modules/tailscale.nix index 0edd968..796e528 100644 --- a/nixos-modules/tailscale.nix +++ b/nixos-modules/tailscale.nix @@ -1,12 +1,26 @@ -{ config, ... }: { +{ lib, config, ... }: +let + cfg = config.lab.tailscale; +in +{ + options = { + lab.tailscale.advertiseExitNode = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + config = { services.tailscale = { enable = true; authKeyFile = config.sops.secrets."tailscale/authKey".path; + useRoutingFeatures = "server"; + openFirewall = true; extraUpFlags = [ "--hostname=${config.networking.hostName}" - ]; + ] ++ lib.lists.optional cfg.advertiseExitNode "--advertise-exit-node" + ++ lib.lists.optional cfg.advertiseExitNode "--advertise-routes=192.168.30.0/24"; }; sops.secrets."tailscale/authKey" = { }; From f961fc24ea4def9f079a0e9ef5ee18c7f32a21da Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 24 Jul 2024 21:25:51 +0200 Subject: [PATCH 054/108] feat: Expose Radicale, Paperless and FreshRSS only on Tailscale fix: Fix flake output names --- README.md | 6 +++--- flake-parts/kubenix.nix | 14 +++++--------- kubenix-modules/freshrss.nix | 14 ++++++-------- kubenix-modules/inbucket.nix | 1 - kubenix-modules/paperless.nix | 15 +++++++-------- kubenix-modules/radicale.nix | 14 ++++++-------- my-lib/globals.nix | 3 +++ 7 files changed, 30 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 6b74f72..a626806 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,12 @@ Each applyset is responsible for a set number of resources within a namespace. If the cluster has not been initialized yet, we must bootstrap it first. Run these deployments: -- `nix run '.#bootstrap-default.deploy'` -- `nix run '.#bootstrap-kube-system.deploy'` +- `nix run '.#bootstrap-default'` +- `nix run '.#bootstrap-kube-system'` Now the cluster has been initialized and we can deploy applications. To explore which applications we can deploy, run `nix flake show`. -Then, for each application, run `nix run '.#.deploy'`. +Then, for each application, run `nix run '.#'`. ## Known bugs diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 8893c62..b2cb229 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -25,10 +25,7 @@ }; }).config.kubernetes; - mkManifest = name: { module, namespace }: - { - manifest = (mkKubernetes name module namespace).result; - }; + mkManifest = name: { module, namespace }: (mkKubernetes name module namespace).result; mkDeployApp = name: { module, namespace }: let @@ -55,10 +52,8 @@ }; in { - deploy = { - type = "app"; - program = "${pkgs.lib.getExe wrappedDeployScript}"; - }; + type = "app"; + program = "${pkgs.lib.getExe wrappedDeployScript}"; }; deployers = { @@ -184,5 +179,6 @@ }; in { - apps = pkgs.lib.mergeAttrs (builtins.mapAttrs mkDeployApp deployers) (builtins.mapAttrs mkManifest deployers); + apps = builtins.mapAttrs mkDeployApp deployers; + packages = builtins.mapAttrs mkManifest deployers; }) diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 0da1ce0..9d229c6 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { secrets.server.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; @@ -57,6 +57,8 @@ }; services.server.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.freshrssIPv4; selector.app = "freshrss"; ports.web = { @@ -67,13 +69,9 @@ }; lab = { - ingresses.web = { - host = "rss.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; + tailscaleIngresses.tailscale = { + host = "freshrss"; + service.name = "server"; }; longhorn.persistentVolumeClaim.data = { diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index d9c2087..909c236 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -52,7 +52,6 @@ service.name = "inbucket"; }; - ingresses.inbucket = { host = "inbucket.kun.is"; entrypoint = "localsecure"; diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index 35caecd..6457e0c 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { secrets = { database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/paperless/databasePassword"; @@ -170,6 +170,9 @@ services = { web.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.paperlessIPv4; + selector = { app = "paperless"; component = "web"; @@ -208,13 +211,9 @@ }; lab = { - ingresses.web = { - host = "paperless.kun.is"; - - service = { - name = "web"; - portName = "web"; - }; + tailscaleIngresses.tailscale = { + host = "paperless"; + service.name = "web"; }; longhorn.persistentVolumeClaim = { diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix index ab2301d..447637a 100644 --- a/kubenix-modules/radicale.nix +++ b/kubenix-modules/radicale.nix @@ -1,4 +1,4 @@ -{ lib, ... }: { +{ lib, myLib, ... }: { kubernetes.resources = { configMaps.server.data = { users = "pim:$apr1$GUiTihkS$dDCkaUxFx/O86m6NCy/yQ."; @@ -86,6 +86,8 @@ }; services.server.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.radicaleIPv4; selector.app = "radicale"; ports.web = { @@ -96,13 +98,9 @@ }; lab = { - ingresses.web = { - host = "dav.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; + tailscaleIngresses.tailscale = { + host = "radicale"; + service.name = "server"; }; longhorn.persistentVolumeClaim.data = { diff --git a/my-lib/globals.nix b/my-lib/globals.nix index e9a5806..d868d4a 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -20,4 +20,7 @@ prowlarrIPv4 = "192.168.30.141"; sonarrIPv4 = "192.168.30.142"; bazarrIPv4 = "192.168.30.143"; + paperlessIPv4 = "192.168.30.144"; + radicaleIPv4 = "192.168.30.145"; + freshrssIPv4 = "192.168.30.146"; } From ae655bba6ad02bcc52b76ca17c1721f5c58c8eca Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 24 Jul 2024 21:43:50 +0200 Subject: [PATCH 055/108] chore: Disable EK poule --- kubenix-modules/traefik.nix | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index 36f49ec..e046bfc 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -30,25 +30,13 @@ }; }; - services = { - ek2024.spec = { - type = "ExternalName"; - externalName = "ek2024.dmz"; + services.esrom.spec = { + type = "ExternalName"; + externalName = "esrom.dmz"; - ports.web = { - port = 80; - targetPort = 80; - }; - }; - - esrom.spec = { - type = "ExternalName"; - externalName = "esrom.dmz"; - - ports.web = { - port = 80; - targetPort = 80; - }; + ports.web = { + port = 80; + targetPort = 80; }; }; }; From fd70b4d934159f3f868c8719a7527935306f67cb Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 24 Jul 2024 21:54:31 +0200 Subject: [PATCH 056/108] Fix: Fix Traefik HTTP redirect after update --- kubenix-modules/traefik.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index e046bfc..3df7d12 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -24,7 +24,7 @@ }; }; - web.redirectTo = "websecure"; + web.redirectTo.port = "websecure"; }; }; }; From 5398db801ca204b4fdf060b3e6378449bfadd892 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 24 Jul 2024 22:21:47 +0200 Subject: [PATCH 057/108] feat(traefik): Expose traefik dashboard on Tailscale --- kubenix-modules/traefik.nix | 44 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index 3df7d12..d9018db 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -30,28 +30,33 @@ }; }; - services.esrom.spec = { - type = "ExternalName"; - externalName = "esrom.dmz"; + services = { + esrom.spec = { + type = "ExternalName"; + externalName = "esrom.dmz"; - ports.web = { - port = 80; - targetPort = 80; + ports.web = { + port = 80; + targetPort = 80; + }; + }; + + traefik-dashboard.spec = { + selector = { + "app.kubernetes.io/name" = "traefik"; + "app.kubernetes.io/instance" = "traefik-kube-system"; + }; + + ports.web = { + port = 80; + targetPort = "traefik"; + }; }; }; }; - lab.ingresses = { - ek2024 = { - host = "ek2024.kun.is"; - - service = { - name = "ek2024"; - portName = "web"; - }; - }; - - esrom = { + lab = { + ingresses.esrom = { host = "esrom.kun.is"; service = { @@ -59,5 +64,10 @@ portName = "web"; }; }; + + tailscaleIngresses.tailscale = { + host = "traefik"; + service.name = "traefik-dashboard"; + }; }; } From 6db856cfe9138b5d5afba95558de77f2cce4ba8f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Thu, 25 Jul 2024 20:30:21 +0200 Subject: [PATCH 058/108] feat: Put nextcloud and immich behind tailscale --- kubenix-modules/immich.nix | 15 +++++++-------- kubenix-modules/nextcloud.nix | 15 +++++++-------- kubenix-modules/syncthing.nix | 2 +- my-lib/globals.nix | 2 ++ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 87f7c5e..64353dd 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { deployments = { immich.spec = { @@ -165,6 +165,9 @@ services = { server.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.immichIPv4; + selector = { app = "immich"; component = "server"; @@ -220,13 +223,9 @@ }; lab = { - ingresses.immich = { - host = "immich.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; + tailscaleIngresses.tailscale = { + host = "immich"; + service.name = "server"; }; longhorn.persistentVolumeClaim = { diff --git a/kubenix-modules/nextcloud.nix b/kubenix-modules/nextcloud.nix index 07fda6d..f499734 100644 --- a/kubenix-modules/nextcloud.nix +++ b/kubenix-modules/nextcloud.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { secrets.database.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/nextcloud/databasePassword"; @@ -108,6 +108,9 @@ services = { server.spec = { + type = "LoadBalancer"; + loadBalancerIP = myLib.globals.nextcloudIPv4; + selector = { app = "nextcloud"; component = "server"; @@ -134,13 +137,9 @@ }; lab = { - ingresses.web = { - host = "cloud.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; + tailscaleIngresses.tailscale = { + host = "nextcloud"; + service.name = "server"; }; longhorn.persistentVolumeClaim = { diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index 42e53b1..a030df8 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -82,7 +82,7 @@ }; tailscaleIngresses.tailscale = { - host = "sync"; + host = "syncthing"; service.name = "syncthing"; }; }; diff --git a/my-lib/globals.nix b/my-lib/globals.nix index d868d4a..28a2163 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -23,4 +23,6 @@ paperlessIPv4 = "192.168.30.144"; radicaleIPv4 = "192.168.30.145"; freshrssIPv4 = "192.168.30.146"; + immichIPv4 = "192.168.30.147"; + nextcloudIPv4 = "192.168.30.148"; } From ea84627e59b840c11de9d0b497bc70b98c354bfa Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 27 Jul 2024 21:12:24 +0200 Subject: [PATCH 059/108] feat: Use Attic as binary cache fix: Improve flake outputs yet again refactor: Delete dead code related to hamnet --- flake-parts/kubenix.nix | 12 ++++++----- flake.nix | 10 +++++++++ machines/bird.conf | 40 ----------------------------------- machines/warwick.nix | 46 ----------------------------------------- 4 files changed, 17 insertions(+), 91 deletions(-) delete mode 100644 machines/bird.conf diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index b2cb229..4c2d875 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -25,7 +25,10 @@ }; }).config.kubernetes; - mkManifest = name: { module, namespace }: (mkKubernetes name module namespace).result; + mkManifest = name: { module, namespace }: { + name = "${name}-manifest"; + value = (mkKubernetes name module namespace).result; + }; mkDeployApp = name: { module, namespace }: let @@ -52,8 +55,8 @@ }; in { - type = "app"; - program = "${pkgs.lib.getExe wrappedDeployScript}"; + name = "${name}-deploy"; + value = wrappedDeployScript; }; deployers = { @@ -179,6 +182,5 @@ }; in { - apps = builtins.mapAttrs mkDeployApp deployers; - packages = builtins.mapAttrs mkManifest deployers; + packages = pkgs.lib.mergeAttrs (pkgs.lib.mapAttrs' mkDeployApp deployers) (pkgs.lib.mapAttrs' mkManifest deployers); }) diff --git a/flake.nix b/flake.nix index f3add24..198e0d5 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,16 @@ { description = "NixOS definitions for our home servers"; + nixConfig = { + extra-substituters = [ + "https://attic.kun.is/nixos-servers" + ]; + + extra-trusted-public-keys = [ + "nixos-servers:JThtPjQjDu3b3qXLgeXSJGgKL4OKQ4uLgTtoo1rg6Vw=" + ]; + }; + inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; diff --git a/machines/bird.conf b/machines/bird.conf deleted file mode 100644 index 22c784c..0000000 --- a/machines/bird.conf +++ /dev/null @@ -1,40 +0,0 @@ -log syslog all; -debug protocols all; - -router id 44.137.17.110; - -protocol bgp hamgre { - local as 4220401706; - neighbor 44.137.61.33 as 4220406100; - source address 44.137.61.34; - multihop; - ipv4 { - import all; - export none; - }; -} - -protocol device { -} - -protocol direct { - interface "lo"; - ipv4 { - }; -} - -protocol kernel { - metric 0; - learn; - ipv4 { - import none; - export all; - }; -} - -protocol static { - route 44.137.17.96/28 via 44.137.61.33; - ipv4 { - }; -} - diff --git a/machines/warwick.nix b/machines/warwick.nix index f8c2af6..9859a28 100644 --- a/machines/warwick.nix +++ b/machines/warwick.nix @@ -8,52 +8,6 @@ monitoring.server.enable = true; tailscale.advertiseExitNode = true; }; - - services.bird2 = { - enable = false; - config = builtins.readFile ./bird.conf; - }; - - #systemd.network = { - # netdevs = { - # hamgre = { - # netdevConfig = { - # Name = "hamgre"; - # Kind = "gre"; - # MTUBytes = "1468"; - # }; - - # tunnelConfig = { - # Remote = "145.220.78.4"; - # #Local = "192.145.57.90"; - # }; - # }; - - # # hambr = { - # # netdevConfig = { - # # Name = "hambr"; - # # Kind = "bridge"; - # # }; - # # }; - # }; - - # networks = { - # "30-main-nic".networkConfig.Tunnel = "hamgre"; - - # "40-hamgre" = { - # matchConfig.Name = "hamgre"; - - # networkConfig = { - # Address = "44.137.61.34/30"; - # }; - # }; - - # # "40-hambr" = { - # # matchConfig.Name = "hambr"; - - # # }; - # }; - #}; }; }; } From 1f72d3463e31d93abc1b25b8ddfe282dadcaf9a2 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 27 Jul 2024 22:32:23 +0200 Subject: [PATCH 060/108] feat: Deploy ntfy closes #93 --- flake-parts/kubenix.nix | 5 ++ kubenix-modules/bootstrap-default.nix | 2 + kubenix-modules/ntfy.nix | 105 ++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 kubenix-modules/ntfy.nix diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 4c2d875..2d3c2b2 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -179,6 +179,11 @@ module = "${self}/kubenix-modules/tailscale.nix"; namespace = "tailscale"; }; + + ntfy = { + module = "${self}/kubenix-modules/ntfy.nix"; + namespace = "ntfy"; + }; }; in { diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index 81dbb8f..7f0371f 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -51,6 +51,7 @@ media = { }; minecraft = { }; tailscale = { }; + ntfy = { }; }; nodes = @@ -127,6 +128,7 @@ sonarr.storage = "150Mi"; bazarr.storage = "25Mi"; minecraft.storage = "1Gi"; + ntfy.storage = "300Mi"; }; tailscaleIngresses.tailscale-longhorn = { diff --git a/kubenix-modules/ntfy.nix b/kubenix-modules/ntfy.nix new file mode 100644 index 0000000..36009ff --- /dev/null +++ b/kubenix-modules/ntfy.nix @@ -0,0 +1,105 @@ +{ lib, ... }: { + kubernetes.resources = { + configMaps.ntfy.data.config = lib.generators.toYAML { } { + base-url = "https://ntfy.kun.is"; + cache-file = "/var/cache/ntfy/cache.db"; + cache-duration = "14d"; + auth-file = "/var/lib/ntfy/user.db"; + auth-default-access = "deny-all"; + attachment-cache-dir = "/var/cache/ntfy-attachments"; + enable-signup = false; + enable-login = true; + visitor-subscription-limit = 100; + }; + + deployments.ntfy.spec = { + selector.matchLabels.app = "ntfy"; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels.app = "ntfy"; + + spec = { + containers.ntfy = { + image = "binwiederhier/ntfy:v2.11.0"; + ports.web.containerPort = 80; + env.TZ.value = "Europe/Amsterdam"; + args = [ "serve" ]; + + volumeMounts = [ + { + name = "cache"; + mountPath = "/var/cache/ntfy"; + } + { + name = "data"; + mountPath = "/var/lib/ntfy"; + } + { + name = "attachment-cache"; + mountPath = "/var/cache/ntfy-attachments"; + } + { + name = "config"; + mountPath = "/etc/ntfy/server.yml"; + subPath = "config"; + } + ]; + }; + + volumes = { + cache.persistentVolumeClaim.claimName = "cache"; + attachment-cache.persistentVolumeClaim.claimName = "attachment-cache"; + data.persistentVolumeClaim.claimName = "data"; + config.configMap.name = "ntfy"; + }; + }; + }; + }; + + persistentVolumeClaims = { + cache.spec = { + accessModes = [ "ReadWriteOnce" ]; + resources.requests.storage = "300Mi"; + }; + + attachment-cache.spec = { + accessModes = [ "ReadWriteOnce" ]; + resources.requests.storage = "500Mi"; + }; + }; + + services.ntfy.spec = { + selector.app = "ntfy"; + + ports.web = { + port = 80; + targetPort = "web"; + }; + }; + }; + + lab = { + ingresses.ntfy = { + host = "ntfy.kun.is"; + + service = { + name = "ntfy"; + portName = "web"; + }; + }; + + longhorn.persistentVolumeClaim.data = { + volumeName = "ntfy"; + storage = "300Mi"; + }; + }; +} From bf1facabd768f163338dd04e78ebd7da7411a3ed Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 28 Jul 2024 14:14:38 +0200 Subject: [PATCH 061/108] feat: Replace transmission with deluge --- kubenix-modules/bootstrap-default.nix | 1 + kubenix-modules/media.nix | 44 ++++++++++++--------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index 7f0371f..dc2386d 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -129,6 +129,7 @@ bazarr.storage = "25Mi"; minecraft.storage = "1Gi"; ntfy.storage = "300Mi"; + deluge.storage = "500Mi"; }; tailscaleIngresses.tailscale-longhorn = { diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index 52b525c..1d1f739 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -72,10 +72,10 @@ }; }; - transmission.spec = { + deluge.spec = { selector.matchLabels = { app = "media"; - component = "transmission"; + component = "deluge"; }; strategy = { @@ -90,23 +90,24 @@ template = { metadata.labels = { app = "media"; - component = "transmission"; + component = "deluge"; }; spec = { - containers.transmission = { - image = "lscr.io/linuxserver/transmission:4.0.6"; + containers.deluge = { + image = "linuxserver/deluge:2.1.1"; imagePullPolicy = "Always"; - ports = { - web.containerPort = 9091; - bittorrent.containerPort = 31780; - }; - env = { PUID.value = "1000"; PGID.value = "1000"; TZ.value = "Europe/Amsterdam"; + DELUGE_LOGLEVEL.value = "info"; + }; + + ports = { + web.containerPort = 8112; + bittorrent.containerPort = 31780; }; volumeMounts = [ @@ -122,14 +123,9 @@ }; volumes = { - config.persistentVolumeClaim.claimName = "transmission"; + config.persistentVolumeClaim.claimName = "deluge"; media.persistentVolumeClaim.claimName = "media"; }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; }; }; }; @@ -419,13 +415,13 @@ }; }; - transmission.spec = { + deluge.spec = { type = "LoadBalancer"; loadBalancerIP = myLib.globals.transmissionIPv4; selector = { app = "media"; - component = "transmission"; + component = "deluge"; }; ports = { @@ -568,9 +564,9 @@ service.name = "prowlarr"; }; - tailscale-transmission = { - host = "transmission"; - service.name = "transmission"; + tailscale-deluge = { + host = "deluge"; + service.name = "deluge"; }; }; @@ -580,9 +576,9 @@ storage = "5Gi"; }; - transmission = { - volumeName = "transmission"; - storage = "25Mi"; + deluge = { + volumeName = "deluge"; + storage = "500Mi"; }; jellyseerr = { From 9fe5ecbb8d184478e58a92fd46f7c9e9afd0cb4f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 28 Jul 2024 14:32:28 +0200 Subject: [PATCH 062/108] refactor: Set image pull policy to IfNotPresent everywhere closes #101 --- kubenix-modules/atuin.nix | 2 +- kubenix-modules/forgejo/default.nix | 2 +- kubenix-modules/freshrss.nix | 2 +- kubenix-modules/immich.nix | 8 ++++---- kubenix-modules/kitchenowl.nix | 2 +- kubenix-modules/media.nix | 14 +++++++------- kubenix-modules/paperless.nix | 6 +++--- kubenix-modules/radicale.nix | 2 +- kubenix-modules/syncthing.nix | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/kubenix-modules/atuin.nix b/kubenix-modules/atuin.nix index cea3eb6..198384e 100644 --- a/kubenix-modules/atuin.nix +++ b/kubenix-modules/atuin.nix @@ -29,7 +29,7 @@ containers = { atuin = { image = "ghcr.io/atuinsh/atuin:18.3.0"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 8888; args = [ "server" "start" ]; diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix index 2dc1cf8..6b9a123 100644 --- a/kubenix-modules/forgejo/default.nix +++ b/kubenix-modules/forgejo/default.nix @@ -28,7 +28,7 @@ containers.forgejo = { image = "codeberg.org/forgejo/forgejo:7.0.5"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { USER_UID.value = "1000"; diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 9d229c6..525e4b4 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -20,7 +20,7 @@ spec = { containers.freshrss = { image = "freshrss/freshrss:1.24.1"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 80; env = { diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 64353dd..8051944 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -29,7 +29,7 @@ containers.immich = { image = "ghcr.io/immich-app/immich-server:v1.108.0"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 3001; env = { @@ -68,7 +68,7 @@ containers.machine-learning = { image = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; ports.ml.containerPort = 3003; env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; @@ -106,7 +106,7 @@ containers.redis = { image = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; ports.redis.containerPort = 6379; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; }; }; }; @@ -138,7 +138,7 @@ containers.postgres = { image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; command = [ "postgres" ]; args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/kitchenowl.nix b/kubenix-modules/kitchenowl.nix index 611279c..ff62a14 100644 --- a/kubenix-modules/kitchenowl.nix +++ b/kubenix-modules/kitchenowl.nix @@ -23,7 +23,7 @@ containers.kitchenowl = { image = "tombursch/kitchenowl:v0.5.1"; ports.web.containerPort = 8080; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env.JWT_SECRET_KEY.valueFrom.secretKeyRef = { name = "server"; diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index 1d1f739..c1159a2 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -26,7 +26,7 @@ containers.jellyfin = { image = "jellyfin/jellyfin:10.9.7"; ports.web.containerPort = 8096; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env.JELLYFIN_PublishedServerUrl.value = "https://media.kun.is"; @@ -96,7 +96,7 @@ spec = { containers.deluge = { image = "linuxserver/deluge:2.1.1"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "1000"; @@ -157,7 +157,7 @@ containers.jellyseerr = { image = "fallenbagel/jellyseerr:1.9.2"; ports.web.containerPort = 5055; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { LOG_LEVEL.value = "debug"; @@ -203,7 +203,7 @@ containers.radarr = { image = "lscr.io/linuxserver/radarr:5.7.0"; ports.web.containerPort = 7878; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "1000"; @@ -263,7 +263,7 @@ containers.prowlarr = { image = "lscr.io/linuxserver/prowlarr:1.20.1"; ports.web.containerPort = 9696; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "1000"; @@ -310,7 +310,7 @@ containers.sonarr = { image = "lscr.io/linuxserver/sonarr:4.0.6"; ports.web.containerPort = 8989; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "1000"; @@ -368,7 +368,7 @@ containers.bazarr = { image = "lscr.io/linuxserver/bazarr:1.4.3"; ports.web.containerPort = 6767; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "1000"; diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index 6457e0c..054362b 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -32,7 +32,7 @@ containers.paperless = { image = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 8000; env = { @@ -102,7 +102,7 @@ containers.redis = { image = "docker.io/library/redis:7"; ports.redis.containerPort = 6379; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; volumeMounts = [{ name = "data"; @@ -143,7 +143,7 @@ containers.postgres = { image = "postgres:15"; ports.postgres.containerPort = 5432; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { POSTGRES_DB.value = "paperless"; diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix index 447637a..7fcc6f8 100644 --- a/kubenix-modules/radicale.nix +++ b/kubenix-modules/radicale.nix @@ -52,7 +52,7 @@ containers.radicale = { image = "tomsquest/docker-radicale:3.2.2.0"; ports.web.containerPort = 5232; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; volumeMounts = [ { diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index a030df8..c5e2304 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -23,7 +23,7 @@ containers.syncthing = { image = "lscr.io/linuxserver/syncthing:1.23.6"; ports.web.containerPort = 8384; - imagePullPolicy = "Always"; + imagePullPolicy = "IfNotPresent"; env = { PUID.value = "33"; From 8067d9a301c081d368fd9fb07403ed00d1d57941 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 28 Jul 2024 14:48:09 +0200 Subject: [PATCH 063/108] docs: Update readme --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a626806..6215c6a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Nix definitions to configure our servers at home. - [nixhelm](https://github.com/farcaller/nixhelm): Nix-digestible Helm charts - [sops-nix](https://github.com/Mic92/sops-nix): Sops secret management for Nix -## Installation +## NixOS ### Prerequisites @@ -28,7 +28,7 @@ Additionally, it deploys an age identity, which is later used for decrypting sec ⚠️ This will wipe your server completely ⚠️ -1. Make sure your have a [Secret service](https://www.gnu.org/software/emacs/manual/html_node/auth/Secret-Service-API.html) running (such as Keepassxc) that provides the age identity. +1. Make sure you can decrypt the Sops-encrypted secrets in `secrets/`. You can test this by running `sops -d secrets/serverKeys.yaml`. 2. Ensure you have root SSH access to the server. 3. Run nixos-anywhere: `nix run '.#bootstrap' ` @@ -37,12 +37,16 @@ Additionally, it deploys an age identity, which is later used for decrypting sec To deploy all servers at once: `nix run 'nixpkgs#deploy-rs' -- '.#' -k` To deploy only one server: `nix run 'nixpkgs#deploy-rs' -- -k --targets '.#'` -## Deploying to Kubernetes +## Kubernetes + +### Prerequisites To deploy to the Kubernetes cluster, first make sure you have an admin account on the cluster. You can generate this using `nix run '.#gen-k3s-cert' ~/.kube`, assuming you have SSH access to the master node. This puts a private key, signed certificate and a kubeconfig in the kubeconfig directory +### Bootstrapping + We are now ready to deploy to the Kubernetes cluster. Deployments are done through an experimental Kubernetes feature called [ApplySets](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-delete-objects). Each applyset is responsible for a set number of resources within a namespace. @@ -52,6 +56,8 @@ Run these deployments: - `nix run '.#bootstrap-default'` - `nix run '.#bootstrap-kube-system'` +### Deployment + Now the cluster has been initialized and we can deploy applications. To explore which applications we can deploy, run `nix flake show`. Then, for each application, run `nix run '.#'`. From 6794fce2a2b0c2652c88b0c89dc4a16f63c4d7dd Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 30 Jul 2024 20:33:07 +0200 Subject: [PATCH 064/108] fix: Don't use tailscale DNS for physical servers fix: Don't do rolling updates for pihole chore: Update flake inputs --- flake.lock | 42 ++++++++++++++++++------------------- kubenix-modules/pihole.nix | 9 ++++++++ nixos-modules/tailscale.nix | 1 + 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index 68aecb0..683a47f 100644 --- a/flake.lock +++ b/flake.lock @@ -50,11 +50,11 @@ ] }, "locked": { - "lastModified": 1720661479, - "narHash": "sha256-nsGgA14vVn0GGiqEfomtVgviRJCuSR3UEopfP8ixW1I=", + "lastModified": 1722217815, + "narHash": "sha256-8r5AJ3n8WEDw3rsZLALSuFQ5kJyWOcssNZvPxYLr2yc=", "owner": "nix-community", "repo": "disko", - "rev": "786965e1b1ed3fd2018d78399984f461e2a44689", + "rev": "1e6f8a7b4634fc051cc9361959bf414fcf17e094", "type": "github" }, "original": { @@ -347,11 +347,11 @@ "poetry2nix": "poetry2nix" }, "locked": { - "lastModified": 1720746402, - "narHash": "sha256-+dGh0ruRbwZLymQQkvK1iqgg7J6gRp4wHxa8OqsNUlU=", + "lastModified": 1722301678, + "narHash": "sha256-dlsJGdLiXGgBSr/7Y+invyY/9+jJsFF6UkUpD7WMXRM=", "owner": "farcaller", "repo": "nixhelm", - "rev": "6fbf227d6b6b17e14a50c84ae66e9541306d4c98", + "rev": "5a983d9da254b178ac5b689405fb5b179815ef91", "type": "github" }, "original": { @@ -362,11 +362,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1720737798, - "narHash": "sha256-G/OtEAts7ZUvW5lrGMXSb8HqRp2Jr9I7reBuvCOL54w=", + "lastModified": 1722332872, + "narHash": "sha256-2xLM4sc5QBfi0U/AANJAW21Bj4ZX479MHPMPkB+eKBU=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "c5013aa7ce2c7ec90acee5d965d950c8348db751", + "rev": "14c333162ba53c02853add87a0000cbd7aa230c2", "type": "github" }, "original": { @@ -394,11 +394,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1720282526, - "narHash": "sha256-dudRkHPRivMNOhd04YI+v4sWvn2SnN5ODSPIu5IVbco=", + "lastModified": 1721524707, + "narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "550ac3e955c30fe96dd8b2223e37e0f5d225c927", + "rev": "556533a23879fc7e5f98dd2e0b31a6911a213171", "type": "github" }, "original": { @@ -410,11 +410,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1720687749, - "narHash": "sha256-nqJ+iK/zyqCJ/YShqCpZ2cJKE1UtjZIEUWLUFZqvxcA=", + "lastModified": 1722141560, + "narHash": "sha256-Ul3rIdesWaiW56PS/Ak3UlJdkwBrD4UcagCmXZR9Z7Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6af55cb91ca2005516b9562f707bb99c8f79bf77", + "rev": "038fb464fcfa79b4f08131b07f2d8c9a6bcc4160", "type": "github" }, "original": { @@ -426,11 +426,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1720691131, - "narHash": "sha256-CWT+KN8aTPyMIx8P303gsVxUnkinIz0a/Cmasz1jyIM=", + "lastModified": 1722221733, + "narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a046c1202e11b62cbede5385ba64908feb7bfac4", + "rev": "12bf09802d77264e441f48e25459c10c93eada2e", "type": "github" }, "original": { @@ -489,11 +489,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1720479166, - "narHash": "sha256-jqvhLDXzTLTHq9ZviFOpcTmXXmnbLfz7mWhgMNipMN4=", + "lastModified": 1722114803, + "narHash": "sha256-s6YhI8UHwQvO4cIFLwl1wZ1eS5Cuuw7ld2VzUchdFP0=", "owner": "Mic92", "repo": "sops-nix", - "rev": "67035a355b1d52d2d238501f8cc1a18706979760", + "rev": "eb34eb588132d653e4c4925d862f1e5a227cc2ab", "type": "github" }, "original": { diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix index a465d7e..b640519 100644 --- a/kubenix-modules/pihole.nix +++ b/kubenix-modules/pihole.nix @@ -5,6 +5,15 @@ deployments.pihole.spec = { selector.matchLabels.app = "pihole"; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels.app = "pihole"; diff --git a/nixos-modules/tailscale.nix b/nixos-modules/tailscale.nix index 796e528..8cfbfb3 100644 --- a/nixos-modules/tailscale.nix +++ b/nixos-modules/tailscale.nix @@ -18,6 +18,7 @@ in openFirewall = true; extraUpFlags = [ + "--accept-dns=false" "--hostname=${config.networking.hostName}" ] ++ lib.lists.optional cfg.advertiseExitNode "--advertise-exit-node" ++ lib.lists.optional cfg.advertiseExitNode "--advertise-routes=192.168.30.0/24"; From e21e8694c17b3565ed6d49920675b4a7362f57ac Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 30 Jul 2024 20:34:37 +0200 Subject: [PATCH 065/108] docs: Add more deployment instructions --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6215c6a..141eb2c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Run these deployments: Now the cluster has been initialized and we can deploy applications. To explore which applications we can deploy, run `nix flake show`. Then, for each application, run `nix run '.#'`. +Or, if you're lazy: `nix flake show --json | jq -r '.packages."x86_64-linux"|keys[]' | grep -- -deploy | xargs -I{} nix run ".#{}"`. ## Known bugs From 872f8fe89e2669e7f3225f753f2bbc2d27c2d9ab Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 30 Jul 2024 21:01:41 +0200 Subject: [PATCH 066/108] chore: Update jellyfin, radarr, prowlarr and sonarr --- kubenix-modules/media.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index c1159a2..98e41a4 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -24,7 +24,7 @@ spec = { containers.jellyfin = { - image = "jellyfin/jellyfin:10.9.7"; + image = "jellyfin/jellyfin:10.9.8"; ports.web.containerPort = 8096; imagePullPolicy = "IfNotPresent"; @@ -201,7 +201,7 @@ spec = { containers.radarr = { - image = "lscr.io/linuxserver/radarr:5.7.0"; + image = "lscr.io/linuxserver/radarr:5.8.3"; ports.web.containerPort = 7878; imagePullPolicy = "IfNotPresent"; @@ -261,7 +261,7 @@ volumes.config.persistentVolumeClaim.claimName = "prowlarr"; containers.prowlarr = { - image = "lscr.io/linuxserver/prowlarr:1.20.1"; + image = "lscr.io/linuxserver/prowlarr:1.21.2"; ports.web.containerPort = 9696; imagePullPolicy = "IfNotPresent"; @@ -308,7 +308,7 @@ spec = { containers.sonarr = { - image = "lscr.io/linuxserver/sonarr:4.0.6"; + image = "lscr.io/linuxserver/sonarr:4.0.8"; ports.web.containerPort = 8989; imagePullPolicy = "IfNotPresent"; From 5a6b9f203ae9f35221cd4c1782d88d28b6255f2c Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 30 Jul 2024 21:28:35 +0200 Subject: [PATCH 067/108] refactor: Extract all image names --- kubenix-modules/attic.nix | 6 +- kubenix-modules/atuin.nix | 6 +- kubenix-modules/bind9/default.nix | 4 +- kubenix-modules/cyberchef.nix | 4 +- kubenix-modules/dnsmasq.nix | 2 +- kubenix-modules/forgejo/default.nix | 2 +- kubenix-modules/freshrss.nix | 2 +- kubenix-modules/hedgedoc.nix | 6 +- kubenix-modules/immich.nix | 8 +-- kubenix-modules/inbucket.nix | 2 +- kubenix-modules/kitchenowl.nix | 4 +- kubenix-modules/kms.nix | 2 +- kubenix-modules/media.nix | 14 ++--- kubenix-modules/minecraft.nix | 2 +- kubenix-modules/nextcloud.nix | 4 +- kubenix-modules/ntfy.nix | 4 +- kubenix-modules/paperless.nix | 6 +- kubenix-modules/pihole.nix | 2 +- kubenix-modules/radicale.nix | 2 +- kubenix-modules/syncthing.nix | 2 +- my-lib/globals.nix | 38 ++++++++++++ nixos-modules/globals.nix | 89 ----------------------------- 22 files changed, 80 insertions(+), 131 deletions(-) delete mode 100644 nixos-modules/globals.nix diff --git a/kubenix-modules/attic.nix b/kubenix-modules/attic.nix index b8fe530..c4e4cf9 100644 --- a/kubenix-modules/attic.nix +++ b/kubenix-modules/attic.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: { +{ pkgs, myLib, ... }: { kubernetes.resources = let atticSettings = { @@ -62,7 +62,7 @@ spec = { containers.attic = { - image = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; + image = myLib.globals.images.attic; ports.web.containerPort = 8080; args = [ "-f" "/etc/atticd/config.toml" ]; @@ -111,7 +111,7 @@ spec = { containers.postgres = { - image = "postgres:15"; + image = myLib.globals.images.atticPostgres; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/atuin.nix b/kubenix-modules/atuin.nix index 198384e..96a1002 100644 --- a/kubenix-modules/atuin.nix +++ b/kubenix-modules/atuin.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { secrets.database.stringData = { databasePassword = "ref+sops://secrets/kubernetes.yaml#/atuin/databasePassword"; @@ -28,7 +28,7 @@ containers = { atuin = { - image = "ghcr.io/atuinsh/atuin:18.3.0"; + image = myLib.globals.images.atuin; imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 8888; args = [ "server" "start" ]; @@ -51,7 +51,7 @@ }; database = { - image = "postgres:14"; + image = myLib.globals.images.atuinPostgres; ports.web.containerPort = 5432; env = { diff --git a/kubenix-modules/bind9/default.nix b/kubenix-modules/bind9/default.nix index 50aaefc..a5411f0 100644 --- a/kubenix-modules/bind9/default.nix +++ b/kubenix-modules/bind9/default.nix @@ -50,7 +50,7 @@ in spec = { containers = { bind9-udp = { - image = "ubuntu/bind9:9.18-22.04_beta"; + image = myLib.globals.images.bind9; envFrom = [{ configMapRef.name = "bind9-env"; }]; ports.dns-udp = { @@ -73,7 +73,7 @@ in }; bind9-tcp = { - image = "ubuntu/bind9:9.18-22.04_beta"; + image = myLib.globals.images.bind9; envFrom = [{ configMapRef.name = "bind9-env"; }]; ports.dns-tcp = { diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index 19c2578..d7ab260 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { deployments.cyberchef.spec = { replicas = 3; @@ -8,7 +8,7 @@ metadata.labels.app = "cyberchef"; spec.containers.cyberchef = { - image = "mpepping/cyberchef"; + image = myLib.globals.images.cyberchef; ports.web.containerPort = 8000; }; }; diff --git a/kubenix-modules/dnsmasq.nix b/kubenix-modules/dnsmasq.nix index bc29d61..90655ea 100644 --- a/kubenix-modules/dnsmasq.nix +++ b/kubenix-modules/dnsmasq.nix @@ -23,7 +23,7 @@ spec = { containers.dnsmasq = { - image = "dockurr/dnsmasq:2.90"; + image = myLib.globals.images.dnsmasq; ports.dns = { containerPort = 53; diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix index 6b9a123..ea98aaf 100644 --- a/kubenix-modules/forgejo/default.nix +++ b/kubenix-modules/forgejo/default.nix @@ -27,7 +27,7 @@ enableServiceLinks = false; containers.forgejo = { - image = "codeberg.org/forgejo/forgejo:7.0.5"; + image = myLib.globals.images.forgejo; imagePullPolicy = "IfNotPresent"; env = { diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix index 525e4b4..614847e 100644 --- a/kubenix-modules/freshrss.nix +++ b/kubenix-modules/freshrss.nix @@ -19,7 +19,7 @@ spec = { containers.freshrss = { - image = "freshrss/freshrss:1.24.1"; + image = myLib.globals.images.freshrss; imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 80; diff --git a/kubenix-modules/hedgedoc.nix b/kubenix-modules/hedgedoc.nix index 1ba013b..b91c0de 100644 --- a/kubenix-modules/hedgedoc.nix +++ b/kubenix-modules/hedgedoc.nix @@ -1,4 +1,4 @@ -{ lib, ... }: { +{ lib, myLib, ... }: { kubernetes.resources = { configMaps.hedgedoc-config.data.config = lib.generators.toJSON { } { useSSL = false; @@ -24,7 +24,7 @@ spec = { containers.hedgedoc = { - image = "quay.io/hedgedoc/hedgedoc:1.9.9"; + image = myLib.globals.images.hedgedoc; ports.web.containerPort = 3000; env = { @@ -87,7 +87,7 @@ spec = { containers.postgres = { - image = "postgres:15"; + image = myLib.globals.images.hedgedocPostgres; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 8051944..19d5e14 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -28,7 +28,7 @@ enableServiceLinks = false; containers.immich = { - image = "ghcr.io/immich-app/immich-server:v1.108.0"; + image = myLib.globals.images.immich; imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 3001; @@ -67,7 +67,7 @@ volumes.cache.persistentVolumeClaim.claimName = "cache"; containers.machine-learning = { - image = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; + image = myLib.globals.images.immichML; imagePullPolicy = "IfNotPresent"; ports.ml.containerPort = 3003; env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; @@ -104,7 +104,7 @@ spec = { containers.redis = { - image = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; + image = myLib.globals.images.immichRedis; ports.redis.containerPort = 6379; imagePullPolicy = "IfNotPresent"; }; @@ -137,7 +137,7 @@ volumes.data.persistentVolumeClaim.claimName = "database"; containers.postgres = { - image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + image = myLib.globals.images.immichPostgres; imagePullPolicy = "IfNotPresent"; command = [ "postgres" ]; args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 909c236..63f8852 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -13,7 +13,7 @@ containers = { inbucket = { - image = "inbucket/inbucket:edge"; + image = myLib.globals.images.inbucket; ports = { web.containerPort = 9000; diff --git a/kubenix-modules/kitchenowl.nix b/kubenix-modules/kitchenowl.nix index ff62a14..9e5e14d 100644 --- a/kubenix-modules/kitchenowl.nix +++ b/kubenix-modules/kitchenowl.nix @@ -1,4 +1,4 @@ -{ +{ myLib, ... }: { kubernetes.resources = { secrets.server.stringData.jwtSecretKey = "ref+sops://secrets/kubernetes.yaml#/kitchenowl/jwtSecretKey"; @@ -21,7 +21,7 @@ volumes.data.persistentVolumeClaim.claimName = "data"; containers.kitchenowl = { - image = "tombursch/kitchenowl:v0.5.1"; + image = myLib.globals.images.kitchenowl; ports.web.containerPort = 8080; imagePullPolicy = "IfNotPresent"; diff --git a/kubenix-modules/kms.nix b/kubenix-modules/kms.nix index 151c8df..8dc37b5 100644 --- a/kubenix-modules/kms.nix +++ b/kubenix-modules/kms.nix @@ -7,7 +7,7 @@ metadata.labels.app = "kms"; spec.containers.kms = { - image = "teddysun/kms"; + image = myLib.globals.images.kms; ports.kms.containerPort = 1688; }; }; diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix index 98e41a4..8e5a7c0 100644 --- a/kubenix-modules/media.nix +++ b/kubenix-modules/media.nix @@ -24,7 +24,7 @@ spec = { containers.jellyfin = { - image = "jellyfin/jellyfin:10.9.8"; + image = myLib.globals.images.jellyfin; ports.web.containerPort = 8096; imagePullPolicy = "IfNotPresent"; @@ -95,7 +95,7 @@ spec = { containers.deluge = { - image = "linuxserver/deluge:2.1.1"; + image = myLib.globals.images.deluge; imagePullPolicy = "IfNotPresent"; env = { @@ -155,7 +155,7 @@ volumes.config.persistentVolumeClaim.claimName = "jellyseerr"; containers.jellyseerr = { - image = "fallenbagel/jellyseerr:1.9.2"; + image = myLib.globals.images.jellyseerr; ports.web.containerPort = 5055; imagePullPolicy = "IfNotPresent"; @@ -201,7 +201,7 @@ spec = { containers.radarr = { - image = "lscr.io/linuxserver/radarr:5.8.3"; + image = myLib.globals.images.radarr; ports.web.containerPort = 7878; imagePullPolicy = "IfNotPresent"; @@ -261,7 +261,7 @@ volumes.config.persistentVolumeClaim.claimName = "prowlarr"; containers.prowlarr = { - image = "lscr.io/linuxserver/prowlarr:1.21.2"; + image = myLib.globals.images.prowlarr; ports.web.containerPort = 9696; imagePullPolicy = "IfNotPresent"; @@ -308,7 +308,7 @@ spec = { containers.sonarr = { - image = "lscr.io/linuxserver/sonarr:4.0.8"; + image = myLib.globals.images.sonarr; ports.web.containerPort = 8989; imagePullPolicy = "IfNotPresent"; @@ -366,7 +366,7 @@ spec = { containers.bazarr = { - image = "lscr.io/linuxserver/bazarr:1.4.3"; + image = myLib.globals.images.bazarr; ports.web.containerPort = 6767; imagePullPolicy = "IfNotPresent"; diff --git a/kubenix-modules/minecraft.nix b/kubenix-modules/minecraft.nix index a3157eb..acf855a 100644 --- a/kubenix-modules/minecraft.nix +++ b/kubenix-modules/minecraft.nix @@ -10,7 +10,7 @@ # volumes.data.persistentVolumeClaim.claimName = "data"; # containers.minecraft = { - # image = "itzg/minecraft-server"; + # image = myLib.globals.images.minecraft; # ports.minecraft.containerPort = 25565; # env.EULA.value = "TRUE"; diff --git a/kubenix-modules/nextcloud.nix b/kubenix-modules/nextcloud.nix index f499734..11f5aef 100644 --- a/kubenix-modules/nextcloud.nix +++ b/kubenix-modules/nextcloud.nix @@ -28,7 +28,7 @@ volumes.data.persistentVolumeClaim.claimName = "data"; containers.nextcloud = { - image = "nextcloud:28"; + image = myLib.globals.images.nextcloud; ports.web.containerPort = 80; env = { @@ -79,7 +79,7 @@ spec = { containers.postgres = { - image = "postgres:15"; + image = myLib.globals.images.nextcloudPostgres; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/ntfy.nix b/kubenix-modules/ntfy.nix index 36009ff..a1c3a27 100644 --- a/kubenix-modules/ntfy.nix +++ b/kubenix-modules/ntfy.nix @@ -1,4 +1,4 @@ -{ lib, ... }: { +{ lib, myLib, ... }: { kubernetes.resources = { configMaps.ntfy.data.config = lib.generators.toYAML { } { base-url = "https://ntfy.kun.is"; @@ -29,7 +29,7 @@ spec = { containers.ntfy = { - image = "binwiederhier/ntfy:v2.11.0"; + image = myLib.globals.images.ntfy; ports.web.containerPort = 80; env.TZ.value = "Europe/Amsterdam"; args = [ "serve" ]; diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index 054362b..f883782 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -31,7 +31,7 @@ volumes.data.persistentVolumeClaim.claimName = "data"; containers.paperless = { - image = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; + image = myLib.globals.images.paperless; imagePullPolicy = "IfNotPresent"; ports.web.containerPort = 8000; @@ -100,7 +100,7 @@ volumes.data.persistentVolumeClaim.claimName = "redisdata"; containers.redis = { - image = "docker.io/library/redis:7"; + image = myLib.globals.images.paperlessRedis; ports.redis.containerPort = 6379; imagePullPolicy = "IfNotPresent"; @@ -141,7 +141,7 @@ spec = { containers.postgres = { - image = "postgres:15"; + image = myLib.globals.images.paperlessPostgres; ports.postgres.containerPort = 5432; imagePullPolicy = "IfNotPresent"; diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix index b640519..0139b6f 100644 --- a/kubenix-modules/pihole.nix +++ b/kubenix-modules/pihole.nix @@ -19,7 +19,7 @@ spec = { containers.pihole = { - image = "pihole/pihole:latest"; + image = myLib.globals.images.pihole; env = { TZ.value = "Europe/Amsterdam"; diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix index 7fcc6f8..9e8701d 100644 --- a/kubenix-modules/radicale.nix +++ b/kubenix-modules/radicale.nix @@ -50,7 +50,7 @@ spec = { containers.radicale = { - image = "tomsquest/docker-radicale:3.2.2.0"; + image = myLib.globals.images.radicale; ports.web.containerPort = 5232; imagePullPolicy = "IfNotPresent"; diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index c5e2304..f68841e 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -21,7 +21,7 @@ serviceAccountName = "syncthing"; containers.syncthing = { - image = "lscr.io/linuxserver/syncthing:1.23.6"; + image = myLib.globals.images.syncthing; ports.web.containerPort = 8384; imagePullPolicy = "IfNotPresent"; diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 28a2163..3f524a7 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -25,4 +25,42 @@ freshrssIPv4 = "192.168.30.146"; immichIPv4 = "192.168.30.147"; nextcloudIPv4 = "192.168.30.148"; + + images = { + jellyfin = "jellyfin/jellyfin:10.9.8"; + deluge = "linuxserver/deluge:2.1.1"; + jellyseerr = "fallenbagel/jellyseerr:1.9.2"; + radarr = "lscr.io/linuxserver/radarr:5.8.3"; + prowlarr = "lscr.io/linuxserver/prowlarr:1.21.2"; + sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; + bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; + atuin = "ghcr.io/atuinsh/atuin:18.3.0"; + atuinPostgres = "postgres:14"; + kms = "teddysun/kms"; + paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; + paperlessRedis = "docker.io/library/redis:7"; + paperlessPostgres = "postgres:15"; + nextcloud = "nextcloud:28"; + nextcloudPostgres = "postgres:15"; + inbucket = "inbucket/inbucket:edge"; + syncthing = "lscr.io/linuxserver/syncthing:1.23.6"; + radicale = "tomsquest/docker-radicale:3.2.2.0"; + ntfy = "binwiederhier/ntfy:v2.11.0"; + forgejo = "codeberg.org/forgejo/forgejo:7.0.5"; + pihole = "pihole/pihole:latest"; + immich = "ghcr.io/immich-app/immich-server:v1.108.0"; + immichML = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; + immichRedis = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; + immichPostgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + kitchenowl = "tombursch/kitchenowl:v0.5.1"; + cyberchef = "mpepping/cyberchef"; + freshrss = "freshrss/freshrss:1.24.1"; + bind9 = "ubuntu/bind9:9.18-22.04_beta"; + dnsmasq = "dockurr/dnsmasq:2.90"; + attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; + atticPostgres = "postgres:15"; + hedgedoc = "quay.io/hedgedoc/hedgedoc:1.9.9"; + hedgedocPostgres = "postgres:15"; + minecraft = "itzg/minecraft-server"; + }; } diff --git a/nixos-modules/globals.nix b/nixos-modules/globals.nix deleted file mode 100644 index 3f62be2..0000000 --- a/nixos-modules/globals.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ lib, ... }: { - options.lab = { - - networking = { - public = { - ipv4 = { - router = lib.mkOption { - type = lib.types.str; - description = '' - Public IPv4 address of the router. - ''; - }; - }; - - ipv6 = { - router = lib.mkOption { - type = lib.types.str; - description = '' - Publicly routable IPv6 address of the router. - ''; - }; - }; - }; - - dmz = { - ipv4 = { - prefixLength = lib.mkOption { - type = lib.types.str; - description = '' - IPv4 prefix length of DMZ network. - ''; - }; - - dockerSwarm = lib.mkOption { - type = lib.types.str; - description = '' - IPv4 address of the Docker Swarm in the DMZ. - ''; - }; - - - router = lib.mkOption { - type = lib.types.str; - description = '' - The router's IPv4 address on the DMZ network. - ''; - }; - - services = lib.mkOption { - type = lib.types.str; - description = '' - The IPv4 address of the interface serving DHCP and DNS on the DMZ network. - ''; - }; - }; - - ipv6 = { - prefixLength = lib.mkOption { - type = lib.types.str; - description = '' - IPv6 prefix length of DMZ network. - ''; - }; - - dockerSwarm = lib.mkOption { - type = lib.types.str; - description = '' - Globally routable IPv6 address of the Docker Swarm. - ''; - }; - - router = lib.mkOption { - type = lib.types.str; - description = '' - The router's IPv6 address on the DMZ network. - ''; - }; - - services = lib.mkOption { - type = lib.types.str; - description = '' - The IPv6 address of the interface serving DHCP and DNS on the DMZ network. - ''; - }; - }; - }; - }; - }; -} From 2c0a60097ace947bdaaa2473c6e70f4c02ba093a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 30 Jul 2024 22:29:10 +0200 Subject: [PATCH 068/108] chore: Update Paperless 2.3 -> 2.11.2 chore: Update Nextcloud 28 -> 29.0.4 chore: Update Syncthing 1.23.6 -> 1.27.9 chore: Update Forgejo 7.0.5 -> 8.0.0 chore: Update Immich 1.108.0 -> 1.111.0 chore: Update Kitchenowl 0.5.1 -> 0.5.2 chore: Pin Pihole to 2024.07.0 fix: Disallow rolling updates for immich ML fix: Use tailscale host as domain --- kubenix-modules/immich.nix | 9 +++++++++ kubenix-modules/paperless.nix | 2 +- my-lib/globals.nix | 18 +++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 19d5e14..63a0cb6 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -57,6 +57,15 @@ component = "machine-learning"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "immich"; diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index f883782..9b91d95 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -44,7 +44,7 @@ PAPERLESS_DATA_DIR.value = "/data/"; PAPERLESS_MEDIA_ROOT.value = "/data/"; PAPERLESS_OCR_LANGUAGES.value = "nld eng"; - PAPERLESS_URL.value = "https://paperless.kun.is"; + PAPERLESS_URL.value = "https://paperless.griffin-mermaid.ts.net"; PAPERLESS_TIME_ZONE.value = "Europe/Amsterdam"; PAPERLESS_OCR_LANGUAGE.value = "nld"; USERMAP_UID.value = "33"; diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 3f524a7..9704459 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -37,22 +37,22 @@ atuin = "ghcr.io/atuinsh/atuin:18.3.0"; atuinPostgres = "postgres:14"; kms = "teddysun/kms"; - paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.3"; + paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.2"; paperlessRedis = "docker.io/library/redis:7"; paperlessPostgres = "postgres:15"; - nextcloud = "nextcloud:28"; + nextcloud = "nextcloud:29.0.4"; nextcloudPostgres = "postgres:15"; inbucket = "inbucket/inbucket:edge"; - syncthing = "lscr.io/linuxserver/syncthing:1.23.6"; + syncthing = "lscr.io/linuxserver/syncthing:1.27.9"; radicale = "tomsquest/docker-radicale:3.2.2.0"; ntfy = "binwiederhier/ntfy:v2.11.0"; - forgejo = "codeberg.org/forgejo/forgejo:7.0.5"; - pihole = "pihole/pihole:latest"; - immich = "ghcr.io/immich-app/immich-server:v1.108.0"; - immichML = "ghcr.io/immich-app/immich-machine-learning:v1.108.0"; - immichRedis = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; + forgejo = "codeberg.org/forgejo/forgejo:8.0.0"; + pihole = "pihole/pihole:2024.07.0"; + immich = "ghcr.io/immich-app/immich-server:v1.111.0"; + immichML = "ghcr.io/immich-app/immich-machine-learning:v1.111.0"; + immichRedis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; immichPostgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; - kitchenowl = "tombursch/kitchenowl:v0.5.1"; + kitchenowl = "tombursch/kitchenowl:v0.5.2"; cyberchef = "mpepping/cyberchef"; freshrss = "freshrss/freshrss:1.24.1"; bind9 = "ubuntu/bind9:9.18-22.04_beta"; From 5432d93f85a9c1cda823259a4fe9a559c14e7a28 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 4 Aug 2024 14:59:11 +0200 Subject: [PATCH 069/108] refactor: Convert configmaps containing secrets to secrets closes #85 --- kubenix-modules/attic.nix | 19 +++++++++++++++---- kubenix-modules/forgejo/default.nix | 8 ++------ kubenix-modules/hedgedoc.nix | 7 ++++++- kubenix-modules/immich.nix | 14 ++++++++++++-- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/kubenix-modules/attic.nix b/kubenix-modules/attic.nix index c4e4cf9..7d59c8b 100644 --- a/kubenix-modules/attic.nix +++ b/kubenix-modules/attic.nix @@ -40,10 +40,12 @@ generatedConfig = (pkgs.formats.toml { }).generate "attic.toml" atticSettings; in { - configMaps.config.data.config = builtins.readFile generatedConfig; - secrets = { - server.stringData.token = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; + server.stringData = { + token = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; + config = builtins.readFile generatedConfig; + }; + database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/attic/databasePassword"; }; @@ -54,6 +56,15 @@ component = "website"; }; + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + template = { metadata.labels = { app = "attic"; @@ -86,7 +97,7 @@ volumes = { data.persistentVolumeClaim.claimName = "data"; - config.configMap.name = "config"; + config.secret.secretName = "server"; }; securityContext = { diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix index ea98aaf..74e89f3 100644 --- a/kubenix-modules/forgejo/default.nix +++ b/kubenix-modules/forgejo/default.nix @@ -1,10 +1,6 @@ { lib, myLib, ... }: { kubernetes.resources = { - configMaps = { - config.data = { - config = lib.generators.toINI { } (import ./config.nix); - }; - }; + secrets.forgejo.stringData.config = lib.generators.toINI { } (import ./config.nix); deployments.server.spec = { selector.matchLabels.app = "forgejo"; @@ -55,7 +51,7 @@ volumes = { data.persistentVolumeClaim.claimName = "data"; - config.configMap.name = "config"; + config.secret.secretName = "forgejo"; }; }; }; diff --git a/kubenix-modules/hedgedoc.nix b/kubenix-modules/hedgedoc.nix index b91c0de..7cb68cc 100644 --- a/kubenix-modules/hedgedoc.nix +++ b/kubenix-modules/hedgedoc.nix @@ -7,6 +7,7 @@ secrets.hedgedoc.stringData = { databaseURL = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databaseURL"; sessionSecret = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/sessionSecret"; + databasePassword = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databasePassword"; }; deployments = { @@ -94,8 +95,12 @@ env = { POSTGRES_DB.value = "hedgedoc"; POSTGRES_USER.value = "hedgedoc"; - POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databasePassword"; PGDATA.value = "/pgdata/data"; + + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "hedgedoc"; + key = "databasePassword"; + }; }; volumeMounts = [{ diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index 63a0cb6..e51297f 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -1,5 +1,7 @@ { myLib, ... }: { kubernetes.resources = { + secrets.immich.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; + deployments = { immich.spec = { selector.matchLabels = { @@ -37,9 +39,13 @@ REDIS_HOSTNAME.value = "redis.immich.svc.cluster.local"; DB_HOSTNAME.value = "postgres.immich.svc.cluster.local"; DB_USERNAME.value = "postgres"; - DB_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; DB_DATABASE_NAME.value = "immich"; IMMICH_MACHINE_LEARNING_URL.value = "http://ml.immich.svc.cluster.local"; + + DB_PASSWORD.valueFrom.secretKeyRef = { + name = "immich"; + key = "databasePassword"; + }; }; volumeMounts = [{ @@ -155,11 +161,15 @@ securityContext.runAsGroup = 999; env = { - POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; POSTGRES_USER.value = "postgres"; POSTGRES_DB.value = "immich"; POSTGRES_INITDB_ARGS.value = "--data-checksums"; PGDATA.value = "/pgdata/data"; + + POSTGRES_PASSWORD.valueFrom.secretKeyRef = { + name = "immich"; + key = "databasePassword"; + }; }; volumeMounts = [{ From 0539d3567805b1241fe91550c7a9968eada7c2a1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 24 Aug 2024 22:28:00 +0200 Subject: [PATCH 070/108] chore(forgejo): update to 8.0.1 --- my-lib/globals.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 9704459..f9d2a30 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -46,7 +46,7 @@ syncthing = "lscr.io/linuxserver/syncthing:1.27.9"; radicale = "tomsquest/docker-radicale:3.2.2.0"; ntfy = "binwiederhier/ntfy:v2.11.0"; - forgejo = "codeberg.org/forgejo/forgejo:8.0.0"; + forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; pihole = "pihole/pihole:2024.07.0"; immich = "ghcr.io/immich-app/immich-server:v1.111.0"; immichML = "ghcr.io/immich-app/immich-machine-learning:v1.111.0"; From 55b18ef4509eef77fa691da8652697cf1cfe214f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 24 Aug 2024 22:30:46 +0200 Subject: [PATCH 071/108] Refactor storage module Add talos and pikvm machines --- .sops.yaml | 4 + configuration.nix | 2 +- machines/atlas.nix | 2 + machines/default.nix | 2 + machines/jefke.nix | 2 + machines/lewis.nix | 1 + machines/pikvm.nix | 23 ++++ machines/talos.nix | 11 ++ machines/warwick.nix | 1 + nixos-modules/storage.nix | 225 +++++++++++++++++++++++--------------- secrets/nixos.yaml | 78 ++++++++----- secrets/serverKeys.yaml | 6 +- 12 files changed, 234 insertions(+), 123 deletions(-) create mode 100644 machines/pikvm.nix create mode 100644 machines/talos.nix diff --git a/.sops.yaml b/.sops.yaml index 17a442c..3abcfb1 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -5,6 +5,8 @@ keys: - &server_jefke age1upnqu4rpxppdw9zmqu8x3rnaqq2r6m82y25zvry5cec63vjsd9gqtl9e02 - &server_lewis age108fn93z2c55g9dm9cv5v4w47pykf3khz7e3dmnpv5dhchwnaau0qs20stq - &server_warwick age1th8rdw4fs3vmgy9gzc0k9xy88tddjj4vasepckfx9h4nlzsg3q3q4cjgwu + - &server_talos age1h5q9ul9f8vd7w7s2fvmpytaghgpv97a9r237agwzc52c76xsdegsugml73 + - &server_pikvm age1smqas3tre2hptnyn72fdzghqcnej48066l4hp6y98n8lkpm3ds4s8t8s0w creation_rules: - path_regex: secrets/(kubernetes|serverKeys).yaml$ @@ -21,3 +23,5 @@ creation_rules: - *server_jefke - *server_lewis - *server_warwick + - *server_talos + - *server_pikvm diff --git a/configuration.nix b/configuration.nix index e53a6f7..3186878 100644 --- a/configuration.nix +++ b/configuration.nix @@ -107,7 +107,7 @@ }; loader = { - systemd-boot.enable = true; + systemd-boot.enable = lib.mkDefault true; efi.canTouchEfiVariables = true; }; }; diff --git a/machines/atlas.nix b/machines/atlas.nix index 477fa25..a9866d4 100644 --- a/machines/atlas.nix +++ b/machines/atlas.nix @@ -4,6 +4,8 @@ kubernetesNodeLabels.storageType = "slow"; nixosModule.lab = { + storage.profile = "kubernetes"; + k3s = { enable = true; serverAddr = "https://jefke.dmz:6443"; diff --git a/machines/default.nix b/machines/default.nix index c1e0351..4adab0f 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -39,6 +39,8 @@ in ./atlas.nix ./jefke.nix ./lewis.nix + ./talos.nix + ./pikvm.nix ]; options = { diff --git a/machines/jefke.nix b/machines/jefke.nix index 877fbb9..362b268 100644 --- a/machines/jefke.nix +++ b/machines/jefke.nix @@ -4,6 +4,8 @@ kubernetesNodeLabels.storageType = "fast"; nixosModule.lab = { + storage.profile = "kubernetes"; + k3s = { enable = true; clusterInit = true; diff --git a/machines/lewis.nix b/machines/lewis.nix index 107f616..6999c81 100644 --- a/machines/lewis.nix +++ b/machines/lewis.nix @@ -8,6 +8,7 @@ nixosModule = { lab = { + storage.profile = "kubernetes"; backups.enable = true; data-sharing.enable = true; diff --git a/machines/pikvm.nix b/machines/pikvm.nix new file mode 100644 index 0000000..6a7bc14 --- /dev/null +++ b/machines/pikvm.nix @@ -0,0 +1,23 @@ +{ + machines.pikvm = { + arch = "aarch64-linux"; + isRaspberryPi = true; + + nixosModule = { config, inputs, lib, ... }: { + # imports = [ "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" ]; + lab = { + storage.profile = "pi"; + }; + + environment.systemPackages = with inputs.nixpkgs.legacyPackages.aarch64-linux; [ + (mplayer.override { + v4lSupport = true; + }) + ffmpeg + v4l-utils + ]; + + boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; + }; + }; +} diff --git a/machines/talos.nix b/machines/talos.nix new file mode 100644 index 0000000..0fa0311 --- /dev/null +++ b/machines/talos.nix @@ -0,0 +1,11 @@ +{ + machines.talos = { + arch = "x86_64-linux"; + + nixosModule = { lib, ... }: { + lab.storage.profile = "normal"; + + # boot.loader.systemd-boot.enable = lib.mkForce false; + }; + }; +} diff --git a/machines/warwick.nix b/machines/warwick.nix index 9859a28..6160f02 100644 --- a/machines/warwick.nix +++ b/machines/warwick.nix @@ -5,6 +5,7 @@ nixosModule = { lib, ... }: { lab = { + storage.profile = "pi"; monitoring.server.enable = true; tailscale.advertiseExitNode = true; }; diff --git a/nixos-modules/storage.nix b/nixos-modules/storage.nix index 13b9297..670cb7f 100644 --- a/nixos-modules/storage.nix +++ b/nixos-modules/storage.nix @@ -1,27 +1,126 @@ -{ lib, config, machine, ... }: -let cfg = config.lab.storage; -in { - options.lab.storage = { - osDisk = lib.mkOption { - type = with lib.types; nullOr str; - description = '' - The disk to be used for the machine's operating system. - ''; - }; - }; +{ lib, config, ... }: +let + cfg = config.lab.storage; + modules = [ + { + config = lib.mkIf (cfg.profile == "pi") { + fileSystems."/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + options = [ "noatime" ]; + }; + }; + } - config = { - fileSystems."/" = lib.mkIf machine.isRaspberryPi { - device = "/dev/disk/by-label/NIXOS_SD"; - fsType = "ext4"; - options = [ "noatime" ]; - }; + { + config = lib.mkIf (cfg.profile == "kubernetes") { + disko.devices = { + disk = { + nvme = { + device = "/dev/nvme0n1"; + type = "disk"; - disko = lib.mkIf (! machine.isRaspberryPi) { - devices = { - disk = { - nvme = { - device = "/dev/nvme0n1"; + content = { + type = "gpt"; + + partitions = { + boot = { + type = "EF00"; + size = "500M"; + + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + + pv_os = { + size = "79G"; + + content = { + type = "lvm_pv"; + vg = "vg_os"; + }; + }; + + pv_nvme_extra = { + size = "100%"; + + content = { + type = "lvm_pv"; + vg = "vg_data"; + }; + }; + }; + }; + }; + + sata = { + device = "/dev/sda"; + type = "disk"; + + content = { + type = "gpt"; + + partitions.pv_sata = { + size = "100%"; + + content = { + type = "lvm_pv"; + vg = "vg_data"; + }; + }; + }; + }; + }; + + lvm_vg = { + vg_os = { + type = "lvm_vg"; + + lvs = { + root = { + size = "75G"; + + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + mountOptions = [ "defaults" ]; + }; + }; + + swap = { + size = "100%FREE"; + content.type = "swap"; + }; + }; + }; + + vg_data = { + type = "lvm_vg"; + + lvs.longhorn = { + size = "100%FREE"; + + content = { + type = "filesystem"; + format = "xfs"; + mountpoint = "/mnt/longhorn"; + }; + }; + }; + }; + }; + }; + } + + { + config = lib.mkIf (cfg.profile == "normal") { + disko.devices = { + disk.sata = { + device = "/dev/sda"; type = "disk"; content = { @@ -39,84 +138,30 @@ in { }; }; - pv_os = { - size = "79G"; - - content = { - type = "lvm_pv"; - vg = "vg_os"; - }; - }; - - pv_nvme_extra = { + root = { size = "100%"; content = { - type = "lvm_pv"; - vg = "vg_data"; + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + mountOptions = [ "defaults" ]; }; }; }; }; }; - - sata = { - device = "/dev/sda"; - type = "disk"; - - content = { - type = "gpt"; - - partitions.pv_sata = { - size = "100%"; - - content = { - type = "lvm_pv"; - vg = "vg_data"; - }; - }; - }; - }; - }; - - lvm_vg = { - vg_os = { - type = "lvm_vg"; - - lvs = { - root = { - size = "75G"; - - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - mountOptions = [ "defaults" ]; - }; - }; - - swap = { - size = "100%FREE"; - content.type = "swap"; - }; - }; - }; - - vg_data = { - type = "lvm_vg"; - - lvs.longhorn = { - size = "100%FREE"; - - content = { - type = "filesystem"; - format = "xfs"; - mountpoint = "/mnt/longhorn"; - }; - }; - }; }; }; + } + ]; +in +{ + imports = modules; + + options.lab.storage = { + profile = lib.mkOption { + type = lib.types.str; }; }; } diff --git a/secrets/nixos.yaml b/secrets/nixos.yaml index 6bbc8e8..3405265 100644 --- a/secrets/nixos.yaml +++ b/secrets/nixos.yaml @@ -22,56 +22,74 @@ sops: - recipient: age189laethzry4ylnd790dmpuc4xjjuwqxruc76caj3ceqhqug4g9qs0upuvw enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOVluY3hiZXVNNnlINHRG - K2Fwa0VIWDlETmZwUzNFbkNHZSttNHhUbnlVCjVVdWZHVzJCTkQyS3VlSXA0WFhY - TnR0TEZBQWwzNlVVdVl2K1RnUzE0UG8KLS0tIHhoU0xGM0xJR3ZwbHJNaTlPUHBQ - VzJCQjQ0NG5sbWFLK2phM2lEdlpuMG8Kw8ftkoEbYrA++cJSfUZRthK2cU+iIzNy - oYxlHm5va6JVZ/Sg05mxBB8kWX410/yCW9nH6ZkLrJ5YmpugePzr2g== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJc244cytDZ29QSG5LMzlU + RXBwZ2FWcGJTMCs2R0o5R2YyRXZOUklIc2hBCjJVS2l0bG1SK3Z4MWpYUWxaWXgv + ZWVYeCt2NFZGME5mYTVycUloZ09wYkUKLS0tIEtPMzRpamc0dkFoZS9JZzNEbzFI + MlBUT1RJanNzcTJkb25rWjZwbW0zeW8KsbrRPWw1qMOBCXZWkgdlVR1+tEqXYix2 + sOV5n3DmeljL2NrKX8j4qRTuxpPQKuJ9FU7DAF8HRWRkyXTnGJ79ow== -----END AGE ENCRYPTED FILE----- - recipient: age159whjxeyw94xmkkephmtlur8e85xd9d5vnvkwkcayfv7el0neqfq863yga enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0bXZMZlVRNWIydFdUcE9T - c0FMN3AvWXUyTUQ4U0VJL3IzcVpXTnVGOTBNCk5rWFlWeVA4b0JRZXY3NHhSbEVp - RlA5cGs0SVg1Rk4xZXBVdWtUcHFURjgKLS0tIHlwTWJQR09DZnBUTWY2NWdFZWZN - RkxTQ1p4VG9sZ0UrWW9ZWnZLNjZtQW8Kax+WCtGOaNYdkmV/Ty2pP9JFgRaHe/Xn - C1o5W2hMBSoLcC14mlokdVKp81dPDQuuxLtDcCgCQU7aOzvWO3CqKg== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJblNBTTFuNFNVSkhFRkhq + ZmlPU1ptRm9VblB6di9LeStVcDV4VGZ6cEYwCngrVVVqdUxVY0RrWFRCK3FxTWh4 + cEhHOGM2Z09CREZSVnFRSnVVQW51M1UKLS0tIEl1K1VoMjhpeUg5UXBsQWNiU0FP + UFE3RDF1bXBZOVVFbVBBWWs5RlZOdDQK6LXDGPl9HBmbYgVlmtjiT2BmQXJ/3K7e + 2eFhmEzFzpE8DS0X7pIV6dSYWHku1CslwlsQK60rJr2ipve6u62sdA== -----END AGE ENCRYPTED FILE----- - recipient: age1unkshctcpucc298kmw9a0qzvtjzgdnjytrxr5p750dv0z95feymqpn68qf enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoMkNqQnY2TkZRaUJaTjAz - TUxVSUhyMzRsMm1OYVllM001UmpvL2lNcXhNCkRxQlMxZHBrNlNlNnIrQUY1NHpn - dzNFeGhlbE1wMlBwN3RxWUZyT1kyYUkKLS0tIGhpRGN5WFRCT1I5eGlhdUhWc3FR - WHZKWTlmN2llUndzeEdGV0xDSGZqZ2sKlZ0CGVfCtDdRl2vW7BxVkrBMFOZ5Fdk6 - 9Z9oqBOde0Mp9FGEwnt+IC79FKIknIyYfMf9tpo9Is85/IvyDHTMwA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJK0Mrc2pnZGZxSW16Tk1j + dE9WaXdUYmtjMVIrdHQ1VkRJSWlhVm5kdzFjCjhkZGNqTEdVblFMdm0yRjZ0TkFz + UWxIL2JEajRXYmhBb1ZFQ3VzQzRsaGsKLS0tIGgvcXVocnlNWGJGaXZ6cXJ3Mmla + U3h5dnlXRnFYQUlYNG5wWTNsSGU1UUkKc5jEmW19ST7/MgR4igBhuB6ic93Qy6GP + jtpUMeH0DDU3Z1/f5400DrHwWgUQRb3Gv8zV1LndzqJMaXL1Afiwdg== -----END AGE ENCRYPTED FILE----- - recipient: age1upnqu4rpxppdw9zmqu8x3rnaqq2r6m82y25zvry5cec63vjsd9gqtl9e02 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIT1VNTTVjcy9rakUwVFBY - UGh6L2l0Q2I1bFlWcG1XYVJiMkhYMnA4YlFzCnRXVmZDWnY4Zi9TK3NCc3huaC9W - dDQ5ek5EY2FQeTVhUWpHVkV3TXhxbncKLS0tIDNKN0hYNjVUdHNaMXYzdUE5Mm85 - NSt2OGp4VENRS1pLWHNQVFdhRU9STXMKXfcamWoU/bz39wstSEEuIJZknZpoOPzE - W/kDJ5xytfydUkYqoIiGH7s1JyHyCpqbRplPrjQZCmNDvXtcq3L/uQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOMXorems4ZVh4T2NQZFFj + a1psYXBFZ3ZXWnYxRnQzOHB5dDlKS2RaKzFNCnpwekhESGMzSzFYVEU3a3V5c2Rq + OGpZa0I5RVVQSzhZZkFlY3FjMXlXV00KLS0tIGRNODFGT2swb0FOZzRDR1FFbzZ5 + VzQ3bUkxeTlLZnNCd1lKc2h4enI1SzgK7vhR+pyRiVFgyt75MYt84pqjoUHsPj1k + 42d2AKB1ZWiD98/vN8LOAGlIyfRCUJB1j9rw3W/PkFs08qvHRLqy3Q== -----END AGE ENCRYPTED FILE----- - recipient: age108fn93z2c55g9dm9cv5v4w47pykf3khz7e3dmnpv5dhchwnaau0qs20stq enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZS1hHTTJudnUrQzJDYUh6 - ZEhjYTFaeXRwQXRrL3g1b05LaXdWMit6M2t3Ck81NVZyTUE0RVo5ZmdRcUZ0ZTBx - MkdUVDRyZ3Bmd21FZkdzckp3eGp1bmMKLS0tIFk5blFPMUlPdXJ2NThYME8reGxv - cXlZMTMvcFhScVBObXZRQXQ4WkI2d1EKFYLSfJlDx2BlBWUebBOy/PV0gu0KyhY8 - WSYL992HR043ENrbmkfbpVHaOZi8imyNKa7FWpLaj/Nuwv/Kfvy7uQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjeG9KTkd6UysxaG8rV0I3 + ODFKOWFBaXZpNEdCSXZxeDBFM2xVSjVsdjFVClhxV2lLaCt3cDNMS3ltQUNBTFBX + NWZqRGU3NzdBNzhHcGFDQ2syT0NRZmsKLS0tIG1oZ2dtV2tkbURUTUE2RlJZaXky + VlFCdENqUnFJOVFVMHRXQ05RZUVnUTgKESkjiK2JwEGyXtET794bzGkURLix4kkP + JB57xHBf4B1/UXu+h+jWQAotQSOFFa7IbtDOVejqT8dHqGDs+16HeQ== -----END AGE ENCRYPTED FILE----- - recipient: age1th8rdw4fs3vmgy9gzc0k9xy88tddjj4vasepckfx9h4nlzsg3q3q4cjgwu enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqZU9Wb0JLTG1kOWZ1YjJQ - SUh1NWxqS0ZGa0xEOHFUOWpYR3hTM2dQRWdZCklBb25LajV6RnZhOUVKLzJjY3lz - MTYvNmRPTEgrc0dJK0g5N2RkdEt0RUUKLS0tIHdxcFJCaTg4ZE5TQVVKS3k5K3Bo - Q0VudEFzRUFGWlNJcHc0VzZJUVRwbHMKjTMUFFbHhDeP7QLmR64yqDEh4naazL9f - etbOvYUkgj4IaB9UgDerG4MjyyHiVVY9Md8Jqe3dOQN0rqXRxNOW1g== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4SFpkRlNQcjBFUkRjRjhk + TW5kQzhTbE1wSmFTZ3l0cTNPSmdydC9nRTBjCmxneSt3TGhzYzhjb0tEY2xMT2tC + bE4wOUgzMFR1dTVOUDFRUXdWOFZQcFEKLS0tIHR5cHBwQkN1d3ZMYitWOG9JRVJh + ZU5tMTM5L3c4QVN6YjZBZEJkRk5yYWcK7TW19C9wI9FMWIDhn8otcNjLwNh1n5lr + f92zaPrmHWC6JVxeKmm3wB3uvONvW0v82DKZJI/gxl41zJTXsapT+Q== + -----END AGE ENCRYPTED FILE----- + - recipient: age1h5q9ul9f8vd7w7s2fvmpytaghgpv97a9r237agwzc52c76xsdegsugml73 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaWUZMVEsxQVFnYWhiZjFQ + bTQxaC9odHpXS0F5VHBrRVZ0UE1yZnJmTVRBCm9Uc2hTdUNOQU9JYVV6MHNiTmor + SUJrOXhta2lqMERWaVNseEpIaDNubEEKLS0tIFBiUG9CaEF0NzhaRm45MUUyYW1L + TnZGZVZONkFZWDZpNGtSek5Ka25PSUUKEXTRK8MsGnSkT5tPX+nFYN1Mons+nEZu + EFCtGzSuAeZWCW4We+264dDZjwlfdj47oBPCk8iwx9N1yoR1BF4LfQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1smqas3tre2hptnyn72fdzghqcnej48066l4hp6y98n8lkpm3ds4s8t8s0w + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5cG9WMzJRbXFXS2JyTzY5 + clh5QmZXc0dYcEU5UkRzMkZKczQwelVhYWhNCi9md3hwSnVRMVU5TU5UZjBWcG52 + WTZRNVlXOXgrcXdKeTNDTEpYcXdrMkEKLS0tIFIwMW5BV1pSWUF3UW5DaHUvVm1Q + dUZJVWRLeFFnV1ZpVThBZGtxai9oMlkKja55rkW/ZthR2AbscOIgHRfYDUCxIAm0 + HKgELNQDz2QXFwS98aHeelLCLufb/hyWBn1y4kx+WWppAtQewByhkA== -----END AGE ENCRYPTED FILE----- lastmodified: "2024-07-22T20:27:25Z" mac: ENC[AES256_GCM,data:zIY2DotoqnJmz/aBRHq+4ZLi/Smi1Bn4phmFsngMY1w0LVauKX95jwKwOhE0PfvIyd8E54N+BoCQ3QmRMv3uvBddScPNSGJgdgDRn8LDWol4/8avDoPFISpNvdS32Ac00UDnMeBEkW4S/oo9CwYHCpEsiwjL6FgjCX/KOK++kzA=,iv:sGCFNJ6gsEOskMlLWUnR9Gnsp8Emc0vdBAl4WN2A1f8=,tag:fHi4CR+exp1roW7UOzhMmQ==,type:str] diff --git a/secrets/serverKeys.yaml b/secrets/serverKeys.yaml index 8db5fe9..6a3d722 100644 --- a/secrets/serverKeys.yaml +++ b/secrets/serverKeys.yaml @@ -2,6 +2,8 @@ atlas: ENC[AES256_GCM,data:TgYf6Jck5L2feQyvyUb2FcLm2M3aSwN0W0xdH6qLU3L4q7LSeB0yB jefke: ENC[AES256_GCM,data:PH+4rNhATssck8cmKZrhw4VoyHtkqKlRt1wH+BlOvxdhw5GNDsiT4DOf0cveJ090XcOpkAxEf2yqnpIiZhallKVMJS3aFxpNpNw=,iv:QJQZo6x4PE3mNIK8KaQ16BlJeZsdorX683lpf2FjAJk=,tag:rljZMJ/xv7kbkPKP/pqZ9A==,type:str] lewis: ENC[AES256_GCM,data:rdm5YMnWkg2MpY2ZGYi11HHGJzY/ssKA5DCv/wbcf8qIXRhRt5heA1un1zCJdYBKlxsVGOuQEtHMKuA/vLYqNnIXxr5NxDxhgIo=,iv:y+fyLns2B/JDuumHIuk4p9PybXf8isd7Ve+1gcX0mp8=,tag:VoAORxiU+6WbhAgkm9lAgQ==,type:str] warwick: ENC[AES256_GCM,data:8ABH+BMdKjLaVG1FkLWksJRtIO8Vu/j1USLGaAAFi6KA/o/S2X936doUl3/D6MKz71i8FwEH410K4JcGJXVboY45Dfp2g1/6bog=,iv:pvXBQcWs/dFSEVe807bpQQKI9n0A/IUxSG0Z1Sl00/Y=,tag:l/sTOe6sNJ34Z2UmmBBBNw==,type:str] +talos: ENC[AES256_GCM,data:DD70h1qX06cuQ+2S6EIxdBWqkECZFO3UmusKvLKXoocuJfA7CU4sM03GJxnlff26mv53LyMUtZsPWgWWQNrwrICXmhg/I4CDAuA=,iv:zoWlL1SjyxXjemnkbQBtgutfXL41/eqpLk6l/fXntmQ=,tag:v64nkexcG9Y2gCqAE8kcwA==,type:str] +pikvm: ENC[AES256_GCM,data:CrOdqkb+MJK7t6+3mkm+MdUqwBRtYY1jMsQvtBOoZYF3h1vPidJRAHZvX5n5aBsbf5DFCcWXRs5v7I18ANyA1TbkZVKLS0PsrQU=,iv:LMo9zpoRF3EEtQ7GtmIVRNsyVFga7Vcvpv7DxHQRhjo=,tag:Ca3KqKmZJzyEcs6SAiuJZg==,type:str] sops: kms: [] gcp_kms: [] @@ -26,8 +28,8 @@ sops: eDdFZERVZUJ2QmYvTUlGMlFFNTlna00KLil0QQySKHDAdFxIZAlWvkCRT2v8RNL7 CWIs/HhjmGk0BEoXIVlmbnAVNATABCCWnUTHFKvvW/8KIDhwgu72Eg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-06-15T19:19:59Z" - mac: ENC[AES256_GCM,data:Y+aBXyowjQTXgteYLU2j1I5cv9UFU/ylrVy9QQub3NLzBbpW4pb+oI2wVcZI0K40jwSX7xOEjgGOtjdLRGTG8/xHm/yf+R0Wgs7fyIxOzcZv8XBadR6f2jUnAPA74ZDQ9ngwh1xyJteQPLwr+XPuGNlylYn/mj/EcwFs1SCok5A=,iv:/7XR2P/nfEicarsCALXhKIbvzsqUYhg9SgT2Z7P3W20=,tag:+uHRHU+WVfWefjHcH/C4fA==,type:str] + lastmodified: "2024-08-20T20:59:29Z" + mac: ENC[AES256_GCM,data:KFBbDkz2ZhG+j/yGVK6spADmNM0t73C0QyD7/KoV/gLCD4jwWRxfAxCAUNlBeHIFrZDfyW2KR04oPA2LBDqASnQcITgRYhbNj51wFjiU6kCT0LK9uIx+hNo3RuAtw21/2qsg9Xf0PvAC33yB+iaNrDDBtiWyg2Aq+q0wdMzXRfU=,iv:MIF4iqOCSaoLyFuyZ32rCN6qCGtlWoNtkt7mXE/njVQ=,tag:rCsyRPNSAam65zarTKLnHg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 From 52efd614fe86d9f68b71aebedb19e1089e2d0d61 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 24 Aug 2024 23:01:52 +0200 Subject: [PATCH 072/108] chore(jellyfin): update to 10.9.9 chore(radarr): update to 5.9.1 chore(paperless): update to 2.11.6 chore(syncthing): update to 1.27.10 chore(immich): update to 1.112.1 chore(freshrss): update to 1.24.2 --- my-lib/globals.nix | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/my-lib/globals.nix b/my-lib/globals.nix index f9d2a30..5daa29e 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -27,34 +27,34 @@ nextcloudIPv4 = "192.168.30.148"; images = { - jellyfin = "jellyfin/jellyfin:10.9.8"; + jellyfin = "jellyfin/jellyfin:10.9.9"; deluge = "linuxserver/deluge:2.1.1"; jellyseerr = "fallenbagel/jellyseerr:1.9.2"; - radarr = "lscr.io/linuxserver/radarr:5.8.3"; + radarr = "lscr.io/linuxserver/radarr:5.9.1"; prowlarr = "lscr.io/linuxserver/prowlarr:1.21.2"; sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; atuin = "ghcr.io/atuinsh/atuin:18.3.0"; atuinPostgres = "postgres:14"; kms = "teddysun/kms"; - paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.2"; + paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.6"; paperlessRedis = "docker.io/library/redis:7"; paperlessPostgres = "postgres:15"; - nextcloud = "nextcloud:29.0.4"; + nextcloud = "nextcloud:29.0.5"; nextcloudPostgres = "postgres:15"; inbucket = "inbucket/inbucket:edge"; - syncthing = "lscr.io/linuxserver/syncthing:1.27.9"; + syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; radicale = "tomsquest/docker-radicale:3.2.2.0"; ntfy = "binwiederhier/ntfy:v2.11.0"; forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; pihole = "pihole/pihole:2024.07.0"; - immich = "ghcr.io/immich-app/immich-server:v1.111.0"; - immichML = "ghcr.io/immich-app/immich-machine-learning:v1.111.0"; + immich = "ghcr.io/immich-app/immich-server:v1.112.1"; + immichML = "ghcr.io/immich-app/immich-machine-learning:v1.112.1"; immichRedis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; immichPostgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; kitchenowl = "tombursch/kitchenowl:v0.5.2"; cyberchef = "mpepping/cyberchef"; - freshrss = "freshrss/freshrss:1.24.1"; + freshrss = "freshrss/freshrss:1.24.2"; bind9 = "ubuntu/bind9:9.18-22.04_beta"; dnsmasq = "dockurr/dnsmasq:2.90"; attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; From e9899c0d0f875cf17cc2bd50d360c524eb0fe4db Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 25 Aug 2024 17:04:31 +0200 Subject: [PATCH 073/108] Resolve cyberchef and radicale images using nix-snapshotter Increase inotify max user instances to 256 Disable tailscale by default --- configuration.nix | 1 + container-images.nix | 2 +- flake-parts/scripts/default.nix | 53 +++++++------- kubenix-modules/cyberchef.nix | 1 + machines/atlas.nix | 1 + machines/jefke.nix | 1 + machines/lewis.nix | 1 + machines/warwick.nix | 6 +- my-lib/globals.nix | 4 +- nixos-modules/k3s/default.nix | 126 ++++++++++++++++++++------------ nixos-modules/tailscale.nix | 14 +++- 11 files changed, 129 insertions(+), 81 deletions(-) diff --git a/configuration.nix b/configuration.nix index 3186878..72a46e9 100644 --- a/configuration.nix +++ b/configuration.nix @@ -91,6 +91,7 @@ boot = lib.mkIf (! machine.isRaspberryPi) { kernelModules = [ "kvm-intel" ]; extraModulePackages = [ ]; + kernel.sysctl."fs.inotify.max_user_instances" = 256; initrd = { kernelModules = [ ]; diff --git a/container-images.nix b/container-images.nix index 037defa..bc9d6a2 100644 --- a/container-images.nix +++ b/container-images.nix @@ -1,2 +1,2 @@ -{ cyberchef = { cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:5044c72dd8070fb6e0595e720fc4440bf6168493b2433db06a1c966406398ba2"; imageName = "mpepping/cyberchef"; sha256 = "177yjfbz0ijc8lfqfr50fhqqmjk72373c0igyrxv3wwg0pyrgpv4"; }; }; } +{ cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:2c89d08580395b932c92d708041c2a702dc8fa899fcc1677901c2dc881bed789"; imageName = "mpepping/cyberchef"; sha256 = "1frlvv6lyghf99pa37l48r7j2wvh7mcb9x99fvf0ba2zhq2xfsy4"; }; radicale = { finalImageName = "tomsquest/docker-radicale"; finalImageTag = "3.2.2.0"; imageDigest = "sha256:af050e02c4a3f7385a09595dd2a1424db6831aa9f24404095c6d2244d1c94138"; imageName = "tomsquest/docker-radicale"; sha256 = "07mxn6iqm0fhb06dwmxdhqnw3c8yi2dm2jpb2n80dxzmvavrv0lk"; }; } diff --git a/flake-parts/scripts/default.nix b/flake-parts/scripts/default.nix index 451e575..80d8ebd 100644 --- a/flake-parts/scripts/default.nix +++ b/flake-parts/scripts/default.nix @@ -30,12 +30,16 @@ in let images = { cyberchef = { - cyberchef = { - image-name = "mpepping/cyberchef"; - image-tag = "latest"; - }; + name = "mpepping/cyberchef"; + tag = "latest"; + }; + + radicale = { + name = "tomsquest/docker-radicale"; + tag = "3.2.2.0"; }; }; + imagesJSON = builtins.toFile "images.json" (builtins.toJSON images); in pkgs.writers.writePython3Bin "prefetch-container-images" @@ -55,31 +59,28 @@ in with open(images_file_name, 'r') as file: data = json.load(file) - for project_name, images in data.items(): - print(f"Prefetching images for project {project_name}", file=sys.stderr) + for image_name, image in data.items(): + name = image["name"] + tag = image["tag"] - for image_name, image in images.items(): - name = image["image-name"] - tag = image["image-tag"] + print(f"Prefetching image {name}:{tag}", file=sys.stderr) - print(f"Prefetching image {name}:{tag}", file=sys.stderr) + prefetch_args = [ + prefetch_docker_cmd, + "--os", "linux", + "--arch", "amd64", + "--image-name", name, + "--image-tag", tag, + "--json", + "--quiet" + ] + result = subprocess.run(prefetch_args, + check=True, + capture_output=True, + text=True) - prefetch_args = [ - prefetch_docker_cmd, - "--os", "linux", - "--arch", "amd64", - "--image-name", name, - "--image-tag", tag, - "--json", - "--quiet" - ] - result = subprocess.run(prefetch_args, - check=True, - capture_output=True, - text=True) - - prefetch_data = json.loads(result.stdout) - results[project_name][image_name] = prefetch_data + prefetch_data = json.loads(result.stdout) + results[image_name] = prefetch_data with tempfile.NamedTemporaryFile(mode='w+', suffix='.json') as temp_file: json.dump(results, temp_file, indent=4) diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix index d7ab260..44bbfef 100644 --- a/kubenix-modules/cyberchef.nix +++ b/kubenix-modules/cyberchef.nix @@ -9,6 +9,7 @@ spec.containers.cyberchef = { image = myLib.globals.images.cyberchef; + imagePullPolicy = "Always"; ports.web.containerPort = 8000; }; }; diff --git a/machines/atlas.nix b/machines/atlas.nix index a9866d4..a6bf86f 100644 --- a/machines/atlas.nix +++ b/machines/atlas.nix @@ -5,6 +5,7 @@ nixosModule.lab = { storage.profile = "kubernetes"; + tailscale.enable = true; k3s = { enable = true; diff --git a/machines/jefke.nix b/machines/jefke.nix index 362b268..096be8c 100644 --- a/machines/jefke.nix +++ b/machines/jefke.nix @@ -5,6 +5,7 @@ nixosModule.lab = { storage.profile = "kubernetes"; + tailscale.enable = true; k3s = { enable = true; diff --git a/machines/lewis.nix b/machines/lewis.nix index 6999c81..5350142 100644 --- a/machines/lewis.nix +++ b/machines/lewis.nix @@ -11,6 +11,7 @@ storage.profile = "kubernetes"; backups.enable = true; data-sharing.enable = true; + tailscale.enable = true; k3s = { enable = true; diff --git a/machines/warwick.nix b/machines/warwick.nix index 6160f02..f000881 100644 --- a/machines/warwick.nix +++ b/machines/warwick.nix @@ -7,7 +7,11 @@ lab = { storage.profile = "pi"; monitoring.server.enable = true; - tailscale.advertiseExitNode = true; + + tailscale = { + advertiseExitNode = true; + enable = true; + }; }; }; }; diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 5daa29e..a5a9808 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -44,7 +44,7 @@ nextcloudPostgres = "postgres:15"; inbucket = "inbucket/inbucket:edge"; syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; - radicale = "tomsquest/docker-radicale:3.2.2.0"; + radicale = "nix:0/var/docker_images/radicale.tar"; ntfy = "binwiederhier/ntfy:v2.11.0"; forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; pihole = "pihole/pihole:2024.07.0"; @@ -53,7 +53,7 @@ immichRedis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; immichPostgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; kitchenowl = "tombursch/kitchenowl:v0.5.2"; - cyberchef = "mpepping/cyberchef"; + cyberchef = "nix:0/var/docker_images/cyberchef.tar"; freshrss = "freshrss/freshrss:1.24.2"; bind9 = "ubuntu/bind9:9.18-22.04_beta"; dnsmasq = "dockurr/dnsmasq:2.90"; diff --git a/nixos-modules/k3s/default.nix b/nixos-modules/k3s/default.nix index d47f182..52def8c 100644 --- a/nixos-modules/k3s/default.nix +++ b/nixos-modules/k3s/default.nix @@ -1,22 +1,6 @@ -{ inputs, pkgs, lib, config, ... }: +{ self, inputs, pkgs, lib, config, ... }: let cfg = config.lab.k3s; - - k3s-cni-plugins = pkgs.buildEnv { - name = "k3s-cni-plugins"; - paths = with pkgs; [ - cni-plugins - cni-plugin-flannel - ]; - }; - - image = pkgs.nix-snapshotter.buildImage { - name = "redis"; - resolvedByNix = true; - config = { - entrypoint = [ "${pkgs.redis}/bin/redis-server" ]; - }; - }; in { options.lab.k3s = { @@ -78,30 +62,40 @@ in address = "/run/nix-snapshotter/nix-snapshotter.sock"; }; - plugins = { - "io.containerd.grpc.v1.cri" = { - stream_server_address = "127.0.0.1"; - stream_server_port = "10010"; - enable_selinux = false; - enable_unprivileged_ports = true; - enable_unprivileged_icmp = true; - disable_apparmor = true; - disable_cgroup = true; - restrict_oom_score_adj = true; - sandbox_image = "rancher/mirrored-pause:3.6"; - containerd.snapshotter = "nix"; - - cni = { - conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d/"; - bin_dir = "${k3s-cni-plugins}/bin"; + plugins = + let + k3s-cni-plugins = pkgs.buildEnv { + name = "k3s-cni-plugins"; + paths = with pkgs; [ + cni-plugins + cni-plugin-flannel + ]; }; - }; + in + { + "io.containerd.grpc.v1.cri" = { + stream_server_address = "127.0.0.1"; + stream_server_port = "10010"; + enable_selinux = false; + enable_unprivileged_ports = true; + enable_unprivileged_icmp = true; + disable_apparmor = true; + disable_cgroup = true; + restrict_oom_score_adj = true; + sandbox_image = "rancher/mirrored-pause:3.6"; + containerd.snapshotter = "nix"; - "io.containerd.transfer.v1.local".unpack_config = [{ - platform = "linux/amd64"; - snapshotter = "nix"; - }]; - }; + cni = { + conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d/"; + bin_dir = "${k3s-cni-plugins}/bin"; + }; + }; + + "io.containerd.transfer.v1.local".unpack_config = [{ + platform = "linux/amd64"; + snapshotter = "nix"; + }]; + }; }; }; @@ -145,9 +139,9 @@ in "L+ /usr/local/bin - - - - /run/current-system/sw/bin/" ]; - system = lib.mkIf (cfg.role == "server") { - activationScripts = { - k3s-bootstrap.text = ( + system.activationScripts = { + k3s-bootstrap = lib.mkIf (cfg.role == "server") { + text = ( let k3sBootstrapFile = (inputs.kubenix.evalModules.x86_64-linux { module = import ./bootstrap.nix; @@ -158,8 +152,10 @@ in ln -sf ${k3sBootstrapFile} /var/lib/rancher/k3s/server/manifests/k3s-bootstrap.json '' ); + }; - k3s-certs.text = '' + k3s-certs = lib.mkIf (cfg.role == "server") { + text = '' mkdir -p /var/lib/rancher/k3s/server/tls/etcd cp -f ${./k3s-ca/server-ca.crt} /var/lib/rancher/k3s/server/tls/server-ca.crt cp -f ${./k3s-ca/client-ca.crt} /var/lib/rancher/k3s/server/tls/client-ca.crt @@ -167,11 +163,47 @@ in cp -f ${./k3s-ca/etcd/peer-ca.crt} /var/lib/rancher/k3s/server/tls/etcd/peer-ca.crt cp -f ${./k3s-ca/etcd/server-ca.crt} /var/lib/rancher/k3s/server/tls/etcd/server-ca.crt ''; - - nix-snapshotter-image = '' - ln -sf ${image} /root/image.tar - ''; }; + + docker-images.text = + let + imageLinkDir = "/var/docker_images"; + imageDefs = import "${self}/container-images.nix"; + + setupCommands = [ + "rm -rf ${imageLinkDir}" + "mkdir -p ${imageLinkDir}" + ]; + + getDockerImageConfig = dockerImage: + let + configJson = pkgs.runCommand "config.json" + { + nativeBuildInputs = [ pkgs.skopeo pkgs.jq ]; + } + '' + skopeo --tmpdir $TMPDIR --insecure-policy inspect docker-archive:${dockerImage} --config | jq '.config' > $out + ''; + in + builtins.fromJSON (builtins.readFile configJson); + + imageDefToLinkCommand = name: imageDef: + let + dockerImage = pkgs.dockerTools.pullImage imageDef; + nixSnapshotterImage = pkgs.nix-snapshotter.buildImage { + inherit name; + resolvedByNix = true; + fromImage = dockerImage; + config = getDockerImageConfig dockerImage; + }; + imageLinkPath = "${imageLinkDir}/${name}.tar"; + in + "ln -sf ${nixSnapshotterImage} ${imageLinkPath}"; + + linkCommandList = lib.attrsets.mapAttrsToList imageDefToLinkCommand imageDefs; + commandList = setupCommands ++ linkCommandList; + in + builtins.concatStringsSep "\n" commandList; }; sops.secrets = diff --git a/nixos-modules/tailscale.nix b/nixos-modules/tailscale.nix index 8cfbfb3..d50408e 100644 --- a/nixos-modules/tailscale.nix +++ b/nixos-modules/tailscale.nix @@ -4,13 +4,17 @@ let in { options = { - lab.tailscale.advertiseExitNode = lib.mkOption { - type = lib.types.bool; - default = false; + lab.tailscale = { + enable = lib.mkEnableOption "tailscale"; + + advertiseExitNode = lib.mkOption { + type = lib.types.bool; + default = false; + }; }; }; - config = { + config = lib.mkIf cfg.enable { services.tailscale = { enable = true; authKeyFile = config.sops.secrets."tailscale/authKey".path; @@ -25,5 +29,7 @@ in }; sops.secrets."tailscale/authKey" = { }; + + systemd.network.wait-online.ignoredInterfaces = [ "tailscale0" ]; }; } From 04439a9ee5d1621b20f58e3fd23dc09ce86748e4 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Thu, 29 Aug 2024 06:53:05 +0200 Subject: [PATCH 074/108] Build tooling around nix-snapshotter --- container-images.nix | 3 +-- flake-parts/scripts/default.nix | 32 +++++++++++++------------------- kubenix-modules/paperless.nix | 4 ++-- my-lib/default.nix | 4 +++- my-lib/globals.nix | 25 ++++++++++++------------- nixos-modules/k3s/default.nix | 14 ++++++++------ 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/container-images.nix b/container-images.nix index bc9d6a2..0dbb7ca 100644 --- a/container-images.nix +++ b/container-images.nix @@ -1,2 +1 @@ -{ cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:2c89d08580395b932c92d708041c2a702dc8fa899fcc1677901c2dc881bed789"; imageName = "mpepping/cyberchef"; sha256 = "1frlvv6lyghf99pa37l48r7j2wvh7mcb9x99fvf0ba2zhq2xfsy4"; }; radicale = { finalImageName = "tomsquest/docker-radicale"; finalImageTag = "3.2.2.0"; imageDigest = "sha256:af050e02c4a3f7385a09595dd2a1424db6831aa9f24404095c6d2244d1c94138"; imageName = "tomsquest/docker-radicale"; sha256 = "07mxn6iqm0fhb06dwmxdhqnw3c8yi2dm2jpb2n80dxzmvavrv0lk"; }; } - +{ attic = { finalImageName = "git.kun.is/home/atticd"; finalImageTag = "fd910d91c2143295e959d2c903e9ea25cf94ba27"; imageDigest = "sha256:309264ff35f2f7cbcb6609c72d816cb41ee62c74d59d4f01cfc05e94a893dae7"; imageName = "git.kun.is/home/atticd"; sha256 = "0cvhhx4s8678ivqnswqmj2mnw81a4wbr65c02y1ayxfv2szdw8bm"; }; atuin = { finalImageName = "ghcr.io/atuinsh/atuin"; finalImageTag = "18.3.0"; imageDigest = "sha256:678def8e9d59652a502759ca431f9c5b54ebdd5e9361507c7fcf24705c9862e0"; imageName = "ghcr.io/atuinsh/atuin"; sha256 = "1lb53p6dz12lwj10v9si7l6j06q1cnfaim4mgi6dkanlynq5mrk6"; }; bazarr = { finalImageName = "lscr.io/linuxserver/bazarr"; finalImageTag = "1.4.3"; imageDigest = "sha256:8573a7d8558d7407ec53c205599d99d9876486621681355d147e9091cd99c58b"; imageName = "lscr.io/linuxserver/bazarr"; sha256 = "0vnvjnj478h76dpr24z56xfp6d6s2j5qhidh7bvmmsnw4hdvic8b"; }; bind9 = { finalImageName = "ubuntu/bind9"; finalImageTag = "9.18-22.04_beta"; imageDigest = "sha256:eb71c990a2efaa37897929bc104ef1b035c527aa2d217bc89da64cf7bdf9a8c8"; imageName = "ubuntu/bind9"; sha256 = "0cdgm9qbxdyhhhnsykn5lcvcjp7kxx9pjjamj7120d3jf6d6zqn2"; }; cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:2c89d08580395b932c92d708041c2a702dc8fa899fcc1677901c2dc881bed789"; imageName = "mpepping/cyberchef"; sha256 = "1frlvv6lyghf99pa37l48r7j2wvh7mcb9x99fvf0ba2zhq2xfsy4"; }; deluge = { finalImageName = "linuxserver/deluge"; finalImageTag = "2.1.1"; imageDigest = "sha256:5af8bd7f0ad2bdc5e7799f5343081f5beb57e74eef88035aed9c18b7cc18ffcd"; imageName = "linuxserver/deluge"; sha256 = "1c73wa74bi0sm5yxs3bdldv4z4vw3pbadkpd3749ybsjxy10s0rk"; }; dnsmasq = { finalImageName = "dockurr/dnsmasq"; finalImageTag = "2.90"; imageDigest = "sha256:c85b08ebcd45463383bfa8a8ba57b2ccda0a0c32869fbf8927ff74f1d33b9e5d"; imageName = "dockurr/dnsmasq"; sha256 = "1vak4nkxq8pdi5yplfan36988n5wr1w0m3ycar0r18215p1ncarc"; }; forgejo = { finalImageName = "codeberg.org/forgejo/forgejo"; finalImageTag = "8.0.1"; imageDigest = "sha256:221639a84fae9d9ec5236a50f4980c3cd5332851949f6e989f5f44cc411cf4fa"; imageName = "codeberg.org/forgejo/forgejo"; sha256 = "0llhjbr6m33yfbkb3c4xjcwywk7w2p6wahg6xiz73rcsjjgg8lz1"; }; freshrss = { finalImageName = "freshrss/freshrss"; finalImageTag = "1.24.2"; imageDigest = "sha256:126b5202e65bbfef1da19be87fb21d9909e104d3ad185775c999b76a420d30bc"; imageName = "freshrss/freshrss"; sha256 = "1pdm7p1lmnmv90zw6pz47f61mlvx0sls3qmlpsn78vl9hz6f4bng"; }; hedgedoc = { finalImageName = "quay.io/hedgedoc/hedgedoc"; finalImageTag = "1.9.9"; imageDigest = "sha256:e0dda4a168e065e62fac0f90758a4e83fee57ae6e91acbb3e46456d4456c6c48"; imageName = "quay.io/hedgedoc/hedgedoc"; sha256 = "1yvmapvzf2n94c1h3zas85pzildl1jd3ip4n3cccfxq9f6dqhy0h"; }; immich = { finalImageName = "ghcr.io/immich-app/immich-server"; finalImageTag = "v1.112.1"; imageDigest = "sha256:c4e817f0eadbd9a6c2699cc884d5e7070428daec813c17db77d31fcca5b78ca6"; imageName = "ghcr.io/immich-app/immich-server"; sha256 = "0vvyhijslldj7hpg33n2cvpn5wrn9fcprw8pw01zh4ziabyy3z07"; }; immich-machine-learning = { finalImageName = "ghcr.io/immich-app/immich-machine-learning"; finalImageTag = "v1.112.1"; imageDigest = "sha256:9600eff5a66ae426293f00b171711bc1647c85cf966d759ee08ab2d05e0580b5"; imageName = "ghcr.io/immich-app/immich-machine-learning"; sha256 = "1m189s6i8hii4vrsjx3ypa5p2brz8sa3fw5jyxhh6qm42r4xnp4c"; }; immich-postgres = { finalImageName = "docker.io/tensorchord/pgvecto-rs"; finalImageTag = "pg14-v0.2.0"; imageDigest = "sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; imageName = "docker.io/tensorchord/pgvecto-rs"; sha256 = "0h1s11z5d4svg2whm7gw11dwpddg5k90fp62q3zirycms787f4d3"; }; immich-redis = { finalImageName = "docker.io/redis"; finalImageTag = "6.2-alpine"; imageDigest = "sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; imageName = "docker.io/redis"; sha256 = "0sscnrn5vpmdq2g62a185nlgf9i5hwcfl630hyh7wzfbgyq4pbzj"; }; inbucket = { finalImageName = "inbucket/inbucket"; finalImageTag = "edge"; imageDigest = "sha256:f7e0bbb13d24970c30690a04ff1599907530c31152fccd20d542028cd8a7650b"; imageName = "inbucket/inbucket"; sha256 = "0whxnp222b09jlcbmwd6y1jbcsqv16ipk182i5ywgjjd0wlvh4i3"; }; jellyfin = { finalImageName = "jellyfin/jellyfin"; finalImageTag = "10.9.9"; imageDigest = "sha256:d6f3d4aa59438ce951d85669f3c22426d20edb7a6b97604c509b5f4825bc8294"; imageName = "jellyfin/jellyfin"; sha256 = "1rn093xyh8prjr3v4zs0ss6z2hbgzy1p5f0gs5dv4kyz4y1gfkhw"; }; jellyseerr = { finalImageName = "fallenbagel/jellyseerr"; finalImageTag = "1.9.2"; imageDigest = "sha256:8f708df0ce3f202056bde5d7bff625eb59efe38f4ee47bdddc7560b6e4a5a214"; imageName = "fallenbagel/jellyseerr"; sha256 = "04ala5cpkv1rhq609yxvyf8wv6ql8ism9zyrxyiil6b1gfgcsfxz"; }; kitchenowl = { finalImageName = "tombursch/kitchenowl"; finalImageTag = "v0.5.2"; imageDigest = "sha256:5d37e09c034884a0495c0460fc849981b71ff1a90908ed29804dda7f13f2d165"; imageName = "tombursch/kitchenowl"; sha256 = "10d6xrdl0si663s27ayqj6w2qq6ly81hpv9nq8whd0i17s7skkmd"; }; kms = { finalImageName = "teddysun/kms"; finalImageTag = "latest"; imageDigest = "sha256:4b366384ef3389eeecec9340468909616c409f9227504f4ee1e659ad1a801976"; imageName = "teddysun/kms"; sha256 = "0jwhlb2wgm0awp36rpann9b9gyfrnwsclhb3phxnc3aan7lc9nnx"; }; minecraft = { finalImageName = "itzg/minecraft-server"; finalImageTag = "latest"; imageDigest = "sha256:3b97ca8f48507f1c85e8d7a32aee5c9bd7e09d4e96584b71aac0b878c8f1d16c"; imageName = "itzg/minecraft-server"; sha256 = "0892ak383841n7zsx76gm7apra603pqajxzmzm0b4797wm69p79i"; }; nextcloud = { finalImageName = "nextcloud"; finalImageTag = "29.0.5"; imageDigest = "sha256:5bbc6e9f207bfddd1515ac82f647c19edf6cdd075d7d253c3118a87c835204f0"; imageName = "nextcloud"; sha256 = "1s4346f522v7nyfhsgmyfyw9s40zv0dhylqdym6vkg0nfidfk08y"; }; ntfy = { finalImageName = "binwiederhier/ntfy"; finalImageTag = "v2.11.0"; imageDigest = "sha256:4a7d0f0adc6d5d9fc36e64ab55ef676e76e124a2bdd50ce115b6d9c1c7430294"; imageName = "binwiederhier/ntfy"; sha256 = "0sqgs5bkgx35wbga95sf3n863lpmwxv84kiic1r8zaibbg54f8b3"; }; paperless = { finalImageName = "ghcr.io/paperless-ngx/paperless-ngx"; finalImageTag = "2.11.6"; imageDigest = "sha256:fca12ddea5509819dd0702cf128944aa23d01dd850a2536a96c2b46fb982b9bb"; imageName = "ghcr.io/paperless-ngx/paperless-ngx"; sha256 = "12myq5liyjgvd9rpz997wwv7gxj8rgsckrsn53gszrr3mh8gp5b6"; }; pihole = { finalImageName = "pihole/pihole"; finalImageTag = "2024.07.0"; imageDigest = "sha256:0def896a596e8d45780b6359dbf82fc8c75ef05b97e095452e67a0a4ccc95377"; imageName = "pihole/pihole"; sha256 = "16a3apailmkdv6kmkfs37y454qlnw77xflpaqxaznh359pnq3y3j"; }; postgres14 = { finalImageName = "postgres"; finalImageTag = "14"; imageDigest = "sha256:e3cc76b6d4dfc8f3547641d67053092e7c108e03ab159c00b48fa8d891e2f7b4"; imageName = "postgres"; sha256 = "0qwjsfq7h5myqfahb9fz0xs4fg1fylrjlyv6ic72hyryhanmh46f"; }; postgres15 = { finalImageName = "postgres"; finalImageTag = "15"; imageDigest = "sha256:0836104ba0de8d09e8d54e2d6a28389fbce9c0f4fe08f4aa065940452ec61c30"; imageName = "postgres"; sha256 = "04264alvi2x1pr34c3iiynlc3fqvm5q12hhkfb14wxir8imxnkqy"; }; prowlarr = { finalImageName = "lscr.io/linuxserver/prowlarr"; finalImageTag = "1.21.2"; imageDigest = "sha256:c93f075dc5afb74dc7a0a55e90974f81425a5d3c5d293022c5416431f4963ce9"; imageName = "lscr.io/linuxserver/prowlarr"; sha256 = "0ab57f7yh9c23v2m1qwk2ycj00gjfk1wjd1b92y0aycwl50dkdpv"; }; radarr = { finalImageName = "lscr.io/linuxserver/radarr"; finalImageTag = "5.9.1"; imageDigest = "sha256:b034531ff81d3e5e1f9fd70c969746040b40e6484c88981ea5d0dee732c10bc3"; imageName = "lscr.io/linuxserver/radarr"; sha256 = "037159jjgjr25w4a258hw53n194zgnlldywnsvhys3yyvcld2rzi"; }; radicale = { finalImageName = "tomsquest/docker-radicale"; finalImageTag = "3.2.2.0"; imageDigest = "sha256:af050e02c4a3f7385a09595dd2a1424db6831aa9f24404095c6d2244d1c94138"; imageName = "tomsquest/docker-radicale"; sha256 = "07mxn6iqm0fhb06dwmxdhqnw3c8yi2dm2jpb2n80dxzmvavrv0lk"; }; redis7 = { finalImageName = "docker.io/library/redis"; finalImageTag = "7"; imageDigest = "sha256:878983f8f5045b28384fc300268cec62bca3b14d5e1a448bec21f28cfcc7bf78"; imageName = "docker.io/library/redis"; sha256 = "09n5i6ps28k7529m822cd34awqpfmnlzi6djfzjd9wzx4gcvgmrh"; }; sonarr = { finalImageName = "lscr.io/linuxserver/sonarr"; finalImageTag = "4.0.8"; imageDigest = "sha256:0777b308a414000505651059a95af373ded6aba8ce5a40b50d7aad333dc912e2"; imageName = "lscr.io/linuxserver/sonarr"; sha256 = "0mdf7h85m01vw59amvgclclrq8b65aijjsbq405pdi520879bis2"; }; syncthing = { finalImageName = "lscr.io/linuxserver/syncthing"; finalImageTag = "1.27.10"; imageDigest = "sha256:d5481de808a1de5a13b814a922b1f6de5fcde64c1ca95b0a065218b56570fae3"; imageName = "lscr.io/linuxserver/syncthing"; sha256 = "08zj0s3q9r9mwnnv6nf6i157z8m6k6qrxwcvka6awg9vb507d49k"; }; } diff --git a/flake-parts/scripts/default.nix b/flake-parts/scripts/default.nix index 80d8ebd..40dd42c 100644 --- a/flake-parts/scripts/default.nix +++ b/flake-parts/scripts/default.nix @@ -1,4 +1,4 @@ -{ flake-utils, pkgs, ... }: flake-utils.lib.eachDefaultSystem (system: +{ myLib, flake-utils, pkgs, ... }: flake-utils.lib.eachDefaultSystem (system: let createScript = { name, runtimeInputs, scriptPath, extraWrapperFlags ? "", ... }: let @@ -28,21 +28,9 @@ in packages.prefetch-container-images = let - images = { - cyberchef = { - name = "mpepping/cyberchef"; - tag = "latest"; - }; - - radicale = { - name = "tomsquest/docker-radicale"; - tag = "3.2.2.0"; - }; - }; - - imagesJSON = builtins.toFile "images.json" (builtins.toJSON images); + imagesJSON = builtins.toFile "images.json" (builtins.toJSON myLib.globals.images); in - pkgs.writers.writePython3Bin "prefetch-container-images" + pkgs.writers.writePython3Bin "prefetch-container-images.py" { } '' import json import subprocess @@ -59,11 +47,13 @@ in with open(images_file_name, 'r') as file: data = json.load(file) - for image_name, image in data.items(): - name = image["name"] - tag = image["tag"] + for image_name, image_ref in data.items(): + [name, tag] = image_ref.split(":", maxsplit=1) + print(f"Prefetching image {image_ref}", file=sys.stderr) - print(f"Prefetching image {name}:{tag}", file=sys.stderr) + digest = "" + if "@" in tag: + [tag, digest] = tag.split("@", maxsplit=1) prefetch_args = [ prefetch_docker_cmd, @@ -74,6 +64,10 @@ in "--json", "--quiet" ] + + if digest: + prefetch_args.extend(["--image-digest", digest]) + result = subprocess.run(prefetch_args, check=True, capture_output=True, diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix index 9b91d95..eaa8f47 100644 --- a/kubenix-modules/paperless.nix +++ b/kubenix-modules/paperless.nix @@ -100,7 +100,7 @@ volumes.data.persistentVolumeClaim.claimName = "redisdata"; containers.redis = { - image = myLib.globals.images.paperlessRedis; + image = myLib.globals.images.redis7; ports.redis.containerPort = 6379; imagePullPolicy = "IfNotPresent"; @@ -141,7 +141,7 @@ spec = { containers.postgres = { - image = myLib.globals.images.paperlessPostgres; + image = myLib.globals.images.postgres15; ports.postgres.containerPort = 5432; imagePullPolicy = "IfNotPresent"; diff --git a/my-lib/default.nix b/my-lib/default.nix index 37e3eeb..766186b 100644 --- a/my-lib/default.nix +++ b/my-lib/default.nix @@ -1,4 +1,6 @@ -lib: { +lib: rec { net = import ./net.nix lib; globals = import ./globals.nix; + + imagePath = name: "nix:0${globals.imageDir}/${name}.tar"; } diff --git a/my-lib/globals.nix b/my-lib/globals.nix index a5a9808..851798c 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -26,6 +26,8 @@ immichIPv4 = "192.168.30.147"; nextcloudIPv4 = "192.168.30.148"; + imageDir = "/var/docker_images"; + images = { jellyfin = "jellyfin/jellyfin:10.9.9"; deluge = "linuxserver/deluge:2.1.1"; @@ -35,32 +37,29 @@ sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; atuin = "ghcr.io/atuinsh/atuin:18.3.0"; - atuinPostgres = "postgres:14"; - kms = "teddysun/kms"; + postgres14 = "postgres:14"; + kms = "teddysun/kms:latest"; paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.6"; - paperlessRedis = "docker.io/library/redis:7"; - paperlessPostgres = "postgres:15"; + redis7 = "docker.io/library/redis:7"; nextcloud = "nextcloud:29.0.5"; - nextcloudPostgres = "postgres:15"; + postgres15 = "postgres:15"; inbucket = "inbucket/inbucket:edge"; syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; - radicale = "nix:0/var/docker_images/radicale.tar"; + radicale = "tomsquest/docker-radicale:3.2.2.0"; ntfy = "binwiederhier/ntfy:v2.11.0"; forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; pihole = "pihole/pihole:2024.07.0"; immich = "ghcr.io/immich-app/immich-server:v1.112.1"; - immichML = "ghcr.io/immich-app/immich-machine-learning:v1.112.1"; - immichRedis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; - immichPostgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.112.1"; + immich-redis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; + immich-postgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; kitchenowl = "tombursch/kitchenowl:v0.5.2"; - cyberchef = "nix:0/var/docker_images/cyberchef.tar"; + cyberchef = "mpepping/cyberchef:latest"; freshrss = "freshrss/freshrss:1.24.2"; bind9 = "ubuntu/bind9:9.18-22.04_beta"; dnsmasq = "dockurr/dnsmasq:2.90"; attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; - atticPostgres = "postgres:15"; hedgedoc = "quay.io/hedgedoc/hedgedoc:1.9.9"; - hedgedocPostgres = "postgres:15"; - minecraft = "itzg/minecraft-server"; + minecraft = "itzg/minecraft-server:latest"; }; } diff --git a/nixos-modules/k3s/default.nix b/nixos-modules/k3s/default.nix index 52def8c..773fb98 100644 --- a/nixos-modules/k3s/default.nix +++ b/nixos-modules/k3s/default.nix @@ -1,4 +1,4 @@ -{ self, inputs, pkgs, lib, config, ... }: +{ self, myLib, inputs, pkgs, lib, config, ... }: let cfg = config.lab.k3s; in @@ -167,12 +167,11 @@ in docker-images.text = let - imageLinkDir = "/var/docker_images"; imageDefs = import "${self}/container-images.nix"; setupCommands = [ - "rm -rf ${imageLinkDir}" - "mkdir -p ${imageLinkDir}" + "rm -rf ${myLib.globals.imageDir}" + "mkdir -p ${myLib.globals.imageDir}" ]; getDockerImageConfig = dockerImage: @@ -196,12 +195,15 @@ in fromImage = dockerImage; config = getDockerImageConfig dockerImage; }; - imageLinkPath = "${imageLinkDir}/${name}.tar"; + imageLinkPath = "${myLib.globals.imageDir}/${name}.tar"; in "ln -sf ${nixSnapshotterImage} ${imageLinkPath}"; linkCommandList = lib.attrsets.mapAttrsToList imageDefToLinkCommand imageDefs; - commandList = setupCommands ++ linkCommandList; + # TODO: Creating Docker images like this seems to *explode* in size. + # Doing this for every image we currently have is infeasible. + # I should investigate why the size increases like that. + commandList = setupCommands; # ++ linkCommandList; in builtins.concatStringsSep "\n" commandList; }; From b139f3d469988a1f1a25c5b4fb2fba0527bf2bf7 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 30 Aug 2024 17:49:11 +0200 Subject: [PATCH 075/108] Add Ansible playbook to configure PiKVM Add Nix shell to flake Monitor PiKVM with Prometheus Serve Prometheus on / --- ansible/ansible.cfg | 4 ++++ ansible/inventory/pikvm.yml | 5 ++++ ansible/main.yml | 6 +++++ ansible/roles/pikvm/tasks/main.yml | 20 ++++++++++++++++ flake-parts/shell.nix | 9 +++++++ flake.nix | 1 + kubenix-modules/attic.nix | 2 +- kubenix-modules/atuin.nix | 2 +- kubenix-modules/hedgedoc.nix | 2 +- kubenix-modules/immich.nix | 6 ++--- kubenix-modules/nextcloud.nix | 2 +- kubenix-modules/traefik.nix | 2 +- machines/default.nix | 4 ++-- nixos-modules/monitoring/default.nix | 35 +++++++++++++++++++++------- 14 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 ansible/ansible.cfg create mode 100644 ansible/inventory/pikvm.yml create mode 100644 ansible/main.yml create mode 100644 ansible/roles/pikvm/tasks/main.yml create mode 100644 flake-parts/shell.nix diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..53d5dad --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = inventory +remote_tmp = /tmp/ansible +ansible_python_interpreter = /usr/bin/python3.12 diff --git a/ansible/inventory/pikvm.yml b/ansible/inventory/pikvm.yml new file mode 100644 index 0000000..7b3205d --- /dev/null +++ b/ansible/inventory/pikvm.yml @@ -0,0 +1,5 @@ +all: + hosts: + pikvm: + ansible_host: pikvm.dmz + ansible_user: root diff --git a/ansible/main.yml b/ansible/main.yml new file mode 100644 index 0000000..6b557e0 --- /dev/null +++ b/ansible/main.yml @@ -0,0 +1,6 @@ +--- +- name: Configure PiKVM server + hosts: all + + roles: + - pikvm diff --git a/ansible/roles/pikvm/tasks/main.yml b/ansible/roles/pikvm/tasks/main.yml new file mode 100644 index 0000000..4a93953 --- /dev/null +++ b/ansible/roles/pikvm/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: Mount filesystem as read-write + ansible.builtin.command: rw + vars: + root_mount: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | first }}" + when: "'ro' in root_mount.options.split(',')" + +- name: Install Tailscale + community.general.pacman: + name: tailscale-pikvm + state: latest + +- name: Enable Tailscale + ansible.builtin.systemd_service: + name: tailscaled + state: started + enabled: true + +- name: Mount filesystem as read-only + ansible.builtin.command: ro diff --git a/flake-parts/shell.nix b/flake-parts/shell.nix new file mode 100644 index 0000000..67e7b03 --- /dev/null +++ b/flake-parts/shell.nix @@ -0,0 +1,9 @@ +{ flake-utils, nixpkgs, ... }: flake-utils.lib.eachDefaultSystem (system: +let + pkgs = nixpkgs.legacyPackages.${system}; +in +{ + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ ansible ]; + }; +}) diff --git a/flake.nix b/flake.nix index 198e0d5..25e1310 100644 --- a/flake.nix +++ b/flake.nix @@ -69,6 +69,7 @@ ./flake-parts/deploy.nix ./flake-parts/nixos.nix ./flake-parts/kubenix.nix + ./flake-parts/shell.nix ] // (flake-utils.lib.eachDefaultSystem (system: { formatter = nixpkgs.legacyPackages.${system}.nixfmt; })); diff --git a/kubenix-modules/attic.nix b/kubenix-modules/attic.nix index 7d59c8b..7e0e79b 100644 --- a/kubenix-modules/attic.nix +++ b/kubenix-modules/attic.nix @@ -122,7 +122,7 @@ spec = { containers.postgres = { - image = myLib.globals.images.atticPostgres; + image = myLib.globals.images.postgres15; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/atuin.nix b/kubenix-modules/atuin.nix index 96a1002..673ccc2 100644 --- a/kubenix-modules/atuin.nix +++ b/kubenix-modules/atuin.nix @@ -51,7 +51,7 @@ }; database = { - image = myLib.globals.images.atuinPostgres; + image = myLib.globals.images.postgres14; ports.web.containerPort = 5432; env = { diff --git a/kubenix-modules/hedgedoc.nix b/kubenix-modules/hedgedoc.nix index 7cb68cc..d9ceeb0 100644 --- a/kubenix-modules/hedgedoc.nix +++ b/kubenix-modules/hedgedoc.nix @@ -88,7 +88,7 @@ spec = { containers.postgres = { - image = myLib.globals.images.hedgedocPostgres; + image = myLib.globals.images.postgres15; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix index e51297f..1bca830 100644 --- a/kubenix-modules/immich.nix +++ b/kubenix-modules/immich.nix @@ -82,7 +82,7 @@ volumes.cache.persistentVolumeClaim.claimName = "cache"; containers.machine-learning = { - image = myLib.globals.images.immichML; + image = myLib.globals.images.immich-machine-learning; imagePullPolicy = "IfNotPresent"; ports.ml.containerPort = 3003; env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; @@ -119,7 +119,7 @@ spec = { containers.redis = { - image = myLib.globals.images.immichRedis; + image = myLib.globals.images.immich-redis; ports.redis.containerPort = 6379; imagePullPolicy = "IfNotPresent"; }; @@ -152,7 +152,7 @@ volumes.data.persistentVolumeClaim.claimName = "database"; containers.postgres = { - image = myLib.globals.images.immichPostgres; + image = myLib.globals.images.immich-postgres; imagePullPolicy = "IfNotPresent"; command = [ "postgres" ]; args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; diff --git a/kubenix-modules/nextcloud.nix b/kubenix-modules/nextcloud.nix index 11f5aef..e5a7056 100644 --- a/kubenix-modules/nextcloud.nix +++ b/kubenix-modules/nextcloud.nix @@ -79,7 +79,7 @@ spec = { containers.postgres = { - image = myLib.globals.images.nextcloudPostgres; + image = myLib.globals.images.postgres15; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix index d9018db..e2d476b 100644 --- a/kubenix-modules/traefik.nix +++ b/kubenix-modules/traefik.nix @@ -65,7 +65,7 @@ }; }; - tailscaleIngresses.tailscale = { + tailscaleIngresses.traefik-dashboard = { host = "traefik"; service.name = "traefik-dashboard"; }; diff --git a/machines/default.nix b/machines/default.nix index 4adab0f..f815d11 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -39,8 +39,8 @@ in ./atlas.nix ./jefke.nix ./lewis.nix - ./talos.nix - ./pikvm.nix + # ./talos.nix + # ./pikvm.nix ]; options = { diff --git a/nixos-modules/monitoring/default.nix b/nixos-modules/monitoring/default.nix index 574af79..2d6560d 100644 --- a/nixos-modules/monitoring/default.nix +++ b/nixos-modules/monitoring/default.nix @@ -23,7 +23,6 @@ in services.prometheus = { enable = cfg.server.enable; - webExternalUrl = "/prometheus"; exporters = { node = { @@ -32,14 +31,34 @@ in }; scrapeConfigs = lib.mkIf cfg.server.enable ( - lib.attrsets.mapAttrsToList - (name: machine: { - job_name = name; + let + generated = lib.attrsets.mapAttrsToList + (name: machine: { + job_name = name; + static_configs = [{ + targets = [ "${name}.dmz:${toString config.services.prometheus.exporters.node.port}" ]; + }]; + }) + machines; + + pikvm = { + job_name = "pikvm"; + metrics_path = "/api/export/prometheus/metrics"; + scheme = "https"; + tls_config.insecure_skip_verify = true; + + # We don't care about security here, it's behind a VPN. + basic_auth = { + username = "admin"; + password = "admin"; + }; + static_configs = [{ - targets = [ "${name}.dmz:${toString config.services.prometheus.exporters.node.port}" ]; + targets = [ "pikvm.dmz" ]; }]; - }) - machines + }; + in + generated ++ [ pikvm ] ); }; @@ -47,7 +66,7 @@ in enable = true; virtualHosts."${config.networking.fqdn}" = { - locations."/prometheus/" = { + locations."/" = { proxyPass = "http://127.0.0.1:${toString config.services.prometheus.port}"; recommendedProxySettings = true; }; From d6f3aadeaff7ea948963d4929e30958ca1c7b548 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 1 Sep 2024 11:39:53 +0200 Subject: [PATCH 076/108] Enable nix garbage collection service --- configuration.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configuration.nix b/configuration.nix index 72a46e9..2a5bf0d 100644 --- a/configuration.nix +++ b/configuration.nix @@ -119,6 +119,13 @@ extraOptions = '' experimental-features = nix-command flakes ''; + + gc = { + automatic = true; + persistent = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; }; system = { From be17c95d8607e458b7f32da857e578a4f40ac3c2 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 1 Sep 2024 16:11:20 +0200 Subject: [PATCH 077/108] Improve documentation of recovering Longhorn volumes --- docs/longhorn.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/longhorn.md b/docs/longhorn.md index 24e854c..532a188 100644 --- a/docs/longhorn.md +++ b/docs/longhorn.md @@ -62,3 +62,14 @@ To restore a backup, perform the following actions: 2. Enable the "backup-nfs" recurring job for the Longhorn volume. 3. Disable the "default" recurring job group for the Longhorn volume. 4. Create the PV, PVC and workload as usual. + +## Recovering Longhorn volumes without a Kubernetes cluster + +1. Navigate to the Longhorn backupstore location (`/mnt/longhorn/persistent/longhorn-backup/backupstore/volumes` for us). +2. Find the directory for the desired volume: `ls **/**`. +3. Determine the last backup for the volume: `cat volume.cfg | jq '.LastBackupName'`. +4. Find the blocks and the order that form the volume: `cat backups/.cfg | jq '.Blocks'`. +5. Extract each block using lz4: `lz4 -d blocks/XX/YY/XXYY.blk block`. +6. Append the blocks to form the file system: `cat block1 block2 block3 > volume.img` +7. Lastly we need to fix the size of the image. We can simply append zero's to the end until the file is long enough so `fsck.ext4` does not complain anymore. +8. Mount the image: `mount -o loop volume.img /mnt/volume`. From c55b0752e7c971bdcabd7d7f70394f04c9d8825f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 6 Sep 2024 19:36:31 +0200 Subject: [PATCH 078/108] radicale: 3.2.2.0 -> 3.2.3.0 immich: v1.112.1 -> v1.114.0 freshrss: 1.24.2 -> 1.24.3 --- my-lib/globals.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/my-lib/globals.nix b/my-lib/globals.nix index 851798c..38aadd5 100644 --- a/my-lib/globals.nix +++ b/my-lib/globals.nix @@ -45,17 +45,17 @@ postgres15 = "postgres:15"; inbucket = "inbucket/inbucket:edge"; syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; - radicale = "tomsquest/docker-radicale:3.2.2.0"; + radicale = "tomsquest/docker-radicale:3.2.3.0"; ntfy = "binwiederhier/ntfy:v2.11.0"; forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; pihole = "pihole/pihole:2024.07.0"; - immich = "ghcr.io/immich-app/immich-server:v1.112.1"; - immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.112.1"; + immich = "ghcr.io/immich-app/immich-server:v1.114.0"; + immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.114.0"; immich-redis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; immich-postgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; kitchenowl = "tombursch/kitchenowl:v0.5.2"; cyberchef = "mpepping/cyberchef:latest"; - freshrss = "freshrss/freshrss:1.24.2"; + freshrss = "freshrss/freshrss:1.24.3"; bind9 = "ubuntu/bind9:9.18-22.04_beta"; dnsmasq = "dockurr/dnsmasq:2.90"; attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; From a335dd4120514e921a916d438a0a9dff7369dc66 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 7 Sep 2024 12:39:30 +0200 Subject: [PATCH 079/108] WIP: remove kubernetes deployments --- flake-parts/machines/atlas.nix | 16 + flake-parts/machines/default.nix | 59 ++ flake-parts/machines/jefke.nix | 16 + flake-parts/machines/lewis.nix | 23 + flake-parts/machines/pikvm.nix | 23 + flake-parts/machines/talos.nix | 11 + flake-parts/machines/warwick.nix | 18 + flake-parts/utils/default.nix | 20 + flake-parts/utils/globals.nix | 65 ++ flake-parts/utils/net.nix | 1323 ++++++++++++++++++++++++++++++ flake.nix | 2 + 11 files changed, 1576 insertions(+) create mode 100644 flake-parts/machines/atlas.nix create mode 100644 flake-parts/machines/default.nix create mode 100644 flake-parts/machines/jefke.nix create mode 100644 flake-parts/machines/lewis.nix create mode 100644 flake-parts/machines/pikvm.nix create mode 100644 flake-parts/machines/talos.nix create mode 100644 flake-parts/machines/warwick.nix create mode 100644 flake-parts/utils/default.nix create mode 100644 flake-parts/utils/globals.nix create mode 100644 flake-parts/utils/net.nix diff --git a/flake-parts/machines/atlas.nix b/flake-parts/machines/atlas.nix new file mode 100644 index 0000000..a6bf86f --- /dev/null +++ b/flake-parts/machines/atlas.nix @@ -0,0 +1,16 @@ +{ + machines.atlas = { + arch = "x86_64-linux"; + kubernetesNodeLabels.storageType = "slow"; + + nixosModule.lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; + + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; + }; + }; + }; +} diff --git a/flake-parts/machines/default.nix b/flake-parts/machines/default.nix new file mode 100644 index 0000000..74aa74e --- /dev/null +++ b/flake-parts/machines/default.nix @@ -0,0 +1,59 @@ +{ nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: +let + pkgs = nixpkgs.legacyPackages.${system}; + lib = pkgs.lib; + + machineOpts = { config, ... }: { + options = { + arch = lib.mkOption { + default = null; + type = with lib.types; nullOr str; + description = '' + CPU architecture of this machine. + ''; + }; + + isRaspberryPi = lib.mkOption { + default = false; + type = lib.types.bool; + }; + + nixosModule = lib.mkOption { + default = { ... }: { }; + type = lib.types.anything; + description = '' + Customized configuration for this machine in the form of a NixOS module. + ''; + }; + + kubernetesNodeLabels = lib.mkOption { + default = null; + type = with lib.types; nullOr attrs; + description = '' + Any labels to add to the Kubernetes node. + ''; + }; + }; + }; + + allOpts = { + options = { + machines = lib.mkOption { + type = with lib.types; attrsOf (submodule machineOpts); + }; + }; + }; +in +{ + machines = (lib.modules.evalModules { + modules = [ + allOpts + ./warwick.nix + ./atlas.nix + ./jefke.nix + ./lewis.nix + # ./talos.nix + # ./pikvm.nix + ]; + }).config.machines; +}) diff --git a/flake-parts/machines/jefke.nix b/flake-parts/machines/jefke.nix new file mode 100644 index 0000000..096be8c --- /dev/null +++ b/flake-parts/machines/jefke.nix @@ -0,0 +1,16 @@ +{ + machines.jefke = { + arch = "x86_64-linux"; + kubernetesNodeLabels.storageType = "fast"; + + nixosModule.lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; + + k3s = { + enable = true; + clusterInit = true; + }; + }; + }; +} diff --git a/flake-parts/machines/lewis.nix b/flake-parts/machines/lewis.nix new file mode 100644 index 0000000..5350142 --- /dev/null +++ b/flake-parts/machines/lewis.nix @@ -0,0 +1,23 @@ +{ + machines.lewis = { + arch = "x86_64-linux"; + kubernetesNodeLabels = { + storageType = "fast"; + hasMedia = "true"; + }; + + nixosModule = { + lab = { + storage.profile = "kubernetes"; + backups.enable = true; + data-sharing.enable = true; + tailscale.enable = true; + + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; + }; + }; + }; + }; +} diff --git a/flake-parts/machines/pikvm.nix b/flake-parts/machines/pikvm.nix new file mode 100644 index 0000000..6a7bc14 --- /dev/null +++ b/flake-parts/machines/pikvm.nix @@ -0,0 +1,23 @@ +{ + machines.pikvm = { + arch = "aarch64-linux"; + isRaspberryPi = true; + + nixosModule = { config, inputs, lib, ... }: { + # imports = [ "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" ]; + lab = { + storage.profile = "pi"; + }; + + environment.systemPackages = with inputs.nixpkgs.legacyPackages.aarch64-linux; [ + (mplayer.override { + v4lSupport = true; + }) + ffmpeg + v4l-utils + ]; + + boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; + }; + }; +} diff --git a/flake-parts/machines/talos.nix b/flake-parts/machines/talos.nix new file mode 100644 index 0000000..0fa0311 --- /dev/null +++ b/flake-parts/machines/talos.nix @@ -0,0 +1,11 @@ +{ + machines.talos = { + arch = "x86_64-linux"; + + nixosModule = { lib, ... }: { + lab.storage.profile = "normal"; + + # boot.loader.systemd-boot.enable = lib.mkForce false; + }; + }; +} diff --git a/flake-parts/machines/warwick.nix b/flake-parts/machines/warwick.nix new file mode 100644 index 0000000..f000881 --- /dev/null +++ b/flake-parts/machines/warwick.nix @@ -0,0 +1,18 @@ +{ + machines.warwick = { + arch = "aarch64-linux"; + isRaspberryPi = true; + + nixosModule = { lib, ... }: { + lab = { + storage.profile = "pi"; + monitoring.server.enable = true; + + tailscale = { + advertiseExitNode = true; + enable = true; + }; + }; + }; + }; +} diff --git a/flake-parts/utils/default.nix b/flake-parts/utils/default.nix new file mode 100644 index 0000000..e0ecf4e --- /dev/null +++ b/flake-parts/utils/default.nix @@ -0,0 +1,20 @@ +{ nixpkgs, flake-utils, ... }: + +let + systemAttrs = flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacypackages.${system}; + lib = pkgs.lib; + in + { + net = import ./net.nix lib; + }); + + nonSystemAttrs = rec { + globals = import ./globals.nix; + imagePath = name: "nix:0${globals.imageDir}/${name}.tar"; + }; + + allAttrs = systemAttrs // nonSystemAttrs; +in +allAttrs diff --git a/flake-parts/utils/globals.nix b/flake-parts/utils/globals.nix new file mode 100644 index 0000000..38aadd5 --- /dev/null +++ b/flake-parts/utils/globals.nix @@ -0,0 +1,65 @@ +{ + routerPublicIPv4 = "192.145.57.90"; + routerPublicIPv6 = "2a0d:6e00:1a77::1"; + bind9Ipv6 = "2a0d:6e00:1a77:30::134"; + + # Load balancer IPv4 + traefikIPv4 = "192.168.30.128"; + kmsIPv4 = "192.168.30.129"; + inbucketIPv4 = "192.168.30.130"; + piholeIPv4 = "192.168.30.131"; + gitIPv4 = "192.168.30.132"; + transmissionIPv4 = "192.168.30.133"; + bind9IPv4 = "192.168.30.134"; + dnsmasqIPv4 = "192.168.30.135"; + minecraftIPv4 = "192.168.30.136"; + jellyseerrIPv4 = "192.168.30.137"; + syncthingIPv4 = "192.168.30.138"; + longhornIPv4 = "192.168.30.139"; + radarrIPv4 = "192.168.30.140"; + prowlarrIPv4 = "192.168.30.141"; + sonarrIPv4 = "192.168.30.142"; + bazarrIPv4 = "192.168.30.143"; + paperlessIPv4 = "192.168.30.144"; + radicaleIPv4 = "192.168.30.145"; + freshrssIPv4 = "192.168.30.146"; + immichIPv4 = "192.168.30.147"; + nextcloudIPv4 = "192.168.30.148"; + + imageDir = "/var/docker_images"; + + images = { + jellyfin = "jellyfin/jellyfin:10.9.9"; + deluge = "linuxserver/deluge:2.1.1"; + jellyseerr = "fallenbagel/jellyseerr:1.9.2"; + radarr = "lscr.io/linuxserver/radarr:5.9.1"; + prowlarr = "lscr.io/linuxserver/prowlarr:1.21.2"; + sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; + bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; + atuin = "ghcr.io/atuinsh/atuin:18.3.0"; + postgres14 = "postgres:14"; + kms = "teddysun/kms:latest"; + paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.6"; + redis7 = "docker.io/library/redis:7"; + nextcloud = "nextcloud:29.0.5"; + postgres15 = "postgres:15"; + inbucket = "inbucket/inbucket:edge"; + syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; + radicale = "tomsquest/docker-radicale:3.2.3.0"; + ntfy = "binwiederhier/ntfy:v2.11.0"; + forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; + pihole = "pihole/pihole:2024.07.0"; + immich = "ghcr.io/immich-app/immich-server:v1.114.0"; + immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.114.0"; + immich-redis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; + immich-postgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + kitchenowl = "tombursch/kitchenowl:v0.5.2"; + cyberchef = "mpepping/cyberchef:latest"; + freshrss = "freshrss/freshrss:1.24.3"; + bind9 = "ubuntu/bind9:9.18-22.04_beta"; + dnsmasq = "dockurr/dnsmasq:2.90"; + attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; + hedgedoc = "quay.io/hedgedoc/hedgedoc:1.9.9"; + minecraft = "itzg/minecraft-server:latest"; + }; +} diff --git a/flake-parts/utils/net.nix b/flake-parts/utils/net.nix new file mode 100644 index 0000000..9f5b0e5 --- /dev/null +++ b/flake-parts/utils/net.nix @@ -0,0 +1,1323 @@ +# IP address arithmetic and validation in Nix by @duairc: +# https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba + +lib: + +let + + net = { + ip = { + + # add :: (ip | mac | integer) -> ip -> ip + # + # Examples: + # + # Adding integer to IPv4: + # > net.ip.add 100 "10.0.0.1" + # "10.0.0.101" + # + # Adding IPv4 to IPv4: + # > net.ip.add "127.0.0.1" "10.0.0.1" + # "137.0.0.2" + # + # Adding IPv6 to IPv4: + # > net.ip.add "::cafe:beef" "10.0.0.1" + # "212.254.186.191" + # + # Adding MAC to IPv4 (overflows): + # > net.ip.add "fe:ed:fa:ce:f0:0d" "10.0.0.1" + # "4.206.240.14" + # + # Adding integer to IPv6: + # > net.ip.add 100 "dead:cafe:beef::" + # "dead:cafe:beef::64" + # + # Adding IPv4 to to IPv6: + # > net.ip.add "127.0.0.1" "dead:cafe:beef::" + # "dead:cafe:beef::7f00:1" + # + # Adding MAC to IPv6: + # > net.ip.add "fe:ed:fa:ce:f0:0d" "dead:cafe:beef::" + # "dead:cafe:beef::feed:face:f00d" + add = delta: ip: + let + function = "net.ip.add"; + delta' = typechecks.numeric function "delta" delta; + ip' = typechecks.ip function "ip" ip; + in + builders.ip (implementations.ip.add delta' ip'); + + # diff :: ip -> ip -> (integer | ipv6) + # + # net.ip.diff is the reverse of net.ip.add: + # + # net.ip.diff (net.ip.add a b) a = b + # net.ip.diff (net.ip.add a b) b = a + # + # The difference between net.ip.diff and net.ip.subtract is that + # net.ip.diff will try its best to return an integer (falling back + # to an IPv6 if the result is too big to fit in an integer). This is + # useful if you have two hosts that you know are on the same network + # and you just want to calculate the offset between them — a result + # like "0.0.0.10" is not very useful (which is what you would get + # from net.ip.subtract). + diff = minuend: subtrahend: + let + function = "net.ip.diff"; + minuend' = typechecks.ip function "minuend" minuend; + subtrahend' = typechecks.ip function "subtrahend" subtrahend; + result = implementations.ip.diff minuend' subtrahend'; + in + if result ? ipv6 + then builders.ipv6 result + else result; + + # subtract :: (ip | mac | integer) -> ip -> ip + # + # net.ip.subtract is also the reverse of net.ip.add: + # + # net.ip.subtract a (net.ip.add a b) = b + # net.ip.subtract b (net.ip.add a b) = a + # + # The difference between net.ip.subtract and net.ip.diff is that + # net.ip.subtract will always return the same type as its "ip" + # parameter. Its implementation takes the "delta" parameter, + # coerces it to be the same type as the "ip" paramter, negates it + # (using two's complement), and then adds it to "ip". + subtract = delta: ip: + let + function = "net.ip.subtract"; + delta' = typechecks.numeric function "delta" delta; + ip' = typechecks.ip function "ip" ip; + in + builders.ip (implementations.ip.subtract delta' ip'); + }; + + mac = { + + # add :: (ip | mac | integer) -> mac -> mac + # + # Examples: + # + # Adding integer to MAC: + # > net.mac.add 100 "fe:ed:fa:ce:f0:0d" + # "fe:ed:fa:ce:f0:71" + # + # Adding IPv4 to MAC: + # > net.mac.add "127.0.0.1" "fe:ed:fa:ce:f0:0d" + # "fe:ee:79:ce:f0:0e" + # + # Adding IPv6 to MAC: + # > net.mac.add "::cafe:beef" "fe:ed:fa:ce:f0:0d" + # "fe:ee:c5:cd:aa:cb + # + # Adding MAC to MAC: + # > net.mac.add "fe:ed:fa:00:00:00" "00:00:00:ce:f0:0d" + # "fe:ed:fa:ce:f0:0d" + add = delta: mac: + let + function = "net.mac.add"; + delta' = typechecks.numeric function "delta" delta; + mac' = typechecks.mac function "mac" mac; + in + builders.mac (implementations.mac.add delta' mac'); + + # diff :: mac -> mac -> integer + # + # net.mac.diff is the reverse of net.mac.add: + # + # net.mac.diff (net.mac.add a b) a = b + # net.mac.diff (net.mac.add a b) b = a + # + # The difference between net.mac.diff and net.mac.subtract is that + # net.mac.diff will always return an integer. + diff = minuend: subtrahend: + let + function = "net.mac.diff"; + minuend' = typechecks.mac function "minuend" minuend; + subtrahend' = typechecks.mac function "subtrahend" subtrahend; + in + implementations.mac.diff minuend' subtrahend'; + + # subtract :: (ip | mac | integer) -> mac -> mac + # + # net.mac.subtract is also the reverse of net.ip.add: + # + # net.mac.subtract a (net.mac.add a b) = b + # net.mac.subtract b (net.mac.add a b) = a + # + # The difference between net.mac.subtract and net.mac.diff is that + # net.mac.subtract will always return a MAC address. + subtract = delta: mac: + let + function = "net.mac.subtract"; + delta' = typechecks.numeric function "delta" delta; + mac' = typechecks.mac function "mac" mac; + in + builders.mac (implementations.mac.subtract delta' mac'); + }; + + cidr = { + # add :: (ip | mac | integer) -> cidr -> cidr + # + # > net.cidr.add 2 "127.0.0.0/8" + # "129.0.0.0/8" + # + # > net.cidr.add (-2) "127.0.0.0/8" + # "125.0.0.0/8" + add = delta: cidr: + let + function = "net.cidr.add"; + delta' = typechecks.numeric function "delta" delta; + cidr' = typechecks.cidr function "cidr" cidr; + in + builders.cidr (implementations.cidr.add delta' cidr'); + + # child :: cidr -> cidr -> bool + # + # > net.cidr.child "10.10.10.0/24" "10.0.0.0/8" + # true + # + # > net.cidr.child "127.0.0.0/8" "10.0.0.0/8" + # false + child = subcidr: cidr: + let + function = "net.cidr.child"; + subcidr' = typechecks.cidr function "subcidr" subcidr; + cidr' = typechecks.cidr function "cidr" cidr; + in + implementations.cidr.child subcidr' cidr'; + + # contains :: ip -> cidr -> bool + # + # > net.cidr.contains "127.0.0.1" "127.0.0.0/8" + # true + # + # > net.cidr.contains "127.0.0.1" "192.168.0.0/16" + # false + contains = ip: cidr: + let + function = "net.cidr.contains"; + ip' = typechecks.ip function "ip" ip; + cidr' = typechecks.cidr function "cidr" cidr; + in + implementations.cidr.contains ip' cidr'; + + # capacity :: cidr -> integer + # + # > net.cidr.capacity "172.16.0.0/12" + # 1048576 + # + # > net.cidr.capacity "dead:cafe:beef::/96" + # 4294967296 + # + # > net.cidr.capacity "dead:cafe:beef::/48" (saturates to maxBound) + # 9223372036854775807 + capacity = cidr: + let + function = "net.cidr.capacity"; + cidr' = typechecks.cidr function "cidr" cidr; + in + implementations.cidr.capacity cidr'; + + # host :: (ip | mac | integer) -> cidr -> ip + # + # > net.cidr.host 10000 "10.0.0.0/8" + # 10.0.39.16 + # + # > net.cidr.host 10000 "dead:cafe:beef::/64" + # "dead:cafe:beef::2710" + # + # net.cidr.host "127.0.0.1" "dead:cafe:beef::/48" + # > "dead:cafe:beef::7f00:1" + # + # Inpsired by: + # https://www.terraform.io/docs/configuration/functions/cidrhost.html + host = hostnum: cidr: + let + function = "net.cidr.host"; + hostnum' = typechecks.numeric function "hostnum" hostnum; + cidr' = typechecks.cidr function "cidr" cidr; + in + builders.ip (implementations.cidr.host hostnum' cidr'); + + # length :: cidr -> integer + # + # > net.cidr.prefix "127.0.0.0/8" + # 8 + # + # > net.cidr.prefix "dead:cafe:beef::/48" + # 48 + length = cidr: + let + function = "net.cidr.length"; + cidr' = typechecks.cidr function "cidr" cidr; + in + implementations.cidr.length cidr'; + + # make :: integer -> ip -> cidr + # + # > net.cidr.make 24 "192.168.0.150" + # "192.168.0.0/24" + # + # > net.cidr.make 40 "dead:cafe:beef::feed:face:f00d" + # "dead:cafe:be00::/40" + make = length: base: + let + function = "net.cidr.make"; + length' = typechecks.int function "length" length; + base' = typechecks.ip function "base" base; + in + builders.cidr (implementations.cidr.make length' base'); + + # netmask :: cidr -> ip + # + # > net.cidr.netmask "192.168.0.0/24" + # "255.255.255.0" + # + # > net.cidr.netmask "dead:cafe:beef::/64" + # "ffff:ffff:ffff:ffff::" + netmask = cidr: + let + function = "net.cidr.netmask"; + cidr' = typechecks.cidr function "cidr" cidr; + in + builders.ip (implementations.cidr.netmask cidr'); + + # size :: cidr -> integer + # + # > net.cidr.prefix "127.0.0.0/8" + # 24 + # + # > net.cidr.prefix "dead:cafe:beef::/48" + # 80 + size = cidr: + let + function = "net.cidr.size"; + cidr' = typechecks.cidr function "cidr" cidr; + in + implementations.cidr.size cidr'; + + # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr + # + # > net.cidr.subnet 4 2 "172.16.0.0/12" + # "172.18.0.0/16" + # + # > net.cidr.subnet 4 15 "10.1.2.0/24" + # "10.1.2.240/28" + # + # > net.cidr.subnet 16 162 "fd00:fd12:3456:7890::/56" + # "fd00:fd12:3456:7800:a200::/72" + # + # Inspired by: + # https://www.terraform.io/docs/configuration/functions/cidrsubnet.html + subnet = length: netnum: cidr: + let + function = "net.cidr.subnet"; + length' = typechecks.int function "length" length; + netnum' = typechecks.numeric function "netnum" netnum; + cidr' = typechecks.cidr function "cidr" cidr; + in + builders.cidr (implementations.cidr.subnet length' netnum' cidr'); + + }; + } // ({ + types = + let + + mkParsedOptionType = { name, description, parser, builder }: + let + normalize = def: def // { + value = builder (parser def.value); + }; + in + lib.mkOptionType { + inherit name description; + check = x: builtins.isString x && parser x != null; + merge = loc: defs: lib.mergeEqualOption loc (map normalize defs); + }; + + dependent-ip = type: cidr: + let + cidrs = + if builtins.isList cidr + then cidr + else [ cidr ]; + in + lib.types.addCheck type (i: lib.any (net.cidr.contains i) cidrs) // { + description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; + }; + + dependent-cidr = type: cidr: + let + cidrs = + if builtins.isList cidr + then cidr + else [ cidr ]; + in + lib.types.addCheck type (i: lib.any (net.cidr.child i) cidrs) // { + description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; + }; + + in + rec { + + ip = mkParsedOptionType { + name = "ip"; + description = "IPv4 or IPv6 address"; + parser = parsers.ip; + builder = builders.ip; + }; + + ip-in = dependent-ip ip; + + ipv4 = mkParsedOptionType { + name = "ipv4"; + description = "IPv4 address"; + parser = parsers.ipv4; + builder = builders.ipv4; + }; + + ipv4-in = dependent-ip ipv4; + + ipv6 = mkParsedOptionType { + name = "ipv6"; + description = "IPv6 address"; + parser = parsers.ipv6; + builder = builders.ipv6; + }; + + ipv6-in = dependent-ip ipv6; + + cidr = mkParsedOptionType { + name = "cidr"; + description = "IPv4 or IPv6 address range in CIDR notation"; + parser = parsers.cidr; + builder = builders.cidr; + }; + + cidr-in = dependent-cidr cidr; + + cidrv4 = mkParsedOptionType { + name = "cidrv4"; + description = "IPv4 address range in CIDR notation"; + parser = parsers.cidrv4; + builder = builders.cidrv4; + }; + + cidrv4-in = dependent-cidr cidrv4; + + cidrv6 = mkParsedOptionType { + name = "cidrv6"; + description = "IPv6 address range in CIDR notation"; + parser = parsers.cidrv6; + builder = builders.cidrv6; + }; + + cidrv6-in = dependent-cidr cidrv6; + + mac = mkParsedOptionType { + name = "mac"; + description = "MAC address"; + parser = parsers.mac; + builder = builders.mac; + }; + + }; + } + ); + + list = { + cons = a: b: [ a ] ++ b; + }; + + bit = + let + shift = n: x: + if n < 0 + then x * math.pow 2 (-n) + else + let + safeDiv = n: d: if d == 0 then 0 else n / d; + d = math.pow 2 n; + in + if x < 0 + then not (safeDiv (not x) d) + else safeDiv x d; + + left = n: shift (-n); + + right = shift; + + and = builtins.bitAnd; + + or = builtins.bitOr; + + xor = builtins.bitXor; + + not = xor (-1); + + mask = n: and (left n 1 - 1); + in + { + inherit left right and or xor not mask; + }; + + math = rec { + max = a: b: + if a > b + then a + else b; + + min = a: b: + if a < b + then a + else b; + + clamp = a: b: c: max a (min b c); + + pow = x: n: + if n == 0 + then 1 + else if bit.and n 1 != 0 + then x * pow (x * x) ((n - 1) / 2) + else pow (x * x) (n / 2); + }; + + parsers = + let + + # fmap :: (a -> b) -> parser a -> parser b + fmap = f: ma: bind ma (a: pure (f a)); + + # pure :: a -> parser a + pure = a: string: { + leftovers = string; + result = a; + }; + + # liftA2 :: (a -> b -> c) -> parser a -> parser b -> parser c + liftA2 = f: ma: mb: bind ma (a: bind mb (b: pure (f a b))); + liftA3 = f: a: b: ap (liftA2 f a b); + liftA4 = f: a: b: c: ap (liftA3 f a b c); + liftA5 = f: a: b: c: d: ap (liftA4 f a b c d); + liftA6 = f: a: b: c: d: e: ap (liftA5 f a b c d e); + + # ap :: parser (a -> b) -> parser a -> parser b + ap = liftA2 (a: a); + + # then_ :: parser a -> parser b -> parser b + then_ = liftA2 (a: b: b); + + # empty :: parser a + empty = string: null; + + # alt :: parser a -> parser a -> parser a + alt = left: right: string: + let + result = left string; + in + if builtins.isNull result + then right string + else result; + + # guard :: bool -> parser {} + guard = condition: if condition then pure { } else empty; + + # mfilter :: (a -> bool) -> parser a -> parser a + mfilter = f: parser: bind parser (a: then_ (guard (f a)) (pure a)); + + # some :: parser a -> parser [a] + some = v: liftA2 list.cons v (many v); + + # many :: parser a -> parser [a] + many = v: alt (some v) (pure [ ]); + + # bind :: parser a -> (a -> parser b) -> parser b + bind = parser: f: string: + let + a = parser string; + in + if builtins.isNull a + then null + else f a.result a.leftovers; + + # run :: parser a -> string -> maybe a + run = parser: string: + let + result = parser string; + in + if builtins.isNull result || result.leftovers != "" + then null + else result.result; + + next = string: + if string == "" + then null + else { + leftovers = builtins.substring 1 (-1) string; + result = builtins.substring 0 1 string; + }; + + # Count how many characters were consumed by a parser + count = parser: string: + let + result = parser string; + in + if builtins.isNull result + then null + else result // { + result = { + inherit (result) result; + count = with result; + builtins.stringLength string - builtins.stringLength leftovers; + }; + }; + + # Limit the parser to n characters at most + limit = n: parser: + fmap (a: a.result) (mfilter (a: a.count <= n) (count parser)); + + # Ensure the parser consumes exactly n characters + exactly = n: parser: + fmap (a: a.result) (mfilter (a: a.count == n) (count parser)); + + char = c: bind next (c': guard (c == c')); + + string = css: + if css == "" + then pure { } + else + let + c = builtins.substring 0 1 css; + cs = builtins.substring 1 (-1) css; + in + then_ (char c) (string cs); + + digit = set: bind next ( + c: then_ + (guard (builtins.hasAttr c set)) + (pure (builtins.getAttr c set)) + ); + + decimalDigits = { + "0" = 0; + "1" = 1; + "2" = 2; + "3" = 3; + "4" = 4; + "5" = 5; + "6" = 6; + "7" = 7; + "8" = 8; + "9" = 9; + }; + + hexadecimalDigits = decimalDigits // { + "a" = 10; + "b" = 11; + "c" = 12; + "d" = 13; + "e" = 14; + "f" = 15; + "A" = 10; + "B" = 11; + "C" = 12; + "D" = 13; + "E" = 14; + "F" = 15; + }; + + fromDecimalDigits = builtins.foldl' (a: c: a * 10 + c) 0; + fromHexadecimalDigits = builtins.foldl' (a: bit.or (bit.left 4 a)) 0; + + # disallow leading zeros + decimal = bind (digit decimalDigits) ( + n: + if n == 0 + then pure 0 + else + fmap + (ns: fromDecimalDigits (list.cons n ns)) + (many (digit decimalDigits)) + ); + + hexadecimal = fmap fromHexadecimalDigits (some (digit hexadecimalDigits)); + + ipv4 = + let + dot = char "."; + + octet = mfilter (n: n < 256) decimal; + + octet' = then_ dot octet; + + fromOctets = a: b: c: d: { + ipv4 = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d; + }; + in + liftA4 fromOctets octet octet' octet' octet'; + + # This is more or less a literal translation of + # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#parser + ipv6 = + let + colon = char ":"; + + hextet = limit 4 hexadecimal; + + fromHextets = hextets: + if builtins.length hextets != 8 + then empty + else + let + a = builtins.elemAt hextets 0; + b = builtins.elemAt hextets 1; + c = builtins.elemAt hextets 2; + d = builtins.elemAt hextets 3; + e = builtins.elemAt hextets 4; + f = builtins.elemAt hextets 5; + g = builtins.elemAt hextets 6; + h = builtins.elemAt hextets 7; + in + pure { + ipv6 = { + a = bit.or (bit.left 16 a) b; + b = bit.or (bit.left 16 c) d; + c = bit.or (bit.left 16 e) f; + d = bit.or (bit.left 16 g) h; + }; + }; + + ipv4' = fmap + ( + address: + let + upper = bit.right 16 address.ipv4; + lower = bit.mask 16 address.ipv4; + in + [ upper lower ] + ) + ipv4; + + part = n: + let + n' = n + 1; + hex = liftA2 list.cons hextet + ( + then_ colon + ( + alt + (then_ colon (doubleColon n')) + (part n') + ) + ); + in + if n == 7 + then fmap (a: [ a ]) hextet + else + if n == 6 + then alt ipv4' hex + else hex; + + doubleColon = n: + bind (alt afterDoubleColon (pure [ ])) ( + rest: + let + missing = 8 - n - builtins.length rest; + in + if missing < 0 + then empty + else pure (builtins.genList (_: 0) missing ++ rest) + ); + + afterDoubleColon = + alt ipv4' + ( + liftA2 list.cons hextet + ( + alt + (then_ colon afterDoubleColon) + (pure [ ]) + ) + ); + + in + bind + ( + alt + ( + then_ + (string "::") + (doubleColon 0) + ) + (part 0) + ) + fromHextets; + + cidrv4 = + liftA2 + (base: length: implementations.cidr.make length base) + ipv4 + (then_ (char "/") (mfilter (n: n <= 32) decimal)); + + cidrv6 = + liftA2 + (base: length: implementations.cidr.make length base) + ipv6 + (then_ (char "/") (mfilter (n: n <= 128) decimal)); + + mac = + let + colon = char ":"; + + octet = exactly 2 hexadecimal; + + octet' = then_ colon octet; + + fromOctets = a: b: c: d: e: f: { + mac = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d)) e)) f; + }; + in + liftA6 fromOctets octet octet' octet' octet' octet' octet'; + + in + { + ipv4 = run ipv4; + ipv6 = run ipv6; + ip = run (alt ipv4 ipv6); + cidrv4 = run cidrv4; + cidrv6 = run cidrv6; + cidr = run (alt cidrv4 cidrv6); + mac = run mac; + numeric = run (alt (alt ipv4 ipv6) mac); + }; + + builders = + let + + ipv4 = address: + let + abcd = address.ipv4; + abc = bit.right 8 abcd; + ab = bit.right 8 abc; + a = bit.right 8 ab; + b = bit.mask 8 ab; + c = bit.mask 8 abc; + d = bit.mask 8 abcd; + in + builtins.concatStringsSep "." (map toString [ a b c d ]); + + # This is more or less a literal translation of + # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#encode + ipv6 = address: + let + + digits = "0123456789abcdef"; + + toHexString = n: + let + rest = bit.right 4 n; + current = bit.mask 4 n; + prefix = + if rest == 0 + then "" + else toHexString rest; + in + "${prefix}${builtins.substring current 1 digits}"; + + in + if (with address.ipv6; a == 0 && b == 0 && c == 0 && d > 65535) + then "::${ipv4 { ipv4 = address.ipv6.d; }}" + else + if (with address.ipv6; a == 0 && b == 0 && c == 65535) + then "::ffff:${ipv4 { ipv4 = address.ipv6.d; }}" + else + let + + a = bit.right 16 address.ipv6.a; + b = bit.mask 16 address.ipv6.a; + c = bit.right 16 address.ipv6.b; + d = bit.mask 16 address.ipv6.b; + e = bit.right 16 address.ipv6.c; + f = bit.mask 16 address.ipv6.c; + g = bit.right 16 address.ipv6.d; + h = bit.mask 16 address.ipv6.d; + + hextets = [ a b c d e f g h ]; + + # calculate the position and size of the longest sequence of + # zeroes within the list of hextets + longest = + let + go = i: current: best: + if i < builtins.length hextets + then + let + n = builtins.elemAt hextets i; + + current' = + if n == 0 + then + if builtins.isNull current + then { + size = 1; + position = i; + } + else current // { + size = current.size + 1; + } + else null; + + best' = + if n == 0 + then + if builtins.isNull best + then current' + else + if current'.size > best.size + then current' + else best + else best; + in + go (i + 1) current' best' + else best; + in + go 0 null null; + + format = hextets: + builtins.concatStringsSep ":" (map toHexString hextets); + in + if builtins.isNull longest + then format hextets + else + let + sublist = i: length: xs: + map + (builtins.elemAt xs) + (builtins.genList (x: x + i) length); + + end = longest.position + longest.size; + + before = sublist 0 longest.position hextets; + + after = sublist end (builtins.length hextets - end) hextets; + in + "${format before}::${format after}"; + + ip = address: + if address ? ipv4 + then ipv4 address + else ipv6 address; + + cidrv4 = cidr: + "${ipv4 cidr.base}/${toString cidr.length}"; + + cidrv6 = cidr: + "${ipv6 cidr.base}/${toString cidr.length}"; + + cidr = cidr: + "${ip cidr.base}/${toString cidr.length}"; + + mac = address: + let + digits = "0123456789abcdef"; + octet = n: + let + upper = bit.right 4 n; + lower = bit.mask 4 n; + in + "${builtins.substring upper 1 digits}${builtins.substring lower 1 digits}"; + in + let + a = bit.mask 8 (bit.right 40 address.mac); + b = bit.mask 8 (bit.right 32 address.mac); + c = bit.mask 8 (bit.right 24 address.mac); + d = bit.mask 8 (bit.right 16 address.mac); + e = bit.mask 8 (bit.right 8 address.mac); + f = bit.mask 8 (bit.right 0 address.mac); + in + "${octet a}:${octet b}:${octet c}:${octet d}:${octet e}:${octet f}"; + + in + { + inherit ipv4 ipv6 ip cidrv4 cidrv6 cidr mac; + }; + + arithmetic = rec { + # or :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) + or = a_: b: + let + a = coerce b a_; + in + if a ? ipv6 + then { + ipv6 = { + a = bit.or a.ipv6.a b.ipv6.a; + b = bit.or a.ipv6.b b.ipv6.b; + c = bit.or a.ipv6.c b.ipv6.c; + d = bit.or a.ipv6.d b.ipv6.d; + }; + } + else if a ? ipv4 + then { + ipv4 = bit.or a.ipv4 b.ipv4; + } + else if a ? mac + then { + mac = bit.or a.mac b.mac; + } + else bit.or a b; + + # and :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) + and = a_: b: + let + a = coerce b a_; + in + if a ? ipv6 + then { + ipv6 = { + a = bit.and a.ipv6.a b.ipv6.a; + b = bit.and a.ipv6.b b.ipv6.b; + c = bit.and a.ipv6.c b.ipv6.c; + d = bit.and a.ipv6.d b.ipv6.d; + }; + } + else if a ? ipv4 + then { + ipv4 = bit.and a.ipv4 b.ipv4; + } + else if a ? mac + then { + mac = bit.and a.mac b.mac; + } + else bit.and a b; + + # not :: (ip | mac | integer) -> (ip | mac | integer) + not = a: + if a ? ipv6 + then { + ipv6 = { + a = bit.mask 32 (bit.not a.ipv6.a); + b = bit.mask 32 (bit.not a.ipv6.b); + c = bit.mask 32 (bit.not a.ipv6.c); + d = bit.mask 32 (bit.not a.ipv6.d); + }; + } + else if a ? ipv4 + then { + ipv4 = bit.mask 32 (bit.not a.ipv4); + } + else if a ? mac + then { + mac = bit.mask 48 (bit.not a.mac); + } + else bit.not a; + + # add :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) + add = + let + split = a: { + fst = bit.mask 32 (bit.right 32 a); + snd = bit.mask 32 a; + }; + in + a_: b: + let + a = coerce b a_; + in + if a ? ipv6 + then + let + a' = split (a.ipv6.a + b.ipv6.a + b'.fst); + b' = split (a.ipv6.b + b.ipv6.b + c'.fst); + c' = split (a.ipv6.c + b.ipv6.c + d'.fst); + d' = split (a.ipv6.d + b.ipv6.d); + in + { + ipv6 = { + a = a'.snd; + b = b'.snd; + c = c'.snd; + d = d'.snd; + }; + } + else if a ? ipv4 + then { + ipv4 = bit.mask 32 (a.ipv4 + b.ipv4); + } + else if a ? mac + then { + mac = bit.mask 48 (a.mac + b.mac); + } + else a + b; + + # subtract :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) + subtract = a: b: add (add 1 (not (coerce b a))) b; + + # diff :: (ip | mac | integer) -> (ip | mac | integer) -> (ipv6 | integer) + diff = a: b: + let + toIPv6 = coerce ({ ipv6.a = 0; }); + result = (subtract b (toIPv6 a)).ipv6; + max32 = bit.left 32 1 - 1; + in + if result.a == 0 && result.b == 0 && bit.right 31 result.c == 0 || result.a == max32 && result.b == max32 && bit.right 31 result.c == 1 + then bit.or (bit.left 32 result.c) result.d + else { + ipv6 = result; + }; + + # left :: integer -> (ip | mac | integer) -> (ip | mac | integer) + left = i: right (-i); + + # right :: integer -> (ip | mac | integer) -> (ip | mac | integer) + right = + let + step = i: x: { + _1 = bit.mask 32 (bit.right (i + 96) x); + _2 = bit.mask 32 (bit.right (i + 64) x); + _3 = bit.mask 32 (bit.right (i + 32) x); + _4 = bit.mask 32 (bit.right i x); + _5 = bit.mask 32 (bit.right (i - 32) x); + _6 = bit.mask 32 (bit.right (i - 64) x); + _7 = bit.mask 32 (bit.right (i - 96) x); + }; + ors = builtins.foldl' bit.or 0; + in + i: x: + if x ? ipv6 + then + let + a' = step i x.ipv6.a; + b' = step i x.ipv6.b; + c' = step i x.ipv6.c; + d' = step i x.ipv6.d; + in + { + ipv6 = { + a = ors [ a'._4 b'._3 c'._2 d'._1 ]; + b = ors [ a'._5 b'._4 c'._3 d'._2 ]; + c = ors [ a'._6 b'._5 c'._4 d'._3 ]; + d = ors [ a'._7 b'._6 c'._5 d'._4 ]; + }; + } + else if x ? ipv4 + then { + ipv4 = bit.mask 32 (bit.right i x.ipv4); + } + else if x ? mac + then { + mac = bit.mask 48 (bit.right i x.mac); + } + else bit.right i x; + + # shadow :: integer -> (ip | mac | integer) -> (ip | mac | integer) + shadow = n: a: and (right n (left n (coerce a (-1)))) a; + + # coshadow :: integer -> (ip | mac | integer) -> (ip | mac | integer) + coshadow = n: a: and (not (right n (left n (coerce a (-1))))) a; + + # coerce :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) + coerce = target: value: + if target ? ipv6 + then + if value ? ipv6 + then value + else if value ? ipv4 + then { + ipv6 = { + a = 0; + b = 0; + c = 0; + d = value.ipv4; + }; + } + else if value ? mac + then { + ipv6 = { + a = 0; + b = 0; + c = bit.right 32 value.mac; + d = bit.mask 32 value.mac; + }; + } + else { + ipv6 = { + a = bit.mask 32 (bit.right 96 value); + b = bit.mask 32 (bit.right 64 value); + c = bit.mask 32 (bit.right 32 value); + d = bit.mask 32 value; + }; + } + else if target ? ipv4 + then + if value ? ipv6 + then { + ipv4 = value.ipv6.d; + } + else if value ? ipv4 + then value + else if value ? mac + then { + ipv4 = bit.mask 32 value.mac; + } + else { + ipv4 = bit.mask 32 value; + } + else if target ? mac + then + if value ? ipv6 + then { + mac = bit.or (bit.left 32 (bit.mask 16 value.ipv6.c)) value.ipv6.d; + } + else if value ? ipv4 + then { + mac = value.ipv4; + } + else if value ? mac + then value + else { + mac = bit.mask 48 value; + } + else + if value ? ipv6 + then + builtins.foldl' bit.or 0 + [ + (bit.left 96 value.ipv6.a) + (bit.left 64 value.ipv6.b) + (bit.left 32 value.ipv6.c) + value.ipv6.d + ] + else if value ? ipv4 + then value.ipv4 + else if value ? mac + then value.mac + else value; + }; + + implementations = { + ip = { + # add :: (ip | mac | integer) -> ip -> ip + add = arithmetic.add; + + # diff :: ip -> ip -> (ipv6 | integer) + diff = arithmetic.diff; + + # subtract :: (ip | mac | integer) -> ip -> ip + subtract = arithmetic.subtract; + }; + + mac = { + # add :: (ip | mac | integer) -> mac -> mac + add = arithmetic.add; + + # diff :: mac -> mac -> (ipv6 | integer) + diff = arithmetic.diff; + + # subtract :: (ip | mac | integer) -> mac -> mac + subtract = arithmetic.subtract; + }; + + cidr = rec { + # add :: (ip | mac | integer) -> cidr -> cidr + add = delta: cidr: + let + size' = size cidr; + in + { + base = arithmetic.left size' (arithmetic.add delta (arithmetic.right size' cidr.base)); + inherit (cidr) length; + }; + + # capacity :: cidr -> integer + capacity = cidr: + let + size' = size cidr; + in + if size' > 62 + then 9223372036854775807 # maxBound to prevent overflow + else bit.left size' 1; + + # child :: cidr -> cidr -> bool + child = subcidr: cidr: + length subcidr > length cidr && contains (host 0 subcidr) cidr; + + # contains :: ip -> cidr -> bool + contains = ip: cidr: host 0 (make cidr.length ip) == host 0 cidr; + + # host :: (ip | mac | integer) -> cidr -> ip + host = index: cidr: + let + index' = arithmetic.coerce cidr.base index; + in + arithmetic.or (arithmetic.shadow cidr.length index') cidr.base; + + # length :: cidr -> integer + length = cidr: cidr.length; + + # netmask :: cidr -> ip + netmask = cidr: arithmetic.coshadow cidr.length (arithmetic.coerce cidr.base (-1)); + + # size :: cidr -> integer + size = cidr: (if cidr.base ? ipv6 then 128 else 32) - cidr.length; + + # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr + subnet = length: index: cidr: + let + length' = cidr.length + length; + index' = arithmetic.coerce cidr.base index; + size = (if cidr.base ? ipv6 then 128 else 32) - length'; + in + make length' (host (arithmetic.left size index') cidr); + + # make :: integer -> ip -> cidr + make = length: base: + let + length' = math.clamp 0 (if base ? ipv6 then 128 else 32) length; + in + { + base = arithmetic.coshadow length' base; + length = length'; + }; + }; + }; + + typechecks = + let + + fail = description: function: argument: + builtins.throw "${function}: ${argument} parameter must be ${description}"; + + meta = parser: description: function: argument: input: + let + error = fail description function argument; + in + if !builtins.isString input + then error + else + let + result = parser input; + in + if builtins.isNull result + then error + else result; + + in + { + int = function: argument: input: + if builtins.isInt input + then input + else fail "an integer" function argument; + ip = meta parsers.ip "an IPv4 or IPv6 address"; + cidr = meta parsers.cidr "an IPv4 or IPv6 address range in CIDR notation"; + mac = meta parsers.mac "a MAC address"; + numeric = function: argument: input: + if builtins.isInt input + then input + else meta parsers.numeric "an integer or IPv4, IPv6 or MAC address" function argument input; + }; + +in +net diff --git a/flake.nix b/flake.nix index 25e1310..379106d 100644 --- a/flake.nix +++ b/flake.nix @@ -70,6 +70,8 @@ ./flake-parts/nixos.nix ./flake-parts/kubenix.nix ./flake-parts/shell.nix + ./flake-parts/utils + ./flake-parts/machines ] // (flake-utils.lib.eachDefaultSystem (system: { formatter = nixpkgs.legacyPackages.${system}.nixfmt; })); From 660191ab42a2f800d4aa09c91ff2acce6bd0a68e Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 7 Sep 2024 13:06:37 +0200 Subject: [PATCH 080/108] Cleanup after kubernetes deployment migration --- .sops.yaml | 2 +- flake-parts/checks.nix | 9 +- flake-parts/deploy.nix | 7 +- flake-parts/kubenix.nix | 191 --- flake-parts/nixos.nix | 6 +- flake-parts/scripts/default.nix | 5 +- flake.lock | 341 +--- flake.nix | 25 +- kubenix-modules/argo.nix | 55 - kubenix-modules/attic.nix | 201 --- kubenix-modules/atuin.nix | 109 -- kubenix-modules/bind9/default.nix | 149 -- kubenix-modules/bind9/kun.is.zone.nix | 52 - kubenix-modules/blog.nix | 37 - kubenix-modules/bootstrap-default.nix | 144 -- kubenix-modules/bootstrap-kube-system.nix | 5 - kubenix-modules/cert-manager/default.nix | 36 - .../cert-manager/manifests/certificate.yaml | 443 ------ .../manifests/certificaterequest.yaml | 196 --- .../cert-manager/manifests/challenge.yaml | 1124 -------------- .../cert-manager/manifests/clusterissuer.yaml | 1371 ----------------- .../cert-manager/manifests/issuer.yaml | 1371 ----------------- .../cert-manager/manifests/order.yaml | 180 --- kubenix-modules/custom-types.nix | 42 - kubenix-modules/custom/default.nix | 7 - kubenix-modules/custom/ingress.nix | 67 - kubenix-modules/custom/longhorn-volume.nix | 149 -- kubenix-modules/custom/tailscale.nix | 52 - kubenix-modules/cyberchef.nix | 36 - kubenix-modules/dnsmasq.nix | 57 - kubenix-modules/forgejo/config.nix | 104 -- kubenix-modules/forgejo/default.nix | 98 -- kubenix-modules/freshrss.nix | 82 - kubenix-modules/hedgedoc.nix | 167 -- kubenix-modules/immich.nix | 262 ---- kubenix-modules/inbucket.nix | 65 - kubenix-modules/kitchenowl.nix | 72 - kubenix-modules/kms.nix | 27 - kubenix-modules/media.nix | 610 -------- kubenix-modules/minecraft.nix | 48 - kubenix-modules/nextcloud.nix | 157 -- kubenix-modules/ntfy.nix | 105 -- kubenix-modules/paperless.nix | 236 --- kubenix-modules/pihole.nix | 108 -- kubenix-modules/radicale.nix | 111 -- kubenix-modules/syncthing.nix | 89 -- kubenix-modules/tailscale.nix | 14 - kubenix-modules/traefik.nix | 73 - machines/atlas.nix | 16 - machines/default.nix | 51 - machines/jefke.nix | 16 - machines/lewis.nix | 23 - machines/pikvm.nix | 23 - machines/talos.nix | 11 - machines/warwick.nix | 18 - nixos-modules/k3s/default.nix | 8 +- secrets/kubernetes.yaml | 60 - 57 files changed, 26 insertions(+), 9097 deletions(-) delete mode 100644 flake-parts/kubenix.nix delete mode 100644 kubenix-modules/argo.nix delete mode 100644 kubenix-modules/attic.nix delete mode 100644 kubenix-modules/atuin.nix delete mode 100644 kubenix-modules/bind9/default.nix delete mode 100644 kubenix-modules/bind9/kun.is.zone.nix delete mode 100644 kubenix-modules/blog.nix delete mode 100644 kubenix-modules/bootstrap-default.nix delete mode 100644 kubenix-modules/bootstrap-kube-system.nix delete mode 100644 kubenix-modules/cert-manager/default.nix delete mode 100644 kubenix-modules/cert-manager/manifests/certificate.yaml delete mode 100644 kubenix-modules/cert-manager/manifests/certificaterequest.yaml delete mode 100644 kubenix-modules/cert-manager/manifests/challenge.yaml delete mode 100644 kubenix-modules/cert-manager/manifests/clusterissuer.yaml delete mode 100644 kubenix-modules/cert-manager/manifests/issuer.yaml delete mode 100644 kubenix-modules/cert-manager/manifests/order.yaml delete mode 100644 kubenix-modules/custom-types.nix delete mode 100644 kubenix-modules/custom/default.nix delete mode 100644 kubenix-modules/custom/ingress.nix delete mode 100644 kubenix-modules/custom/longhorn-volume.nix delete mode 100644 kubenix-modules/custom/tailscale.nix delete mode 100644 kubenix-modules/cyberchef.nix delete mode 100644 kubenix-modules/dnsmasq.nix delete mode 100644 kubenix-modules/forgejo/config.nix delete mode 100644 kubenix-modules/forgejo/default.nix delete mode 100644 kubenix-modules/freshrss.nix delete mode 100644 kubenix-modules/hedgedoc.nix delete mode 100644 kubenix-modules/immich.nix delete mode 100644 kubenix-modules/inbucket.nix delete mode 100644 kubenix-modules/kitchenowl.nix delete mode 100644 kubenix-modules/kms.nix delete mode 100644 kubenix-modules/media.nix delete mode 100644 kubenix-modules/minecraft.nix delete mode 100644 kubenix-modules/nextcloud.nix delete mode 100644 kubenix-modules/ntfy.nix delete mode 100644 kubenix-modules/paperless.nix delete mode 100644 kubenix-modules/pihole.nix delete mode 100644 kubenix-modules/radicale.nix delete mode 100644 kubenix-modules/syncthing.nix delete mode 100644 kubenix-modules/tailscale.nix delete mode 100644 kubenix-modules/traefik.nix delete mode 100644 machines/atlas.nix delete mode 100644 machines/default.nix delete mode 100644 machines/jefke.nix delete mode 100644 machines/lewis.nix delete mode 100644 machines/pikvm.nix delete mode 100644 machines/talos.nix delete mode 100644 machines/warwick.nix delete mode 100644 secrets/kubernetes.yaml diff --git a/.sops.yaml b/.sops.yaml index 3abcfb1..0644f7e 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -9,7 +9,7 @@ keys: - &server_pikvm age1smqas3tre2hptnyn72fdzghqcnej48066l4hp6y98n8lkpm3ds4s8t8s0w creation_rules: - - path_regex: secrets/(kubernetes|serverKeys).yaml$ + - path_regex: secrets/serverKeys.yaml$ key_groups: - age: - *admin_pim diff --git a/flake-parts/checks.nix b/flake-parts/checks.nix index f723510..2e77b84 100644 --- a/flake-parts/checks.nix +++ b/flake-parts/checks.nix @@ -1,12 +1,15 @@ -{ self, pkgs, machines, flake-utils, deploy-rs, ... }: flake-utils.lib.eachDefaultSystem (system: { +{ self, nixpkgs, flake-utils, deploy-rs, ... }: flake-utils.lib.eachDefaultSystem (system: +let + pkgs = nixpkgs.legacyPackages.${system}; +in +{ # Deploy-rs' flake checks seem broken for architectures different from the deployment machine. # We skip these here. - checks = deploy-rs.lib.${system}.deployChecks ( pkgs.lib.attrsets.updateManyAttrsByPath [{ path = [ "nodes" ]; update = pkgs.lib.attrsets.filterAttrs (name: node: - machines.${name}.arch == system + self.machines.${name}.arch == system ); }] self.deploy diff --git a/flake-parts/deploy.nix b/flake-parts/deploy.nix index 9dee0bb..5da2ab6 100644 --- a/flake-parts/deploy.nix +++ b/flake-parts/deploy.nix @@ -1,9 +1,10 @@ -{ self, pkgs, machines, deploy-rs, ... }: +{ self, deploy-rs, ... }: let + deployArch = "x86_64-linux"; mkDeployNodes = nodeDef: builtins.mapAttrs (name: machine: nodeDef name machine) - machines; + self.machines.${deployArch}; in { deploy = { @@ -17,7 +18,7 @@ in { hostname = nixosConfiguration.config.networking.fqdn; profiles.system = { - remoteBuild = machine.arch != pkgs.stdenv.hostPlatform.system; + remoteBuild = machine.arch != deployArch; path = deploy-rs.lib.${machine.arch}.activate.nixos nixosConfiguration; }; }); diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix deleted file mode 100644 index 2d3c2b2..0000000 --- a/flake-parts/kubenix.nix +++ /dev/null @@ -1,191 +0,0 @@ -{ self, pkgs, machines, dns, myLib, flake-utils, kubenix, nixhelm, blog-pim, ... }: flake-utils.lib.eachDefaultSystem - (system: - let - deployScript = (pkgs.writeScriptBin "applyset-deploy.sh" (builtins.readFile ./applyset-deploy.sh)).overrideAttrs (old: { - buildCommand = "${old.buildCommand}\npatchShebangs $out"; - }); - - mkKubernetes = name: module: namespace: (kubenix.evalModules.${system} { - specialArgs = { inherit namespace myLib blog-pim dns nixhelm system machines; }; - - module = { kubenix, ... }: - { - imports = [ - kubenix.modules.k8s - kubenix.modules.helm - "${self}/kubenix-modules/custom" - "${self}/kubenix-modules/custom-types.nix" - module - ]; - - config = { - kubenix.project = name; - kubernetes.namespace = namespace; - }; - }; - }).config.kubernetes; - - mkManifest = name: { module, namespace }: { - name = "${name}-manifest"; - value = (mkKubernetes name module namespace).result; - }; - - mkDeployApp = name: { module, namespace }: - let - kubernetes = mkKubernetes name module namespace; - kubeconfig = kubernetes.kubeconfig or ""; - result = kubernetes.result or ""; - - wrappedDeployScript = pkgs.symlinkJoin - { - name = "applyset-deploy.sh"; - paths = [ deployScript pkgs.vals pkgs.kubectl ]; - buildInputs = [ pkgs.makeWrapper ]; - passthru.manifest = result; - meta.mainProgram = "applyset-deploy.sh"; - - postBuild = '' - wrapProgram $out/bin/applyset-deploy.sh \ - --suffix PATH : "$out/bin" \ - --run 'export KUBECONFIG=''${KUBECONFIG:-${toString kubeconfig}}' \ - --set MANIFEST '${result}' \ - --set APPLYSET 'applyset-${name}' \ - --set NAMESPACE '${namespace}' - ''; - }; - in - { - name = "${name}-deploy"; - value = wrappedDeployScript; - }; - - deployers = { - bootstrap-default = { - module = "${self}/kubenix-modules/bootstrap-default.nix"; - namespace = "default"; - }; - - bootstrap-kube-system = { - module = "${self}/kubenix-modules/bootstrap-kube-system.nix"; - namespace = "kube-system"; - }; - - cyberchef = { - module = "${self}/kubenix-modules/cyberchef.nix"; - namespace = "static-websites"; - }; - - freshrss = { - module = "${self}/kubenix-modules/freshrss.nix"; - namespace = "freshrss"; - }; - - radicale = { - module = "${self}/kubenix-modules/radicale.nix"; - namespace = "radicale"; - }; - - kms = { - module = "${self}/kubenix-modules/kms.nix"; - namespace = "kms"; - }; - - atuin = { - module = "${self}/kubenix-modules/atuin.nix"; - namespace = "atuin"; - }; - - blog = { - module = "${self}/kubenix-modules/blog.nix"; - namespace = "static-websites"; - }; - - nextcloud = { - module = "${self}/kubenix-modules/nextcloud.nix"; - namespace = "nextcloud"; - }; - - hedgedoc = { - module = "${self}/kubenix-modules/hedgedoc.nix"; - namespace = "hedgedoc"; - }; - - kitchenowl = { - module = "${self}/kubenix-modules/kitchenowl.nix"; - namespace = "kitchenowl"; - }; - - forgejo = { - module = "${self}/kubenix-modules/forgejo"; - namespace = "forgejo"; - }; - - paperless = { - module = "${self}/kubenix-modules/paperless.nix"; - namespace = "paperless"; - }; - - syncthing = { - module = "${self}/kubenix-modules/syncthing.nix"; - namespace = "syncthing"; - }; - - pihole = { - module = "${self}/kubenix-modules/pihole.nix"; - namespace = "dns"; - }; - - immich = { - module = "${self}/kubenix-modules/immich.nix"; - namespace = "immich"; - }; - - attic = { - module = "${self}/kubenix-modules/attic.nix"; - namespace = "attic"; - }; - - inbucket = { - module = "${self}/kubenix-modules/inbucket.nix"; - namespace = "inbucket"; - }; - - dnsmasq = { - module = "${self}/kubenix-modules/dnsmasq.nix"; - namespace = "dns"; - }; - - bind9 = { - module = "${self}/kubenix-modules/bind9"; - namespace = "dns"; - }; - - media = { - module = "${self}/kubenix-modules/media.nix"; - namespace = "media"; - }; - - traefik = { - module = "${self}/kubenix-modules/traefik.nix"; - namespace = "kube-system"; - }; - - minecraft = { - module = "${self}/kubenix-modules/minecraft.nix"; - namespace = "minecraft"; - }; - - tailscale = { - module = "${self}/kubenix-modules/tailscale.nix"; - namespace = "tailscale"; - }; - - ntfy = { - module = "${self}/kubenix-modules/ntfy.nix"; - namespace = "ntfy"; - }; - }; - in - { - packages = pkgs.lib.mergeAttrs (pkgs.lib.mapAttrs' mkDeployApp deployers) (pkgs.lib.mapAttrs' mkManifest deployers); - }) diff --git a/flake-parts/nixos.nix b/flake-parts/nixos.nix index a45f2b3..38afa07 100644 --- a/flake-parts/nixos.nix +++ b/flake-parts/nixos.nix @@ -1,5 +1,7 @@ -{ self, myLib, nixpkgs, machines, ... }@inputs: +{ self, nixpkgs, ... }@inputs: let + deployArch = "x86_64-linux"; + machines = self.machines.${deployArch}; mkNixosSystems = systemDef: builtins.mapAttrs (name: machine: @@ -11,7 +13,7 @@ in nixosConfigurations = mkNixosSystems (name: machine: { system = machine.arch; - specialArgs = { inherit self inputs myLib machine machines; }; + specialArgs = { inherit self inputs machine machines; }; modules = [ "${self}/configuration.nix" diff --git a/flake-parts/scripts/default.nix b/flake-parts/scripts/default.nix index 40dd42c..fda7269 100644 --- a/flake-parts/scripts/default.nix +++ b/flake-parts/scripts/default.nix @@ -1,5 +1,6 @@ -{ myLib, flake-utils, pkgs, ... }: flake-utils.lib.eachDefaultSystem (system: +{ self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; createScript = { name, runtimeInputs, scriptPath, extraWrapperFlags ? "", ... }: let script = (pkgs.writeScriptBin name (builtins.readFile scriptPath)).overrideAttrs (old: { @@ -28,7 +29,7 @@ in packages.prefetch-container-images = let - imagesJSON = builtins.toFile "images.json" (builtins.toJSON myLib.globals.images); + imagesJSON = builtins.toFile "images.json" (builtins.toJSON self.globals.images); in pkgs.writers.writePython3Bin "prefetch-container-images.py" { } '' diff --git a/flake.lock b/flake.lock index 683a47f..9525357 100644 --- a/flake.lock +++ b/flake.lock @@ -1,28 +1,5 @@ { "nodes": { - "blog-pim": { - "inputs": { - "flutils": "flutils", - "nginx": "nginx", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1715503080, - "narHash": "sha256-/VnzHTpTq3u0z2Vgu/vKU0SHwOUIu8olHDORWT0IofM=", - "ref": "refs/heads/master", - "rev": "7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5", - "revCount": 21, - "type": "git", - "url": "https://git.kun.is/home/blog-pim" - }, - "original": { - "rev": "7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5", - "type": "git", - "url": "https://git.kun.is/home/blog-pim" - } - }, "deploy-rs": { "inputs": { "flake-compat": "flake-compat", @@ -101,22 +78,6 @@ } }, "flake-compat_2": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_3": { "flake": false, "locked": { "lastModified": 1696426674, @@ -170,7 +131,7 @@ }, "flake-utils_2": { "inputs": { - "systems": "systems_3" + "systems": "systems_2" }, "locked": { "lastModified": 1710146030, @@ -186,138 +147,9 @@ "type": "github" } }, - "flake-utils_3": { - "inputs": { - "systems": "systems_5" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "id": "flake-utils", - "type": "indirect" - } - }, - "flake-utils_4": { - "inputs": { - "systems": "systems_6" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flutils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "kubenix": { - "inputs": { - "flake-compat": "flake-compat_2", - "nixpkgs": [ - "nixpkgs-unstable" - ], - "systems": "systems_4", - "treefmt": "treefmt" - }, - "locked": { - "lastModified": 1717788185, - "narHash": "sha256-Uc6QSQqJa2lyv/1W4StwoKrjtq7cFjlKNhdrtanToGo=", - "owner": "pizzapim", - "repo": "kubenix", - "rev": "a9590abe23a2f7577bc3271d90955e9ccc2923fe", - "type": "github" - }, - "original": { - "owner": "pizzapim", - "repo": "kubenix", - "type": "github" - } - }, - "nginx": { - "flake": false, - "locked": { - "lastModified": 1713277799, - "narHash": "sha256-VNDzQvUGeh54F3s6SIq6lBrp4RatURzJoJqVorexttA=", - "owner": "nginx", - "repo": "nginx", - "rev": "d8a849ae3c99ee5ca82c9a06074761e937dac6d6", - "type": "github" - }, - "original": { - "owner": "nginx", - "repo": "nginx", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "nixhelm", - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1703863825, - "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, - "nix-kube-generators": { - "locked": { - "lastModified": 1708155396, - "narHash": "sha256-A/BIeJjiRS7sBYP6tFJa/WHDPHe7DGTCkSEKXttYeAQ=", - "owner": "farcaller", - "repo": "nix-kube-generators", - "rev": "14dbd5e5b40615937900f71d9a9851b59b4d9a88", - "type": "github" - }, - "original": { - "owner": "farcaller", - "repo": "nix-kube-generators", - "type": "github" - } - }, "nix-snapshotter": { "inputs": { - "flake-compat": "flake-compat_3", + "flake-compat": "flake-compat_2", "flake-parts": "flake-parts", "nixpkgs": [ "nixpkgs-unstable" @@ -337,29 +169,6 @@ "type": "github" } }, - "nixhelm": { - "inputs": { - "flake-utils": "flake-utils_3", - "nix-kube-generators": "nix-kube-generators", - "nixpkgs": [ - "nixpkgs" - ], - "poetry2nix": "poetry2nix" - }, - "locked": { - "lastModified": 1722301678, - "narHash": "sha256-dlsJGdLiXGgBSr/7Y+invyY/9+jJsFF6UkUpD7WMXRM=", - "owner": "farcaller", - "repo": "nixhelm", - "rev": "5a983d9da254b178ac5b689405fb5b179815ef91", - "type": "github" - }, - "original": { - "owner": "farcaller", - "repo": "nixhelm", - "type": "github" - } - }, "nixos-hardware": { "locked": { "lastModified": 1722332872, @@ -440,41 +249,13 @@ "type": "github" } }, - "poetry2nix": { - "inputs": { - "flake-utils": "flake-utils_4", - "nix-github-actions": "nix-github-actions", - "nixpkgs": [ - "nixhelm", - "nixpkgs" - ], - "systems": "systems_7", - "treefmt-nix": "treefmt-nix" - }, - "locked": { - "lastModified": 1718285706, - "narHash": "sha256-DScsBM+kZvxOva7QegfdtleebMXh30XPxDQr/1IGKYo=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "a5be1bbbe0af0266147a88e0ec43b18c722f2bb9", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "poetry2nix", - "type": "github" - } - }, "root": { "inputs": { - "blog-pim": "blog-pim", "deploy-rs": "deploy-rs", "disko": "disko", "dns": "dns", "flake-utils": "flake-utils_2", - "kubenix": "kubenix", "nix-snapshotter": "nix-snapshotter", - "nixhelm": "nixhelm", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", @@ -532,125 +313,9 @@ "type": "github" } }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "id": "systems", - "type": "indirect" - } - }, - "systems_5": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_6": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_7": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "id": "systems", - "type": "indirect" - } - }, - "treefmt": { - "inputs": { - "nixpkgs": [ - "kubenix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1688026376, - "narHash": "sha256-qJmkr9BWDpqblk4E9/rCsAEl39y2n4Ycw6KRopvpUcY=", - "owner": "numtide", - "repo": "treefmt-nix", - "rev": "df3f32b0cc253dfc7009b7317e8f0e7ccd70b1cf", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "treefmt-nix", - "type": "github" - } - }, - "treefmt-nix": { - "inputs": { - "nixpkgs": [ - "nixhelm", - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1717850719, - "narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=", - "owner": "numtide", - "repo": "treefmt-nix", - "rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "treefmt-nix", - "type": "github" - } - }, "utils": { "inputs": { - "systems": "systems_2" + "systems": "systems" }, "locked": { "lastModified": 1701680307, diff --git a/flake.nix b/flake.nix index 379106d..1349edf 100644 --- a/flake.nix +++ b/flake.nix @@ -28,22 +28,6 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - nixhelm = { - url = "github:farcaller/nixhelm"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - blog-pim = { - # HACK: pinning this to a specific revision, as my automation is broken. - url = "git+https://git.kun.is/home/blog-pim?rev=7296f7f5bf5f089a5137036dcbd8058cf3e4a9e5"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - kubenix = { - url = "github:pizzapim/kubenix"; - inputs.nixpkgs.follows = "nixpkgs-unstable"; - }; - sops-nix = { url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; @@ -57,18 +41,11 @@ outputs = inputs@{ self, nixpkgs, flake-utils, ... }: - let - system = "x86_64-linux"; - pkgs = import nixpkgs { inherit system; }; - machines = (pkgs.lib.modules.evalModules { modules = [ (import ./machines) ]; }).config.machines; - myLib = import ./my-lib pkgs.lib; - in - flake-utils.lib.meld (inputs // { inherit pkgs machines myLib; }) [ + flake-utils.lib.meld inputs [ ./flake-parts/scripts ./flake-parts/checks.nix ./flake-parts/deploy.nix ./flake-parts/nixos.nix - ./flake-parts/kubenix.nix ./flake-parts/shell.nix ./flake-parts/utils ./flake-parts/machines diff --git a/kubenix-modules/argo.nix b/kubenix-modules/argo.nix deleted file mode 100644 index f4ec981..0000000 --- a/kubenix-modules/argo.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ - kubernetes.resources = { - ingresses.argo-workflows = { - metadata.annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt"; - "traefik.ingress.kubernetes.io/router.entrypoints" = "localsecure"; - }; - - spec = { - ingressClassName = "traefik"; - - rules = [{ - host = "workflows.kun.is"; - - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = "argo-workflows-server"; - port.number = 2746; - }; - }]; - }]; - - tls = [{ - secretName = "argo-workflows-tls"; - hosts = [ "workflows.kun.is" ]; - }]; - }; - }; - - clusterRoles.argo-admin.rules = [{ - apiGroups = [ "argoproj.io" ]; - verbs = [ "*" ]; - resources = [ "*" ]; - }]; - - serviceAccounts.argo-admin = { }; - - clusterRoleBindings.argo-admin = { - subjects = [{ - kind = "ServiceAccount"; - name = "argo-admin"; - namespace = "default"; - }]; - - roleRef = { - kind = "ClusterRole"; - name = "argo-admin"; - apiGroup = "rbac.authorization.k8s.io"; - }; - }; - }; -} diff --git a/kubenix-modules/attic.nix b/kubenix-modules/attic.nix deleted file mode 100644 index 7e0e79b..0000000 --- a/kubenix-modules/attic.nix +++ /dev/null @@ -1,201 +0,0 @@ -{ pkgs, myLib, ... }: { - kubernetes.resources = - let - atticSettings = { - # The '+" is to explicitly denote the end of the Vals expression. - # This is done because we quote the template for the INI file. - # See: https://github.com/helmfile/vals?tab=readme-ov-file#expression-syntax - database.url = "ref+sops://secrets/kubernetes.yaml#attic/databaseURL+"; - - storage = { - type = "local"; - path = "/var/lib/atticd/storage"; - }; - - listen = "[::]:8080"; - - # Data chunking - # - # Warning: If you change any of the values here, it will be - # difficult to reuse existing chunks for newly-uploaded NARs - # since the cutpoints will be different. As a result, the - # deduplication ratio will suffer for a while after the change. - chunking = { - # The minimum NAR size to trigger chunking - # - # If 0, chunking is disabled entirely for newly-uploaded NARs. - # If 1, all NARs are chunked. - nar-size-threshold = 64 * 1024; # 64 KiB - - # The preferred minimum size of a chunk, in bytes - min-size = 16 * 1024; # 16 KiB - - # The preferred average size of a chunk, in bytes - avg-size = 64 * 1024; # 64 KiB - - # The preferred maximum size of a chunk, in bytes - max-size = 256 * 1024; # 256 KiB - }; - }; - generatedConfig = (pkgs.formats.toml { }).generate "attic.toml" atticSettings; - in - { - secrets = { - server.stringData = { - token = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; - config = builtins.readFile generatedConfig; - }; - - database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/attic/databasePassword"; - }; - - deployments = { - attic.spec = { - selector.matchLabels = { - app = "attic"; - component = "website"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "attic"; - component = "website"; - }; - - spec = { - containers.attic = { - image = myLib.globals.images.attic; - ports.web.containerPort = 8080; - args = [ "-f" "/etc/atticd/config.toml" ]; - - env.ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64.valueFrom.secretKeyRef = { - name = "server"; - key = "token"; - }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/var/lib/atticd/storage"; - } - { - name = "config"; - mountPath = "/etc/atticd/config.toml"; - subPath = "config"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "data"; - config.secret.secretName = "server"; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - attic-db.spec = { - selector.matchLabels = { - app = "attic"; - component = "database"; - }; - - template = { - metadata.labels = { - app = "attic"; - component = "database"; - }; - - spec = { - containers.postgres = { - image = myLib.globals.images.postgres15; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - - env = { - POSTGRES_DB.value = "attic"; - POSTGRES_USER.value = "attic"; - PGDATA.value = "/pgdata/data"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "database"; - key = "password"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; - }; - - volumes.data.persistentVolumeClaim.claimName = "database"; - }; - }; - }; - }; - - services = { - attic.spec = { - selector = { - app = "attic"; - component = "website"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - database.spec = { - selector = { - app = "attic"; - component = "database"; - }; - - ports.postgres = { - port = 5432; - targetPort = "postgres"; - }; - }; - }; - }; - - lab = { - ingresses.attic = { - host = "attic.kun.is"; - - service = { - name = "attic"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim = { - data = { - volumeName = "attic"; - storage = "15Gi"; - }; - - database = { - volumeName = "attic-db"; - storage = "150Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/atuin.nix b/kubenix-modules/atuin.nix deleted file mode 100644 index 673ccc2..0000000 --- a/kubenix-modules/atuin.nix +++ /dev/null @@ -1,109 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.database.stringData = { - databasePassword = "ref+sops://secrets/kubernetes.yaml#/atuin/databasePassword"; - databaseURL = "ref+sops://secrets/kubernetes.yaml#/atuin/databaseURL"; - }; - - deployments.server.spec = { - selector.matchLabels.app = "atuin"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "atuin"; - - spec = { - volumes = { - data.persistentVolumeClaim.claimName = "data"; - database.persistentVolumeClaim.claimName = "database"; - }; - - containers = { - atuin = { - image = myLib.globals.images.atuin; - imagePullPolicy = "IfNotPresent"; - ports.web.containerPort = 8888; - args = [ "server" "start" ]; - - env = { - ATUIN_HOST.value = "0.0.0.0"; - ATUIN_PORT.value = "8888"; - ATUIN_OPEN_REGISTRATION.value = "false"; - - ATUIN_DB_URI.valueFrom.secretKeyRef = { - name = "database"; - key = "databaseURL"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/config"; - }]; - }; - - database = { - image = myLib.globals.images.postgres14; - ports.web.containerPort = 5432; - - env = { - POSTGRES_DB.value = "atuin"; - POSTGRES_USER.value = "atuin"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "database"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "database"; - mountPath = "/var/lib/postgresql/data"; - }]; - }; - }; - }; - }; - }; - - services.server.spec = { - selector.app = "atuin"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab = { - ingresses.server = { - host = "atuin.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim = { - data = { - volumeName = "atuin"; - storage = "300Mi"; - }; - - database = { - volumeName = "atuin-db"; - storage = "300Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/bind9/default.nix b/kubenix-modules/bind9/default.nix deleted file mode 100644 index a5411f0..0000000 --- a/kubenix-modules/bind9/default.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ myLib, dns, ... }: -let - kunisZone = dns.lib.toString "kun.is" (import ./kun.is.zone.nix myLib dns); -in -{ - kubernetes.resources = { - configMaps = { - bind9-env.data.TZ = "Europe/Amsterdam"; - - bind9-config.data = { - # TODO: this was copied from nix's generated bind config - # Is there a way to generate this without actually running the nixos module? - config = '' - acl cachenetworks { 127.0.0.0/24; }; - acl badnetworks { }; - - options { - listen-on { any; }; - listen-on-v6 { any; }; - allow-query { cachenetworks; }; - blackhole { badnetworks; }; - forward first; - forwarders { }; - directory "/run/named"; - pid-file "/run/named/named.pid"; - allow-transfer { none; }; - allow-recursion { none; }; - version none; - notify no; - }; - - zone "kun.is" { - type master; - file "/etc/bind/kun.is.zone"; - allow-transfer { }; - allow-query { any; }; - }; - ''; - - kunis-zone = kunisZone; - }; - }; - - deployments.bind9.spec = { - selector.matchLabels.app = "bind9"; - - template = { - metadata.labels.app = "bind9"; - - spec = { - containers = { - bind9-udp = { - image = myLib.globals.images.bind9; - envFrom = [{ configMapRef.name = "bind9-env"; }]; - - ports.dns-udp = { - containerPort = 53; - protocol = "UDP"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/etc/bind/named.conf"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/etc/bind/kun.is.zone"; - subPath = "kunis-zone"; - } - ]; - }; - - bind9-tcp = { - image = myLib.globals.images.bind9; - envFrom = [{ configMapRef.name = "bind9-env"; }]; - - ports.dns-tcp = { - containerPort = 53; - protocol = "TCP"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/etc/bind/named.conf"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/etc/bind/kun.is.zone"; - subPath = "kunis-zone"; - } - ]; - }; - }; - - volumes = [{ - name = "config"; - configMap.name = "bind9-config"; - }]; - }; - }; - }; - - services = { - bind9-udp = { - metadata.annotations = { - "metallb.universe.tf/loadBalancerIPs" = "${myLib.globals.bind9IPv4},${myLib.globals.bind9Ipv6}"; - "metallb.universe.tf/allow-shared-ip" = "dns"; - }; - - spec = { - type = "LoadBalancer"; - selector.app = "bind9"; - ipFamilies = [ "IPv4" "IPv6" ]; - ipFamilyPolicy = "RequireDualStack"; - - ports.dns = { - port = 53; - targetPort = "dns-udp"; - protocol = "UDP"; - }; - }; - }; - - bind9-tcp = { - metadata.annotations = { - "metallb.universe.tf/loadBalancerIPs" = "${myLib.globals.bind9IPv4},${myLib.globals.bind9Ipv6}"; - "metallb.universe.tf/allow-shared-ip" = "dns"; - }; - - spec = { - type = "LoadBalancer"; - selector.app = "bind9"; - ipFamilies = [ "IPv4" "IPv6" ]; - ipFamilyPolicy = "RequireDualStack"; - - ports.dns = { - port = 53; - targetPort = "dns-tcp"; - protocol = "TCP"; - }; - }; - }; - }; - }; -} diff --git a/kubenix-modules/bind9/kun.is.zone.nix b/kubenix-modules/bind9/kun.is.zone.nix deleted file mode 100644 index 8a33cb0..0000000 --- a/kubenix-modules/bind9/kun.is.zone.nix +++ /dev/null @@ -1,52 +0,0 @@ -myLib: dns: with dns.lib.combinators; { - CAA = letsEncrypt "caa@kun.is"; - - SOA = { - nameServer = "ns1"; - adminEmail = "webmaster.kun.is"; - serial = 2024041301; - }; - - NS = [ - "ns1.kun.is." - "ns2.kun.is." - ]; - - MX = [ - (mx.mx 10 "mail.kun.is.") - ]; - - TXT = [ - (with spf; soft [ "include:spf.glasnet.nl" ]) - ]; - - subdomains = rec { - "*".A = [ myLib.globals.routerPublicIPv4 ]; - - ns = { - A = [ myLib.globals.routerPublicIPv4 ]; - AAAA = [ ]; - }; - - ns1 = ns; - ns2 = ns; - - wg = { - A = [ myLib.globals.routerPublicIPv4 ]; - AAAA = [ ]; - }; - - #for SMTP2GO to be able send emails from kun.is domain - em670271 = { - CNAME = [ "return.smtp2go.net." ]; - }; - - "s670271._domainkey" = { - CNAME = [ "dkim.smtp2go.net." ]; - }; - - link = { - CNAME = [ "track.smtp2go.net." ]; - }; - }; -} diff --git a/kubenix-modules/blog.nix b/kubenix-modules/blog.nix deleted file mode 100644 index 3dd65ab..0000000 --- a/kubenix-modules/blog.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ blog-pim, ... }: { - kubernetes.resources = { - deployments.blog.spec = { - replicas = 3; - selector.matchLabels.app = "blog"; - - template = { - metadata.labels.app = "blog"; - - spec = { - containers.blog = { - image = "git.kun.is/home/blog-pim:${blog-pim.rev}"; - ports.web.containerPort = 80; - }; - }; - }; - }; - - services.blog.spec = { - selector.app = "blog"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab.ingresses.blog = { - host = "pim.kun.is"; - - service = { - name = "blog"; - portName = "web"; - }; - }; -} diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix deleted file mode 100644 index dc2386d..0000000 --- a/kubenix-modules/bootstrap-default.nix +++ /dev/null @@ -1,144 +0,0 @@ -{ lib, nixhelm, system, machines, myLib, ... }: { - kubernetes = { - helm.releases = { - metallb = { - chart = nixhelm.chartsDerivations.${system}.metallb.metallb; - includeCRDs = true; - }; - - # argo-workflows = { - # chart = nixhelm.chartsDerivations.${system}.argoproj.argo-workflows; - # includeCRDs = true; - # }; - - longhorn = { - chart = nixhelm.chartsDerivations.${system}.longhorn.longhorn; - includeCRDs = true; - - values = { - persistence.defaultClassReplicaCount = 2; - service.ui.type = "LoadBalancer"; - - defaultSettings = { - defaultDataPath = "/mnt/longhorn"; - storageMinimalAvailablePercentage = 0; - allowRecurringJobWhileVolumeDetached = true; - backupTarget = "nfs://lewis.dmz:/mnt/longhorn/persistent/longhorn-backup"; - }; - }; - }; - }; - - resources = { - services.longhorn-frontend.spec.loadBalancerIP = myLib.globals.longhornIPv4; - - namespaces = { - static-websites = { }; - freshrss = { }; - radicale = { }; - kms = { }; - atuin = { }; - nextcloud = { }; - hedgedoc = { }; - kitchenowl = { }; - forgejo = { }; - paperless = { }; - syncthing = { }; - immich = { }; - attic = { }; - inbucket = { }; - dns = { }; - media = { }; - minecraft = { }; - tailscale = { }; - ntfy = { }; - }; - - nodes = - let - machinesWithKubernetesLabels = lib.filterAttrs (name: machine: machine.kubernetesNodeLabels != null) machines; - in - builtins.mapAttrs - (name: machine: { - metadata.labels = machine.kubernetesNodeLabels; - }) - machinesWithKubernetesLabels; - - recurringJobs.backup-nfs.spec = { - cron = "0 1 * * *"; # One o'clock at night - task = "backup"; - retain = 2; # We don't need many, as we also make Borg backups. - concurrency = 1; - }; - - ipAddressPools.main.spec.addresses = [ "192.168.30.128-192.168.30.200" "2a0d:6e00:1a77:30::2-2a0d:6e00:1a77:30:ffff:ffff:ffff:fffe" ]; - l2Advertisements.main.metadata = { }; - - persistentVolumes = { - music-syncthing.spec = { - capacity.storage = "1Gi"; - accessModes = [ "ReadWriteMany" ]; - - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/media/music"; - }; - }; - - media-media.spec = { - capacity.storage = "1Gi"; - accessModes = [ "ReadWriteMany" ]; - - nfs = { - server = "lewis.dmz"; - path = "/mnt/longhorn/persistent/media"; - }; - }; - }; - }; - }; - - lab = { - longhorn.persistentVolume = { - freshrss.storage = "1Gi"; - radicale.storage = "200Mi"; - atuin.storage = "300Mi"; - atuin-db.storage = "300Mi"; - nextcloud.storage = "50Gi"; - nextcloud-db.storage = "400Mi"; - hedgedoc-uploads.storage = "50Mi"; - hedgedoc-db.storage = "100Mi"; - kitchenowl.storage = "100Mi"; - forgejo.storage = "20Gi"; - paperless-data.storage = "10Gi"; - paperless-redisdata.storage = "20Mi"; - paperless-db.storage = "150Mi"; - syncthing.storage = "400Mi"; - pihole-data.storage = "750Mi"; - pihole-dnsmasq.storage = "16Mi"; - immich.storage = "50Gi"; - immich-db.storage = "5Gi"; - attic.storage = "15Gi"; - attic-db.storage = "150Mi"; - jellyfin.storage = "5Gi"; - transmission.storage = "25Mi"; - jellyseerr.storage = "75Mi"; - radarr.storage = "300Mi"; - prowlarr.storage = "150Mi"; - sonarr.storage = "150Mi"; - bazarr.storage = "25Mi"; - minecraft.storage = "1Gi"; - ntfy.storage = "300Mi"; - deluge.storage = "500Mi"; - }; - - tailscaleIngresses.tailscale-longhorn = { - host = "longhorn"; - - service = { - name = "longhorn-frontend"; - portName = "http"; - }; - }; - }; -} diff --git a/kubenix-modules/bootstrap-kube-system.nix b/kubenix-modules/bootstrap-kube-system.nix deleted file mode 100644 index 1e2ed59..0000000 --- a/kubenix-modules/bootstrap-kube-system.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imports = [ - ./cert-manager - ]; -} diff --git a/kubenix-modules/cert-manager/default.nix b/kubenix-modules/cert-manager/default.nix deleted file mode 100644 index 81570a6..0000000 --- a/kubenix-modules/cert-manager/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ nixhelm, system, ... }: { - kubernetes = { - # TODO: These were copied from https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.crds.yaml - # See https://cert-manager.io/docs/installation/helm/ - # Seems kubenix cannot import a list of resources, only individual resources. - # Might be good to create a PR for this. - imports = [ - ./manifests/certificaterequest.yaml - ./manifests/certificate.yaml - ./manifests/challenge.yaml - ./manifests/clusterissuer.yaml - ./manifests/issuer.yaml - ./manifests/order.yaml - ]; - - helm.releases = { - cert-manager = { - chart = nixhelm.chartsDerivations.${system}.jetstack.cert-manager; - includeCRDs = false; - namespace = "kube-system"; - }; - }; - - resources.clusterIssuers.letsencrypt = { - spec.acme = { - server = "https://acme-v02.api.letsencrypt.org/directory"; - email = "pim@kunis.nl"; - privateKeySecretRef.name = "letsencrypt-private-key"; - solvers = [{ - selector = { }; - http01.ingress.class = "traefik"; - }]; - }; - }; - }; -} diff --git a/kubenix-modules/cert-manager/manifests/certificate.yaml b/kubenix-modules/cert-manager/manifests/certificate.yaml deleted file mode 100644 index 040a02b..0000000 --- a/kubenix-modules/cert-manager/manifests/certificate.yaml +++ /dev/null @@ -1,443 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificates.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: 'cert-manager' - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: cert-manager.io - names: - kind: Certificate - listKind: CertificateList - plural: certificates - shortNames: - - cert - - certs - singular: certificate - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.secretName - name: Secret - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: "A Certificate resource should be created to ensure an up to date and signed X.509 certificate is stored in the Kubernetes Secret resource named in `spec.secretName`. \n The stored certificate will be renewed before it expires (as configured by `spec.renewBefore`)." - type: object - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Specification of the desired state of the Certificate resource. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - secretName - properties: - additionalOutputFormats: - description: "Defines extra output formats of the private key and signed certificate chain to be written to this Certificate's target Secret. \n This is an Alpha Feature and is only enabled with the `--feature-gates=AdditionalCertificateOutputFormats=true` option set on both the controller and webhook components." - type: array - items: - description: CertificateAdditionalOutputFormat defines an additional output format of a Certificate resource. These contain supplementary data formats of the signed certificate chain and paired private key. - type: object - required: - - type - properties: - type: - description: Type is the name of the format type that should be written to the Certificate's target Secret. - type: string - enum: - - DER - - CombinedPEM - commonName: - description: "Requested common name X509 certificate subject attribute. More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 NOTE: TLS clients will ignore this value when any subject alternative name is set (see https://tools.ietf.org/html/rfc6125#section-6.4.4). \n Should have a length of 64 characters or fewer to avoid generating invalid CSRs. Cannot be set if the `literalSubject` field is set." - type: string - dnsNames: - description: Requested DNS subject alternative names. - type: array - items: - type: string - duration: - description: "Requested 'duration' (i.e. lifetime) of the Certificate. Note that the issuer may choose to ignore the requested duration, just like any other requested attribute. \n If unset, this defaults to 90 days. Minimum accepted duration is 1 hour. Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration." - type: string - emailAddresses: - description: Requested email subject alternative names. - type: array - items: - type: string - encodeUsagesInRequest: - description: "Whether the KeyUsage and ExtKeyUsage extensions should be set in the encoded CSR. \n This option defaults to true, and should only be disabled if the target issuer does not support CSRs with these X509 KeyUsage/ ExtKeyUsage extensions." - type: boolean - ipAddresses: - description: Requested IP address subject alternative names. - type: array - items: - type: string - isCA: - description: "Requested basic constraints isCA value. The isCA value is used to set the `isCA` field on the created CertificateRequest resources. Note that the issuer may choose to ignore the requested isCA value, just like any other requested attribute. \n If true, this will automatically add the `cert sign` usage to the list of requested `usages`." - type: boolean - issuerRef: - description: "Reference to the issuer responsible for issuing the certificate. If the issuer is namespace-scoped, it must be in the same namespace as the Certificate. If the issuer is cluster-scoped, it can be used from any namespace. \n The `name` field of the reference must always be specified." - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - keystores: - description: Additional keystore output formats to be stored in the Certificate's Secret. - type: object - properties: - jks: - description: JKS configures options for storing a JKS keystore in the `spec.secretName` Secret resource. - type: object - required: - - create - - passwordSecretRef - properties: - create: - description: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will be updated immediately. If the issuer provided a CA certificate, a file named `truststore.jks` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority - type: boolean - passwordSecretRef: - description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the JKS keystore. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - pkcs12: - description: PKCS12 configures options for storing a PKCS12 keystore in the `spec.secretName` Secret resource. - type: object - required: - - create - - passwordSecretRef - properties: - create: - description: Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will be updated immediately. If the issuer provided a CA certificate, a file named `truststore.p12` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority - type: boolean - passwordSecretRef: - description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the PKCS12 keystore. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - profile: - description: "Profile specifies the key and certificate encryption algorithms and the HMAC algorithm used to create the PKCS12 keystore. Default value is `LegacyRC2` for backward compatibility. \n If provided, allowed values are: `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms (eg. because of company policy). Please note that the security of the algorithm is not that important in reality, because the unencrypted certificate and private key are also stored in the Secret." - type: string - enum: - - LegacyRC2 - - LegacyDES - - Modern2023 - literalSubject: - description: "Requested X.509 certificate subject, represented using the LDAP \"String Representation of a Distinguished Name\" [1]. Important: the LDAP string format also specifies the order of the attributes in the subject, this is important when issuing certs for LDAP authentication. Example: `CN=foo,DC=corp,DC=example,DC=com` More info [1]: https://datatracker.ietf.org/doc/html/rfc4514 More info: https://github.com/cert-manager/cert-manager/issues/3203 More info: https://github.com/cert-manager/cert-manager/issues/4424 \n Cannot be set if the `subject` or `commonName` field is set. This is an Alpha Feature and is only enabled with the `--feature-gates=LiteralCertificateSubject=true` option set on both the controller and webhook components." - type: string - nameConstraints: - description: "x.509 certificate NameConstraint extension which MUST NOT be used in a non-CA certificate. More Info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 \n This is an Alpha Feature and is only enabled with the `--feature-gates=NameConstraints=true` option set on both the controller and webhook components." - type: object - properties: - critical: - description: if true then the name constraints are marked critical. - type: boolean - excluded: - description: Excluded contains the constraints which must be disallowed. Any name matching a restriction in the excluded field is invalid regardless of information appearing in the permitted - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: IPRanges is a list of IP Ranges that are permitted or excluded. This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - permitted: - description: Permitted contains the constraints in which the names must be located. - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: IPRanges is a list of IP Ranges that are permitted or excluded. This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - otherNames: - description: '`otherNames` is an escape hatch for SAN that allows any type. We currently restrict the support to string like otherNames, cf RFC 5280 p 37 Any UTF8 String valued otherName can be passed with by setting the keys oid: x.x.x.x and UTF8Value: somevalue for `otherName`. Most commonly this would be UPN set with oid: 1.3.6.1.4.1.311.20.2.3 You should ensure that any OID passed is valid for the UTF8String type as we do not explicitly validate this.' - type: array - items: - type: object - properties: - oid: - description: OID is the object identifier for the otherName SAN. The object identifier must be expressed as a dotted string, for example, "1.2.840.113556.1.4.221". - type: string - utf8Value: - description: utf8Value is the string value of the otherName SAN. The utf8Value accepts any valid UTF8 string to set as value for the otherName SAN. - type: string - privateKey: - description: Private key options. These include the key algorithm and size, the used encoding and the rotation policy. - type: object - properties: - algorithm: - description: "Algorithm is the private key algorithm of the corresponding private key for this certificate. \n If provided, allowed values are either `RSA`, `ECDSA` or `Ed25519`. If `algorithm` is specified and `size` is not provided, key size of 2048 will be used for `RSA` key algorithm and key size of 256 will be used for `ECDSA` key algorithm. key size is ignored when using the `Ed25519` key algorithm." - type: string - enum: - - RSA - - ECDSA - - Ed25519 - encoding: - description: "The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. \n If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified." - type: string - enum: - - PKCS1 - - PKCS8 - rotationPolicy: - description: "RotationPolicy controls how private keys should be regenerated when a re-issuance is being processed. \n If set to `Never`, a private key will only be generated if one does not already exist in the target `spec.secretName`. If one does exists but it does not have the correct algorithm or size, a warning will be raised to await user intervention. If set to `Always`, a private key matching the specified requirements will be generated whenever a re-issuance occurs. Default is `Never` for backward compatibility." - type: string - enum: - - Never - - Always - size: - description: "Size is the key bit size of the corresponding private key for this certificate. \n If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. If `algorithm` is set to `Ed25519`, Size is ignored. No other values are allowed." - type: integer - renewBefore: - description: "How long before the currently issued certificate's expiry cert-manager should renew the certificate. For example, if a certificate is valid for 60 minutes, and `renewBefore=10m`, cert-manager will begin to attempt to renew the certificate 50 minutes after it was issued (i.e. when there are 10 minutes remaining until the certificate is no longer valid). \n NOTE: The actual lifetime of the issued certificate is used to determine the renewal time. If an issuer returns a certificate with a different lifetime than the one requested, cert-manager will use the lifetime of the issued certificate. \n If unset, this defaults to 1/3 of the issued certificate's lifetime. Minimum accepted value is 5 minutes. Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration." - type: string - revisionHistoryLimit: - description: "The maximum number of CertificateRequest revisions that are maintained in the Certificate's history. Each revision represents a single `CertificateRequest` created by this Certificate, either when it was created, renewed, or Spec was changed. Revisions will be removed by oldest first if the number of revisions exceeds this number. \n If set, revisionHistoryLimit must be a value of `1` or greater. If unset (`nil`), revisions will not be garbage collected. Default value is `nil`." - type: integer - format: int32 - secretName: - description: Name of the Secret resource that will be automatically created and managed by this Certificate resource. It will be populated with a private key and certificate, signed by the denoted issuer. The Secret resource lives in the same namespace as the Certificate resource. - type: string - secretTemplate: - description: Defines annotations and labels to be copied to the Certificate's Secret. Labels and annotations on the Secret will be changed as they appear on the SecretTemplate when added or removed. SecretTemplate annotations are added in conjunction with, and cannot overwrite, the base set of annotations cert-manager sets on the Certificate's Secret. - type: object - properties: - annotations: - description: Annotations is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - labels: - description: Labels is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - subject: - description: "Requested set of X509 certificate subject attributes. More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 \n The common name attribute is specified separately in the `commonName` field. Cannot be set if the `literalSubject` field is set." - type: object - properties: - countries: - description: Countries to be used on the Certificate. - type: array - items: - type: string - localities: - description: Cities to be used on the Certificate. - type: array - items: - type: string - organizationalUnits: - description: Organizational Units to be used on the Certificate. - type: array - items: - type: string - organizations: - description: Organizations to be used on the Certificate. - type: array - items: - type: string - postalCodes: - description: Postal codes to be used on the Certificate. - type: array - items: - type: string - provinces: - description: State/Provinces to be used on the Certificate. - type: array - items: - type: string - serialNumber: - description: Serial number to be used on the Certificate. - type: string - streetAddresses: - description: Street addresses to be used on the Certificate. - type: array - items: - type: string - uris: - description: Requested URI subject alternative names. - type: array - items: - type: string - usages: - description: "Requested key usages and extended key usages. These usages are used to set the `usages` field on the created CertificateRequest resources. If `encodeUsagesInRequest` is unset or set to `true`, the usages will additionally be encoded in the `request` field which contains the CSR blob. \n If unset, defaults to `digital signature` and `key encipherment`." - type: array - items: - description: "KeyUsage specifies valid usage contexts for keys. See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3 https://tools.ietf.org/html/rfc5280#section-4.2.1.12 \n Valid KeyUsage values are as follows: \"signing\", \"digital signature\", \"content commitment\", \"key encipherment\", \"key agreement\", \"data encipherment\", \"cert sign\", \"crl sign\", \"encipher only\", \"decipher only\", \"any\", \"server auth\", \"client auth\", \"code signing\", \"email protection\", \"s/mime\", \"ipsec end system\", \"ipsec tunnel\", \"ipsec user\", \"timestamping\", \"ocsp signing\", \"microsoft sgc\", \"netscape sgc\"" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - status: - description: 'Status of the Certificate. This is set and managed automatically. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' - type: object - properties: - conditions: - description: List of status conditions to indicate the status of certificates. Known condition types are `Ready` and `Issuing`. - type: array - items: - description: CertificateCondition contains condition information for an Certificate. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. - type: string - format: date-time - message: - description: Message is a human readable description of the details of the last transition, complementing reason. - type: string - observedGeneration: - description: If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Certificate. - type: integer - format: int64 - reason: - description: Reason is a brief machine readable explanation for the condition's last transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`, `Issuing`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failedIssuanceAttempts: - description: The number of continuous failed issuance attempts up till now. This field gets removed (if set) on a successful issuance and gets set to 1 if unset and an issuance has failed. If an issuance has failed, the delay till the next issuance will be calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - 1). - type: integer - lastFailureTime: - description: LastFailureTime is set only if the lastest issuance for this Certificate failed and contains the time of the failure. If an issuance has failed, the delay till the next issuance will be calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - 1). If the latest issuance has succeeded this field will be unset. - type: string - format: date-time - nextPrivateKeySecretName: - description: The name of the Secret resource containing the private key to be used for the next certificate iteration. The keymanager controller will automatically set this field if the `Issuing` condition is set to `True`. It will automatically unset this field when the Issuing condition is not set or False. - type: string - notAfter: - description: The expiration time of the certificate stored in the secret named by this resource in `spec.secretName`. - type: string - format: date-time - notBefore: - description: The time after which the certificate stored in the secret named by this resource in `spec.secretName` is valid. - type: string - format: date-time - renewalTime: - description: RenewalTime is the time at which the certificate will be next renewed. If not set, no upcoming renewal is scheduled. - type: string - format: date-time - revision: - description: "The current 'revision' of the certificate as issued. \n When a CertificateRequest resource is created, it will have the `cert-manager.io/certificate-revision` set to one greater than the current value of this field. \n Upon issuance, this field will be set to the value of the annotation on the CertificateRequest resource used to issue the certificate. \n Persisting the value on the CertificateRequest resource allows the certificates controller to know whether a request is part of an old issuance or if it is part of the ongoing revision's issuance by checking if the revision value in the annotation is greater than this field." - type: integer - served: true - storage: true diff --git a/kubenix-modules/cert-manager/manifests/certificaterequest.yaml b/kubenix-modules/cert-manager/manifests/certificaterequest.yaml deleted file mode 100644 index 3adaaf7..0000000 --- a/kubenix-modules/cert-manager/manifests/certificaterequest.yaml +++ /dev/null @@ -1,196 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificaterequests.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: 'cert-manager' - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: cert-manager.io - names: - kind: CertificateRequest - listKind: CertificateRequestList - plural: certificaterequests - shortNames: - - cr - - crs - singular: certificaterequest - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Approved")].status - name: Approved - type: string - - jsonPath: .status.conditions[?(@.type=="Denied")].status - name: Denied - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - type: string - - jsonPath: .spec.username - name: Requestor - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `Ready` status condition and its `status.failureTime` field. \n A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used." - type: object - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Specification of the desired state of the CertificateRequest resource. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - request - properties: - duration: - description: Requested 'duration' (i.e. lifetime) of the Certificate. Note that the issuer may choose to ignore the requested duration, just like any other requested attribute. - type: string - extra: - description: Extra contains extra attributes of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable. - type: object - additionalProperties: - type: array - items: - type: string - groups: - description: Groups contains group membership of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable. - type: array - items: - type: string - x-kubernetes-list-type: atomic - isCA: - description: "Requested basic constraints isCA value. Note that the issuer may choose to ignore the requested isCA value, just like any other requested attribute. \n NOTE: If the CSR in the `Request` field has a BasicConstraints extension, it must have the same isCA value as specified here. \n If true, this will automatically add the `cert sign` usage to the list of requested `usages`." - type: boolean - issuerRef: - description: "Reference to the issuer responsible for issuing the certificate. If the issuer is namespace-scoped, it must be in the same namespace as the Certificate. If the issuer is cluster-scoped, it can be used from any namespace. \n The `name` field of the reference must always be specified." - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: "The PEM-encoded X.509 certificate signing request to be submitted to the issuer for signing. \n If the CSR has a BasicConstraints extension, its isCA attribute must match the `isCA` value of this CertificateRequest. If the CSR has a KeyUsage extension, its key usages must match the key usages in the `usages` field of this CertificateRequest. If the CSR has a ExtKeyUsage extension, its extended key usages must match the extended key usages in the `usages` field of this CertificateRequest." - type: string - format: byte - uid: - description: UID contains the uid of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable. - type: string - usages: - description: "Requested key usages and extended key usages. \n NOTE: If the CSR in the `Request` field has uses the KeyUsage or ExtKeyUsage extension, these extensions must have the same values as specified here without any additional values. \n If unset, defaults to `digital signature` and `key encipherment`." - type: array - items: - description: "KeyUsage specifies valid usage contexts for keys. See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3 https://tools.ietf.org/html/rfc5280#section-4.2.1.12 \n Valid KeyUsage values are as follows: \"signing\", \"digital signature\", \"content commitment\", \"key encipherment\", \"key agreement\", \"data encipherment\", \"cert sign\", \"crl sign\", \"encipher only\", \"decipher only\", \"any\", \"server auth\", \"client auth\", \"code signing\", \"email protection\", \"s/mime\", \"ipsec end system\", \"ipsec tunnel\", \"ipsec user\", \"timestamping\", \"ocsp signing\", \"microsoft sgc\", \"netscape sgc\"" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - username: - description: Username contains the name of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable. - type: string - status: - description: 'Status of the CertificateRequest. This is set and managed automatically. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' - type: object - properties: - ca: - description: The PEM encoded X.509 certificate of the signer, also known as the CA (Certificate Authority). This is set on a best-effort basis by different issuers. If not set, the CA is assumed to be unknown/not available. - type: string - format: byte - certificate: - description: The PEM encoded X.509 certificate resulting from the certificate signing request. If not set, the CertificateRequest has either not been completed or has failed. More information on failure can be found by checking the `conditions` field. - type: string - format: byte - conditions: - description: List of status conditions to indicate the status of a CertificateRequest. Known condition types are `Ready`, `InvalidRequest`, `Approved` and `Denied`. - type: array - items: - description: CertificateRequestCondition contains condition information for a CertificateRequest. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. - type: string - format: date-time - message: - description: Message is a human readable description of the details of the last transition, complementing reason. - type: string - reason: - description: Reason is a brief machine readable explanation for the condition's last transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`, `InvalidRequest`, `Approved`, `Denied`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failureTime: - description: FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off. - type: string - format: date-time - served: true - storage: true diff --git a/kubenix-modules/cert-manager/manifests/challenge.yaml b/kubenix-modules/cert-manager/manifests/challenge.yaml deleted file mode 100644 index b325770..0000000 --- a/kubenix-modules/cert-manager/manifests/challenge.yaml +++ /dev/null @@ -1,1124 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: challenges.acme.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: 'cert-manager' - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: acme.cert-manager.io - names: - kind: Challenge - listKind: ChallengeList - plural: challenges - singular: challenge - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.dnsName - name: Domain - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1 - schema: - openAPIV3Schema: - description: Challenge is a type to represent a Challenge request with an ACME server - type: object - required: - - metadata - - spec - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - type: object - required: - - authorizationURL - - dnsName - - issuerRef - - key - - solver - - token - - type - - url - properties: - authorizationURL: - description: The URL to the ACME Authorization resource that this challenge is a part of. - type: string - dnsName: - description: dnsName is the identifier that this challenge is for, e.g. example.com. If the requested DNSName is a 'wildcard', this field MUST be set to the non-wildcard domain, e.g. for `*.example.com`, it must be `example.com`. - type: string - issuerRef: - description: References a properly configured ACME-type Issuer which should be used to create this Challenge. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Challenge will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - key: - description: 'The ACME challenge key for this challenge For HTTP01 challenges, this is the value that must be responded with to complete the HTTP01 challenge in the format: `.`. For DNS01 challenges, this is the base64 encoded SHA256 sum of the `.` text that must be set as the TXT record content.' - type: string - solver: - description: Contains the domain solving configuration that should be used to solve this challenge resource. - type: object - properties: - dns01: - description: Configures cert-manager to attempt to complete authorizations by performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: 'Auth: Azure Service Principal: The ClientID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientSecret and TenantID must also be set.' - type: string - clientSecretSecretRef: - description: 'Auth: Azure Service Principal: A reference to a Secret containing the password associated with the Service Principal. If set, ClientID and TenantID must also be set.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: 'Auth: Azure Workload Identity or Azure Managed Service Identity: Settings to enable Azure Workload Identity or Azure Managed Service Identity If set, ClientID, ClientSecret and TenantID must not be set.' - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity - type: string - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: 'Auth: Azure Service Principal: The TenantID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientID and ClientSecret must also be set.' - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: HostedZoneName is an optional field that tells cert-manager in which Cloud DNS zone the challenge record has to be created. If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: 'API key to use to authenticate with Cloudflare. Note: using an API token to authenticate is now the recommended method as it allows greater control of permissions.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: CNAMEStrategy configures how the DNS01 provider should handle CNAME records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - rfc2136: - description: Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: The IP address or hostname of an authoritative DNS server supporting RFC2136 in the form host:port. If the host is an IPv6 address it must be enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. This field is required. - type: string - tsigAlgorithm: - description: 'The TSIG Algorithm configured in the DNS supporting RFC2136. Used only when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. Supported values are (case-insensitive): ``HMACMD5`` (default), ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``.' - type: string - tsigKeyName: - description: The TSIG Key name configured in the DNS. If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: The name of the secret containing the TSIG value. If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - required: - - region - properties: - accessKeyID: - description: 'The AccessKeyID is used for authentication. Cannot be set when SecretAccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: string - accessKeyIDSecretRef: - description: 'The SecretAccessKey is used for authentication. If set, pull the AWS access key ID from a key within a Kubernetes Secret. Cannot be set when AccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do an lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: Always set the region when using AccessKeyID and SecretAccessKey - type: string - role: - description: Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: 'The SecretAccessKey is used for authentication. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - webhook: - description: Configure an external webhook based DNS01 challenge solver to manage DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: Additional configuration that should be passed to the webhook apiserver when challenges are processed. This can contain arbitrary JSON data. Secret values should not be specified in this stanza. If secret values are needed (e.g. credentials for a DNS service), you should use a SecretKeySelector to reference a Secret resource. For details on the schema of this field, consult the webhook provider implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: The API group name that should be used when POSTing ChallengePayload resources to the webhook apiserver. This should be the same as the GroupName specified in the webhook provider implementation. - type: string - solverName: - description: The name of the solver to use, as defined in the webhook provider implementation. This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: Configures cert-manager to attempt to complete authorizations by performing the HTTP01 challenge flow. It is not possible to obtain certificates for wildcard domain names (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: The Gateway API is a sig-network community API that models service networking in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will create HTTPRoutes with the specified labels in the same namespace as the challenge. This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: Custom labels that will be applied to HTTPRoutes created by cert-manager while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: 'When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. cert-manager needs to know which parentRefs should be used when creating the HTTPRoute. Usually, the parentRef references a Gateway. See: https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways' - type: array - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n This API may be extended in the future to support additional kinds of parent resources. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - type: object - required: - - name - properties: - group: - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - description: "Kind is kind of the referent. \n There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n Support for other resources is Implementation-Specific." - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: "Name is the name of the referent. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service. \n ParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n Support: Core" - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n When the parent resource is a Service, this targets a specific port in the Service spec. When both Port (experimental) and SectionName are specified, the name and port of the selected port must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - type: integer - format: int32 - maximum: 65535 - minimum: 1 - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. * Service: Port Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. Note that attaching Routes to Services as Parents is part of experimental Mesh support and is not supported for any other purpose. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: The ingress based HTTP01 challenge solver will solve challenges by creating or modifying Ingress resources in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: This field configures the annotation `kubernetes.io/ingress.class` when creating Ingress resources to solve ACME challenges that use this challenge solver. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressClassName: - description: This field configures the field `ingressClassName` on the created Ingress resources used to solve ACME challenges that use this challenge solver. This is the recommended way of configuring the ingress class. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: Optional ingress template used to configure the ACME challenge solver ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the ingress used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - podTemplate: - description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the create ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: PodSpec defines overrides for the HTTP01 challenge solver pod. Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. - type: array - items: - description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - type: object - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - x-kubernetes-map-type: atomic - nodeSelector: - description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . - type: object - properties: - effect: - description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. - type: object - properties: - dnsNames: - description: List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - dnsZones: - description: List of DNSZones that this solver will be used to solve. The most specific DNS zone match specified here will take precedence over other DNS zone matches, so a solver specifying sys.example.com will be selected over one specifying example.com for the domain www.sys.example.com. If multiple solvers match with the same dnsZones value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - matchLabels: - description: A label selector that is used to refine the set of certificate's that this challenge solver will apply to. - type: object - additionalProperties: - type: string - token: - description: The ACME challenge token for this challenge. This is the raw value returned from the ACME server. - type: string - type: - description: The type of ACME challenge this resource represents. One of "HTTP-01" or "DNS-01". - type: string - enum: - - HTTP-01 - - DNS-01 - url: - description: The URL of the ACME Challenge resource for this challenge. This can be used to lookup details about the status of this challenge. - type: string - wildcard: - description: wildcard will be true if this challenge is for a wildcard identifier, for example '*.example.com'. - type: boolean - status: - type: object - properties: - presented: - description: presented will be set to true if the challenge values for this challenge are currently 'presented'. This *does not* imply the self check is passing. Only that the values have been 'submitted' for the appropriate challenge mechanism (i.e. the DNS01 TXT record has been presented, or the HTTP01 configuration has been configured). - type: boolean - processing: - description: Used to denote whether this challenge should be processed or not. This field will only be set to true by the 'scheduling' component. It will only be set to false by the 'challenges' controller, after the challenge has reached a final state or timed out. If this field is set to false, the challenge controller will not take any more action. - type: boolean - reason: - description: Contains human readable information on why the Challenge is in the current state. - type: string - state: - description: Contains the current 'state' of the challenge. If not set, the state of the challenge is unknown. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - served: true - storage: true - subresources: - status: {} diff --git a/kubenix-modules/cert-manager/manifests/clusterissuer.yaml b/kubenix-modules/cert-manager/manifests/clusterissuer.yaml deleted file mode 100644 index 2b0a028..0000000 --- a/kubenix-modules/cert-manager/manifests/clusterissuer.yaml +++ /dev/null @@ -1,1371 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: clusterissuers.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: "cert-manager" - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: cert-manager.io - names: - kind: ClusterIssuer - listKind: ClusterIssuerList - plural: clusterissuers - singular: clusterissuer - categories: - - cert-manager - scope: Cluster - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: A ClusterIssuer represents a certificate issuing authority which can be referenced as part of `issuerRef` fields. It is similar to an Issuer, however it is cluster-scoped and therefore can be referenced by resources that exist in *any* namespace, not just the same namespace as the referent. - type: object - required: - - spec - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Desired state of the ClusterIssuer resource. - type: object - properties: - acme: - description: ACME configures this issuer to communicate with a RFC8555 (ACME) server to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: Base64-encoded bundle of PEM CAs which can be used to validate the certificate chain presented by the ACME server. Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various kinds of security vulnerabilities. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: Enables or disables generating a new ACME account key. If true, the Issuer resource will *not* request a new account but will expect the account key to be supplied via an existing secret. If false, the cert-manager system will generate a new ACME account key for the Issuer. Defaults to false. - type: boolean - email: - description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. - type: boolean - externalAccountBinding: - description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: 'Deprecated: keyAlgorithm field exists for historical compatibility reasons and should not be used. The algorithm is now hardcoded to HS256 in golang/x/crypto/acme.' - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes Secret which holds the symmetric MAC key of the External Account Binding. The `key` is the index string that is paired with the key data in the Secret and should not be confused with the key data itself, or indeed with the External Account Binding keyID above. The secret key stored in the Secret **must** be un-padded, base64 URL encoded data. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - preferredChain: - description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the ACME alternative chains that has a certificate with this value as its issuer''s CN' - type: string - maxLength: 64 - privateKeySecretRef: - description: PrivateKey is the name of a Kubernetes Secret resource that will be used to store the automatically generated ACME account private key. Optionally, a `key` may be specified to select a specific entry within the named Secret resource. If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - server: - description: 'Server is the URL used to access the ACME server''s ''directory'' endpoint. For example, for Let''s Encrypt''s staging endpoint, you would use: "https://acme-staging-v02.api.letsencrypt.org/directory". Only ACME v2 endpoints (i.e. RFC 8555) are supported.' - type: string - skipTLSVerify: - description: 'INSECURE: Enables or disables validation of the ACME server TLS certificate. If true, requests to the ACME server will not have the TLS certificate chain validated. Mutually exclusive with CABundle; prefer using CABundle to prevent various kinds of security vulnerabilities. Only enable this option in development environments. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection. Defaults to false.' - type: boolean - solvers: - description: 'Solvers is a list of challenge solvers that will be used to solve ACME challenges for the matching domains. Solver configurations must be provided in order to obtain certificates from an ACME server. For more information, see: https://cert-manager.io/docs/configuration/acme/' - type: array - items: - description: An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. A selector may be provided to use different solving strategies for different DNS names. Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: Configures cert-manager to attempt to complete authorizations by performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: 'Auth: Azure Service Principal: The ClientID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientSecret and TenantID must also be set.' - type: string - clientSecretSecretRef: - description: 'Auth: Azure Service Principal: A reference to a Secret containing the password associated with the Service Principal. If set, ClientID and TenantID must also be set.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: 'Auth: Azure Workload Identity or Azure Managed Service Identity: Settings to enable Azure Workload Identity or Azure Managed Service Identity If set, ClientID, ClientSecret and TenantID must not be set.' - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity - type: string - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: 'Auth: Azure Service Principal: The TenantID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientID and ClientSecret must also be set.' - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: HostedZoneName is an optional field that tells cert-manager in which Cloud DNS zone the challenge record has to be created. If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: 'API key to use to authenticate with Cloudflare. Note: using an API token to authenticate is now the recommended method as it allows greater control of permissions.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: CNAMEStrategy configures how the DNS01 provider should handle CNAME records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - rfc2136: - description: Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: The IP address or hostname of an authoritative DNS server supporting RFC2136 in the form host:port. If the host is an IPv6 address it must be enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. This field is required. - type: string - tsigAlgorithm: - description: 'The TSIG Algorithm configured in the DNS supporting RFC2136. Used only when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. Supported values are (case-insensitive): ``HMACMD5`` (default), ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``.' - type: string - tsigKeyName: - description: The TSIG Key name configured in the DNS. If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: The name of the secret containing the TSIG value. If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - required: - - region - properties: - accessKeyID: - description: 'The AccessKeyID is used for authentication. Cannot be set when SecretAccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: string - accessKeyIDSecretRef: - description: 'The SecretAccessKey is used for authentication. If set, pull the AWS access key ID from a key within a Kubernetes Secret. Cannot be set when AccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do an lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: Always set the region when using AccessKeyID and SecretAccessKey - type: string - role: - description: Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: 'The SecretAccessKey is used for authentication. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - webhook: - description: Configure an external webhook based DNS01 challenge solver to manage DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: Additional configuration that should be passed to the webhook apiserver when challenges are processed. This can contain arbitrary JSON data. Secret values should not be specified in this stanza. If secret values are needed (e.g. credentials for a DNS service), you should use a SecretKeySelector to reference a Secret resource. For details on the schema of this field, consult the webhook provider implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: The API group name that should be used when POSTing ChallengePayload resources to the webhook apiserver. This should be the same as the GroupName specified in the webhook provider implementation. - type: string - solverName: - description: The name of the solver to use, as defined in the webhook provider implementation. This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: Configures cert-manager to attempt to complete authorizations by performing the HTTP01 challenge flow. It is not possible to obtain certificates for wildcard domain names (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: The Gateway API is a sig-network community API that models service networking in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will create HTTPRoutes with the specified labels in the same namespace as the challenge. This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: Custom labels that will be applied to HTTPRoutes created by cert-manager while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: 'When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. cert-manager needs to know which parentRefs should be used when creating the HTTPRoute. Usually, the parentRef references a Gateway. See: https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways' - type: array - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n This API may be extended in the future to support additional kinds of parent resources. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - type: object - required: - - name - properties: - group: - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - description: "Kind is kind of the referent. \n There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n Support for other resources is Implementation-Specific." - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: "Name is the name of the referent. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service. \n ParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n Support: Core" - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n When the parent resource is a Service, this targets a specific port in the Service spec. When both Port (experimental) and SectionName are specified, the name and port of the selected port must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - type: integer - format: int32 - maximum: 65535 - minimum: 1 - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. * Service: Port Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. Note that attaching Routes to Services as Parents is part of experimental Mesh support and is not supported for any other purpose. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: The ingress based HTTP01 challenge solver will solve challenges by creating or modifying Ingress resources in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: This field configures the annotation `kubernetes.io/ingress.class` when creating Ingress resources to solve ACME challenges that use this challenge solver. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressClassName: - description: This field configures the field `ingressClassName` on the created Ingress resources used to solve ACME challenges that use this challenge solver. This is the recommended way of configuring the ingress class. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: Optional ingress template used to configure the ACME challenge solver ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the ingress used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - podTemplate: - description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the create ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: PodSpec defines overrides for the HTTP01 challenge solver pod. Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. - type: array - items: - description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - type: object - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - x-kubernetes-map-type: atomic - nodeSelector: - description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . - type: object - properties: - effect: - description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. - type: object - properties: - dnsNames: - description: List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - dnsZones: - description: List of DNSZones that this solver will be used to solve. The most specific DNS zone match specified here will take precedence over other DNS zone matches, so a solver specifying sys.example.com will be selected over one specifying example.com for the domain www.sys.example.com. If multiple solvers match with the same dnsZones value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - matchLabels: - description: A label selector that is used to refine the set of certificate's that this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: CA configures this issuer to sign certificates using a signing CA keypair stored in a Secret resource. This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate will be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: SecretName is the name of the secret used to sign Certificates issued by this Issuer. - type: string - selfSigned: - description: SelfSigned configures this issuer to 'self sign' certificates using the private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: Vault configures this issuer to sign certificates using a HashiCorp Vault PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: The Vault mountPath here is the mount path to use when authenticating with Vault. For example, setting a value to `/v1/auth/foo`, will use the path `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: The required Secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. Use of 'ambient credentials' is not supported. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - serviceAccountRef: - description: A reference to a service account that will be used to request a bound token (also known as "projected token"). Compared to using "secretRef", using this field means that you don't rely on statically bound tokens. To use this field, you must configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - caBundle: - description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by Vault. Only used if using HTTPS to connect to Vault and ignored for HTTP connections. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: Reference to a Secret containing a bundle of PEM-encoded CAs to use when verifying the certificate chain presented by Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault PKI backend''s `sign` endpoint, e.g: "my_pki_mount/sign/my-role-name".' - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: Venafi configures this issuer to sign certificates using a Venafi TPP or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: Cloud specifies the Venafi cloud configuration settings. Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - url: - description: URL is the base URL for Venafi Cloud. Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: TPP specifies Trust Protection Platform configuration settings. Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. If undefined, the certificate bundle in the cert-manager controller container is used to validate the chain. - type: string - format: byte - credentialsRef: - description: CredentialsRef is a reference to a Secret containing the username and password for the TPP server. The secret must contain two keys, 'username' and 'password'. - type: object - required: - - name - properties: - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - url: - description: 'URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, for example: "https://tpp.example.com/vedsdk".' - type: string - zone: - description: Zone is the Venafi Policy Zone to use for this issuer. All requests made to the Venafi platform will be restricted by the named zone policy. This field is required. - type: string - status: - description: Status of the ClusterIssuer. This is set and managed automatically. - type: object - properties: - acme: - description: ACME specific status options. This field should only be set if the Issuer is configured to use an ACME server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: LastPrivateKeyHash is a hash of the private key associated with the latest registered ACME account, in order to track changes made to registered account associated with the Issuer - type: string - lastRegisteredEmail: - description: LastRegisteredEmail is the email associated with the latest registered ACME account, in order to track changes made to registered account associated with the Issuer - type: string - uri: - description: URI is the unique account identifier, which can also be used to retrieve account details from the CA - type: string - conditions: - description: List of status conditions to indicate the status of a CertificateRequest. Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. - type: string - format: date-time - message: - description: Message is a human readable description of the details of the last transition, complementing reason. - type: string - observedGeneration: - description: If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: Reason is a brief machine readable explanation for the condition's last transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true diff --git a/kubenix-modules/cert-manager/manifests/issuer.yaml b/kubenix-modules/cert-manager/manifests/issuer.yaml deleted file mode 100644 index 20807f1..0000000 --- a/kubenix-modules/cert-manager/manifests/issuer.yaml +++ /dev/null @@ -1,1371 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: issuers.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: "cert-manager" - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: cert-manager.io - names: - kind: Issuer - listKind: IssuerList - plural: issuers - singular: issuer - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: An Issuer represents a certificate issuing authority which can be referenced as part of `issuerRef` fields. It is scoped to a single namespace and can therefore only be referenced by resources within the same namespace. - type: object - required: - - spec - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Desired state of the Issuer resource. - type: object - properties: - acme: - description: ACME configures this issuer to communicate with a RFC8555 (ACME) server to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: Base64-encoded bundle of PEM CAs which can be used to validate the certificate chain presented by the ACME server. Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various kinds of security vulnerabilities. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: Enables or disables generating a new ACME account key. If true, the Issuer resource will *not* request a new account but will expect the account key to be supplied via an existing secret. If false, the cert-manager system will generate a new ACME account key for the Issuer. Defaults to false. - type: boolean - email: - description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. - type: boolean - externalAccountBinding: - description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: 'Deprecated: keyAlgorithm field exists for historical compatibility reasons and should not be used. The algorithm is now hardcoded to HS256 in golang/x/crypto/acme.' - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes Secret which holds the symmetric MAC key of the External Account Binding. The `key` is the index string that is paired with the key data in the Secret and should not be confused with the key data itself, or indeed with the External Account Binding keyID above. The secret key stored in the Secret **must** be un-padded, base64 URL encoded data. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - preferredChain: - description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the ACME alternative chains that has a certificate with this value as its issuer''s CN' - type: string - maxLength: 64 - privateKeySecretRef: - description: PrivateKey is the name of a Kubernetes Secret resource that will be used to store the automatically generated ACME account private key. Optionally, a `key` may be specified to select a specific entry within the named Secret resource. If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - server: - description: 'Server is the URL used to access the ACME server''s ''directory'' endpoint. For example, for Let''s Encrypt''s staging endpoint, you would use: "https://acme-staging-v02.api.letsencrypt.org/directory". Only ACME v2 endpoints (i.e. RFC 8555) are supported.' - type: string - skipTLSVerify: - description: 'INSECURE: Enables or disables validation of the ACME server TLS certificate. If true, requests to the ACME server will not have the TLS certificate chain validated. Mutually exclusive with CABundle; prefer using CABundle to prevent various kinds of security vulnerabilities. Only enable this option in development environments. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection. Defaults to false.' - type: boolean - solvers: - description: 'Solvers is a list of challenge solvers that will be used to solve ACME challenges for the matching domains. Solver configurations must be provided in order to obtain certificates from an ACME server. For more information, see: https://cert-manager.io/docs/configuration/acme/' - type: array - items: - description: An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. A selector may be provided to use different solving strategies for different DNS names. Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: Configures cert-manager to attempt to complete authorizations by performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientSecretSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - clientTokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: 'Auth: Azure Service Principal: The ClientID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientSecret and TenantID must also be set.' - type: string - clientSecretSecretRef: - description: 'Auth: Azure Service Principal: A reference to a Secret containing the password associated with the Service Principal. If set, ClientID and TenantID must also be set.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: 'Auth: Azure Workload Identity or Azure Managed Service Identity: Settings to enable Azure Workload Identity or Azure Managed Service Identity If set, ClientID, ClientSecret and TenantID must not be set.' - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: resource ID of the managed identity, can not be used at the same time as clientID Cannot be used for Azure Managed Service Identity - type: string - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: 'Auth: Azure Service Principal: The TenantID of the Azure Service Principal used to authenticate with Azure DNS. If set, ClientID and ClientSecret must also be set.' - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: HostedZoneName is an optional field that tells cert-manager in which Cloud DNS zone the challenge record has to be created. If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: 'API key to use to authenticate with Cloudflare. Note: using an API token to authenticate is now the recommended method as it allows greater control of permissions.' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: CNAMEStrategy configures how the DNS01 provider should handle CNAME records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: A reference to a specific 'key' within a Secret resource. In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - rfc2136: - description: Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: The IP address or hostname of an authoritative DNS server supporting RFC2136 in the form host:port. If the host is an IPv6 address it must be enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. This field is required. - type: string - tsigAlgorithm: - description: 'The TSIG Algorithm configured in the DNS supporting RFC2136. Used only when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. Supported values are (case-insensitive): ``HMACMD5`` (default), ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``.' - type: string - tsigKeyName: - description: The TSIG Key name configured in the DNS. If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: The name of the secret containing the TSIG value. If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - required: - - region - properties: - accessKeyID: - description: 'The AccessKeyID is used for authentication. Cannot be set when SecretAccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: string - accessKeyIDSecretRef: - description: 'The SecretAccessKey is used for authentication. If set, pull the AWS access key ID from a key within a Kubernetes Secret. Cannot be set when AccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do an lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: Always set the region when using AccessKeyID and SecretAccessKey - type: string - role: - description: Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: 'The SecretAccessKey is used for authentication. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials' - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - webhook: - description: Configure an external webhook based DNS01 challenge solver to manage DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: Additional configuration that should be passed to the webhook apiserver when challenges are processed. This can contain arbitrary JSON data. Secret values should not be specified in this stanza. If secret values are needed (e.g. credentials for a DNS service), you should use a SecretKeySelector to reference a Secret resource. For details on the schema of this field, consult the webhook provider implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: The API group name that should be used when POSTing ChallengePayload resources to the webhook apiserver. This should be the same as the GroupName specified in the webhook provider implementation. - type: string - solverName: - description: The name of the solver to use, as defined in the webhook provider implementation. This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: Configures cert-manager to attempt to complete authorizations by performing the HTTP01 challenge flow. It is not possible to obtain certificates for wildcard domain names (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: The Gateway API is a sig-network community API that models service networking in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will create HTTPRoutes with the specified labels in the same namespace as the challenge. This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: Custom labels that will be applied to HTTPRoutes created by cert-manager while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: 'When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. cert-manager needs to know which parentRefs should be used when creating the HTTPRoute. Usually, the parentRef references a Gateway. See: https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways' - type: array - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n This API may be extended in the future to support additional kinds of parent resources. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - type: object - required: - - name - properties: - group: - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - description: "Kind is kind of the referent. \n There are two kinds of parent resources with \"Core\" support: \n * Gateway (Gateway conformance profile) * Service (Mesh conformance profile, experimental, ClusterIP Services only) \n Support for other resources is Implementation-Specific." - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: "Name is the name of the referent. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service. \n ParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n Support: Core" - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n When the parent resource is a Service, this targets a specific port in the Service spec. When both Port (experimental) and SectionName are specified, the name and port of the selected port must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - type: integer - format: int32 - maximum: 65535 - minimum: 1 - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. * Service: Port Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. Note that attaching Routes to Services as Parents is part of experimental Mesh support and is not supported for any other purpose. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: The ingress based HTTP01 challenge solver will solve challenges by creating or modifying Ingress resources in order to route requests for '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: This field configures the annotation `kubernetes.io/ingress.class` when creating Ingress resources to solve ACME challenges that use this challenge solver. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressClassName: - description: This field configures the field `ingressClassName` on the created Ingress resources used to solve ACME challenges that use this challenge solver. This is the recommended way of configuring the ingress class. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: Optional ingress template used to configure the ACME challenge solver ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the ingress used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources. Only one of `class`, `name` or `ingressClassName` may be specified. - type: string - podTemplate: - description: Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges. - type: object - properties: - metadata: - description: ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the 'labels' and 'annotations' fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the create ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: PodSpec defines overrides for the HTTP01 challenge solver pod. Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. - type: array - items: - description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-map-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - weight: - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. - type: integer - format: int32 - requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - type: array - items: - type: string - matchLabels: - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - topologyKey: - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. - type: string - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - type: object - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - x-kubernetes-map-type: atomic - nodeSelector: - description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . - type: object - properties: - effect: - description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the 'default' solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead. - type: object - properties: - dnsNames: - description: List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - dnsZones: - description: List of DNSZones that this solver will be used to solve. The most specific DNS zone match specified here will take precedence over other DNS zone matches, so a solver specifying sys.example.com will be selected over one specifying example.com for the domain www.sys.example.com. If multiple solvers match with the same dnsZones value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected. - type: array - items: - type: string - matchLabels: - description: A label selector that is used to refine the set of certificate's that this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: CA configures this issuer to sign certificates using a signing CA keypair stored in a Secret resource. This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate will be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: SecretName is the name of the secret used to sign Certificates issued by this Issuer. - type: string - selfSigned: - description: SelfSigned configures this issuer to 'self sign' certificates using the private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: Vault configures this issuer to sign certificates using a HashiCorp Vault PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: 'Path where the App Role authentication backend is mounted in Vault, e.g: "approle"' - type: string - roleId: - description: RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault. - type: string - secretRef: - description: Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The `key` field must be specified and denotes which entry within the Secret resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - kubernetes: - description: Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: The Vault mountPath here is the mount path to use when authenticating with Vault. For example, setting a value to `/v1/auth/foo`, will use the path `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: The required Secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. Use of 'ambient credentials' is not supported. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - serviceAccountRef: - description: A reference to a service account that will be used to request a bound token (also known as "projected token"). Compared to using "secretRef", using this field means that you don't rely on statically bound tokens. To use this field, you must configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - caBundle: - description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by Vault. Only used if using HTTPS to connect to Vault and ignored for HTTP connections. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: Reference to a Secret containing a bundle of PEM-encoded CAs to use when verifying the certificate chain presented by Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces' - type: string - path: - description: 'Path is the mount path of the Vault PKI backend''s `sign` endpoint, e.g: "my_pki_mount/sign/my-role-name".' - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: Venafi configures this issuer to sign certificates using a Venafi TPP or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: Cloud specifies the Venafi cloud configuration settings. Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required. - type: string - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - url: - description: URL is the base URL for Venafi Cloud. Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: TPP specifies Trust Protection Platform configuration settings. Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. If undefined, the certificate bundle in the cert-manager controller container is used to validate the chain. - type: string - format: byte - credentialsRef: - description: CredentialsRef is a reference to a Secret containing the username and password for the TPP server. The secret must contain two keys, 'username' and 'password'. - type: object - required: - - name - properties: - name: - description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - url: - description: 'URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, for example: "https://tpp.example.com/vedsdk".' - type: string - zone: - description: Zone is the Venafi Policy Zone to use for this issuer. All requests made to the Venafi platform will be restricted by the named zone policy. This field is required. - type: string - status: - description: Status of the Issuer. This is set and managed automatically. - type: object - properties: - acme: - description: ACME specific status options. This field should only be set if the Issuer is configured to use an ACME server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: LastPrivateKeyHash is a hash of the private key associated with the latest registered ACME account, in order to track changes made to registered account associated with the Issuer - type: string - lastRegisteredEmail: - description: LastRegisteredEmail is the email associated with the latest registered ACME account, in order to track changes made to registered account associated with the Issuer - type: string - uri: - description: URI is the unique account identifier, which can also be used to retrieve account details from the CA - type: string - conditions: - description: List of status conditions to indicate the status of a CertificateRequest. Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: LastTransitionTime is the timestamp corresponding to the last status change of this condition. - type: string - format: date-time - message: - description: Message is a human readable description of the details of the last transition, complementing reason. - type: string - observedGeneration: - description: If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: Reason is a brief machine readable explanation for the condition's last transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true diff --git a/kubenix-modules/cert-manager/manifests/order.yaml b/kubenix-modules/cert-manager/manifests/order.yaml deleted file mode 100644 index d3a2a68..0000000 --- a/kubenix-modules/cert-manager/manifests/order.yaml +++ /dev/null @@ -1,180 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: orders.acme.cert-manager.io - labels: - app: 'cert-manager' - app.kubernetes.io/name: 'cert-manager' - app.kubernetes.io/instance: 'cert-manager' - # Generated labels - app.kubernetes.io/version: "v1.14.4" -spec: - group: acme.cert-manager.io - names: - kind: Order - listKind: OrderList - plural: orders - singular: order - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: Order is a type to represent an Order with an ACME server - type: object - required: - - metadata - - spec - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - type: object - required: - - issuerRef - - request - properties: - commonName: - description: CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in `dnsNames` or `ipAddresses`. This field must match the corresponding field on the DER encoded CSR. - type: string - dnsNames: - description: DNSNames is a list of DNS names that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - duration: - description: Duration is the duration for the not after date for the requested certificate. this is set on order creation as pe the ACME spec. - type: string - ipAddresses: - description: IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - issuerRef: - description: IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an 'ACME' Issuer, an error will be returned and the Order will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order. - type: string - format: byte - status: - type: object - properties: - authorizations: - description: Authorizations contains data returned from the ACME server on what authorizations must be completed in order to validate the DNS names specified on the Order. - type: array - items: - description: ACMEAuthorization contains data returned from the ACME server on an authorization that must be completed in order validate a DNS name on an ACME Order resource. - type: object - required: - - url - properties: - challenges: - description: Challenges specifies the challenge types offered by the ACME server. One of these challenge types will be selected when validating the DNS name and an appropriate Challenge resource will be created to perform the ACME challenge process. - type: array - items: - description: Challenge specifies a challenge offered by the ACME server for an Order. An appropriate Challenge resource can be created to perform the ACME challenge process. - type: object - required: - - token - - type - - url - properties: - token: - description: Token is the token that must be presented for this challenge. This is used to compute the 'key' that must also be presented. - type: string - type: - description: Type is the type of challenge being offered, e.g. 'http-01', 'dns-01', 'tls-sni-01', etc. This is the raw value retrieved from the ACME server. Only 'http-01' and 'dns-01' are supported by cert-manager, other values will be ignored. - type: string - url: - description: URL is the URL of this challenge. It can be used to retrieve additional metadata about the Challenge from the ACME server. - type: string - identifier: - description: Identifier is the DNS name to be validated as part of this authorization - type: string - initialState: - description: InitialState is the initial state of the ACME authorization when first fetched from the ACME server. If an Authorization is already 'valid', the Order controller will not create a Challenge resource for the authorization. This will occur when working with an ACME server that enables 'authz reuse' (such as Let's Encrypt's production endpoint). If not set and 'identifier' is set, the state is assumed to be pending and a Challenge will be created. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: URL is the URL of the Authorization that must be completed - type: string - wildcard: - description: Wildcard will be true if this authorization is for a wildcard DNS name. If this is true, the identifier will be the *non-wildcard* version of the DNS name. For example, if '*.example.com' is the DNS name being validated, this field will be 'true' and the 'identifier' field will be 'example.com'. - type: boolean - certificate: - description: Certificate is a copy of the PEM encoded certificate for this Order. This field will be populated after the order has been successfully finalized with the ACME server, and the order has transitioned to the 'valid' state. - type: string - format: byte - failureTime: - description: FailureTime stores the time that this order failed. This is used to influence garbage collection and back-off. - type: string - format: date-time - finalizeURL: - description: FinalizeURL of the Order. This is used to obtain certificates for this order once it has been completed. - type: string - reason: - description: Reason optionally provides more information about a why the order is in the current state. - type: string - state: - description: State contains the current state of this Order resource. States 'success' and 'expired' are 'final' - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: URL of the Order. This will initially be empty when the resource is first created. The Order controller will populate this field when the Order is first processed. This field will be immutable after it is initially set. - type: string - served: true - storage: true diff --git a/kubenix-modules/custom-types.nix b/kubenix-modules/custom-types.nix deleted file mode 100644 index 0a6a7f7..0000000 --- a/kubenix-modules/custom-types.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ - kubernetes.customTypes = { - # HACK: These are dummy custom types. - # This is needed, because the CRDs imported as a chart are not available as Nix modules. - # There is no nix-based validation on resources defined using these types! - # See: https://github.com/hall/kubenix/issues/34 - ipAddressPool = { - attrName = "ipAddressPools"; - group = "metallb.io"; - version = "v1beta1"; - kind = "IPAddressPool"; - }; - - l2Advertisement = { - attrName = "l2Advertisements"; - group = "metallb.io"; - version = "v1beta1"; - kind = "L2Advertisement"; - }; - - helmChartConfig = { - attrName = "helmChartConfigs"; - group = "helm.cattle.io"; - version = "v1"; - kind = "HelmChartConfig"; - }; - - clusterIssuer = { - attrName = "clusterIssuers"; - group = "cert-manager.io"; - version = "v1"; - kind = "ClusterIssuer"; - }; - - recurringJob = { - attrName = "recurringJobs"; - group = "longhorn.io"; - version = "v1beta1"; - kind = "RecurringJob"; - }; - }; -} diff --git a/kubenix-modules/custom/default.nix b/kubenix-modules/custom/default.nix deleted file mode 100644 index f5cc500..0000000 --- a/kubenix-modules/custom/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ - imports = [ - ./ingress.nix - ./longhorn-volume.nix - ./tailscale.nix - ]; -} diff --git a/kubenix-modules/custom/ingress.nix b/kubenix-modules/custom/ingress.nix deleted file mode 100644 index 99b2e78..0000000 --- a/kubenix-modules/custom/ingress.nix +++ /dev/null @@ -1,67 +0,0 @@ -{ lib, config, ... }: -let - ingressOpts = { name, ... }: { - options = { - host = lib.mkOption { - type = lib.types.str; - }; - - entrypoint = lib.mkOption { - type = lib.types.str; - default = "websecure"; - }; - - service = { - name = lib.mkOption { - type = lib.types.str; - }; - - portName = lib.mkOption { - type = lib.types.str; - }; - }; - }; - }; -in -{ - options = { - lab.ingresses = lib.mkOption { - type = with lib.types; attrsOf (submodule ingressOpts); - default = { }; - }; - }; - - config = { - kubernetes.resources.ingresses = builtins.mapAttrs - (name: ingress: { - metadata.annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt"; - "traefik.ingress.kubernetes.io/router.entrypoints" = ingress.entrypoint; - }; - - spec = { - ingressClassName = "traefik"; - - rules = [{ - host = ingress.host; - - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = ingress.service.name; - port.name = ingress.service.portName; - }; - }]; - }]; - - tls = [{ - secretName = "${name}-tls"; - hosts = [ ingress.host ]; - }]; - }; - }) - config.lab.ingresses; - }; -} diff --git a/kubenix-modules/custom/longhorn-volume.nix b/kubenix-modules/custom/longhorn-volume.nix deleted file mode 100644 index 868e16f..0000000 --- a/kubenix-modules/custom/longhorn-volume.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ lib, config, ... }: -let - longhornVolumeOpts = { name, ... }: { - options = { - storage = lib.mkOption { - type = lib.types.str; - }; - - namespace = lib.mkOption { - type = lib.types.str; - default = "default"; - }; - }; - }; - - longhornPVOpts = { name, ... }: { - options = { - storage = lib.mkOption { - type = lib.types.str; - }; - }; - }; - - longhornPVCOpts = { name, ... }: { - options = { - volumeName = lib.mkOption { - type = lib.types.str; - default = name; - }; - - # TODO: ideally we take this from the longhornPV so we don't duplicate this information. - storage = lib.mkOption { - type = lib.types.str; - }; - }; - }; -in -{ - options = { - lab.longhornVolumes = lib.mkOption { - type = with lib.types; attrsOf (submodule longhornVolumeOpts); - default = { }; - }; - - lab.longhorn = { - persistentVolume = lib.mkOption { - type = with lib.types; attrsOf (submodule longhornPVOpts); - default = { }; - }; - - persistentVolumeClaim = lib.mkOption { - type = with lib.types; attrsOf (submodule longhornPVCOpts); - default = { }; - }; - }; - }; - - config = { - kubernetes.resources = { - persistentVolumes = lib.mergeAttrs - (builtins.mapAttrs - (name: longhornVolume: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - capacity.storage = longhornVolume.storage; - persistentVolumeReclaimPolicy = "Delete"; - volumeMode = "Filesystem"; - - claimRef = { - inherit name; - namespace = longhornVolume.namespace; - }; - - csi = { - driver = "driver.longhorn.io"; - fsType = "ext4"; - volumeHandle = name; - - volumeAttributes = { - dataLocality = "disabled"; - fromBackup = ""; - fsType = "ext4"; - numberOfReplicas = "2"; - staleReplicaTimeout = "30"; - unmapMarkSnapChainRemoved = "ignored"; - - recurringJobSelector = lib.generators.toYAML { } [{ - name = "backup-nfs"; - isGroup = false; - }]; - }; - }; - }; - }) - config.lab.longhornVolumes) - (builtins.mapAttrs - (name: longhornPV: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - capacity.storage = longhornPV.storage; - persistentVolumeReclaimPolicy = "Delete"; - volumeMode = "Filesystem"; - - csi = { - driver = "driver.longhorn.io"; - fsType = "ext4"; - volumeHandle = name; - - volumeAttributes = { - dataLocality = "disabled"; - fromBackup = ""; - fsType = "ext4"; - numberOfReplicas = "2"; - staleReplicaTimeout = "30"; - unmapMarkSnapChainRemoved = "ignored"; - - recurringJobSelector = lib.generators.toYAML { } [{ - name = "backup-nfs"; - isGroup = false; - }]; - }; - }; - }; - }) - config.lab.longhorn.persistentVolume); - - persistentVolumeClaims = lib.mergeAttrs - (builtins.mapAttrs - (name: longhornVolume: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = longhornVolume.storage; - storageClassName = ""; - }; - }) - config.lab.longhornVolumes) - (builtins.mapAttrs - (name: longhornPVC: { - spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = longhornPVC.storage; - storageClassName = ""; - volumeName = longhornPVC.volumeName; - }; - }) - config.lab.longhorn.persistentVolumeClaim); - }; - }; -} diff --git a/kubenix-modules/custom/tailscale.nix b/kubenix-modules/custom/tailscale.nix deleted file mode 100644 index 29ad04f..0000000 --- a/kubenix-modules/custom/tailscale.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ lib, config, ... }: { - options = with lib.types; { - lab.tailscaleIngresses = lib.mkOption { - type = attrsOf (submodule { - options = { - host = lib.mkOption { type = str; }; - - service = { - name = lib.mkOption { type = str; }; - - portName = lib.mkOption { - type = str; - default = "web"; - }; - }; - }; - }); - - default = { }; - }; - }; - - config = - let - cfg = config.lab.tailscaleIngresses; - - mkTailscaleIngress = name: { host, service }: { - spec = { - ingressClassName = "tailscale"; - - rules = [{ - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = service.name; - port.name = service.portName; - }; - }]; - }]; - - tls = [{ - hosts = [ host ]; - }]; - }; - }; - in - { - kubernetes.resources.ingresses = builtins.mapAttrs mkTailscaleIngress cfg; - }; -} diff --git a/kubenix-modules/cyberchef.nix b/kubenix-modules/cyberchef.nix deleted file mode 100644 index 44bbfef..0000000 --- a/kubenix-modules/cyberchef.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - deployments.cyberchef.spec = { - replicas = 3; - selector.matchLabels.app = "cyberchef"; - - template = { - metadata.labels.app = "cyberchef"; - - spec.containers.cyberchef = { - image = myLib.globals.images.cyberchef; - imagePullPolicy = "Always"; - ports.web.containerPort = 8000; - }; - }; - }; - - services.cyberchef.spec = { - selector.app = "cyberchef"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab.ingresses.cyberchef = { - host = "cyberchef.kun.is"; - - service = { - name = "cyberchef"; - portName = "web"; - }; - }; -} diff --git a/kubenix-modules/dnsmasq.nix b/kubenix-modules/dnsmasq.nix deleted file mode 100644 index 90655ea..0000000 --- a/kubenix-modules/dnsmasq.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - configMaps.dnsmasq-config.data.config = '' - address=/kms.kun.is/${myLib.globals.kmsIPv4} - address=/ssh.git.kun.is/${myLib.globals.gitIPv4} - alias=${myLib.globals.routerPublicIPv4},${myLib.globals.traefikIPv4} - expand-hosts - host-record=hermes.dmz,${myLib.globals.dnsmasqIPv4} - local=/dmz/ - log-queries - no-hosts - no-resolv - port=53 - server=192.168.30.1 - server=/kun.is/${myLib.globals.bind9IPv4} - ''; - - deployments.dnsmasq.spec = { - selector.matchLabels.app = "dnsmasq"; - - template = { - metadata.labels.app = "dnsmasq"; - - spec = { - containers.dnsmasq = { - image = myLib.globals.images.dnsmasq; - - ports.dns = { - containerPort = 53; - protocol = "UDP"; - }; - - volumeMounts = [{ - name = "config"; - mountPath = "/etc/dnsmasq.conf"; - subPath = "config"; - }]; - }; - - volumes.config.configMap.name = "dnsmasq-config"; - }; - }; - }; - - services.dnsmasq.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.dnsmasqIPv4; - selector.app = "dnsmasq"; - - ports.dns = { - port = 53; - targetPort = "dns"; - protocol = "UDP"; - }; - }; - }; -} diff --git a/kubenix-modules/forgejo/config.nix b/kubenix-modules/forgejo/config.nix deleted file mode 100644 index 7247cf2..0000000 --- a/kubenix-modules/forgejo/config.nix +++ /dev/null @@ -1,104 +0,0 @@ -{ - "repository.local".LOCAL_COPY_PATH = "/data/gitea/tmp/local-repo"; - "repository.upload".TEMP_PATH = "/data/gitea/uploads"; - attachment.PATH = "/data/gitea/attachments"; - lfs.PATH = "/data/git/lfs"; - mailer.ENABLED = false; - "repository.pull-request".DEFAULT_MERGE_STYLE = "merge"; - "repository.signing".DEFAULT_TRUST_MODEL = "committer"; - ui.DEFAULT_THEME = "forgejo-light"; - oauth2 = { - ENABLED = false; - JWT_SECRET = "ref+sops://secrets/kubernetes.yaml#/forgejo/jwtSecret"; - }; - - DEFAULT = { - APP_NAME = "Forgejo: Beyond coding. We forge."; - RUN_MODE = "prod"; - RUN_USER = "git"; - WORK_PATH = "/data/gitea"; - }; - - repository = { - ROOT = "/data/git/repositories"; - DEFAULT_BRANCH = "master"; - }; - - server = { - APP_DATA_PATH = "/data/gitea"; - DOMAIN = "git.kun.is"; - SSH_DOMAIN = "ssh.git.kun.is"; - HTTP_PORT = 3000; - ROOT_URL = "https://git.kun.is"; - DISABLE_SSH = false; - SSH_PORT = 56287; - SSH_LISTEN_PORT = 22; - LFS_START_SERVER = true; - LFS_JWT_SECRET = "ref+sops://secrets/kubernetes.yaml#/forgejo/lfsJwtSecret"; - OFFLINE_MODE = false; - }; - - database = { - PATH = "/data/gitea/gitea.db"; - DB_TYPE = "sqlite3"; - HOST = "localhost:3306"; - NAME = "gitea"; - USER = "root"; - PASSWD = ""; - LOG_SQL = false; - SCHEMA = ""; - SSL_MODE = "disable"; - CHARSET = "utf8"; - }; - - indexer = { - ISSUE_INDEXER_PATH = "/data/gitea/indexers/issues.bleve"; - ISSUE_INDEXER_TYPE = "db"; - }; - - session = { - PROVIDER_CONFIG = "/data/gitea/sessions"; - PROVIDER = "file"; - }; - - picture = { - AVATAR_UPLOAD_PATH = "/data/gitea/avatars"; - REPOSITORY_AVATAR_UPLOAD_PATH = "/data/gitea/repo-avatars"; - ENABLE_FEDERATED_AVATAR = false; - }; - - log = { - MODE = "console"; - LEVEL = "info"; - "logger.router.MODE" = "console"; - ROOT_PATH = "/data/gitea/log"; - "logger.access.MODE" = "console"; - }; - - security = { - INSTALL_LOCK = true; - SECRET_KEY = ""; - REVERSE_PROXY_LIMIT = 1; - REVERSE_PROXY_TRUSTED_PROXIES = "*"; - INTERNAL_TOKEN = "ref+sops://secrets/kubernetes.yaml#/forgejo/internalToken"; - PASSWORD_HASH_ALGO = "pbkdf2"; - }; - - service = { - DISABLE_REGISTRATION = true; - REQUIRE_SIGNIN_VIEW = false; - REGISTER_EMAIL_CONFIRM = false; - ENABLE_NOTIFY_MAIL = false; - ALLOW_ONLY_EXTERNAL_REGISTRATION = false; - ENABLE_CAPTCHA = false; - DEFAULT_KEEP_EMAIL_PRIVATE = true; - DEFAULT_ALLOW_CREATE_ORGANIZATION = true; - DEFAULT_ENABLE_TIMETRACKING = true; - NO_REPLY_ADDRESS = "noreply.localhost"; - }; - - openid = { - ENABLE_OPENID_SIGNIN = true; - ENABLE_OPENID_SIGNUP = false; - }; -} diff --git a/kubenix-modules/forgejo/default.nix b/kubenix-modules/forgejo/default.nix deleted file mode 100644 index 74e89f3..0000000 --- a/kubenix-modules/forgejo/default.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ lib, myLib, ... }: { - kubernetes.resources = { - secrets.forgejo.stringData.config = lib.generators.toINI { } (import ./config.nix); - - deployments.server.spec = { - selector.matchLabels.app = "forgejo"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "forgejo"; - - spec = { - # This disables services from becoming environmental variables - # to prevent SSH_PORT clashing with Forgejo config. - enableServiceLinks = false; - - containers.forgejo = { - image = myLib.globals.images.forgejo; - imagePullPolicy = "IfNotPresent"; - - env = { - USER_UID.value = "1000"; - USER_GID.value = "1000"; - }; - - ports = { - web.containerPort = 3000; - ssh.containerPort = 22; - }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/data"; - } - { - name = "config"; - mountPath = "/data/gitea/conf/app.ini"; - subPath = "config"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "data"; - config.secret.secretName = "forgejo"; - }; - }; - }; - }; - - services = { - web.spec = { - selector.app = "forgejo"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - ssh.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.gitIPv4; - selector.app = "forgejo"; - - ports.ssh = { - port = 56287; - targetPort = "ssh"; - }; - }; - }; - }; - - lab = { - ingresses.web = { - host = "git.kun.is"; - - service = { - name = "web"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim.data = { - volumeName = "forgejo"; - storage = "20Gi"; - }; - }; -} diff --git a/kubenix-modules/freshrss.nix b/kubenix-modules/freshrss.nix deleted file mode 100644 index 614847e..0000000 --- a/kubenix-modules/freshrss.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.server.stringData.adminPassword = "ref+sops://secrets/kubernetes.yaml#/freshrss/password"; - - deployments.server.spec = { - selector.matchLabels.app = "freshrss"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "freshrss"; - - spec = { - containers.freshrss = { - image = myLib.globals.images.freshrss; - imagePullPolicy = "IfNotPresent"; - ports.web.containerPort = 80; - - env = { - TZ.value = "Europe/Amsterdam"; - CRON_MIN.value = "2,32"; - ADMIN_EMAIL.value = "pim@kunis.nl"; - PUBLISHED_PORT.value = "443"; - - ADMIN_PASSWORD.valueFrom.secretKeyRef = { - name = "server"; - key = "adminPassword"; - }; - - ADMIN_API_PASSWORD.valueFrom.secretKeyRef = { - name = "server"; - key = "adminPassword"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/var/www/FreshRSS/data"; - }]; - }; - - volumes.data.persistentVolumeClaim.claimName = "data"; - - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - services.server.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.freshrssIPv4; - selector.app = "freshrss"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "freshrss"; - service.name = "server"; - }; - - longhorn.persistentVolumeClaim.data = { - volumeName = "freshrss"; - storage = "1Gi"; - }; - }; -} diff --git a/kubenix-modules/hedgedoc.nix b/kubenix-modules/hedgedoc.nix deleted file mode 100644 index d9ceeb0..0000000 --- a/kubenix-modules/hedgedoc.nix +++ /dev/null @@ -1,167 +0,0 @@ -{ lib, myLib, ... }: { - kubernetes.resources = { - configMaps.hedgedoc-config.data.config = lib.generators.toJSON { } { - useSSL = false; - }; - - secrets.hedgedoc.stringData = { - databaseURL = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databaseURL"; - sessionSecret = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/sessionSecret"; - databasePassword = "ref+sops://secrets/kubernetes.yaml#/hedgedoc/databasePassword"; - }; - - deployments = { - server.spec = { - selector.matchLabels = { - app = "hedgedoc"; - component = "website"; - }; - - template = { - metadata.labels = { - app = "hedgedoc"; - component = "website"; - }; - - spec = { - containers.hedgedoc = { - image = myLib.globals.images.hedgedoc; - ports.web.containerPort = 3000; - - env = { - CMD_DOMAIN.value = "md.kun.is"; - CMD_PORT.value = "3000"; - CMD_URL_ADDPORT.value = "false"; - CMD_ALLOW_ANONYMOUS.value = "true"; - CMD_ALLOW_EMAIL_REGISTER.value = "false"; - CMD_PROTOCOL_USESSL.value = "true"; - CMD_CSP_ENABLE.value = "false"; - - CMD_DB_URL.valueFrom.secretKeyRef = { - name = "hedgedoc"; - key = "databaseURL"; - }; - - CMD_SESSION_SECRET.valueFrom.secretKeyRef = { - name = "hedgedoc"; - key = "sessionSecret"; - }; - }; - - volumeMounts = [ - { - name = "uploads"; - mountPath = "/hedgedoc/public/uploads"; - } - { - name = "config"; - mountPath = "/hedgedoc/config.json"; - subPath = "config"; - } - ]; - }; - - volumes = { - uploads.persistentVolumeClaim.claimName = "uploads"; - config.configMap.name = "hedgedoc-config"; - }; - - securityContext = { - fsGroup = 65534; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - database.spec = { - selector.matchLabels = { - app = "hedgedoc"; - component = "database"; - }; - - template = { - metadata.labels = { - app = "hedgedoc"; - component = "database"; - }; - - spec = { - containers.postgres = { - image = myLib.globals.images.postgres15; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - - env = { - POSTGRES_DB.value = "hedgedoc"; - POSTGRES_USER.value = "hedgedoc"; - PGDATA.value = "/pgdata/data"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "hedgedoc"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "database"; - mountPath = "/pgdata"; - }]; - }; - - volumes.database.persistentVolumeClaim.claimName = "database"; - }; - }; - }; - }; - - services = { - server.spec = { - selector = { - app = "hedgedoc"; - component = "website"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - database.spec = { - selector = { - app = "hedgedoc"; - component = "database"; - }; - - ports.postgres = { - port = 5432; - targetPort = "postgres"; - }; - }; - }; - }; - - lab = { - ingresses.web = { - host = "md.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim = { - uploads = { - volumeName = "hedgedoc-uploads"; - storage = "50Mi"; - }; - - database = { - volumeName = "hedgedoc-db"; - storage = "100Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix deleted file mode 100644 index 1bca830..0000000 --- a/kubenix-modules/immich.nix +++ /dev/null @@ -1,262 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.immich.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; - - deployments = { - immich.spec = { - selector.matchLabels = { - app = "immich"; - component = "server"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "immich"; - component = "server"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "data"; - - enableServiceLinks = false; - - containers.immich = { - image = myLib.globals.images.immich; - imagePullPolicy = "IfNotPresent"; - ports.web.containerPort = 3001; - - env = { - TZ.value = "Europe/Amsterdam"; - REDIS_HOSTNAME.value = "redis.immich.svc.cluster.local"; - DB_HOSTNAME.value = "postgres.immich.svc.cluster.local"; - DB_USERNAME.value = "postgres"; - DB_DATABASE_NAME.value = "immich"; - IMMICH_MACHINE_LEARNING_URL.value = "http://ml.immich.svc.cluster.local"; - - DB_PASSWORD.valueFrom.secretKeyRef = { - name = "immich"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/usr/src/app/upload"; - }]; - }; - }; - }; - }; - - ml.spec = { - selector.matchLabels = { - app = "immich"; - component = "machine-learning"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "immich"; - component = "machine-learning"; - }; - - spec = { - volumes.cache.persistentVolumeClaim.claimName = "cache"; - - containers.machine-learning = { - image = myLib.globals.images.immich-machine-learning; - imagePullPolicy = "IfNotPresent"; - ports.ml.containerPort = 3003; - env.MACHINE_LEARNING_WORKER_TIMEOUT.value = "600"; - - volumeMounts = [{ - name = "cache"; - mountPath = "/cache"; - }]; - }; - }; - }; - }; - - redis.spec = { - selector.matchLabels = { - app = "immich"; - component = "redis"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "immich"; - component = "redis"; - }; - - spec = { - containers.redis = { - image = myLib.globals.images.immich-redis; - ports.redis.containerPort = 6379; - imagePullPolicy = "IfNotPresent"; - }; - }; - }; - }; - - database.spec = { - selector.matchLabels = { - app = "immich"; - component = "database"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "immich"; - component = "database"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "database"; - - containers.postgres = { - image = myLib.globals.images.immich-postgres; - imagePullPolicy = "IfNotPresent"; - command = [ "postgres" ]; - args = [ "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; - ports.postgres.containerPort = 5432; - securityContext.runAsUser = 999; - securityContext.runAsGroup = 999; - - env = { - POSTGRES_USER.value = "postgres"; - POSTGRES_DB.value = "immich"; - POSTGRES_INITDB_ARGS.value = "--data-checksums"; - PGDATA.value = "/pgdata/data"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "immich"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; - }; - }; - }; - }; - }; - - services = { - server.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.immichIPv4; - - selector = { - app = "immich"; - component = "server"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - redis.spec = { - selector = { - app = "immich"; - component = "redis"; - }; - - ports.redis = { - port = 6379; - targetPort = "redis"; - }; - }; - - ml.spec = { - selector = { - app = "immich"; - component = "machine-learning"; - }; - - ports.ml = { - port = 80; - targetPort = "ml"; - }; - }; - - postgres.spec = { - selector = { - app = "immich"; - component = "database"; - }; - - ports.postgres = { - port = 5432; - targetPort = "postgres"; - }; - }; - }; - - persistentVolumeClaims.cache.spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = "5Gi"; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "immich"; - service.name = "server"; - }; - - longhorn.persistentVolumeClaim = { - data = { - volumeName = "immich"; - storage = "50Gi"; - }; - - database = { - volumeName = "immich-db"; - storage = "5Gi"; - }; - }; - }; -} diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix deleted file mode 100644 index 63f8852..0000000 --- a/kubenix-modules/inbucket.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - serviceAccounts.inbucket = { }; - - deployments.inbucket.spec = { - selector.matchLabels.app = "inbucket"; - - template = { - metadata.labels.app = "inbucket"; - - spec = { - serviceAccountName = "inbucket"; - - containers = { - inbucket = { - image = myLib.globals.images.inbucket; - - ports = { - web.containerPort = 9000; - smtp.containerPort = 2500; - }; - }; - }; - }; - }; - }; - - services = { - inbucket.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.inbucketIPv4; - selector.app = "inbucket"; - - ports = { - smtp = { - port = 25; - targetPort = "smtp"; - }; - - web = { - port = 80; - targetPort = "web"; - }; - }; - }; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "inbucket"; - service.name = "inbucket"; - }; - - ingresses.inbucket = { - host = "inbucket.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "inbucket"; - portName = "web"; - }; - }; - }; -} diff --git a/kubenix-modules/kitchenowl.nix b/kubenix-modules/kitchenowl.nix deleted file mode 100644 index 9e5e14d..0000000 --- a/kubenix-modules/kitchenowl.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.server.stringData.jwtSecretKey = "ref+sops://secrets/kubernetes.yaml#/kitchenowl/jwtSecretKey"; - - deployments.server.spec = { - selector.matchLabels.app = "kitchenowl"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "kitchenowl"; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "data"; - - containers.kitchenowl = { - image = myLib.globals.images.kitchenowl; - ports.web.containerPort = 8080; - imagePullPolicy = "IfNotPresent"; - - env.JWT_SECRET_KEY.valueFrom.secretKeyRef = { - name = "server"; - key = "jwtSecretKey"; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - services.server.spec = { - selector.app = "kitchenowl"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab = { - ingresses.web = { - host = "boodschappen.kun.is"; - - service = { - name = "server"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim.data = { - volumeName = "kitchenowl"; - storage = "100Mi"; - }; - }; -} diff --git a/kubenix-modules/kms.nix b/kubenix-modules/kms.nix deleted file mode 100644 index 8dc37b5..0000000 --- a/kubenix-modules/kms.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - deployments.server.spec = { - selector.matchLabels.app = "kms"; - - template = { - metadata.labels.app = "kms"; - - spec.containers.kms = { - image = myLib.globals.images.kms; - ports.kms.containerPort = 1688; - }; - }; - }; - - services.server.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.kmsIPv4; - selector.app = "kms"; - - ports.kms = { - port = 1688; - targetPort = "kms"; - }; - }; - }; -} diff --git a/kubenix-modules/media.nix b/kubenix-modules/media.nix deleted file mode 100644 index 8e5a7c0..0000000 --- a/kubenix-modules/media.nix +++ /dev/null @@ -1,610 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - deployments = { - jellyfin.spec = { - selector.matchLabels = { - app = "media"; - component = "jellyfin"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "jellyfin"; - }; - - spec = { - containers.jellyfin = { - image = myLib.globals.images.jellyfin; - ports.web.containerPort = 8096; - imagePullPolicy = "IfNotPresent"; - - env.JELLYFIN_PublishedServerUrl.value = "https://media.kun.is"; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - { - name = "cache"; - mountPath = "/config/transcodes"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "jellyfin"; - cache.persistentVolumeClaim.claimName = "jellyfin-cache"; - - media.hostPath = { - path = "/mnt/longhorn/persistent/media"; - type = "Directory"; - }; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; - - affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms = [{ - matchExpressions = [{ - key = "hasMedia"; - operator = "In"; - values = [ "true" ]; - }]; - }]; - }; - }; - }; - - deluge.spec = { - selector.matchLabels = { - app = "media"; - component = "deluge"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "deluge"; - }; - - spec = { - containers.deluge = { - image = myLib.globals.images.deluge; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "1000"; - PGID.value = "1000"; - TZ.value = "Europe/Amsterdam"; - DELUGE_LOGLEVEL.value = "info"; - }; - - ports = { - web.containerPort = 8112; - bittorrent.containerPort = 31780; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "deluge"; - media.persistentVolumeClaim.claimName = "media"; - }; - }; - }; - }; - - jellyseerr.spec = { - selector.matchLabels = { - app = "media"; - component = "jellyseerr"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "jellyseerr"; - }; - - spec = { - volumes.config.persistentVolumeClaim.claimName = "jellyseerr"; - - containers.jellyseerr = { - image = myLib.globals.images.jellyseerr; - ports.web.containerPort = 5055; - imagePullPolicy = "IfNotPresent"; - - env = { - LOG_LEVEL.value = "debug"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [{ - name = "config"; - mountPath = "/app/config"; - }]; - }; - - securityContext = { - fsGroup = 0; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - radarr.spec = { - selector.matchLabels = { - app = "media"; - component = "radarr"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "radarr"; - }; - - spec = { - containers.radarr = { - image = myLib.globals.images.radarr; - ports.web.containerPort = 7878; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "1000"; - PGID.value = "1000"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "radarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - prowlarr.spec = { - selector.matchLabels = { - app = "media"; - component = "prowlarr"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "prowlarr"; - }; - - spec = { - volumes.config.persistentVolumeClaim.claimName = "prowlarr"; - - containers.prowlarr = { - image = myLib.globals.images.prowlarr; - ports.web.containerPort = 9696; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "1000"; - PGID.value = "1000"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [{ - name = "config"; - mountPath = "/config"; - }]; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - sonarr.spec = { - selector.matchLabels = { - app = "media"; - component = "sonarr"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "sonarr"; - }; - - spec = { - containers.sonarr = { - image = myLib.globals.images.sonarr; - ports.web.containerPort = 8989; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "1000"; - PGID.value = "1000"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "sonarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - bazarr.spec = { - selector.matchLabels = { - app = "media"; - component = "bazarr"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "media"; - component = "bazarr"; - }; - - spec = { - containers.bazarr = { - image = myLib.globals.images.bazarr; - ports.web.containerPort = 6767; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "1000"; - PGID.value = "1000"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "media"; - mountPath = "/media"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "bazarr"; - media.persistentVolumeClaim.claimName = "media"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - }; - - services = { - jellyfin.spec = { - selector = { - app = "media"; - component = "jellyfin"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - deluge.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.transmissionIPv4; - - selector = { - app = "media"; - component = "deluge"; - }; - - ports = { - bittorrent = { - port = 31780; - targetPort = "bittorrent"; - }; - - web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - jellyseerr.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.jellyseerrIPv4; - - selector = { - app = "media"; - component = "jellyseerr"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - radarr.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.radarrIPv4; - - selector = { - app = "media"; - component = "radarr"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - prowlarr.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.prowlarrIPv4; - - selector = { - app = "media"; - component = "prowlarr"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - sonarr.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.sonarrIPv4; - - selector = { - app = "media"; - component = "sonarr"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - bazarr.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.bazarrIPv4; - - selector = { - app = "media"; - component = "bazarr"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - persistentVolumeClaims = { - jellyfin-cache.spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = "20Gi"; - }; - - media.spec = { - accessModes = [ "ReadWriteMany" ]; - storageClassName = ""; - resources.requests.storage = "1Mi"; - volumeName = "media-media"; - }; - }; - }; - - lab = { - ingresses.jellyfin = { - host = "media.kun.is"; - - service = { - name = "jellyfin"; - portName = "web"; - }; - }; - - tailscaleIngresses = { - tailscale-jellyseerr = { - host = "jellyseerr"; - service.name = "jellyseerr"; - }; - - tailscale-radarr = { - host = "radarr"; - service.name = "radarr"; - }; - - tailscale-sonarr = { - host = "sonarr"; - service.name = "sonarr"; - }; - - tailscale-bazarr = { - host = "bazarr"; - service.name = "bazarr"; - }; - - tailscale-prowlarr = { - host = "prowlarr"; - service.name = "prowlarr"; - }; - - tailscale-deluge = { - host = "deluge"; - service.name = "deluge"; - }; - }; - - longhorn.persistentVolumeClaim = { - jellyfin = { - volumeName = "jellyfin"; - storage = "5Gi"; - }; - - deluge = { - volumeName = "deluge"; - storage = "500Mi"; - }; - - jellyseerr = { - volumeName = "jellyseerr"; - storage = "75Mi"; - }; - - radarr = { - volumeName = "radarr"; - storage = "300Mi"; - }; - - prowlarr = { - volumeName = "prowlarr"; - storage = "150Mi"; - }; - - sonarr = { - volumeName = "sonarr"; - storage = "150Mi"; - }; - - bazarr = { - volumeName = "bazarr"; - storage = "25Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/minecraft.nix b/kubenix-modules/minecraft.nix deleted file mode 100644 index acf855a..0000000 --- a/kubenix-modules/minecraft.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ myLib, ... }: { - # kubernetes.resources = { - # deployments.minecraft.spec = { - # selector.matchLabels.app = "minecraft"; - - # template = { - # metadata.labels.app = "minecraft"; - - # spec = { - # volumes.data.persistentVolumeClaim.claimName = "data"; - - # containers.minecraft = { - # image = myLib.globals.images.minecraft; - # ports.minecraft.containerPort = 25565; - - # env.EULA.value = "TRUE"; - - # volumeMounts = [{ - # name = "data"; - # mountPath = "/data"; - # }]; - # }; - - # securityContext = { - # fsGroup = 1000; - # fsGroupChangePolicy = "OnRootMismatch"; - # }; - # }; - # }; - # }; - - # services.minecraft.spec = { - # type = "LoadBalancer"; - # loadBalancerIP = myLib.globals.minecraftIPv4; - # selector.app = "minecraft"; - - # ports.minecraft = { - # port = 25565; - # targetPort = "minecraft"; - # }; - # }; - # }; - - lab.longhorn.persistentVolumeClaim.data = { - volumeName = "minecraft"; - storage = "1Gi"; - }; -} diff --git a/kubenix-modules/nextcloud.nix b/kubenix-modules/nextcloud.nix deleted file mode 100644 index e5a7056..0000000 --- a/kubenix-modules/nextcloud.nix +++ /dev/null @@ -1,157 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.database.stringData.databasePassword = "ref+sops://secrets/kubernetes.yaml#/nextcloud/databasePassword"; - - deployments = { - server.spec = { - selector.matchLabels = { - app = "nextcloud"; - component = "server"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "nextcloud"; - component = "server"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "data"; - - containers.nextcloud = { - image = myLib.globals.images.nextcloud; - ports.web.containerPort = 80; - - env = { - POSTGRES_USER.value = "nextcloud"; - POSTGRES_DB.value = "nextcloud"; - POSTGRES_HOST.value = "lewis.dmz"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "database"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/var/www/html"; - }]; - }; - - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; - - affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution = [{ - weight = 1; - preference.matchExpressions = [{ - key = "storageType"; - operator = "In"; - values = [ "fast" ]; - }]; - }]; - }; - }; - }; - - database.spec = { - selector.matchLabels = { - app = "nextcloud"; - component = "database"; - }; - - template = { - metadata.labels = { - app = "nextcloud"; - component = "database"; - }; - - spec = { - containers.postgres = { - image = myLib.globals.images.postgres15; - imagePullPolicy = "IfNotPresent"; - ports.postgres.containerPort = 5432; - - env = { - POSTGRES_DB.value = "nextcloud"; - POSTGRES_USER.value = "nextcloud"; - PGDATA.value = "/pgdata/data"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "database"; - key = "databasePassword"; - }; - }; - - volumeMounts = [{ - name = "database"; - mountPath = "/pgdata"; - }]; - }; - - volumes.database.persistentVolumeClaim.claimName = "database"; - }; - }; - }; - }; - - services = { - server.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.nextcloudIPv4; - - selector = { - app = "nextcloud"; - component = "server"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - database.spec = { - selector = { - app = "nextcloud"; - component = "database"; - }; - - ports.postgres = { - port = 5432; - targetPort = "postgres"; - }; - }; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "nextcloud"; - service.name = "server"; - }; - - longhorn.persistentVolumeClaim = { - data = { - volumeName = "nextcloud"; - storage = "50Gi"; - }; - - database = { - volumeName = "nextcloud-db"; - storage = "400Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/ntfy.nix b/kubenix-modules/ntfy.nix deleted file mode 100644 index a1c3a27..0000000 --- a/kubenix-modules/ntfy.nix +++ /dev/null @@ -1,105 +0,0 @@ -{ lib, myLib, ... }: { - kubernetes.resources = { - configMaps.ntfy.data.config = lib.generators.toYAML { } { - base-url = "https://ntfy.kun.is"; - cache-file = "/var/cache/ntfy/cache.db"; - cache-duration = "14d"; - auth-file = "/var/lib/ntfy/user.db"; - auth-default-access = "deny-all"; - attachment-cache-dir = "/var/cache/ntfy-attachments"; - enable-signup = false; - enable-login = true; - visitor-subscription-limit = 100; - }; - - deployments.ntfy.spec = { - selector.matchLabels.app = "ntfy"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "ntfy"; - - spec = { - containers.ntfy = { - image = myLib.globals.images.ntfy; - ports.web.containerPort = 80; - env.TZ.value = "Europe/Amsterdam"; - args = [ "serve" ]; - - volumeMounts = [ - { - name = "cache"; - mountPath = "/var/cache/ntfy"; - } - { - name = "data"; - mountPath = "/var/lib/ntfy"; - } - { - name = "attachment-cache"; - mountPath = "/var/cache/ntfy-attachments"; - } - { - name = "config"; - mountPath = "/etc/ntfy/server.yml"; - subPath = "config"; - } - ]; - }; - - volumes = { - cache.persistentVolumeClaim.claimName = "cache"; - attachment-cache.persistentVolumeClaim.claimName = "attachment-cache"; - data.persistentVolumeClaim.claimName = "data"; - config.configMap.name = "ntfy"; - }; - }; - }; - }; - - persistentVolumeClaims = { - cache.spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = "300Mi"; - }; - - attachment-cache.spec = { - accessModes = [ "ReadWriteOnce" ]; - resources.requests.storage = "500Mi"; - }; - }; - - services.ntfy.spec = { - selector.app = "ntfy"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab = { - ingresses.ntfy = { - host = "ntfy.kun.is"; - - service = { - name = "ntfy"; - portName = "web"; - }; - }; - - longhorn.persistentVolumeClaim.data = { - volumeName = "ntfy"; - storage = "300Mi"; - }; - }; -} diff --git a/kubenix-modules/paperless.nix b/kubenix-modules/paperless.nix deleted file mode 100644 index eaa8f47..0000000 --- a/kubenix-modules/paperless.nix +++ /dev/null @@ -1,236 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets = { - database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/paperless/databasePassword"; - server.stringData.secretKey = "ref+sops://secrets/kubernetes.yaml#/paperless/secretKey"; - }; - - deployments = { - server.spec = { - selector.matchLabels = { - app = "paperless"; - component = "web"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "paperless"; - component = "web"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "data"; - - containers.paperless = { - image = myLib.globals.images.paperless; - imagePullPolicy = "IfNotPresent"; - ports.web.containerPort = 8000; - - env = { - PAPERLESS_REDIS.value = "redis://redis.paperless.svc.cluster.local:6379"; - PAPERLESS_DBENGINE.value = "postgresql"; - PAPERLESS_DBHOST.value = "database.paperless.svc.cluster.local"; - PAPERLESS_DBNAME.value = "paperless"; - PAPERLESS_DBUSER.value = "paperless"; - PAPERLESS_DATA_DIR.value = "/data/"; - PAPERLESS_MEDIA_ROOT.value = "/data/"; - PAPERLESS_OCR_LANGUAGES.value = "nld eng"; - PAPERLESS_URL.value = "https://paperless.griffin-mermaid.ts.net"; - PAPERLESS_TIME_ZONE.value = "Europe/Amsterdam"; - PAPERLESS_OCR_LANGUAGE.value = "nld"; - USERMAP_UID.value = "33"; - USERMAP_GID.value = "33"; - - PAPERLESS_DBPASS.valueFrom.secretKeyRef = { - name = "database"; - key = "password"; - }; - - PAPERLESS_SECRET_KEY.valueFrom.secretKeyRef = { - name = "server"; - key = "secretKey"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; - }; - - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - redis.spec = { - selector.matchLabels = { - app = "paperless"; - component = "redis"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "paperless"; - component = "redis"; - }; - - spec = { - volumes.data.persistentVolumeClaim.claimName = "redisdata"; - - containers.redis = { - image = myLib.globals.images.redis7; - ports.redis.containerPort = 6379; - imagePullPolicy = "IfNotPresent"; - - volumeMounts = [{ - name = "data"; - mountPath = "/data"; - }]; - }; - - securityContext = { - fsGroup = 999; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - database.spec = { - selector.matchLabels = { - app = "paperless"; - component = "database"; - }; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels = { - app = "paperless"; - component = "database"; - }; - - spec = { - containers.postgres = { - image = myLib.globals.images.postgres15; - ports.postgres.containerPort = 5432; - imagePullPolicy = "IfNotPresent"; - - env = { - POSTGRES_DB.value = "paperless"; - POSTGRES_USER.value = "paperless"; - PGDATA.value = "/pgdata/data"; - - POSTGRES_PASSWORD.valueFrom.secretKeyRef = { - name = "database"; - key = "password"; - }; - }; - - volumeMounts = [{ - name = "data"; - mountPath = "/pgdata"; - }]; - }; - - volumes.data.persistentVolumeClaim.claimName = "database"; - }; - }; - }; - }; - - services = { - web.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.paperlessIPv4; - - selector = { - app = "paperless"; - component = "web"; - }; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - redis.spec = { - selector = { - app = "paperless"; - component = "redis"; - }; - - ports.redis = { - port = 6379; - targetPort = "redis"; - }; - }; - - database.spec = { - selector = { - app = "paperless"; - component = "database"; - }; - - ports.postgres = { - port = 5432; - targetPort = "postgres"; - }; - }; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "paperless"; - service.name = "web"; - }; - - longhorn.persistentVolumeClaim = { - data = { - volumeName = "paperless-data"; - storage = "10Gi"; - }; - - redisdata = { - volumeName = "paperless-redisdata"; - storage = "20Mi"; - }; - - database = { - volumeName = "paperless-db"; - storage = "150Mi"; - }; - }; - }; -} diff --git a/kubenix-modules/pihole.nix b/kubenix-modules/pihole.nix deleted file mode 100644 index 0139b6f..0000000 --- a/kubenix-modules/pihole.nix +++ /dev/null @@ -1,108 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - secrets.pihole.stringData.webPassword = "ref+sops://secrets/kubernetes.yaml#/pihole/password"; - - deployments.pihole.spec = { - selector.matchLabels.app = "pihole"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "pihole"; - - spec = { - containers.pihole = { - image = myLib.globals.images.pihole; - - env = { - TZ.value = "Europe/Amsterdam"; - PIHOLE_DNS_.value = "192.168.30.1"; - - WEBPASSWORD.valueFrom.secretKeyRef = { - name = "pihole"; - key = "webPassword"; - }; - }; - - ports = { - web.containerPort = 80; - - dns = { - containerPort = 53; - protocol = "UDP"; - }; - }; - - volumeMounts = [ - { - name = "data"; - mountPath = "/etc/pihole"; - } - { - name = "dnsmasq"; - mountPath = "/etc/dnsmasq.d"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "pihole-data"; - dnsmasq.persistentVolumeClaim.claimName = "pihole-dnsmasq"; - }; - - securityContext = { - fsGroup = 1000; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - services = { - pihole.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.piholeIPv4; - selector.app = "pihole"; - - ports = { - dns = { - protocol = "UDP"; - port = 53; - targetPort = "dns"; - }; - - web = { - port = 80; - targetPort = "web"; - }; - }; - }; - }; - }; - - lab = { - longhorn.persistentVolumeClaim = { - pihole-data = { - volumeName = "pihole-data"; - storage = "750Mi"; - }; - - pihole-dnsmasq = { - volumeName = "pihole-dnsmasq"; - storage = "16Mi"; - }; - }; - - tailscaleIngresses.tailscale-pihole = { - host = "pihole"; - service.name = "pihole"; - }; - }; -} diff --git a/kubenix-modules/radicale.nix b/kubenix-modules/radicale.nix deleted file mode 100644 index 9e8701d..0000000 --- a/kubenix-modules/radicale.nix +++ /dev/null @@ -1,111 +0,0 @@ -{ lib, myLib, ... }: { - kubernetes.resources = { - configMaps.server.data = { - users = "pim:$apr1$GUiTihkS$dDCkaUxFx/O86m6NCy/yQ."; - - config = lib.generators.toINI { } { - server = { - hosts = "0.0.0.0:5232, [::]:5232"; - ssl = false; - }; - - encoding = { - request = "utf-8"; - stock = "utf-8"; - }; - - auth = { - realm = "Radicale - Password Required"; - type = "htpasswd"; - htpasswd_filename = "/config/users"; - htpasswd_encryption = "md5"; - }; - - rights.type = "owner_only"; - - storage = { - type = "multifilesystem"; - filesystem_folder = "/data"; - }; - - logging = { }; - headers = { }; - }; - }; - - deployments.server.spec = { - selector.matchLabels.app = "radicale"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "radicale"; - - spec = { - containers.radicale = { - image = myLib.globals.images.radicale; - ports.web.containerPort = 5232; - imagePullPolicy = "IfNotPresent"; - - volumeMounts = [ - { - name = "data"; - mountPath = "/data"; - } - { - name = "config"; - mountPath = "/config/config"; - subPath = "config"; - } - { - name = "config"; - mountPath = "/config/users"; - subPath = "users"; - } - ]; - }; - - volumes = { - data.persistentVolumeClaim.claimName = "data"; - config.configMap.name = "server"; - }; - - securityContext = { - fsGroup = 2999; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - services.server.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.radicaleIPv4; - selector.app = "radicale"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - }; - - lab = { - tailscaleIngresses.tailscale = { - host = "radicale"; - service.name = "server"; - }; - - longhorn.persistentVolumeClaim.data = { - volumeName = "radicale"; - storage = "200Mi"; - }; - }; -} diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix deleted file mode 100644 index f68841e..0000000 --- a/kubenix-modules/syncthing.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ myLib, ... }: { - kubernetes.resources = { - serviceAccounts.syncthing = { }; - - deployments.syncthing.spec = { - selector.matchLabels.app = "syncthing"; - - strategy = { - type = "RollingUpdate"; - - rollingUpdate = { - maxSurge = 0; - maxUnavailable = 1; - }; - }; - - template = { - metadata.labels.app = "syncthing"; - - spec = { - serviceAccountName = "syncthing"; - - containers.syncthing = { - image = myLib.globals.images.syncthing; - ports.web.containerPort = 8384; - imagePullPolicy = "IfNotPresent"; - - env = { - PUID.value = "33"; - PGID.value = "33"; - TZ.value = "Europe/Amsterdam"; - }; - - volumeMounts = [ - { - name = "config"; - mountPath = "/config"; - } - { - name = "music"; - mountPath = "/music"; - } - ]; - }; - - volumes = { - config.persistentVolumeClaim.claimName = "config"; - music.persistentVolumeClaim.claimName = "music"; - }; - - securityContext = { - fsGroup = 33; - fsGroupChangePolicy = "OnRootMismatch"; - }; - }; - }; - }; - - services.syncthing.spec = { - type = "LoadBalancer"; - loadBalancerIP = myLib.globals.syncthingIPv4; - selector.app = "syncthing"; - - ports.web = { - port = 80; - targetPort = "web"; - }; - }; - - persistentVolumeClaims.music.spec = { - accessModes = [ "ReadWriteMany" ]; - storageClassName = ""; - resources.requests.storage = "1Mi"; - volumeName = "music-syncthing"; - }; - }; - - lab = { - longhorn.persistentVolumeClaim.config = { - volumeName = "syncthing"; - storage = "400Mi"; - }; - - tailscaleIngresses.tailscale = { - host = "syncthing"; - service.name = "syncthing"; - }; - }; -} diff --git a/kubenix-modules/tailscale.nix b/kubenix-modules/tailscale.nix deleted file mode 100644 index 6181417..0000000 --- a/kubenix-modules/tailscale.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ nixhelm, system, ... }: { - kubernetes = { - helm.releases.tailscale = { - chart = nixhelm.chartsDerivations.${system}.tailscale.tailscale-operator; - includeCRDs = true; - namespace = "tailscale"; - }; - - resources.secrets.operator-oauth.stringData = { - client_id = "ref+sops://secrets/kubernetes.yaml#/tailscale/clientID"; - client_secret = "ref+sops://secrets/kubernetes.yaml#/tailscale/clientSecret"; - }; - }; -} diff --git a/kubenix-modules/traefik.nix b/kubenix-modules/traefik.nix deleted file mode 100644 index e2d476b..0000000 --- a/kubenix-modules/traefik.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ lib, myLib, ... }: { - kubernetes.resources = { - helmChartConfigs = { - traefik = { - # Override Traefik's service with a static load balancer IP. - # Create endpoint for HTTPS on port 444. - # Allow external name services for servers in LAN. - spec.valuesContent = lib.generators.toYAML { } { - providers.kubernetesIngress.allowExternalNameServices = true; - service.loadBalancerIP = myLib.globals.traefikIPv4; - - ports = { - localsecure = { - port = 8444; - expose = true; - exposedPort = 444; - protocol = "TCP"; - - tls = { - enabled = true; - options = ""; - certResolver = ""; - domains = [ ]; - }; - }; - - web.redirectTo.port = "websecure"; - }; - }; - }; - }; - - services = { - esrom.spec = { - type = "ExternalName"; - externalName = "esrom.dmz"; - - ports.web = { - port = 80; - targetPort = 80; - }; - }; - - traefik-dashboard.spec = { - selector = { - "app.kubernetes.io/name" = "traefik"; - "app.kubernetes.io/instance" = "traefik-kube-system"; - }; - - ports.web = { - port = 80; - targetPort = "traefik"; - }; - }; - }; - }; - - lab = { - ingresses.esrom = { - host = "esrom.kun.is"; - - service = { - name = "esrom"; - portName = "web"; - }; - }; - - tailscaleIngresses.traefik-dashboard = { - host = "traefik"; - service.name = "traefik-dashboard"; - }; - }; -} diff --git a/machines/atlas.nix b/machines/atlas.nix deleted file mode 100644 index a6bf86f..0000000 --- a/machines/atlas.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - machines.atlas = { - arch = "x86_64-linux"; - kubernetesNodeLabels.storageType = "slow"; - - nixosModule.lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; - - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; - }; - }; - }; -} diff --git a/machines/default.nix b/machines/default.nix deleted file mode 100644 index f815d11..0000000 --- a/machines/default.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ lib, ... }: -let - machineOpts = { config, ... }: { - options = { - arch = lib.mkOption { - default = null; - type = with lib.types; nullOr str; - description = '' - CPU architecture of this machine. - ''; - }; - - isRaspberryPi = lib.mkOption { - default = false; - type = lib.types.bool; - }; - - nixosModule = lib.mkOption { - default = { ... }: { }; - type = lib.types.anything; - description = '' - Customized configuration for this machine in the form of a NixOS module. - ''; - }; - - kubernetesNodeLabels = lib.mkOption { - default = null; - type = with lib.types; nullOr attrs; - description = '' - Any labels to add to the Kubernetes node. - ''; - }; - }; - }; -in -{ - imports = [ - ./warwick.nix - ./atlas.nix - ./jefke.nix - ./lewis.nix - # ./talos.nix - # ./pikvm.nix - ]; - - options = { - machines = lib.mkOption { - type = with lib.types; attrsOf (submodule machineOpts); - }; - }; -} diff --git a/machines/jefke.nix b/machines/jefke.nix deleted file mode 100644 index 096be8c..0000000 --- a/machines/jefke.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - machines.jefke = { - arch = "x86_64-linux"; - kubernetesNodeLabels.storageType = "fast"; - - nixosModule.lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; - - k3s = { - enable = true; - clusterInit = true; - }; - }; - }; -} diff --git a/machines/lewis.nix b/machines/lewis.nix deleted file mode 100644 index 5350142..0000000 --- a/machines/lewis.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ - machines.lewis = { - arch = "x86_64-linux"; - kubernetesNodeLabels = { - storageType = "fast"; - hasMedia = "true"; - }; - - nixosModule = { - lab = { - storage.profile = "kubernetes"; - backups.enable = true; - data-sharing.enable = true; - tailscale.enable = true; - - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; - }; - }; - }; - }; -} diff --git a/machines/pikvm.nix b/machines/pikvm.nix deleted file mode 100644 index 6a7bc14..0000000 --- a/machines/pikvm.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ - machines.pikvm = { - arch = "aarch64-linux"; - isRaspberryPi = true; - - nixosModule = { config, inputs, lib, ... }: { - # imports = [ "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" ]; - lab = { - storage.profile = "pi"; - }; - - environment.systemPackages = with inputs.nixpkgs.legacyPackages.aarch64-linux; [ - (mplayer.override { - v4lSupport = true; - }) - ffmpeg - v4l-utils - ]; - - boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; - }; - }; -} diff --git a/machines/talos.nix b/machines/talos.nix deleted file mode 100644 index 0fa0311..0000000 --- a/machines/talos.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - machines.talos = { - arch = "x86_64-linux"; - - nixosModule = { lib, ... }: { - lab.storage.profile = "normal"; - - # boot.loader.systemd-boot.enable = lib.mkForce false; - }; - }; -} diff --git a/machines/warwick.nix b/machines/warwick.nix deleted file mode 100644 index f000881..0000000 --- a/machines/warwick.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - machines.warwick = { - arch = "aarch64-linux"; - isRaspberryPi = true; - - nixosModule = { lib, ... }: { - lab = { - storage.profile = "pi"; - monitoring.server.enable = true; - - tailscale = { - advertiseExitNode = true; - enable = true; - }; - }; - }; - }; -} diff --git a/nixos-modules/k3s/default.nix b/nixos-modules/k3s/default.nix index 773fb98..a5249a8 100644 --- a/nixos-modules/k3s/default.nix +++ b/nixos-modules/k3s/default.nix @@ -1,4 +1,4 @@ -{ self, myLib, inputs, pkgs, lib, config, ... }: +{ self, inputs, pkgs, lib, config, ... }: let cfg = config.lab.k3s; in @@ -170,8 +170,8 @@ in imageDefs = import "${self}/container-images.nix"; setupCommands = [ - "rm -rf ${myLib.globals.imageDir}" - "mkdir -p ${myLib.globals.imageDir}" + "rm -rf ${self.globals.imageDir}" + "mkdir -p ${self.globals.imageDir}" ]; getDockerImageConfig = dockerImage: @@ -195,7 +195,7 @@ in fromImage = dockerImage; config = getDockerImageConfig dockerImage; }; - imageLinkPath = "${myLib.globals.imageDir}/${name}.tar"; + imageLinkPath = "${self.globals.imageDir}/${name}.tar"; in "ln -sf ${nixSnapshotterImage} ${imageLinkPath}"; diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml deleted file mode 100644 index e38b0d3..0000000 --- a/secrets/kubernetes.yaml +++ /dev/null @@ -1,60 +0,0 @@ -freshrss: - password: ENC[AES256_GCM,data:LDLp7cEToWA7zpd5UK+eBUHDaSEtNpFjI7C0LRE+72n0Vu1saPOdSQ==,iv:OEJDcFZwxGJ9vVD1lH7QY5Ue4Kfmx37v9kSEbI0YvRI=,tag:gIyquRc9t+GOOre8MKWxHQ==,type:str] -pihole: - password: ENC[AES256_GCM,data:yqPpovQKmP7NgUMI3w1p8t7RjbxNsMMHZbsNEaleyLJTqnDzNqONsQ==,iv:i+ys/EZelT4a4Sr0RpDto8udk/9yYC6pzl3FiUZQxrQ=,tag:FlvbMN6fuo+VV50YyuMeGg==,type:str] -hedgedoc: - databaseURL: ENC[AES256_GCM,data:VVz5meJM/SWC9+gWvorSj4ymLRux0vQPbI0kQLFrUGz2bocaRFzDqHAKbF4sd5iSzc6y5LQqwUfOgNoVrKhIROzKxStOmaQAWTLAJvfdReAqQoEaLVuLcZeML9QIhqvdAvPV5kVMznJ1u5YczSA=,iv:wU/GrAYSF2y0JWl0Nz6UuYmII0kCPIZ+UfAGI/1mUsE=,tag:xVOUwd5T6VHZ7vrpj9FMxg==,type:str] - sessionSecret: ENC[AES256_GCM,data:FhYr4rFNHmtk9jUcjM4UthepS/5Z4x7WPAE5lTB94WmHrALbzZl2M3JcmibR6/z1FtAJhCsaPZ7Xeg8nOZtU2g==,iv:7soqcd8A+yNfXEZg0qDjOZgfsUIFHfflxByuf7nZk3Y=,tag:x/rmaXo4nTdA080Zl/0MiQ==,type:str] - databasePassword: ENC[AES256_GCM,data:Fv1qeGvXZ93KvdFCCz9t9Dzhe7wKGOfR0lj64lzRM3s48E5FYdrH0w==,iv:cqhIOUKiSSkBpf95Eza9C9l8PX6YmTBpvBAR4+ibgeA=,tag:r8ZvF6l8oNeOt3d5UCA7Ww==,type:str] -nextcloud: - databasePassword: ENC[AES256_GCM,data:Xz0zUpu/W12Io1LSh5CLvGkq1X6yQErz4kdCdTyNZTw=,iv:OkY1fGzHmmbO9u+e9yNlLjJf8dqQtePTj9ifaDBFJ4g=,tag:S8/z9HJTPCZo43wAB5fWpA==,type:str] -paperless: - databasePassword: ENC[AES256_GCM,data:eF4+lxuTnvm+NYwZiU1VFp8Y2JQ=,iv:c36Rk2pEkiqXkLngpyZNulObxek+evvfeugYiBYJrBo=,tag:T0uArgOkJYCvCgmdJauhIg==,type:str] - secretKey: ENC[AES256_GCM,data:ByJpX/tIyzb4fewUOI9MwFBVHkc=,iv:08GvsSOI1OkckH01nzmsyhGoQYl82vyWIDEjrNUQUgk=,tag:YgVY0C7XmlQYw+Aup5LIPw==,type:str] -kitchenowl: - jwtSecretKey: ENC[AES256_GCM,data:9TyqeYlfhvhVg4WOn++/wrqguTM=,iv:+EgGaZxeI+npq5VAX7MHRDYQm8uRcKa8+u2wkn/dwr4=,tag:ATIuPdZQwuDQ+R8nVWWWIA==,type:str] -forgejo: - lfsJwtSecret: ENC[AES256_GCM,data:VWyUDUKZ6km0YPZLejnISBI3wkmOi26CS55NZm+eWbiymGDN9Z9xUQ4FTA==,iv:gGhNGtEEOJnsmq9GMIAImkVOPWMwYq+kDQeWoHVU860=,tag:63z/7PJKI0ePXbJ94radpw==,type:str] - internalToken: ENC[AES256_GCM,data:nKLE/Ir8Ewm3GuRzUNZZTShnMMx6avxYu40PvMEti14Be0YmQhJ0IZruRdpktyW1Jj4n5ksXhk+qsO/vEIzQaJmPU1RxN6vsGGk6EBIwMP0kuUNmp25lPefafoJvxoQpXdJvkLy8f8MC,iv:dUki8hCTOF1O5fmwDqZAkaE1OCH3IL/SFPBDSJ/GMiU=,tag:HUpkVqJg53H8uEmHFqJ7+w==,type:str] - jwtSecret: ENC[AES256_GCM,data:ZIGOR53XCE1kGPQIpaY6ImbLMISbTpmC8R1oRFbjQGxHDG9dQuBigyjs5w==,iv:14WHd/RwniA7+YFGGrs+oyHx5Cc9G+D/IV9aBqn3KOI=,tag:+3LiFnV3Emx4i4efSRmthw==,type:str] -attic: - jwtToken: ENC[AES256_GCM,data:nAuryLY1xD9ur3qDcsJXPJPLFcPwssPKv+/BoivZ4aO6ec6rmOaYAkSRsBjgANyKhssbn0fhGsdyhMBwdHTXDnnIo67amFdxxSe+jJlGtcBXcekaOfD0Ug==,iv:h+h7CD8oI8u2ItzD/KKM16FKaG2xuVqIKh4r1TGjYtw=,tag:Er141FCK8usfzRRtrawHOw==,type:str] - databaseURL: ENC[AES256_GCM,data:caKIXEAOIqWl1tjZItabbdYjotKjMwrPYJKR8mj/Zs0LkrUhOzOlyybNIhHAR/5rqHZlAhimVnVIxh/95g6AJOCNNukbForHUbj/PxkVUG8E,iv:9uh9FyN7n7M+FMLe5G/Z3NmbCgqc3t2SRocc4xL/Qbc=,tag:4JAb3qJUMIkBrAIAuKhjWQ==,type:str] - databasePassword: ENC[AES256_GCM,data:Zwv5DKkihOUU/yL1tvbZl1+bPtI=,iv:C+6n6RHo1zTUJ/g0DWCWNxtLbusoYmDHMySsea5Jpz0=,tag:+pyw0WqnX5rMQxSl/48L5A==,type:str] -atuin: - databaseURL: ENC[AES256_GCM,data:IBmND/J2Pzz+CDCeNBRtErxSQIi8PeUuLGN4rIXKSLwZ6TGJKcNmbuxQDvWkCnI1crx3oak=,iv:wc3G/00oIuaiGF4mA2vIm35wFGxT0a3Ox3k1C9YBAx4=,tag:MQPcsR+vrD85DttYYi6jUw==,type:str] - databasePassword: ENC[AES256_GCM,data:qfWOmFfBOuguOfb1Z51F527ic3o=,iv:4Yx5rpzZHzRlfvZydcBNFRStEO0P4uIcjDqxgRgQmHE=,tag:pbJXcUdvul7nCrXQ9ylAdQ==,type:str] -immich: - databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] -tailscale: - clientID: ENC[AES256_GCM,data:p5gGizzxAsRpW/a9GAkFZnc=,iv:DBJbEy2GbYUxvsY1MlvlVsLR+/DH/FYlQJIyxbt457c=,tag:Glm3/25WLO1VwKHWCm8wMw==,type:str] - clientSecret: ENC[AES256_GCM,data:/rB7WGmo0uyszwtMR1yAFzJ8F8USw1P7Cx5rKwOWXxPFTWZ88EaKOnDcDo5mwJVpe4OobGe+L83qwkq4lOPi,iv:QZ0dBSyYaWMD9+c2Mgmel2/3warW1f2fmeijm/HMTOE=,tag:VUxij/19MVpPhQ3SK4vvHw==,type:str] -sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] - age: - - recipient: age189laethzry4ylnd790dmpuc4xjjuwqxruc76caj3ceqhqug4g9qs0upuvw - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuYnNhbmtEQlpEYUV6Vklo - S1NKZkJ0ZGhOdHA3Y1lmUUUzTzh2Q1IxSUNnClZLdnJtUGNZTVUxZ0ozd1FDT0tL - VVhhcVJEaThjNWlUMGlxcG5VOVMwYjQKLS0tIGhJdHBVdnpZNzE0QmdRQzViVGpM - UGI4V2U1Ri9md3RHUVpvbFdtQ0NCNDQKl5QEg2FTMz6oTPF5s8pItduVJLPyLben - B/7KYQd6blJfM7mhF6eUQ61AWehvtzUhIPf57ZhFjpKj+Vzho4Bumw== - -----END AGE ENCRYPTED FILE----- - - recipient: age159whjxeyw94xmkkephmtlur8e85xd9d5vnvkwkcayfv7el0neqfq863yga - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2ckF3dzArMTBrYnNjZmJo - MzV5NDJoNWpEQmo2TXFzUmdQUUlpa1dIblNZCkhGSklTYVdCa1hJOUoyeDUyc29L - Q05DVEY4M2QxOThXNTJjcTBWNkRQVHMKLS0tIHdyVS9zR1VzQzdTUXJFSlFObWpT - aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP - Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-21T17:48:17Z" - mac: ENC[AES256_GCM,data:iseLH9pFaZ65lwf0wT386TN/ysscGBuSrJ+8aYI+3YzxHzPjcySaTcnvZ9gBB5ZF8tD15CkwlegNl7P2atx0jvigpKouE1n6Xvv2gKHjDvtqF/gCpdu1EmQOC/krfhRVJm0CtYTGKM7OHjb+dxuwrfeyiftjkXnNsgnl4sg57jM=,iv:QdrzTIRFZgCPSrIKiczLKgXMvd1QoPztYFowj/5GHtc=,tag:gUgzbV4yrstl+caasAlzAg==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.8.1 From 6dd363a2a8d58fb6bd7baf9740eb18d40a3f803b Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 7 Sep 2024 13:59:04 +0200 Subject: [PATCH 081/108] Restructure and clean up code --- flake-parts/checks.nix => checks.nix | 0 flake-parts/deploy.nix => deploy.nix | 0 flake-parts/applyset-deploy.sh | 7 - flake.nix | 14 +- {flake-parts/machines => machines}/atlas.nix | 0 .../machines => machines}/default.nix | 0 {flake-parts/machines => machines}/jefke.nix | 0 {flake-parts/machines => machines}/lewis.nix | 0 {flake-parts/machines => machines}/pikvm.nix | 0 {flake-parts/machines => machines}/talos.nix | 0 .../machines => machines}/warwick.nix | 0 {nixos-modules => modules}/backups.nix | 0 {nixos-modules => modules}/data-sharing.nix | 0 configuration.nix => modules/default.nix | 12 +- {nixos-modules => modules}/k3s/bootstrap.nix | 0 {nixos-modules => modules}/k3s/default.nix | 0 .../k3s/k3s-ca/client-ca.crt | 0 .../k3s/k3s-ca/etcd/peer-ca.crt | 0 .../k3s/k3s-ca/etcd/server-ca.crt | 0 .../k3s/k3s-ca/request-header-ca.crt | 0 .../k3s/k3s-ca/server-ca.crt | 0 .../monitoring/default.nix | 0 .../networking/default.nix | 0 {nixos-modules => modules}/storage.nix | 0 {nixos-modules => modules}/tailscale.nix | 0 my-lib/default.nix | 6 - my-lib/globals.nix | 65 - my-lib/net.nix | 1323 ----------------- nixos-modules/default.nix | 11 - flake-parts/nixos.nix => nixos.nix | 2 +- {flake-parts/scripts => scripts}/bootstrap.sh | 0 {flake-parts/scripts => scripts}/default.nix | 0 .../scripts => scripts}/gen-k3s-cert.sh | 0 flake-parts/shell.nix => shell.nix | 0 {flake-parts/utils => utils}/default.nix | 0 {flake-parts/utils => utils}/globals.nix | 0 {flake-parts/utils => utils}/net.nix | 0 37 files changed, 17 insertions(+), 1423 deletions(-) rename flake-parts/checks.nix => checks.nix (100%) rename flake-parts/deploy.nix => deploy.nix (100%) delete mode 100755 flake-parts/applyset-deploy.sh rename {flake-parts/machines => machines}/atlas.nix (100%) rename {flake-parts/machines => machines}/default.nix (100%) rename {flake-parts/machines => machines}/jefke.nix (100%) rename {flake-parts/machines => machines}/lewis.nix (100%) rename {flake-parts/machines => machines}/pikvm.nix (100%) rename {flake-parts/machines => machines}/talos.nix (100%) rename {flake-parts/machines => machines}/warwick.nix (100%) rename {nixos-modules => modules}/backups.nix (100%) rename {nixos-modules => modules}/data-sharing.nix (100%) rename configuration.nix => modules/default.nix (93%) rename {nixos-modules => modules}/k3s/bootstrap.nix (100%) rename {nixos-modules => modules}/k3s/default.nix (100%) rename {nixos-modules => modules}/k3s/k3s-ca/client-ca.crt (100%) rename {nixos-modules => modules}/k3s/k3s-ca/etcd/peer-ca.crt (100%) rename {nixos-modules => modules}/k3s/k3s-ca/etcd/server-ca.crt (100%) rename {nixos-modules => modules}/k3s/k3s-ca/request-header-ca.crt (100%) rename {nixos-modules => modules}/k3s/k3s-ca/server-ca.crt (100%) rename {nixos-modules => modules}/monitoring/default.nix (100%) rename {nixos-modules => modules}/networking/default.nix (100%) rename {nixos-modules => modules}/storage.nix (100%) rename {nixos-modules => modules}/tailscale.nix (100%) delete mode 100644 my-lib/default.nix delete mode 100644 my-lib/globals.nix delete mode 100644 my-lib/net.nix delete mode 100644 nixos-modules/default.nix rename flake-parts/nixos.nix => nixos.nix (93%) rename {flake-parts/scripts => scripts}/bootstrap.sh (100%) rename {flake-parts/scripts => scripts}/default.nix (100%) rename {flake-parts/scripts => scripts}/gen-k3s-cert.sh (100%) rename flake-parts/shell.nix => shell.nix (100%) rename {flake-parts/utils => utils}/default.nix (100%) rename {flake-parts/utils => utils}/globals.nix (100%) rename {flake-parts/utils => utils}/net.nix (100%) diff --git a/flake-parts/checks.nix b/checks.nix similarity index 100% rename from flake-parts/checks.nix rename to checks.nix diff --git a/flake-parts/deploy.nix b/deploy.nix similarity index 100% rename from flake-parts/deploy.nix rename to deploy.nix diff --git a/flake-parts/applyset-deploy.sh b/flake-parts/applyset-deploy.sh deleted file mode 100755 index d6cf7b9..0000000 --- a/flake-parts/applyset-deploy.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -IFS=$'\n\t' - -export KUBECTL_APPLYSET=true -vals eval -fail-on-missing-key-in-map <$MANIFEST | kubectl apply -f - --prune --applyset $APPLYSET --namespace $NAMESPACE diff --git a/flake.nix b/flake.nix index 1349edf..a321172 100644 --- a/flake.nix +++ b/flake.nix @@ -42,13 +42,13 @@ outputs = inputs@{ self, nixpkgs, flake-utils, ... }: flake-utils.lib.meld inputs [ - ./flake-parts/scripts - ./flake-parts/checks.nix - ./flake-parts/deploy.nix - ./flake-parts/nixos.nix - ./flake-parts/shell.nix - ./flake-parts/utils - ./flake-parts/machines + ./scripts + ./checks.nix + ./deploy.nix + ./nixos.nix + ./shell.nix + ./utils + ./machines ] // (flake-utils.lib.eachDefaultSystem (system: { formatter = nixpkgs.legacyPackages.${system}.nixfmt; })); diff --git a/flake-parts/machines/atlas.nix b/machines/atlas.nix similarity index 100% rename from flake-parts/machines/atlas.nix rename to machines/atlas.nix diff --git a/flake-parts/machines/default.nix b/machines/default.nix similarity index 100% rename from flake-parts/machines/default.nix rename to machines/default.nix diff --git a/flake-parts/machines/jefke.nix b/machines/jefke.nix similarity index 100% rename from flake-parts/machines/jefke.nix rename to machines/jefke.nix diff --git a/flake-parts/machines/lewis.nix b/machines/lewis.nix similarity index 100% rename from flake-parts/machines/lewis.nix rename to machines/lewis.nix diff --git a/flake-parts/machines/pikvm.nix b/machines/pikvm.nix similarity index 100% rename from flake-parts/machines/pikvm.nix rename to machines/pikvm.nix diff --git a/flake-parts/machines/talos.nix b/machines/talos.nix similarity index 100% rename from flake-parts/machines/talos.nix rename to machines/talos.nix diff --git a/flake-parts/machines/warwick.nix b/machines/warwick.nix similarity index 100% rename from flake-parts/machines/warwick.nix rename to machines/warwick.nix diff --git a/nixos-modules/backups.nix b/modules/backups.nix similarity index 100% rename from nixos-modules/backups.nix rename to modules/backups.nix diff --git a/nixos-modules/data-sharing.nix b/modules/data-sharing.nix similarity index 100% rename from nixos-modules/data-sharing.nix rename to modules/data-sharing.nix diff --git a/configuration.nix b/modules/default.nix similarity index 93% rename from configuration.nix rename to modules/default.nix index 2a5bf0d..a05a57f 100644 --- a/configuration.nix +++ b/modules/default.nix @@ -1,6 +1,12 @@ -{ pkgs, self, config, lib, inputs, machine, ... }: { +{ self, pkgs, config, lib, inputs, machine, ... }: { imports = [ - "${self}/nixos-modules" + ./storage.nix + ./backups.nix + ./networking + ./data-sharing.nix + ./monitoring + ./k3s + ./tailscale.nix machine.nixosModule inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops @@ -140,7 +146,7 @@ sops = { age.keyFile = "/root/.config/sops/age/keys.txt"; - defaultSopsFile = ./secrets/nixos.yaml; + defaultSopsFile = "${self}/secrets/nixos.yaml"; }; }; } diff --git a/nixos-modules/k3s/bootstrap.nix b/modules/k3s/bootstrap.nix similarity index 100% rename from nixos-modules/k3s/bootstrap.nix rename to modules/k3s/bootstrap.nix diff --git a/nixos-modules/k3s/default.nix b/modules/k3s/default.nix similarity index 100% rename from nixos-modules/k3s/default.nix rename to modules/k3s/default.nix diff --git a/nixos-modules/k3s/k3s-ca/client-ca.crt b/modules/k3s/k3s-ca/client-ca.crt similarity index 100% rename from nixos-modules/k3s/k3s-ca/client-ca.crt rename to modules/k3s/k3s-ca/client-ca.crt diff --git a/nixos-modules/k3s/k3s-ca/etcd/peer-ca.crt b/modules/k3s/k3s-ca/etcd/peer-ca.crt similarity index 100% rename from nixos-modules/k3s/k3s-ca/etcd/peer-ca.crt rename to modules/k3s/k3s-ca/etcd/peer-ca.crt diff --git a/nixos-modules/k3s/k3s-ca/etcd/server-ca.crt b/modules/k3s/k3s-ca/etcd/server-ca.crt similarity index 100% rename from nixos-modules/k3s/k3s-ca/etcd/server-ca.crt rename to modules/k3s/k3s-ca/etcd/server-ca.crt diff --git a/nixos-modules/k3s/k3s-ca/request-header-ca.crt b/modules/k3s/k3s-ca/request-header-ca.crt similarity index 100% rename from nixos-modules/k3s/k3s-ca/request-header-ca.crt rename to modules/k3s/k3s-ca/request-header-ca.crt diff --git a/nixos-modules/k3s/k3s-ca/server-ca.crt b/modules/k3s/k3s-ca/server-ca.crt similarity index 100% rename from nixos-modules/k3s/k3s-ca/server-ca.crt rename to modules/k3s/k3s-ca/server-ca.crt diff --git a/nixos-modules/monitoring/default.nix b/modules/monitoring/default.nix similarity index 100% rename from nixos-modules/monitoring/default.nix rename to modules/monitoring/default.nix diff --git a/nixos-modules/networking/default.nix b/modules/networking/default.nix similarity index 100% rename from nixos-modules/networking/default.nix rename to modules/networking/default.nix diff --git a/nixos-modules/storage.nix b/modules/storage.nix similarity index 100% rename from nixos-modules/storage.nix rename to modules/storage.nix diff --git a/nixos-modules/tailscale.nix b/modules/tailscale.nix similarity index 100% rename from nixos-modules/tailscale.nix rename to modules/tailscale.nix diff --git a/my-lib/default.nix b/my-lib/default.nix deleted file mode 100644 index 766186b..0000000 --- a/my-lib/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -lib: rec { - net = import ./net.nix lib; - globals = import ./globals.nix; - - imagePath = name: "nix:0${globals.imageDir}/${name}.tar"; -} diff --git a/my-lib/globals.nix b/my-lib/globals.nix deleted file mode 100644 index 38aadd5..0000000 --- a/my-lib/globals.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - routerPublicIPv4 = "192.145.57.90"; - routerPublicIPv6 = "2a0d:6e00:1a77::1"; - bind9Ipv6 = "2a0d:6e00:1a77:30::134"; - - # Load balancer IPv4 - traefikIPv4 = "192.168.30.128"; - kmsIPv4 = "192.168.30.129"; - inbucketIPv4 = "192.168.30.130"; - piholeIPv4 = "192.168.30.131"; - gitIPv4 = "192.168.30.132"; - transmissionIPv4 = "192.168.30.133"; - bind9IPv4 = "192.168.30.134"; - dnsmasqIPv4 = "192.168.30.135"; - minecraftIPv4 = "192.168.30.136"; - jellyseerrIPv4 = "192.168.30.137"; - syncthingIPv4 = "192.168.30.138"; - longhornIPv4 = "192.168.30.139"; - radarrIPv4 = "192.168.30.140"; - prowlarrIPv4 = "192.168.30.141"; - sonarrIPv4 = "192.168.30.142"; - bazarrIPv4 = "192.168.30.143"; - paperlessIPv4 = "192.168.30.144"; - radicaleIPv4 = "192.168.30.145"; - freshrssIPv4 = "192.168.30.146"; - immichIPv4 = "192.168.30.147"; - nextcloudIPv4 = "192.168.30.148"; - - imageDir = "/var/docker_images"; - - images = { - jellyfin = "jellyfin/jellyfin:10.9.9"; - deluge = "linuxserver/deluge:2.1.1"; - jellyseerr = "fallenbagel/jellyseerr:1.9.2"; - radarr = "lscr.io/linuxserver/radarr:5.9.1"; - prowlarr = "lscr.io/linuxserver/prowlarr:1.21.2"; - sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; - bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; - atuin = "ghcr.io/atuinsh/atuin:18.3.0"; - postgres14 = "postgres:14"; - kms = "teddysun/kms:latest"; - paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.6"; - redis7 = "docker.io/library/redis:7"; - nextcloud = "nextcloud:29.0.5"; - postgres15 = "postgres:15"; - inbucket = "inbucket/inbucket:edge"; - syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; - radicale = "tomsquest/docker-radicale:3.2.3.0"; - ntfy = "binwiederhier/ntfy:v2.11.0"; - forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; - pihole = "pihole/pihole:2024.07.0"; - immich = "ghcr.io/immich-app/immich-server:v1.114.0"; - immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.114.0"; - immich-redis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; - immich-postgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; - kitchenowl = "tombursch/kitchenowl:v0.5.2"; - cyberchef = "mpepping/cyberchef:latest"; - freshrss = "freshrss/freshrss:1.24.3"; - bind9 = "ubuntu/bind9:9.18-22.04_beta"; - dnsmasq = "dockurr/dnsmasq:2.90"; - attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; - hedgedoc = "quay.io/hedgedoc/hedgedoc:1.9.9"; - minecraft = "itzg/minecraft-server:latest"; - }; -} diff --git a/my-lib/net.nix b/my-lib/net.nix deleted file mode 100644 index 9f5b0e5..0000000 --- a/my-lib/net.nix +++ /dev/null @@ -1,1323 +0,0 @@ -# IP address arithmetic and validation in Nix by @duairc: -# https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba - -lib: - -let - - net = { - ip = { - - # add :: (ip | mac | integer) -> ip -> ip - # - # Examples: - # - # Adding integer to IPv4: - # > net.ip.add 100 "10.0.0.1" - # "10.0.0.101" - # - # Adding IPv4 to IPv4: - # > net.ip.add "127.0.0.1" "10.0.0.1" - # "137.0.0.2" - # - # Adding IPv6 to IPv4: - # > net.ip.add "::cafe:beef" "10.0.0.1" - # "212.254.186.191" - # - # Adding MAC to IPv4 (overflows): - # > net.ip.add "fe:ed:fa:ce:f0:0d" "10.0.0.1" - # "4.206.240.14" - # - # Adding integer to IPv6: - # > net.ip.add 100 "dead:cafe:beef::" - # "dead:cafe:beef::64" - # - # Adding IPv4 to to IPv6: - # > net.ip.add "127.0.0.1" "dead:cafe:beef::" - # "dead:cafe:beef::7f00:1" - # - # Adding MAC to IPv6: - # > net.ip.add "fe:ed:fa:ce:f0:0d" "dead:cafe:beef::" - # "dead:cafe:beef::feed:face:f00d" - add = delta: ip: - let - function = "net.ip.add"; - delta' = typechecks.numeric function "delta" delta; - ip' = typechecks.ip function "ip" ip; - in - builders.ip (implementations.ip.add delta' ip'); - - # diff :: ip -> ip -> (integer | ipv6) - # - # net.ip.diff is the reverse of net.ip.add: - # - # net.ip.diff (net.ip.add a b) a = b - # net.ip.diff (net.ip.add a b) b = a - # - # The difference between net.ip.diff and net.ip.subtract is that - # net.ip.diff will try its best to return an integer (falling back - # to an IPv6 if the result is too big to fit in an integer). This is - # useful if you have two hosts that you know are on the same network - # and you just want to calculate the offset between them — a result - # like "0.0.0.10" is not very useful (which is what you would get - # from net.ip.subtract). - diff = minuend: subtrahend: - let - function = "net.ip.diff"; - minuend' = typechecks.ip function "minuend" minuend; - subtrahend' = typechecks.ip function "subtrahend" subtrahend; - result = implementations.ip.diff minuend' subtrahend'; - in - if result ? ipv6 - then builders.ipv6 result - else result; - - # subtract :: (ip | mac | integer) -> ip -> ip - # - # net.ip.subtract is also the reverse of net.ip.add: - # - # net.ip.subtract a (net.ip.add a b) = b - # net.ip.subtract b (net.ip.add a b) = a - # - # The difference between net.ip.subtract and net.ip.diff is that - # net.ip.subtract will always return the same type as its "ip" - # parameter. Its implementation takes the "delta" parameter, - # coerces it to be the same type as the "ip" paramter, negates it - # (using two's complement), and then adds it to "ip". - subtract = delta: ip: - let - function = "net.ip.subtract"; - delta' = typechecks.numeric function "delta" delta; - ip' = typechecks.ip function "ip" ip; - in - builders.ip (implementations.ip.subtract delta' ip'); - }; - - mac = { - - # add :: (ip | mac | integer) -> mac -> mac - # - # Examples: - # - # Adding integer to MAC: - # > net.mac.add 100 "fe:ed:fa:ce:f0:0d" - # "fe:ed:fa:ce:f0:71" - # - # Adding IPv4 to MAC: - # > net.mac.add "127.0.0.1" "fe:ed:fa:ce:f0:0d" - # "fe:ee:79:ce:f0:0e" - # - # Adding IPv6 to MAC: - # > net.mac.add "::cafe:beef" "fe:ed:fa:ce:f0:0d" - # "fe:ee:c5:cd:aa:cb - # - # Adding MAC to MAC: - # > net.mac.add "fe:ed:fa:00:00:00" "00:00:00:ce:f0:0d" - # "fe:ed:fa:ce:f0:0d" - add = delta: mac: - let - function = "net.mac.add"; - delta' = typechecks.numeric function "delta" delta; - mac' = typechecks.mac function "mac" mac; - in - builders.mac (implementations.mac.add delta' mac'); - - # diff :: mac -> mac -> integer - # - # net.mac.diff is the reverse of net.mac.add: - # - # net.mac.diff (net.mac.add a b) a = b - # net.mac.diff (net.mac.add a b) b = a - # - # The difference between net.mac.diff and net.mac.subtract is that - # net.mac.diff will always return an integer. - diff = minuend: subtrahend: - let - function = "net.mac.diff"; - minuend' = typechecks.mac function "minuend" minuend; - subtrahend' = typechecks.mac function "subtrahend" subtrahend; - in - implementations.mac.diff minuend' subtrahend'; - - # subtract :: (ip | mac | integer) -> mac -> mac - # - # net.mac.subtract is also the reverse of net.ip.add: - # - # net.mac.subtract a (net.mac.add a b) = b - # net.mac.subtract b (net.mac.add a b) = a - # - # The difference between net.mac.subtract and net.mac.diff is that - # net.mac.subtract will always return a MAC address. - subtract = delta: mac: - let - function = "net.mac.subtract"; - delta' = typechecks.numeric function "delta" delta; - mac' = typechecks.mac function "mac" mac; - in - builders.mac (implementations.mac.subtract delta' mac'); - }; - - cidr = { - # add :: (ip | mac | integer) -> cidr -> cidr - # - # > net.cidr.add 2 "127.0.0.0/8" - # "129.0.0.0/8" - # - # > net.cidr.add (-2) "127.0.0.0/8" - # "125.0.0.0/8" - add = delta: cidr: - let - function = "net.cidr.add"; - delta' = typechecks.numeric function "delta" delta; - cidr' = typechecks.cidr function "cidr" cidr; - in - builders.cidr (implementations.cidr.add delta' cidr'); - - # child :: cidr -> cidr -> bool - # - # > net.cidr.child "10.10.10.0/24" "10.0.0.0/8" - # true - # - # > net.cidr.child "127.0.0.0/8" "10.0.0.0/8" - # false - child = subcidr: cidr: - let - function = "net.cidr.child"; - subcidr' = typechecks.cidr function "subcidr" subcidr; - cidr' = typechecks.cidr function "cidr" cidr; - in - implementations.cidr.child subcidr' cidr'; - - # contains :: ip -> cidr -> bool - # - # > net.cidr.contains "127.0.0.1" "127.0.0.0/8" - # true - # - # > net.cidr.contains "127.0.0.1" "192.168.0.0/16" - # false - contains = ip: cidr: - let - function = "net.cidr.contains"; - ip' = typechecks.ip function "ip" ip; - cidr' = typechecks.cidr function "cidr" cidr; - in - implementations.cidr.contains ip' cidr'; - - # capacity :: cidr -> integer - # - # > net.cidr.capacity "172.16.0.0/12" - # 1048576 - # - # > net.cidr.capacity "dead:cafe:beef::/96" - # 4294967296 - # - # > net.cidr.capacity "dead:cafe:beef::/48" (saturates to maxBound) - # 9223372036854775807 - capacity = cidr: - let - function = "net.cidr.capacity"; - cidr' = typechecks.cidr function "cidr" cidr; - in - implementations.cidr.capacity cidr'; - - # host :: (ip | mac | integer) -> cidr -> ip - # - # > net.cidr.host 10000 "10.0.0.0/8" - # 10.0.39.16 - # - # > net.cidr.host 10000 "dead:cafe:beef::/64" - # "dead:cafe:beef::2710" - # - # net.cidr.host "127.0.0.1" "dead:cafe:beef::/48" - # > "dead:cafe:beef::7f00:1" - # - # Inpsired by: - # https://www.terraform.io/docs/configuration/functions/cidrhost.html - host = hostnum: cidr: - let - function = "net.cidr.host"; - hostnum' = typechecks.numeric function "hostnum" hostnum; - cidr' = typechecks.cidr function "cidr" cidr; - in - builders.ip (implementations.cidr.host hostnum' cidr'); - - # length :: cidr -> integer - # - # > net.cidr.prefix "127.0.0.0/8" - # 8 - # - # > net.cidr.prefix "dead:cafe:beef::/48" - # 48 - length = cidr: - let - function = "net.cidr.length"; - cidr' = typechecks.cidr function "cidr" cidr; - in - implementations.cidr.length cidr'; - - # make :: integer -> ip -> cidr - # - # > net.cidr.make 24 "192.168.0.150" - # "192.168.0.0/24" - # - # > net.cidr.make 40 "dead:cafe:beef::feed:face:f00d" - # "dead:cafe:be00::/40" - make = length: base: - let - function = "net.cidr.make"; - length' = typechecks.int function "length" length; - base' = typechecks.ip function "base" base; - in - builders.cidr (implementations.cidr.make length' base'); - - # netmask :: cidr -> ip - # - # > net.cidr.netmask "192.168.0.0/24" - # "255.255.255.0" - # - # > net.cidr.netmask "dead:cafe:beef::/64" - # "ffff:ffff:ffff:ffff::" - netmask = cidr: - let - function = "net.cidr.netmask"; - cidr' = typechecks.cidr function "cidr" cidr; - in - builders.ip (implementations.cidr.netmask cidr'); - - # size :: cidr -> integer - # - # > net.cidr.prefix "127.0.0.0/8" - # 24 - # - # > net.cidr.prefix "dead:cafe:beef::/48" - # 80 - size = cidr: - let - function = "net.cidr.size"; - cidr' = typechecks.cidr function "cidr" cidr; - in - implementations.cidr.size cidr'; - - # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr - # - # > net.cidr.subnet 4 2 "172.16.0.0/12" - # "172.18.0.0/16" - # - # > net.cidr.subnet 4 15 "10.1.2.0/24" - # "10.1.2.240/28" - # - # > net.cidr.subnet 16 162 "fd00:fd12:3456:7890::/56" - # "fd00:fd12:3456:7800:a200::/72" - # - # Inspired by: - # https://www.terraform.io/docs/configuration/functions/cidrsubnet.html - subnet = length: netnum: cidr: - let - function = "net.cidr.subnet"; - length' = typechecks.int function "length" length; - netnum' = typechecks.numeric function "netnum" netnum; - cidr' = typechecks.cidr function "cidr" cidr; - in - builders.cidr (implementations.cidr.subnet length' netnum' cidr'); - - }; - } // ({ - types = - let - - mkParsedOptionType = { name, description, parser, builder }: - let - normalize = def: def // { - value = builder (parser def.value); - }; - in - lib.mkOptionType { - inherit name description; - check = x: builtins.isString x && parser x != null; - merge = loc: defs: lib.mergeEqualOption loc (map normalize defs); - }; - - dependent-ip = type: cidr: - let - cidrs = - if builtins.isList cidr - then cidr - else [ cidr ]; - in - lib.types.addCheck type (i: lib.any (net.cidr.contains i) cidrs) // { - description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; - }; - - dependent-cidr = type: cidr: - let - cidrs = - if builtins.isList cidr - then cidr - else [ cidr ]; - in - lib.types.addCheck type (i: lib.any (net.cidr.child i) cidrs) // { - description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; - }; - - in - rec { - - ip = mkParsedOptionType { - name = "ip"; - description = "IPv4 or IPv6 address"; - parser = parsers.ip; - builder = builders.ip; - }; - - ip-in = dependent-ip ip; - - ipv4 = mkParsedOptionType { - name = "ipv4"; - description = "IPv4 address"; - parser = parsers.ipv4; - builder = builders.ipv4; - }; - - ipv4-in = dependent-ip ipv4; - - ipv6 = mkParsedOptionType { - name = "ipv6"; - description = "IPv6 address"; - parser = parsers.ipv6; - builder = builders.ipv6; - }; - - ipv6-in = dependent-ip ipv6; - - cidr = mkParsedOptionType { - name = "cidr"; - description = "IPv4 or IPv6 address range in CIDR notation"; - parser = parsers.cidr; - builder = builders.cidr; - }; - - cidr-in = dependent-cidr cidr; - - cidrv4 = mkParsedOptionType { - name = "cidrv4"; - description = "IPv4 address range in CIDR notation"; - parser = parsers.cidrv4; - builder = builders.cidrv4; - }; - - cidrv4-in = dependent-cidr cidrv4; - - cidrv6 = mkParsedOptionType { - name = "cidrv6"; - description = "IPv6 address range in CIDR notation"; - parser = parsers.cidrv6; - builder = builders.cidrv6; - }; - - cidrv6-in = dependent-cidr cidrv6; - - mac = mkParsedOptionType { - name = "mac"; - description = "MAC address"; - parser = parsers.mac; - builder = builders.mac; - }; - - }; - } - ); - - list = { - cons = a: b: [ a ] ++ b; - }; - - bit = - let - shift = n: x: - if n < 0 - then x * math.pow 2 (-n) - else - let - safeDiv = n: d: if d == 0 then 0 else n / d; - d = math.pow 2 n; - in - if x < 0 - then not (safeDiv (not x) d) - else safeDiv x d; - - left = n: shift (-n); - - right = shift; - - and = builtins.bitAnd; - - or = builtins.bitOr; - - xor = builtins.bitXor; - - not = xor (-1); - - mask = n: and (left n 1 - 1); - in - { - inherit left right and or xor not mask; - }; - - math = rec { - max = a: b: - if a > b - then a - else b; - - min = a: b: - if a < b - then a - else b; - - clamp = a: b: c: max a (min b c); - - pow = x: n: - if n == 0 - then 1 - else if bit.and n 1 != 0 - then x * pow (x * x) ((n - 1) / 2) - else pow (x * x) (n / 2); - }; - - parsers = - let - - # fmap :: (a -> b) -> parser a -> parser b - fmap = f: ma: bind ma (a: pure (f a)); - - # pure :: a -> parser a - pure = a: string: { - leftovers = string; - result = a; - }; - - # liftA2 :: (a -> b -> c) -> parser a -> parser b -> parser c - liftA2 = f: ma: mb: bind ma (a: bind mb (b: pure (f a b))); - liftA3 = f: a: b: ap (liftA2 f a b); - liftA4 = f: a: b: c: ap (liftA3 f a b c); - liftA5 = f: a: b: c: d: ap (liftA4 f a b c d); - liftA6 = f: a: b: c: d: e: ap (liftA5 f a b c d e); - - # ap :: parser (a -> b) -> parser a -> parser b - ap = liftA2 (a: a); - - # then_ :: parser a -> parser b -> parser b - then_ = liftA2 (a: b: b); - - # empty :: parser a - empty = string: null; - - # alt :: parser a -> parser a -> parser a - alt = left: right: string: - let - result = left string; - in - if builtins.isNull result - then right string - else result; - - # guard :: bool -> parser {} - guard = condition: if condition then pure { } else empty; - - # mfilter :: (a -> bool) -> parser a -> parser a - mfilter = f: parser: bind parser (a: then_ (guard (f a)) (pure a)); - - # some :: parser a -> parser [a] - some = v: liftA2 list.cons v (many v); - - # many :: parser a -> parser [a] - many = v: alt (some v) (pure [ ]); - - # bind :: parser a -> (a -> parser b) -> parser b - bind = parser: f: string: - let - a = parser string; - in - if builtins.isNull a - then null - else f a.result a.leftovers; - - # run :: parser a -> string -> maybe a - run = parser: string: - let - result = parser string; - in - if builtins.isNull result || result.leftovers != "" - then null - else result.result; - - next = string: - if string == "" - then null - else { - leftovers = builtins.substring 1 (-1) string; - result = builtins.substring 0 1 string; - }; - - # Count how many characters were consumed by a parser - count = parser: string: - let - result = parser string; - in - if builtins.isNull result - then null - else result // { - result = { - inherit (result) result; - count = with result; - builtins.stringLength string - builtins.stringLength leftovers; - }; - }; - - # Limit the parser to n characters at most - limit = n: parser: - fmap (a: a.result) (mfilter (a: a.count <= n) (count parser)); - - # Ensure the parser consumes exactly n characters - exactly = n: parser: - fmap (a: a.result) (mfilter (a: a.count == n) (count parser)); - - char = c: bind next (c': guard (c == c')); - - string = css: - if css == "" - then pure { } - else - let - c = builtins.substring 0 1 css; - cs = builtins.substring 1 (-1) css; - in - then_ (char c) (string cs); - - digit = set: bind next ( - c: then_ - (guard (builtins.hasAttr c set)) - (pure (builtins.getAttr c set)) - ); - - decimalDigits = { - "0" = 0; - "1" = 1; - "2" = 2; - "3" = 3; - "4" = 4; - "5" = 5; - "6" = 6; - "7" = 7; - "8" = 8; - "9" = 9; - }; - - hexadecimalDigits = decimalDigits // { - "a" = 10; - "b" = 11; - "c" = 12; - "d" = 13; - "e" = 14; - "f" = 15; - "A" = 10; - "B" = 11; - "C" = 12; - "D" = 13; - "E" = 14; - "F" = 15; - }; - - fromDecimalDigits = builtins.foldl' (a: c: a * 10 + c) 0; - fromHexadecimalDigits = builtins.foldl' (a: bit.or (bit.left 4 a)) 0; - - # disallow leading zeros - decimal = bind (digit decimalDigits) ( - n: - if n == 0 - then pure 0 - else - fmap - (ns: fromDecimalDigits (list.cons n ns)) - (many (digit decimalDigits)) - ); - - hexadecimal = fmap fromHexadecimalDigits (some (digit hexadecimalDigits)); - - ipv4 = - let - dot = char "."; - - octet = mfilter (n: n < 256) decimal; - - octet' = then_ dot octet; - - fromOctets = a: b: c: d: { - ipv4 = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d; - }; - in - liftA4 fromOctets octet octet' octet' octet'; - - # This is more or less a literal translation of - # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#parser - ipv6 = - let - colon = char ":"; - - hextet = limit 4 hexadecimal; - - fromHextets = hextets: - if builtins.length hextets != 8 - then empty - else - let - a = builtins.elemAt hextets 0; - b = builtins.elemAt hextets 1; - c = builtins.elemAt hextets 2; - d = builtins.elemAt hextets 3; - e = builtins.elemAt hextets 4; - f = builtins.elemAt hextets 5; - g = builtins.elemAt hextets 6; - h = builtins.elemAt hextets 7; - in - pure { - ipv6 = { - a = bit.or (bit.left 16 a) b; - b = bit.or (bit.left 16 c) d; - c = bit.or (bit.left 16 e) f; - d = bit.or (bit.left 16 g) h; - }; - }; - - ipv4' = fmap - ( - address: - let - upper = bit.right 16 address.ipv4; - lower = bit.mask 16 address.ipv4; - in - [ upper lower ] - ) - ipv4; - - part = n: - let - n' = n + 1; - hex = liftA2 list.cons hextet - ( - then_ colon - ( - alt - (then_ colon (doubleColon n')) - (part n') - ) - ); - in - if n == 7 - then fmap (a: [ a ]) hextet - else - if n == 6 - then alt ipv4' hex - else hex; - - doubleColon = n: - bind (alt afterDoubleColon (pure [ ])) ( - rest: - let - missing = 8 - n - builtins.length rest; - in - if missing < 0 - then empty - else pure (builtins.genList (_: 0) missing ++ rest) - ); - - afterDoubleColon = - alt ipv4' - ( - liftA2 list.cons hextet - ( - alt - (then_ colon afterDoubleColon) - (pure [ ]) - ) - ); - - in - bind - ( - alt - ( - then_ - (string "::") - (doubleColon 0) - ) - (part 0) - ) - fromHextets; - - cidrv4 = - liftA2 - (base: length: implementations.cidr.make length base) - ipv4 - (then_ (char "/") (mfilter (n: n <= 32) decimal)); - - cidrv6 = - liftA2 - (base: length: implementations.cidr.make length base) - ipv6 - (then_ (char "/") (mfilter (n: n <= 128) decimal)); - - mac = - let - colon = char ":"; - - octet = exactly 2 hexadecimal; - - octet' = then_ colon octet; - - fromOctets = a: b: c: d: e: f: { - mac = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d)) e)) f; - }; - in - liftA6 fromOctets octet octet' octet' octet' octet' octet'; - - in - { - ipv4 = run ipv4; - ipv6 = run ipv6; - ip = run (alt ipv4 ipv6); - cidrv4 = run cidrv4; - cidrv6 = run cidrv6; - cidr = run (alt cidrv4 cidrv6); - mac = run mac; - numeric = run (alt (alt ipv4 ipv6) mac); - }; - - builders = - let - - ipv4 = address: - let - abcd = address.ipv4; - abc = bit.right 8 abcd; - ab = bit.right 8 abc; - a = bit.right 8 ab; - b = bit.mask 8 ab; - c = bit.mask 8 abc; - d = bit.mask 8 abcd; - in - builtins.concatStringsSep "." (map toString [ a b c d ]); - - # This is more or less a literal translation of - # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#encode - ipv6 = address: - let - - digits = "0123456789abcdef"; - - toHexString = n: - let - rest = bit.right 4 n; - current = bit.mask 4 n; - prefix = - if rest == 0 - then "" - else toHexString rest; - in - "${prefix}${builtins.substring current 1 digits}"; - - in - if (with address.ipv6; a == 0 && b == 0 && c == 0 && d > 65535) - then "::${ipv4 { ipv4 = address.ipv6.d; }}" - else - if (with address.ipv6; a == 0 && b == 0 && c == 65535) - then "::ffff:${ipv4 { ipv4 = address.ipv6.d; }}" - else - let - - a = bit.right 16 address.ipv6.a; - b = bit.mask 16 address.ipv6.a; - c = bit.right 16 address.ipv6.b; - d = bit.mask 16 address.ipv6.b; - e = bit.right 16 address.ipv6.c; - f = bit.mask 16 address.ipv6.c; - g = bit.right 16 address.ipv6.d; - h = bit.mask 16 address.ipv6.d; - - hextets = [ a b c d e f g h ]; - - # calculate the position and size of the longest sequence of - # zeroes within the list of hextets - longest = - let - go = i: current: best: - if i < builtins.length hextets - then - let - n = builtins.elemAt hextets i; - - current' = - if n == 0 - then - if builtins.isNull current - then { - size = 1; - position = i; - } - else current // { - size = current.size + 1; - } - else null; - - best' = - if n == 0 - then - if builtins.isNull best - then current' - else - if current'.size > best.size - then current' - else best - else best; - in - go (i + 1) current' best' - else best; - in - go 0 null null; - - format = hextets: - builtins.concatStringsSep ":" (map toHexString hextets); - in - if builtins.isNull longest - then format hextets - else - let - sublist = i: length: xs: - map - (builtins.elemAt xs) - (builtins.genList (x: x + i) length); - - end = longest.position + longest.size; - - before = sublist 0 longest.position hextets; - - after = sublist end (builtins.length hextets - end) hextets; - in - "${format before}::${format after}"; - - ip = address: - if address ? ipv4 - then ipv4 address - else ipv6 address; - - cidrv4 = cidr: - "${ipv4 cidr.base}/${toString cidr.length}"; - - cidrv6 = cidr: - "${ipv6 cidr.base}/${toString cidr.length}"; - - cidr = cidr: - "${ip cidr.base}/${toString cidr.length}"; - - mac = address: - let - digits = "0123456789abcdef"; - octet = n: - let - upper = bit.right 4 n; - lower = bit.mask 4 n; - in - "${builtins.substring upper 1 digits}${builtins.substring lower 1 digits}"; - in - let - a = bit.mask 8 (bit.right 40 address.mac); - b = bit.mask 8 (bit.right 32 address.mac); - c = bit.mask 8 (bit.right 24 address.mac); - d = bit.mask 8 (bit.right 16 address.mac); - e = bit.mask 8 (bit.right 8 address.mac); - f = bit.mask 8 (bit.right 0 address.mac); - in - "${octet a}:${octet b}:${octet c}:${octet d}:${octet e}:${octet f}"; - - in - { - inherit ipv4 ipv6 ip cidrv4 cidrv6 cidr mac; - }; - - arithmetic = rec { - # or :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - or = a_: b: - let - a = coerce b a_; - in - if a ? ipv6 - then { - ipv6 = { - a = bit.or a.ipv6.a b.ipv6.a; - b = bit.or a.ipv6.b b.ipv6.b; - c = bit.or a.ipv6.c b.ipv6.c; - d = bit.or a.ipv6.d b.ipv6.d; - }; - } - else if a ? ipv4 - then { - ipv4 = bit.or a.ipv4 b.ipv4; - } - else if a ? mac - then { - mac = bit.or a.mac b.mac; - } - else bit.or a b; - - # and :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - and = a_: b: - let - a = coerce b a_; - in - if a ? ipv6 - then { - ipv6 = { - a = bit.and a.ipv6.a b.ipv6.a; - b = bit.and a.ipv6.b b.ipv6.b; - c = bit.and a.ipv6.c b.ipv6.c; - d = bit.and a.ipv6.d b.ipv6.d; - }; - } - else if a ? ipv4 - then { - ipv4 = bit.and a.ipv4 b.ipv4; - } - else if a ? mac - then { - mac = bit.and a.mac b.mac; - } - else bit.and a b; - - # not :: (ip | mac | integer) -> (ip | mac | integer) - not = a: - if a ? ipv6 - then { - ipv6 = { - a = bit.mask 32 (bit.not a.ipv6.a); - b = bit.mask 32 (bit.not a.ipv6.b); - c = bit.mask 32 (bit.not a.ipv6.c); - d = bit.mask 32 (bit.not a.ipv6.d); - }; - } - else if a ? ipv4 - then { - ipv4 = bit.mask 32 (bit.not a.ipv4); - } - else if a ? mac - then { - mac = bit.mask 48 (bit.not a.mac); - } - else bit.not a; - - # add :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - add = - let - split = a: { - fst = bit.mask 32 (bit.right 32 a); - snd = bit.mask 32 a; - }; - in - a_: b: - let - a = coerce b a_; - in - if a ? ipv6 - then - let - a' = split (a.ipv6.a + b.ipv6.a + b'.fst); - b' = split (a.ipv6.b + b.ipv6.b + c'.fst); - c' = split (a.ipv6.c + b.ipv6.c + d'.fst); - d' = split (a.ipv6.d + b.ipv6.d); - in - { - ipv6 = { - a = a'.snd; - b = b'.snd; - c = c'.snd; - d = d'.snd; - }; - } - else if a ? ipv4 - then { - ipv4 = bit.mask 32 (a.ipv4 + b.ipv4); - } - else if a ? mac - then { - mac = bit.mask 48 (a.mac + b.mac); - } - else a + b; - - # subtract :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - subtract = a: b: add (add 1 (not (coerce b a))) b; - - # diff :: (ip | mac | integer) -> (ip | mac | integer) -> (ipv6 | integer) - diff = a: b: - let - toIPv6 = coerce ({ ipv6.a = 0; }); - result = (subtract b (toIPv6 a)).ipv6; - max32 = bit.left 32 1 - 1; - in - if result.a == 0 && result.b == 0 && bit.right 31 result.c == 0 || result.a == max32 && result.b == max32 && bit.right 31 result.c == 1 - then bit.or (bit.left 32 result.c) result.d - else { - ipv6 = result; - }; - - # left :: integer -> (ip | mac | integer) -> (ip | mac | integer) - left = i: right (-i); - - # right :: integer -> (ip | mac | integer) -> (ip | mac | integer) - right = - let - step = i: x: { - _1 = bit.mask 32 (bit.right (i + 96) x); - _2 = bit.mask 32 (bit.right (i + 64) x); - _3 = bit.mask 32 (bit.right (i + 32) x); - _4 = bit.mask 32 (bit.right i x); - _5 = bit.mask 32 (bit.right (i - 32) x); - _6 = bit.mask 32 (bit.right (i - 64) x); - _7 = bit.mask 32 (bit.right (i - 96) x); - }; - ors = builtins.foldl' bit.or 0; - in - i: x: - if x ? ipv6 - then - let - a' = step i x.ipv6.a; - b' = step i x.ipv6.b; - c' = step i x.ipv6.c; - d' = step i x.ipv6.d; - in - { - ipv6 = { - a = ors [ a'._4 b'._3 c'._2 d'._1 ]; - b = ors [ a'._5 b'._4 c'._3 d'._2 ]; - c = ors [ a'._6 b'._5 c'._4 d'._3 ]; - d = ors [ a'._7 b'._6 c'._5 d'._4 ]; - }; - } - else if x ? ipv4 - then { - ipv4 = bit.mask 32 (bit.right i x.ipv4); - } - else if x ? mac - then { - mac = bit.mask 48 (bit.right i x.mac); - } - else bit.right i x; - - # shadow :: integer -> (ip | mac | integer) -> (ip | mac | integer) - shadow = n: a: and (right n (left n (coerce a (-1)))) a; - - # coshadow :: integer -> (ip | mac | integer) -> (ip | mac | integer) - coshadow = n: a: and (not (right n (left n (coerce a (-1))))) a; - - # coerce :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - coerce = target: value: - if target ? ipv6 - then - if value ? ipv6 - then value - else if value ? ipv4 - then { - ipv6 = { - a = 0; - b = 0; - c = 0; - d = value.ipv4; - }; - } - else if value ? mac - then { - ipv6 = { - a = 0; - b = 0; - c = bit.right 32 value.mac; - d = bit.mask 32 value.mac; - }; - } - else { - ipv6 = { - a = bit.mask 32 (bit.right 96 value); - b = bit.mask 32 (bit.right 64 value); - c = bit.mask 32 (bit.right 32 value); - d = bit.mask 32 value; - }; - } - else if target ? ipv4 - then - if value ? ipv6 - then { - ipv4 = value.ipv6.d; - } - else if value ? ipv4 - then value - else if value ? mac - then { - ipv4 = bit.mask 32 value.mac; - } - else { - ipv4 = bit.mask 32 value; - } - else if target ? mac - then - if value ? ipv6 - then { - mac = bit.or (bit.left 32 (bit.mask 16 value.ipv6.c)) value.ipv6.d; - } - else if value ? ipv4 - then { - mac = value.ipv4; - } - else if value ? mac - then value - else { - mac = bit.mask 48 value; - } - else - if value ? ipv6 - then - builtins.foldl' bit.or 0 - [ - (bit.left 96 value.ipv6.a) - (bit.left 64 value.ipv6.b) - (bit.left 32 value.ipv6.c) - value.ipv6.d - ] - else if value ? ipv4 - then value.ipv4 - else if value ? mac - then value.mac - else value; - }; - - implementations = { - ip = { - # add :: (ip | mac | integer) -> ip -> ip - add = arithmetic.add; - - # diff :: ip -> ip -> (ipv6 | integer) - diff = arithmetic.diff; - - # subtract :: (ip | mac | integer) -> ip -> ip - subtract = arithmetic.subtract; - }; - - mac = { - # add :: (ip | mac | integer) -> mac -> mac - add = arithmetic.add; - - # diff :: mac -> mac -> (ipv6 | integer) - diff = arithmetic.diff; - - # subtract :: (ip | mac | integer) -> mac -> mac - subtract = arithmetic.subtract; - }; - - cidr = rec { - # add :: (ip | mac | integer) -> cidr -> cidr - add = delta: cidr: - let - size' = size cidr; - in - { - base = arithmetic.left size' (arithmetic.add delta (arithmetic.right size' cidr.base)); - inherit (cidr) length; - }; - - # capacity :: cidr -> integer - capacity = cidr: - let - size' = size cidr; - in - if size' > 62 - then 9223372036854775807 # maxBound to prevent overflow - else bit.left size' 1; - - # child :: cidr -> cidr -> bool - child = subcidr: cidr: - length subcidr > length cidr && contains (host 0 subcidr) cidr; - - # contains :: ip -> cidr -> bool - contains = ip: cidr: host 0 (make cidr.length ip) == host 0 cidr; - - # host :: (ip | mac | integer) -> cidr -> ip - host = index: cidr: - let - index' = arithmetic.coerce cidr.base index; - in - arithmetic.or (arithmetic.shadow cidr.length index') cidr.base; - - # length :: cidr -> integer - length = cidr: cidr.length; - - # netmask :: cidr -> ip - netmask = cidr: arithmetic.coshadow cidr.length (arithmetic.coerce cidr.base (-1)); - - # size :: cidr -> integer - size = cidr: (if cidr.base ? ipv6 then 128 else 32) - cidr.length; - - # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr - subnet = length: index: cidr: - let - length' = cidr.length + length; - index' = arithmetic.coerce cidr.base index; - size = (if cidr.base ? ipv6 then 128 else 32) - length'; - in - make length' (host (arithmetic.left size index') cidr); - - # make :: integer -> ip -> cidr - make = length: base: - let - length' = math.clamp 0 (if base ? ipv6 then 128 else 32) length; - in - { - base = arithmetic.coshadow length' base; - length = length'; - }; - }; - }; - - typechecks = - let - - fail = description: function: argument: - builtins.throw "${function}: ${argument} parameter must be ${description}"; - - meta = parser: description: function: argument: input: - let - error = fail description function argument; - in - if !builtins.isString input - then error - else - let - result = parser input; - in - if builtins.isNull result - then error - else result; - - in - { - int = function: argument: input: - if builtins.isInt input - then input - else fail "an integer" function argument; - ip = meta parsers.ip "an IPv4 or IPv6 address"; - cidr = meta parsers.cidr "an IPv4 or IPv6 address range in CIDR notation"; - mac = meta parsers.mac "a MAC address"; - numeric = function: argument: input: - if builtins.isInt input - then input - else meta parsers.numeric "an integer or IPv4, IPv6 or MAC address" function argument input; - }; - -in -net diff --git a/nixos-modules/default.nix b/nixos-modules/default.nix deleted file mode 100644 index 4ee9a8b..0000000 --- a/nixos-modules/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - imports = [ - ./storage.nix - ./backups.nix - ./networking - ./data-sharing.nix - ./monitoring - ./k3s - ./tailscale.nix - ]; -} diff --git a/flake-parts/nixos.nix b/nixos.nix similarity index 93% rename from flake-parts/nixos.nix rename to nixos.nix index 38afa07..21c0023 100644 --- a/flake-parts/nixos.nix +++ b/nixos.nix @@ -16,7 +16,7 @@ in specialArgs = { inherit self inputs machine machines; }; modules = [ - "${self}/configuration.nix" + "${self}/modules" { networking.hostName = name; } ]; }); diff --git a/flake-parts/scripts/bootstrap.sh b/scripts/bootstrap.sh similarity index 100% rename from flake-parts/scripts/bootstrap.sh rename to scripts/bootstrap.sh diff --git a/flake-parts/scripts/default.nix b/scripts/default.nix similarity index 100% rename from flake-parts/scripts/default.nix rename to scripts/default.nix diff --git a/flake-parts/scripts/gen-k3s-cert.sh b/scripts/gen-k3s-cert.sh similarity index 100% rename from flake-parts/scripts/gen-k3s-cert.sh rename to scripts/gen-k3s-cert.sh diff --git a/flake-parts/shell.nix b/shell.nix similarity index 100% rename from flake-parts/shell.nix rename to shell.nix diff --git a/flake-parts/utils/default.nix b/utils/default.nix similarity index 100% rename from flake-parts/utils/default.nix rename to utils/default.nix diff --git a/flake-parts/utils/globals.nix b/utils/globals.nix similarity index 100% rename from flake-parts/utils/globals.nix rename to utils/globals.nix diff --git a/flake-parts/utils/net.nix b/utils/net.nix similarity index 100% rename from flake-parts/utils/net.nix rename to utils/net.nix From 8744db7f1fa984c8d8ff1f71c69ead6ebb9d7608 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 7 Sep 2024 14:01:00 +0200 Subject: [PATCH 082/108] Rename pikvm ansible playbook --- ansible/{main.yml => pikvm.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ansible/{main.yml => pikvm.yml} (100%) diff --git a/ansible/main.yml b/ansible/pikvm.yml similarity index 100% rename from ansible/main.yml rename to ansible/pikvm.yml From ad4d78ed2a8272e6474f4ed04c42ef75bd27da8b Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 7 Sep 2024 21:58:27 +0200 Subject: [PATCH 083/108] Move more stuff to kubernetes-deployments Remove kubernetes stuff from readme --- README.md | 36 ++--------------- docs/longhorn.md | 75 ----------------------------------- docs/media.md | 11 ------ flake.nix | 2 +- scripts/default.nix | 6 --- scripts/gen-k3s-cert.sh | 88 ----------------------------------------- 6 files changed, 4 insertions(+), 214 deletions(-) delete mode 100644 docs/longhorn.md delete mode 100644 docs/media.md delete mode 100644 scripts/gen-k3s-cert.sh diff --git a/README.md b/README.md index 141eb2c..d18af32 100644 --- a/README.md +++ b/README.md @@ -9,18 +9,14 @@ Nix definitions to configure our servers at home. - [dns.nix](https://github.com/kirelagin/dns.nix): A Nix DSL for defining DNS zones - [flake-utils](https://github.com/numtide/flake-utils): Handy utilities to develop Nix flakes - [nixos-hardware](https://github.com/NixOS/nixos-hardware): Hardware-specific NixOS modules. Doing the heavy lifting for our Raspberry Pi -- [kubenix](https://kubenix.org/): declare and deploy Kubernetes resources using Nix -- [nixhelm](https://github.com/farcaller/nixhelm): Nix-digestible Helm charts - [sops-nix](https://github.com/Mic92/sops-nix): Sops secret management for Nix -## NixOS - -### Prerequisites +## Prerequisites 1. Install the Nix package manager or NixOS ([link](https://nixos.org/download)) 2. Enable flake and nix commands ([link](https://nixos.wiki/wiki/Flakes#Enable_flakes_permanently_in_NixOS)) -### Bootstrapping +## Bootstrapping We bootstrap our servers using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere). This reformats the hard disk of the server and installs a fresh NixOS. @@ -32,37 +28,11 @@ Additionally, it deploys an age identity, which is later used for decrypting sec 2. Ensure you have root SSH access to the server. 3. Run nixos-anywhere: `nix run '.#bootstrap' ` -### Deployment +## Deployment To deploy all servers at once: `nix run 'nixpkgs#deploy-rs' -- '.#' -k` To deploy only one server: `nix run 'nixpkgs#deploy-rs' -- -k --targets '.#'` -## Kubernetes - -### Prerequisites - -To deploy to the Kubernetes cluster, first make sure you have an admin account on the cluster. -You can generate this using `nix run '.#gen-k3s-cert' ~/.kube`, assuming you have SSH access to the master node. -This puts a private key, signed certificate and a kubeconfig in the kubeconfig directory - -### Bootstrapping - -We are now ready to deploy to the Kubernetes cluster. -Deployments are done through an experimental Kubernetes feature called [ApplySets](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#how-to-delete-objects). -Each applyset is responsible for a set number of resources within a namespace. - -If the cluster has not been initialized yet, we must bootstrap it first. -Run these deployments: -- `nix run '.#bootstrap-default'` -- `nix run '.#bootstrap-kube-system'` - -### Deployment - -Now the cluster has been initialized and we can deploy applications. -To explore which applications we can deploy, run `nix flake show`. -Then, for each application, run `nix run '.#'`. -Or, if you're lazy: `nix flake show --json | jq -r '.packages."x86_64-linux"|keys[]' | grep -- -deploy | xargs -I{} nix run ".#{}"`. - ## Known bugs ### Rsync not available during bootstrap diff --git a/docs/longhorn.md b/docs/longhorn.md deleted file mode 100644 index 532a188..0000000 --- a/docs/longhorn.md +++ /dev/null @@ -1,75 +0,0 @@ -# Longhorn notes - -## Migration from NFS to Longhorn - -1. Delete the workload, and delete the PVC and PVC using NFS. -2. Create Longhorn volumes as described below. -3. Copy NFS data from lewis.dmz to local disk. -4. Spin up a temporary pod and mount the Longhorn volume(s) in it: - ```nix - { - pods.testje.spec = { - containers.testje = { - image = "nginx"; - - volumeMounts = [ - { - name = "uploads"; - mountPath = "/hedgedoc/public/uploads"; - } - ]; - }; - - volumes = { - uploads.persistentVolumeClaim.claimName = "hedgedoc-uploads"; - }; - }; - } - ``` -5. Use `kubectl cp` to copy the data from the local disk to the pod. -6. Delete the temporary pod. -7. Be sure to set the group ownership of the mount to the correct GID. -7. Create the workload with updated volume mounts. -8. Delete the data from local disk. - -## Creation of new Longhorn volumes - -While it seems handy to use a K8s StorageClass for Longhorn, we do *not* want to use that. -If you use a StorageClass, a PV and Longhorn volume will be automatically provisioned. -These will have the name `pvc-`, where the UID of the PVC is random. -This makes it hard to restore a backup to a Longhorn volume with the correct name. - -Instead, we want to manually create the Longhorn volumes via the web UI. -Then, we can create the PV and PVC as usual using our K8s provisioning tool (e.g. Kubectl/Kubenix). - -Follow these actions to create a Volume: -1. Using the Longhorn web UI, create a new Longhorn volume, keeping the following in mind: - - The size can be some more than what we expect to reasonable use. We use storage-overprovisioning, so the total size of volumes can exceed real disk size. - - The number of replicas should be 2. -2. Enable the "backup-nfs" recurring job for the Longhorn volume. -3. Disable the "default" recurring job group for the Longhorn volume. -4. Create the PV, PVC and workload as usual. - -## Disaster recovery using Longhorn backups - -Backing up Longhorn volumes is very easy, but restoring them is more tricky. -We consider here the case when all our machines are wiped, and all we have left is Longhorn backups. -To restore a backup, perform the following actions: -1. Restore the latest snapshot in the relevant Longhorn backup, keeping the following in mind: - - The name should remain the same (i.e. the one chosen at Longhorn volume creation). - - The number of replicas should be 2. - - Disable recurring jobs. -2. Enable the "backup-nfs" recurring job for the Longhorn volume. -3. Disable the "default" recurring job group for the Longhorn volume. -4. Create the PV, PVC and workload as usual. - -## Recovering Longhorn volumes without a Kubernetes cluster - -1. Navigate to the Longhorn backupstore location (`/mnt/longhorn/persistent/longhorn-backup/backupstore/volumes` for us). -2. Find the directory for the desired volume: `ls **/**`. -3. Determine the last backup for the volume: `cat volume.cfg | jq '.LastBackupName'`. -4. Find the blocks and the order that form the volume: `cat backups/.cfg | jq '.Blocks'`. -5. Extract each block using lz4: `lz4 -d blocks/XX/YY/XXYY.blk block`. -6. Append the blocks to form the file system: `cat block1 block2 block3 > volume.img` -7. Lastly we need to fix the size of the image. We can simply append zero's to the end until the file is long enough so `fsck.ext4` does not complain anymore. -8. Mount the image: `mount -o loop volume.img /mnt/volume`. diff --git a/docs/media.md b/docs/media.md deleted file mode 100644 index 34f0fc7..0000000 --- a/docs/media.md +++ /dev/null @@ -1,11 +0,0 @@ -# Media - -[profilarr](https://github.com/Dictionarry-Hub/profilarr) was used to import the "1080p Transparent" quality profile to both Radarr and Sonarr. -Profilarr has some neat tools that magically applies custom formats and quality definitions. -As far as I understand, these are used to indentify files that are high quality. -Profilarr can then also import a quality profile, which uses the aforementioned definitions to select torrents in my desired format. -In my case, I have chosen "1080p Transparent." -According to the [docs](https://selectarr.pages.dev/): -> Projected Size: 10 - 15gb -> -> Description: Prioritizes 1080p transparent releases. Lossy audio is allowed, and all upgrades are allowed. HDR is banned. diff --git a/flake.nix b/flake.nix index a321172..1d4652a 100644 --- a/flake.nix +++ b/flake.nix @@ -40,7 +40,7 @@ }; outputs = - inputs@{ self, nixpkgs, flake-utils, ... }: + inputs@{ nixpkgs, flake-utils, ... }: flake-utils.lib.meld inputs [ ./scripts ./checks.nix diff --git a/scripts/default.nix b/scripts/default.nix index fda7269..1a7401c 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -21,12 +21,6 @@ in scriptPath = ./bootstrap.sh; }; - packages.gen-k3s-cert = createScript { - name = "create-k3s-cert"; - runtimeInputs = with pkgs; [ openssl coreutils openssh yq ]; - scriptPath = ./gen-k3s-cert.sh; - }; - packages.prefetch-container-images = let imagesJSON = builtins.toFile "images.json" (builtins.toJSON self.globals.images); diff --git a/scripts/gen-k3s-cert.sh b/scripts/gen-k3s-cert.sh deleted file mode 100644 index 405f9f9..0000000 --- a/scripts/gen-k3s-cert.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -IFS=$'\n\t' - -username="${1-}" -host="${2-}" -output_path="${3:-.}" - -if [ -z "$username" ] || [ -z "$host" ] - then - echo "Usage: $0 USERNAME HOST [OUTPUTPATH]" - exit 1 -fi - -# Create a temporary directory -temp=$(mktemp -d) - -# Function to cleanup temporary directory on exit -cleanup() { - rm -rf "$temp" -} -trap cleanup EXIT - -echo Generating the private key -openssl genpkey -algorithm ed25519 -out "$temp/key.pem" - -echo Generating the certificate request -openssl req -new -key "$temp/key.pem" -out "$temp/req.csr" -subj "/CN=$username" - -echo Creating K8S CSR manifest -csr="$(cat "$temp/req.csr" | base64 | tr -d '\n')" -k8s_csr="apiVersion: certificates.k8s.io/v1 -kind: CertificateSigningRequest -metadata: - name: $username-csr -spec: - request: $csr - expirationSeconds: 307584000 # 10 years - signerName: kubernetes.io/kube-apiserver-client - usages: - - digital signature - - key encipherment - - client auth -" - -echo Creating K8S CSR resource -ssh "root@$host" "echo \"$k8s_csr\" | k3s kubectl apply -f -" - -echo Approving K8S CSR -ssh "root@$host" "k3s kubectl certificate approve $username-csr" - -echo Retrieving approved certificate -encoded_cert="$(ssh root@"$host" "k3s kubectl get csr $username-csr -o jsonpath='{.status.certificate}'")" - -echo Retrieving default K3S kubeconfig -base_kubeconfig="$(ssh root@"$host" "cat /etc/rancher/k3s/k3s.yaml")" - -echo Getting certificate authority data from default kubeconfig -cert_authority_data="$(echo -n "$base_kubeconfig" | yq -r '.clusters[0].cluster."certificate-authority-data"')" - -echo Generating final kubeconfig -result_kubeconfig="apiVersion: v1 -clusters: -- cluster: - certificate-authority-data: $cert_authority_data - server: https://$host:6443 - name: default -contexts: -- context: - cluster: default - user: $username - name: default -current-context: default -kind: Config -preferences: {} -users: -- name: $username - user: - client-certificate: $username.crt - client-key: $username.key -" - -echo Writing resulting files to "$output_path" -echo -n "$encoded_cert" | base64 -d > $output_path/$username.crt -echo -n "$result_kubeconfig" > $output_path/config -cp $temp/key.pem $output_path/$username.key - From 85cba9a3ffe6e274b5721b7221487bfe2b4bc0ce Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 17 Sep 2024 13:22:34 +0200 Subject: [PATCH 084/108] Deploy NixNG-built dnsmasq container image --- flake.lock | 99 ++++++++++++++++++++++++++++++++++++++++- flake.nix | 10 +++++ modules/k3s/default.nix | 27 ++++++++++- modules/k3s/dnsmasq.nix | 41 +++++++++++++++++ 4 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 modules/k3s/dnsmasq.nix diff --git a/flake.lock b/flake.lock index 9525357..5926008 100644 --- a/flake.lock +++ b/flake.lock @@ -78,6 +78,22 @@ } }, "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { "flake": false, "locked": { "lastModified": 1696426674, @@ -147,9 +163,32 @@ "type": "github" } }, - "nix-snapshotter": { + "kubenix": { "inputs": { "flake-compat": "flake-compat_2", + "nixpkgs": [ + "nixpkgs-unstable" + ], + "systems": "systems_3", + "treefmt": "treefmt" + }, + "locked": { + "lastModified": 1717788185, + "narHash": "sha256-Uc6QSQqJa2lyv/1W4StwoKrjtq7cFjlKNhdrtanToGo=", + "owner": "pizzapim", + "repo": "kubenix", + "rev": "a9590abe23a2f7577bc3271d90955e9ccc2923fe", + "type": "github" + }, + "original": { + "owner": "pizzapim", + "repo": "kubenix", + "type": "github" + } + }, + "nix-snapshotter": { + "inputs": { + "flake-compat": "flake-compat_3", "flake-parts": "flake-parts", "nixpkgs": [ "nixpkgs-unstable" @@ -169,6 +208,27 @@ "type": "github" } }, + "nixng": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1726571270, + "narHash": "sha256-LEug48WOL+mmFYtKM57e/oudgjBk2Km5zIP3p27hF8I=", + "owner": "pizzapim", + "repo": "NixNG", + "rev": "9538892da603608f0176d07d33b1265e038c0adf", + "type": "github" + }, + "original": { + "owner": "pizzapim", + "ref": "dnsmasq", + "repo": "NixNG", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1722332872, @@ -255,7 +315,9 @@ "disko": "disko", "dns": "dns", "flake-utils": "flake-utils_2", + "kubenix": "kubenix", "nix-snapshotter": "nix-snapshotter", + "nixng": "nixng", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", @@ -313,6 +375,41 @@ "type": "github" } }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "id": "systems", + "type": "indirect" + } + }, + "treefmt": { + "inputs": { + "nixpkgs": [ + "kubenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688026376, + "narHash": "sha256-qJmkr9BWDpqblk4E9/rCsAEl39y2n4Ycw6KRopvpUcY=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "df3f32b0cc253dfc7009b7317e8f0e7ccd70b1cf", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "utils": { "inputs": { "systems": "systems" diff --git a/flake.nix b/flake.nix index 1d4652a..6aa6909 100644 --- a/flake.nix +++ b/flake.nix @@ -37,6 +37,16 @@ url = "github:pdtpartners/nix-snapshotter"; inputs.nixpkgs.follows = "nixpkgs-unstable"; }; + + nixng = { + url = "github:pizzapim/NixNG/dnsmasq"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + kubenix = { + url = "github:pizzapim/kubenix"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; + }; }; outputs = diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index a5249a8..da524ff 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -1,4 +1,4 @@ -{ self, inputs, pkgs, lib, config, ... }: +{ self, inputs, pkgs, lib, config, globals, ... }: let cfg = config.lab.k3s; in @@ -165,6 +165,31 @@ in ''; }; + nixng = lib.mkIf (cfg.role == "server") + ( + let + dnsmasqStream = (import ./dnsmasq.nix { + inherit (inputs) nixpkgs nixng; + inherit (inputs.nixng) nglib; + inherit (self) globals; + }).config.system.build.ociImage.stream; + + dnsmasqImage = pkgs.stdenv.mkDerivation { + name = "dnsmasq.tar"; + src = dnsmasqStream; + dontUnpack = true; + buildPhase = '' + $src > $out + ''; + }; + in + { + text = '' + ln -sf ${dnsmasqImage} /root/dnsmasq.tar + ''; + } + ); + docker-images.text = let imageDefs = import "${self}/container-images.nix"; diff --git a/modules/k3s/dnsmasq.nix b/modules/k3s/dnsmasq.nix new file mode 100644 index 0000000..6fc8c4f --- /dev/null +++ b/modules/k3s/dnsmasq.nix @@ -0,0 +1,41 @@ +{ globals, nixpkgs, nglib, ... }: +nglib.makeSystem { + inherit nixpkgs; + system = "x86_64-linux"; + name = "nixng-dnsmasq"; + + config = { ... }: { + dumb-init = { + enable = true; + type.services = { }; + }; + + init.services.dnsmasq = { + shutdownOnExit = true; + }; + + services.dnsmasq = { + enable = true; + + settings = { + address = [ + "/kms.kun.is/${globals.kmsIPv4}" + "/ssh.git.kun.is/${globals.gitIPv4}" + ]; + + alias = "${globals.routerPublicIPv4},${globals.traefikIPv4}"; + expand-hosts = true; + local = "/dmz/"; + log-queries = true; + no-hosts = true; + no-resolv = true; + port = 53; + + server = [ + "192.168.30.1" + "/kun.is/${globals.bind9IPv4}" + ]; + }; + }; + }; +} From eb90e5d1bd3159df70fa1995372d073b7ff776b3 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 17 Sep 2024 14:19:44 +0200 Subject: [PATCH 085/108] Change location of dnsmasq image --- modules/k3s/default.nix | 4 +++- utils/globals.nix | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index da524ff..8c0cd55 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -185,7 +185,9 @@ in in { text = '' - ln -sf ${dnsmasqImage} /root/dnsmasq.tar + rm -rf ${self.globals.imageDir} + mkdir -p ${self.globals.imageDir} + ln -sf ${dnsmasqImage} ${self.globals.imageDir}/dnsmasq.tar ''; } ); diff --git a/utils/globals.nix b/utils/globals.nix index 38aadd5..02ba866 100644 --- a/utils/globals.nix +++ b/utils/globals.nix @@ -26,7 +26,7 @@ immichIPv4 = "192.168.30.147"; nextcloudIPv4 = "192.168.30.148"; - imageDir = "/var/docker_images"; + imageDir = "/var/container_images"; images = { jellyfin = "jellyfin/jellyfin:10.9.9"; From 553992ec2f36d1a4967377243b99d17654e5ce1a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 22 Sep 2024 20:40:54 +0200 Subject: [PATCH 086/108] Remove code to prefetch Docker images --- container-images.nix | 1 - modules/k3s/default.nix | 44 +------------------------- scripts/default.nix | 70 +---------------------------------------- 3 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 container-images.nix diff --git a/container-images.nix b/container-images.nix deleted file mode 100644 index 0dbb7ca..0000000 --- a/container-images.nix +++ /dev/null @@ -1 +0,0 @@ -{ attic = { finalImageName = "git.kun.is/home/atticd"; finalImageTag = "fd910d91c2143295e959d2c903e9ea25cf94ba27"; imageDigest = "sha256:309264ff35f2f7cbcb6609c72d816cb41ee62c74d59d4f01cfc05e94a893dae7"; imageName = "git.kun.is/home/atticd"; sha256 = "0cvhhx4s8678ivqnswqmj2mnw81a4wbr65c02y1ayxfv2szdw8bm"; }; atuin = { finalImageName = "ghcr.io/atuinsh/atuin"; finalImageTag = "18.3.0"; imageDigest = "sha256:678def8e9d59652a502759ca431f9c5b54ebdd5e9361507c7fcf24705c9862e0"; imageName = "ghcr.io/atuinsh/atuin"; sha256 = "1lb53p6dz12lwj10v9si7l6j06q1cnfaim4mgi6dkanlynq5mrk6"; }; bazarr = { finalImageName = "lscr.io/linuxserver/bazarr"; finalImageTag = "1.4.3"; imageDigest = "sha256:8573a7d8558d7407ec53c205599d99d9876486621681355d147e9091cd99c58b"; imageName = "lscr.io/linuxserver/bazarr"; sha256 = "0vnvjnj478h76dpr24z56xfp6d6s2j5qhidh7bvmmsnw4hdvic8b"; }; bind9 = { finalImageName = "ubuntu/bind9"; finalImageTag = "9.18-22.04_beta"; imageDigest = "sha256:eb71c990a2efaa37897929bc104ef1b035c527aa2d217bc89da64cf7bdf9a8c8"; imageName = "ubuntu/bind9"; sha256 = "0cdgm9qbxdyhhhnsykn5lcvcjp7kxx9pjjamj7120d3jf6d6zqn2"; }; cyberchef = { finalImageName = "mpepping/cyberchef"; finalImageTag = "latest"; imageDigest = "sha256:2c89d08580395b932c92d708041c2a702dc8fa899fcc1677901c2dc881bed789"; imageName = "mpepping/cyberchef"; sha256 = "1frlvv6lyghf99pa37l48r7j2wvh7mcb9x99fvf0ba2zhq2xfsy4"; }; deluge = { finalImageName = "linuxserver/deluge"; finalImageTag = "2.1.1"; imageDigest = "sha256:5af8bd7f0ad2bdc5e7799f5343081f5beb57e74eef88035aed9c18b7cc18ffcd"; imageName = "linuxserver/deluge"; sha256 = "1c73wa74bi0sm5yxs3bdldv4z4vw3pbadkpd3749ybsjxy10s0rk"; }; dnsmasq = { finalImageName = "dockurr/dnsmasq"; finalImageTag = "2.90"; imageDigest = "sha256:c85b08ebcd45463383bfa8a8ba57b2ccda0a0c32869fbf8927ff74f1d33b9e5d"; imageName = "dockurr/dnsmasq"; sha256 = "1vak4nkxq8pdi5yplfan36988n5wr1w0m3ycar0r18215p1ncarc"; }; forgejo = { finalImageName = "codeberg.org/forgejo/forgejo"; finalImageTag = "8.0.1"; imageDigest = "sha256:221639a84fae9d9ec5236a50f4980c3cd5332851949f6e989f5f44cc411cf4fa"; imageName = "codeberg.org/forgejo/forgejo"; sha256 = "0llhjbr6m33yfbkb3c4xjcwywk7w2p6wahg6xiz73rcsjjgg8lz1"; }; freshrss = { finalImageName = "freshrss/freshrss"; finalImageTag = "1.24.2"; imageDigest = "sha256:126b5202e65bbfef1da19be87fb21d9909e104d3ad185775c999b76a420d30bc"; imageName = "freshrss/freshrss"; sha256 = "1pdm7p1lmnmv90zw6pz47f61mlvx0sls3qmlpsn78vl9hz6f4bng"; }; hedgedoc = { finalImageName = "quay.io/hedgedoc/hedgedoc"; finalImageTag = "1.9.9"; imageDigest = "sha256:e0dda4a168e065e62fac0f90758a4e83fee57ae6e91acbb3e46456d4456c6c48"; imageName = "quay.io/hedgedoc/hedgedoc"; sha256 = "1yvmapvzf2n94c1h3zas85pzildl1jd3ip4n3cccfxq9f6dqhy0h"; }; immich = { finalImageName = "ghcr.io/immich-app/immich-server"; finalImageTag = "v1.112.1"; imageDigest = "sha256:c4e817f0eadbd9a6c2699cc884d5e7070428daec813c17db77d31fcca5b78ca6"; imageName = "ghcr.io/immich-app/immich-server"; sha256 = "0vvyhijslldj7hpg33n2cvpn5wrn9fcprw8pw01zh4ziabyy3z07"; }; immich-machine-learning = { finalImageName = "ghcr.io/immich-app/immich-machine-learning"; finalImageTag = "v1.112.1"; imageDigest = "sha256:9600eff5a66ae426293f00b171711bc1647c85cf966d759ee08ab2d05e0580b5"; imageName = "ghcr.io/immich-app/immich-machine-learning"; sha256 = "1m189s6i8hii4vrsjx3ypa5p2brz8sa3fw5jyxhh6qm42r4xnp4c"; }; immich-postgres = { finalImageName = "docker.io/tensorchord/pgvecto-rs"; finalImageTag = "pg14-v0.2.0"; imageDigest = "sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; imageName = "docker.io/tensorchord/pgvecto-rs"; sha256 = "0h1s11z5d4svg2whm7gw11dwpddg5k90fp62q3zirycms787f4d3"; }; immich-redis = { finalImageName = "docker.io/redis"; finalImageTag = "6.2-alpine"; imageDigest = "sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; imageName = "docker.io/redis"; sha256 = "0sscnrn5vpmdq2g62a185nlgf9i5hwcfl630hyh7wzfbgyq4pbzj"; }; inbucket = { finalImageName = "inbucket/inbucket"; finalImageTag = "edge"; imageDigest = "sha256:f7e0bbb13d24970c30690a04ff1599907530c31152fccd20d542028cd8a7650b"; imageName = "inbucket/inbucket"; sha256 = "0whxnp222b09jlcbmwd6y1jbcsqv16ipk182i5ywgjjd0wlvh4i3"; }; jellyfin = { finalImageName = "jellyfin/jellyfin"; finalImageTag = "10.9.9"; imageDigest = "sha256:d6f3d4aa59438ce951d85669f3c22426d20edb7a6b97604c509b5f4825bc8294"; imageName = "jellyfin/jellyfin"; sha256 = "1rn093xyh8prjr3v4zs0ss6z2hbgzy1p5f0gs5dv4kyz4y1gfkhw"; }; jellyseerr = { finalImageName = "fallenbagel/jellyseerr"; finalImageTag = "1.9.2"; imageDigest = "sha256:8f708df0ce3f202056bde5d7bff625eb59efe38f4ee47bdddc7560b6e4a5a214"; imageName = "fallenbagel/jellyseerr"; sha256 = "04ala5cpkv1rhq609yxvyf8wv6ql8ism9zyrxyiil6b1gfgcsfxz"; }; kitchenowl = { finalImageName = "tombursch/kitchenowl"; finalImageTag = "v0.5.2"; imageDigest = "sha256:5d37e09c034884a0495c0460fc849981b71ff1a90908ed29804dda7f13f2d165"; imageName = "tombursch/kitchenowl"; sha256 = "10d6xrdl0si663s27ayqj6w2qq6ly81hpv9nq8whd0i17s7skkmd"; }; kms = { finalImageName = "teddysun/kms"; finalImageTag = "latest"; imageDigest = "sha256:4b366384ef3389eeecec9340468909616c409f9227504f4ee1e659ad1a801976"; imageName = "teddysun/kms"; sha256 = "0jwhlb2wgm0awp36rpann9b9gyfrnwsclhb3phxnc3aan7lc9nnx"; }; minecraft = { finalImageName = "itzg/minecraft-server"; finalImageTag = "latest"; imageDigest = "sha256:3b97ca8f48507f1c85e8d7a32aee5c9bd7e09d4e96584b71aac0b878c8f1d16c"; imageName = "itzg/minecraft-server"; sha256 = "0892ak383841n7zsx76gm7apra603pqajxzmzm0b4797wm69p79i"; }; nextcloud = { finalImageName = "nextcloud"; finalImageTag = "29.0.5"; imageDigest = "sha256:5bbc6e9f207bfddd1515ac82f647c19edf6cdd075d7d253c3118a87c835204f0"; imageName = "nextcloud"; sha256 = "1s4346f522v7nyfhsgmyfyw9s40zv0dhylqdym6vkg0nfidfk08y"; }; ntfy = { finalImageName = "binwiederhier/ntfy"; finalImageTag = "v2.11.0"; imageDigest = "sha256:4a7d0f0adc6d5d9fc36e64ab55ef676e76e124a2bdd50ce115b6d9c1c7430294"; imageName = "binwiederhier/ntfy"; sha256 = "0sqgs5bkgx35wbga95sf3n863lpmwxv84kiic1r8zaibbg54f8b3"; }; paperless = { finalImageName = "ghcr.io/paperless-ngx/paperless-ngx"; finalImageTag = "2.11.6"; imageDigest = "sha256:fca12ddea5509819dd0702cf128944aa23d01dd850a2536a96c2b46fb982b9bb"; imageName = "ghcr.io/paperless-ngx/paperless-ngx"; sha256 = "12myq5liyjgvd9rpz997wwv7gxj8rgsckrsn53gszrr3mh8gp5b6"; }; pihole = { finalImageName = "pihole/pihole"; finalImageTag = "2024.07.0"; imageDigest = "sha256:0def896a596e8d45780b6359dbf82fc8c75ef05b97e095452e67a0a4ccc95377"; imageName = "pihole/pihole"; sha256 = "16a3apailmkdv6kmkfs37y454qlnw77xflpaqxaznh359pnq3y3j"; }; postgres14 = { finalImageName = "postgres"; finalImageTag = "14"; imageDigest = "sha256:e3cc76b6d4dfc8f3547641d67053092e7c108e03ab159c00b48fa8d891e2f7b4"; imageName = "postgres"; sha256 = "0qwjsfq7h5myqfahb9fz0xs4fg1fylrjlyv6ic72hyryhanmh46f"; }; postgres15 = { finalImageName = "postgres"; finalImageTag = "15"; imageDigest = "sha256:0836104ba0de8d09e8d54e2d6a28389fbce9c0f4fe08f4aa065940452ec61c30"; imageName = "postgres"; sha256 = "04264alvi2x1pr34c3iiynlc3fqvm5q12hhkfb14wxir8imxnkqy"; }; prowlarr = { finalImageName = "lscr.io/linuxserver/prowlarr"; finalImageTag = "1.21.2"; imageDigest = "sha256:c93f075dc5afb74dc7a0a55e90974f81425a5d3c5d293022c5416431f4963ce9"; imageName = "lscr.io/linuxserver/prowlarr"; sha256 = "0ab57f7yh9c23v2m1qwk2ycj00gjfk1wjd1b92y0aycwl50dkdpv"; }; radarr = { finalImageName = "lscr.io/linuxserver/radarr"; finalImageTag = "5.9.1"; imageDigest = "sha256:b034531ff81d3e5e1f9fd70c969746040b40e6484c88981ea5d0dee732c10bc3"; imageName = "lscr.io/linuxserver/radarr"; sha256 = "037159jjgjr25w4a258hw53n194zgnlldywnsvhys3yyvcld2rzi"; }; radicale = { finalImageName = "tomsquest/docker-radicale"; finalImageTag = "3.2.2.0"; imageDigest = "sha256:af050e02c4a3f7385a09595dd2a1424db6831aa9f24404095c6d2244d1c94138"; imageName = "tomsquest/docker-radicale"; sha256 = "07mxn6iqm0fhb06dwmxdhqnw3c8yi2dm2jpb2n80dxzmvavrv0lk"; }; redis7 = { finalImageName = "docker.io/library/redis"; finalImageTag = "7"; imageDigest = "sha256:878983f8f5045b28384fc300268cec62bca3b14d5e1a448bec21f28cfcc7bf78"; imageName = "docker.io/library/redis"; sha256 = "09n5i6ps28k7529m822cd34awqpfmnlzi6djfzjd9wzx4gcvgmrh"; }; sonarr = { finalImageName = "lscr.io/linuxserver/sonarr"; finalImageTag = "4.0.8"; imageDigest = "sha256:0777b308a414000505651059a95af373ded6aba8ce5a40b50d7aad333dc912e2"; imageName = "lscr.io/linuxserver/sonarr"; sha256 = "0mdf7h85m01vw59amvgclclrq8b65aijjsbq405pdi520879bis2"; }; syncthing = { finalImageName = "lscr.io/linuxserver/syncthing"; finalImageTag = "1.27.10"; imageDigest = "sha256:d5481de808a1de5a13b814a922b1f6de5fcde64c1ca95b0a065218b56570fae3"; imageName = "lscr.io/linuxserver/syncthing"; sha256 = "08zj0s3q9r9mwnnv6nf6i157z8m6k6qrxwcvka6awg9vb507d49k"; }; } diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index 8c0cd55..f4cec44 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -1,4 +1,4 @@ -{ self, inputs, pkgs, lib, config, globals, ... }: +{ self, inputs, pkgs, lib, config, ... }: let cfg = config.lab.k3s; in @@ -191,48 +191,6 @@ in ''; } ); - - docker-images.text = - let - imageDefs = import "${self}/container-images.nix"; - - setupCommands = [ - "rm -rf ${self.globals.imageDir}" - "mkdir -p ${self.globals.imageDir}" - ]; - - getDockerImageConfig = dockerImage: - let - configJson = pkgs.runCommand "config.json" - { - nativeBuildInputs = [ pkgs.skopeo pkgs.jq ]; - } - '' - skopeo --tmpdir $TMPDIR --insecure-policy inspect docker-archive:${dockerImage} --config | jq '.config' > $out - ''; - in - builtins.fromJSON (builtins.readFile configJson); - - imageDefToLinkCommand = name: imageDef: - let - dockerImage = pkgs.dockerTools.pullImage imageDef; - nixSnapshotterImage = pkgs.nix-snapshotter.buildImage { - inherit name; - resolvedByNix = true; - fromImage = dockerImage; - config = getDockerImageConfig dockerImage; - }; - imageLinkPath = "${self.globals.imageDir}/${name}.tar"; - in - "ln -sf ${nixSnapshotterImage} ${imageLinkPath}"; - - linkCommandList = lib.attrsets.mapAttrsToList imageDefToLinkCommand imageDefs; - # TODO: Creating Docker images like this seems to *explode* in size. - # Doing this for every image we currently have is infeasible. - # I should investigate why the size increases like that. - commandList = setupCommands; # ++ linkCommandList; - in - builtins.concatStringsSep "\n" commandList; }; sops.secrets = diff --git a/scripts/default.nix b/scripts/default.nix index 1a7401c..e1ffbbc 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -1,4 +1,4 @@ -{ self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: +{ nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; createScript = { name, runtimeInputs, scriptPath, extraWrapperFlags ? "", ... }: @@ -20,72 +20,4 @@ in runtimeInputs = with pkgs; [ sops coreutils nixos-anywhere ]; scriptPath = ./bootstrap.sh; }; - - packages.prefetch-container-images = - let - imagesJSON = builtins.toFile "images.json" (builtins.toJSON self.globals.images); - in - pkgs.writers.writePython3Bin "prefetch-container-images.py" - { } '' - import json - import subprocess - import tempfile - import sys - from collections import defaultdict - - prefetch_docker_cmd = "${pkgs.lib.getExe pkgs.nix-prefetch-docker}" # noqa: E501 - nix_cmd = "${pkgs.lib.getExe pkgs.nix}" # noqa: E501 - images_file_name = "${imagesJSON}" - - results = defaultdict(lambda: defaultdict(dict)) - - with open(images_file_name, 'r') as file: - data = json.load(file) - - for image_name, image_ref in data.items(): - [name, tag] = image_ref.split(":", maxsplit=1) - print(f"Prefetching image {image_ref}", file=sys.stderr) - - digest = "" - if "@" in tag: - [tag, digest] = tag.split("@", maxsplit=1) - - prefetch_args = [ - prefetch_docker_cmd, - "--os", "linux", - "--arch", "amd64", - "--image-name", name, - "--image-tag", tag, - "--json", - "--quiet" - ] - - if digest: - prefetch_args.extend(["--image-digest", digest]) - - result = subprocess.run(prefetch_args, - check=True, - capture_output=True, - text=True) - - prefetch_data = json.loads(result.stdout) - results[image_name] = prefetch_data - - with tempfile.NamedTemporaryFile(mode='w+', suffix='.json') as temp_file: - json.dump(results, temp_file, indent=4) - temp_file.flush() - - to_nix_args = [ - nix_cmd, - "eval", - "--impure", - "--expr", f'builtins.fromJSON (builtins.readFile {temp_file.name})' - ] - result = subprocess.run(to_nix_args, - check=True, - capture_output=True, - text=True) - - print(result.stdout) - ''; }) From e91f37d700efcb3361db10efff53929852932117 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 22 Sep 2024 21:11:09 +0200 Subject: [PATCH 087/108] Remove deploy checks Move image globals to kubernetes repo --- checks.nix | 17 ----------------- flake.nix | 1 - utils/globals.nix | 35 ----------------------------------- 3 files changed, 53 deletions(-) delete mode 100644 checks.nix diff --git a/checks.nix b/checks.nix deleted file mode 100644 index 2e77b84..0000000 --- a/checks.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ self, nixpkgs, flake-utils, deploy-rs, ... }: flake-utils.lib.eachDefaultSystem (system: -let - pkgs = nixpkgs.legacyPackages.${system}; -in -{ - # Deploy-rs' flake checks seem broken for architectures different from the deployment machine. - # We skip these here. - checks = deploy-rs.lib.${system}.deployChecks ( - pkgs.lib.attrsets.updateManyAttrsByPath [{ - path = [ "nodes" ]; - update = pkgs.lib.attrsets.filterAttrs (name: node: - self.machines.${name}.arch == system - ); - }] - self.deploy - ); -}) diff --git a/flake.nix b/flake.nix index 6aa6909..e7ee847 100644 --- a/flake.nix +++ b/flake.nix @@ -53,7 +53,6 @@ inputs@{ nixpkgs, flake-utils, ... }: flake-utils.lib.meld inputs [ ./scripts - ./checks.nix ./deploy.nix ./nixos.nix ./shell.nix diff --git a/utils/globals.nix b/utils/globals.nix index 02ba866..2269d8b 100644 --- a/utils/globals.nix +++ b/utils/globals.nix @@ -27,39 +27,4 @@ nextcloudIPv4 = "192.168.30.148"; imageDir = "/var/container_images"; - - images = { - jellyfin = "jellyfin/jellyfin:10.9.9"; - deluge = "linuxserver/deluge:2.1.1"; - jellyseerr = "fallenbagel/jellyseerr:1.9.2"; - radarr = "lscr.io/linuxserver/radarr:5.9.1"; - prowlarr = "lscr.io/linuxserver/prowlarr:1.21.2"; - sonarr = "lscr.io/linuxserver/sonarr:4.0.8"; - bazarr = "lscr.io/linuxserver/bazarr:1.4.3"; - atuin = "ghcr.io/atuinsh/atuin:18.3.0"; - postgres14 = "postgres:14"; - kms = "teddysun/kms:latest"; - paperless = "ghcr.io/paperless-ngx/paperless-ngx:2.11.6"; - redis7 = "docker.io/library/redis:7"; - nextcloud = "nextcloud:29.0.5"; - postgres15 = "postgres:15"; - inbucket = "inbucket/inbucket:edge"; - syncthing = "lscr.io/linuxserver/syncthing:1.27.10"; - radicale = "tomsquest/docker-radicale:3.2.3.0"; - ntfy = "binwiederhier/ntfy:v2.11.0"; - forgejo = "codeberg.org/forgejo/forgejo:8.0.1"; - pihole = "pihole/pihole:2024.07.0"; - immich = "ghcr.io/immich-app/immich-server:v1.114.0"; - immich-machine-learning = "ghcr.io/immich-app/immich-machine-learning:v1.114.0"; - immich-redis = "docker.io/redis:6.2-alpine@sha256:e3b17ba9479deec4b7d1eeec1548a253acc5374d68d3b27937fcfe4df8d18c7e"; - immich-postgres = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; - kitchenowl = "tombursch/kitchenowl:v0.5.2"; - cyberchef = "mpepping/cyberchef:latest"; - freshrss = "freshrss/freshrss:1.24.3"; - bind9 = "ubuntu/bind9:9.18-22.04_beta"; - dnsmasq = "dockurr/dnsmasq:2.90"; - attic = "git.kun.is/home/atticd:fd910d91c2143295e959d2c903e9ea25cf94ba27"; - hedgedoc = "quay.io/hedgedoc/hedgedoc:1.9.9"; - minecraft = "itzg/minecraft-server:latest"; - }; } From 3d456b1a4383d2f40cceb691182c4364333fe934 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 22 Sep 2024 22:46:56 +0200 Subject: [PATCH 088/108] Make machines' nixos module an attrset --- machines/lewis.nix | 18 ++++++++---------- machines/warwick.nix | 14 ++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/machines/lewis.nix b/machines/lewis.nix index 5350142..c20bbb2 100644 --- a/machines/lewis.nix +++ b/machines/lewis.nix @@ -6,17 +6,15 @@ hasMedia = "true"; }; - nixosModule = { - lab = { - storage.profile = "kubernetes"; - backups.enable = true; - data-sharing.enable = true; - tailscale.enable = true; + nixosModule.lab = { + storage.profile = "kubernetes"; + backups.enable = true; + data-sharing.enable = true; + tailscale.enable = true; - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; - }; + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; }; }; }; diff --git a/machines/warwick.nix b/machines/warwick.nix index f000881..15e276d 100644 --- a/machines/warwick.nix +++ b/machines/warwick.nix @@ -3,15 +3,13 @@ arch = "aarch64-linux"; isRaspberryPi = true; - nixosModule = { lib, ... }: { - lab = { - storage.profile = "pi"; - monitoring.server.enable = true; + nixosModule.lab = { + storage.profile = "pi"; + monitoring.server.enable = true; - tailscale = { - advertiseExitNode = true; - enable = true; - }; + tailscale = { + advertiseExitNode = true; + enable = true; }; }; }; From fcc2848523f2350167e6894620d63740526c186f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Tue, 24 Sep 2024 22:45:07 +0200 Subject: [PATCH 089/108] Disable DNS and GSSAPI auth on sshd Remove NixNG code --- modules/default.nix | 2 ++ modules/k3s/default.nix | 27 --------------------------- modules/k3s/dnsmasq.nix | 41 ----------------------------------------- utils/default.nix | 3 +-- utils/globals.nix | 2 -- 5 files changed, 3 insertions(+), 72 deletions(-) delete mode 100644 modules/k3s/dnsmasq.nix diff --git a/modules/default.nix b/modules/default.nix index a05a57f..7628bdb 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -52,6 +52,8 @@ settings = { PasswordAuthentication = false; KbdInteractiveAuthentication = false; + GSSAPIAuthentication = false; + UseDns = false; }; }; }; diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index f4cec44..d638c81 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -164,33 +164,6 @@ in cp -f ${./k3s-ca/etcd/server-ca.crt} /var/lib/rancher/k3s/server/tls/etcd/server-ca.crt ''; }; - - nixng = lib.mkIf (cfg.role == "server") - ( - let - dnsmasqStream = (import ./dnsmasq.nix { - inherit (inputs) nixpkgs nixng; - inherit (inputs.nixng) nglib; - inherit (self) globals; - }).config.system.build.ociImage.stream; - - dnsmasqImage = pkgs.stdenv.mkDerivation { - name = "dnsmasq.tar"; - src = dnsmasqStream; - dontUnpack = true; - buildPhase = '' - $src > $out - ''; - }; - in - { - text = '' - rm -rf ${self.globals.imageDir} - mkdir -p ${self.globals.imageDir} - ln -sf ${dnsmasqImage} ${self.globals.imageDir}/dnsmasq.tar - ''; - } - ); }; sops.secrets = diff --git a/modules/k3s/dnsmasq.nix b/modules/k3s/dnsmasq.nix deleted file mode 100644 index 6fc8c4f..0000000 --- a/modules/k3s/dnsmasq.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ globals, nixpkgs, nglib, ... }: -nglib.makeSystem { - inherit nixpkgs; - system = "x86_64-linux"; - name = "nixng-dnsmasq"; - - config = { ... }: { - dumb-init = { - enable = true; - type.services = { }; - }; - - init.services.dnsmasq = { - shutdownOnExit = true; - }; - - services.dnsmasq = { - enable = true; - - settings = { - address = [ - "/kms.kun.is/${globals.kmsIPv4}" - "/ssh.git.kun.is/${globals.gitIPv4}" - ]; - - alias = "${globals.routerPublicIPv4},${globals.traefikIPv4}"; - expand-hosts = true; - local = "/dmz/"; - log-queries = true; - no-hosts = true; - no-resolv = true; - port = 53; - - server = [ - "192.168.30.1" - "/kun.is/${globals.bind9IPv4}" - ]; - }; - }; - }; -} diff --git a/utils/default.nix b/utils/default.nix index e0ecf4e..297fc3c 100644 --- a/utils/default.nix +++ b/utils/default.nix @@ -10,9 +10,8 @@ let net = import ./net.nix lib; }); - nonSystemAttrs = rec { + nonSystemAttrs = { globals = import ./globals.nix; - imagePath = name: "nix:0${globals.imageDir}/${name}.tar"; }; allAttrs = systemAttrs // nonSystemAttrs; diff --git a/utils/globals.nix b/utils/globals.nix index 2269d8b..28a2163 100644 --- a/utils/globals.nix +++ b/utils/globals.nix @@ -25,6 +25,4 @@ freshrssIPv4 = "192.168.30.146"; immichIPv4 = "192.168.30.147"; nextcloudIPv4 = "192.168.30.148"; - - imageDir = "/var/container_images"; } From 2352a1a9177fbb7d3fed042cc74f80e079196020 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Fri, 25 Oct 2024 15:48:12 +0200 Subject: [PATCH 090/108] Update flake inputs --- flake.lock | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/flake.lock b/flake.lock index 5926008..34d0281 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ "utils": "utils" }, "locked": { - "lastModified": 1718194053, - "narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=", + "lastModified": 1727447169, + "narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=", "owner": "serokell", "repo": "deploy-rs", - "rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a", + "rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76", "type": "github" }, "original": { @@ -27,11 +27,11 @@ ] }, "locked": { - "lastModified": 1722217815, - "narHash": "sha256-8r5AJ3n8WEDw3rsZLALSuFQ5kJyWOcssNZvPxYLr2yc=", + "lastModified": 1729712798, + "narHash": "sha256-a+Aakkb+amHw4biOZ0iMo8xYl37uUL48YEXIC5PYJ/8=", "owner": "nix-community", "repo": "disko", - "rev": "1e6f8a7b4634fc051cc9361959bf414fcf17e094", + "rev": "09a776702b004fdf9c41a024e1299d575ee18a7d", "type": "github" }, "original": { @@ -48,11 +48,11 @@ ] }, "locked": { - "lastModified": 1719459426, - "narHash": "sha256-4Kn9Pb3lvsik/VYsEAYgXpkcmLhrr0tTE6oIT2PMSPA=", + "lastModified": 1726867691, + "narHash": "sha256-IK3r16N9pizf53AipOmrcrcyjVsPJwC4PI5hIqEyKwQ=", "owner": "kirelagin", "repo": "dns.nix", - "rev": "e6693931023206f1f3c2bfc57d2c98b5f27f52e6", + "rev": "a3196708a56dee76186a9415c187473b94e6cbae", "type": "github" }, "original": { @@ -150,11 +150,11 @@ "systems": "systems_2" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -195,11 +195,11 @@ ] }, "locked": { - "lastModified": 1715438114, - "narHash": "sha256-btb702TXuhDg0D6tW0dCOy4+II9Wl6BJ0LvpT+O9wrs=", + "lastModified": 1729627456, + "narHash": "sha256-TCZdXCmnqCPsd3PjLv/LDSKJhTspLliL0DE+c/XP9BY=", "owner": "pdtpartners", "repo": "nix-snapshotter", - "rev": "7b251c9356bc7bb383ebeedcd0045b3ae431bff7", + "rev": "f2957822a3748c91e678657a1cfd009b0440bbfd", "type": "github" }, "original": { @@ -231,11 +231,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1722332872, - "narHash": "sha256-2xLM4sc5QBfi0U/AANJAW21Bj4ZX479MHPMPkB+eKBU=", + "lastModified": 1729742320, + "narHash": "sha256-u3Of8xRkN//me8PU+RucKA59/6RNy4B2jcGAF36P4jI=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "14c333162ba53c02853add87a0000cbd7aa230c2", + "rev": "e8a2f6d5513fe7b7d15701b2d05404ffdc3b6dda", "type": "github" }, "original": { @@ -263,11 +263,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1721524707, - "narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=", + "lastModified": 1729357638, + "narHash": "sha256-66RHecx+zohbZwJVEPF7uuwHeqf8rykZTMCTqIrOew4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "556533a23879fc7e5f98dd2e0b31a6911a213171", + "rev": "bb8c2cf7ea0dd2e18a52746b2c3a5b0c73b93c22", "type": "github" }, "original": { @@ -279,11 +279,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1722141560, - "narHash": "sha256-Ul3rIdesWaiW56PS/Ak3UlJdkwBrD4UcagCmXZR9Z7Y=", + "lastModified": 1729818716, + "narHash": "sha256-XRfkUsxLzFkMn3Tpstio1gNOIQ+2PZPCKbifJ2IXxlw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "038fb464fcfa79b4f08131b07f2d8c9a6bcc4160", + "rev": "062c4f59744fcffa2e5aa3ef443dc8b4d1674ed6", "type": "github" }, "original": { @@ -295,11 +295,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1722221733, - "narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=", + "lastModified": 1729691686, + "narHash": "sha256-BAuPWW+9fa1moZTU+jFh+1cUtmsuF8asgzFwejM4wac=", "owner": "nixos", "repo": "nixpkgs", - "rev": "12bf09802d77264e441f48e25459c10c93eada2e", + "rev": "32e940c7c420600ef0d1ef396dc63b04ee9cad37", "type": "github" }, "original": { @@ -332,11 +332,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1722114803, - "narHash": "sha256-s6YhI8UHwQvO4cIFLwl1wZ1eS5Cuuw7ld2VzUchdFP0=", + "lastModified": 1729775275, + "narHash": "sha256-J2vtHq9sw1wWm0aTMXpEEAzsVCUMZDTEe5kiBYccpLE=", "owner": "Mic92", "repo": "sops-nix", - "rev": "eb34eb588132d653e4c4925d862f1e5a227cc2ab", + "rev": "78a0e634fc8981d6b564f08b6715c69a755c4c7d", "type": "github" }, "original": { From eed797fb13e383d2a002ff04382b46247dc0582e Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 28 Oct 2024 14:11:40 +0100 Subject: [PATCH 091/108] Use treefmt-nix and Alejandro --- flake.nix | 11 ++++++++--- formatter.nix | 9 +++++++++ treefmt.nix | 4 ++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 formatter.nix create mode 100644 treefmt.nix diff --git a/flake.nix b/flake.nix index e7ee847..3b34261 100644 --- a/flake.nix +++ b/flake.nix @@ -17,6 +17,12 @@ deploy-rs.url = "github:serokell/deploy-rs"; nixos-hardware.url = "github:NixOS/nixos-hardware/master"; flake-utils.url = "github:numtide/flake-utils"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + + pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs-unstable"; + }; disko = { url = "github:nix-community/disko"; @@ -58,7 +64,6 @@ ./shell.nix ./utils ./machines - ] // (flake-utils.lib.eachDefaultSystem (system: { - formatter = nixpkgs.legacyPackages.${system}.nixfmt; - })); + ./formatter.nix + ]; } diff --git a/formatter.nix b/formatter.nix new file mode 100644 index 0000000..8696b53 --- /dev/null +++ b/formatter.nix @@ -0,0 +1,9 @@ +{ nixpkgs, treefmt-nix, flake-utils, ...}: flake-utils.lib.eachDefaultSystem (system: +let + pkgs = nixpkgs.legacyPackages.${system}; + treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; +in +{ + formatter = treefmtEval.config.build.wrapper; +} +) diff --git a/treefmt.nix b/treefmt.nix new file mode 100644 index 0000000..e6da195 --- /dev/null +++ b/treefmt.nix @@ -0,0 +1,4 @@ +{...}: { + projectRootFile = "flake.nix"; + programs.alejandra.enable = true; +} From 5341235bc3435efa4cf3015954e06ca278570c1f Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 28 Oct 2024 14:12:06 +0100 Subject: [PATCH 092/108] Format repo --- deploy.nix | 34 +- flake.lock | 116 ++- flake.nix | 7 +- formatter.nix | 19 +- machines/default.nix | 40 +- machines/pikvm.nix | 9 +- machines/talos.nix | 2 +- modules/backups.nix | 27 +- modules/data-sharing.nix | 18 +- modules/default.nix | 48 +- modules/k3s/bootstrap.nix | 4 +- modules/k3s/default.nix | 148 +-- modules/monitoring/default.nix | 37 +- modules/networking/default.nix | 6 +- modules/storage.nix | 16 +- modules/tailscale.nix | 26 +- nixos.nix | 21 +- scripts/default.nix | 34 +- shell.nix | 13 +- utils/default.nix | 24 +- utils/net.nix | 1627 +++++++++++++++----------------- 21 files changed, 1200 insertions(+), 1076 deletions(-) diff --git a/deploy.nix b/deploy.nix index 5da2ab6..e8886c7 100644 --- a/deploy.nix +++ b/deploy.nix @@ -1,26 +1,26 @@ -{ self, deploy-rs, ... }: -let +{ + self, + deploy-rs, + ... +}: let deployArch = "x86_64-linux"; mkDeployNodes = nodeDef: builtins.mapAttrs - (name: machine: nodeDef name machine) - self.machines.${deployArch}; -in -{ + (name: machine: nodeDef name machine) + self.machines.${deployArch}; +in { deploy = { sshUser = "root"; user = "root"; - nodes = mkDeployNodes (name: machine: - let - nixosConfiguration = self.nixosConfigurations.${name}; - in - { - hostname = nixosConfiguration.config.networking.fqdn; - profiles.system = { - remoteBuild = machine.arch != deployArch; - path = deploy-rs.lib.${machine.arch}.activate.nixos nixosConfiguration; - }; - }); + nodes = mkDeployNodes (name: machine: let + nixosConfiguration = self.nixosConfigurations.${name}; + in { + hostname = nixosConfiguration.config.networking.fqdn; + profiles.system = { + remoteBuild = machine.arch != deployArch; + path = deploy-rs.lib.${machine.arch}.activate.nixos nixosConfiguration; + }; + }); }; } diff --git a/flake.lock b/flake.lock index 34d0281..074e833 100644 --- a/flake.lock +++ b/flake.lock @@ -109,6 +109,22 @@ "type": "github" } }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -163,6 +179,27 @@ "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "kubenix": { "inputs": { "flake-compat": "flake-compat_2", @@ -262,6 +299,22 @@ } }, "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { "locked": { "lastModified": 1729357638, "narHash": "sha256-66RHecx+zohbZwJVEPF7uuwHeqf8rykZTMCTqIrOew4=", @@ -309,6 +362,45 @@ "type": "github" } }, + "nixpkgs_3": { + "locked": { + "lastModified": 1726871744, + "narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat_4", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs-unstable" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1729104314, + "narHash": "sha256-pZRZsq5oCdJt3upZIU4aslS9XwFJ+/nVtALHIciX/BI=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "deploy-rs": "deploy-rs", @@ -321,7 +413,9 @@ "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", - "sops-nix": "sops-nix" + "pre-commit-hooks": "pre-commit-hooks", + "sops-nix": "sops-nix", + "treefmt-nix": "treefmt-nix" } }, "sops-nix": { @@ -329,7 +423,7 @@ "nixpkgs": [ "nixpkgs" ], - "nixpkgs-stable": "nixpkgs-stable" + "nixpkgs-stable": "nixpkgs-stable_2" }, "locked": { "lastModified": 1729775275, @@ -410,6 +504,24 @@ "type": "github" } }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1730025913, + "narHash": "sha256-Y9NtFmP8ciLyRsopcCx1tyoaaStKeq+EndwtGCgww7I=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "bae131e525cc8718da22fbeb8d8c7c43c4ea502a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "utils": { "inputs": { "systems": "systems" diff --git a/flake.nix b/flake.nix index 3b34261..0238d94 100644 --- a/flake.nix +++ b/flake.nix @@ -55,8 +55,11 @@ }; }; - outputs = - inputs@{ nixpkgs, flake-utils, ... }: + outputs = inputs @ { + nixpkgs, + flake-utils, + ... + }: flake-utils.lib.meld inputs [ ./scripts ./deploy.nix diff --git a/formatter.nix b/formatter.nix index 8696b53..0d42f9c 100644 --- a/formatter.nix +++ b/formatter.nix @@ -1,9 +1,14 @@ -{ nixpkgs, treefmt-nix, flake-utils, ...}: flake-utils.lib.eachDefaultSystem (system: -let - pkgs = nixpkgs.legacyPackages.${system}; - treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; -in { - formatter = treefmtEval.config.build.wrapper; -} + nixpkgs, + treefmt-nix, + flake-utils, + ... +}: +flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = nixpkgs.legacyPackages.${system}; + treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; + in { + formatter = treefmtEval.config.build.wrapper; + } ) diff --git a/machines/default.nix b/machines/default.nix index 74aa74e..261980b 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -1,9 +1,13 @@ -{ nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: -let +{ + nixpkgs, + flake-utils, + ... +}: +flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; lib = pkgs.lib; - machineOpts = { config, ... }: { + machineOpts = {config, ...}: { options = { arch = lib.mkOption { default = null; @@ -19,7 +23,7 @@ let }; nixosModule = lib.mkOption { - default = { ... }: { }; + default = {...}: {}; type = lib.types.anything; description = '' Customized configuration for this machine in the form of a NixOS module. @@ -43,17 +47,19 @@ let }; }; }; -in -{ - machines = (lib.modules.evalModules { - modules = [ - allOpts - ./warwick.nix - ./atlas.nix - ./jefke.nix - ./lewis.nix - # ./talos.nix - # ./pikvm.nix - ]; - }).config.machines; +in { + machines = + (lib.modules.evalModules { + modules = [ + allOpts + ./warwick.nix + ./atlas.nix + ./jefke.nix + ./lewis.nix + # ./talos.nix + # ./pikvm.nix + ]; + }) + .config + .machines; }) diff --git a/machines/pikvm.nix b/machines/pikvm.nix index 6a7bc14..d384897 100644 --- a/machines/pikvm.nix +++ b/machines/pikvm.nix @@ -3,7 +3,12 @@ arch = "aarch64-linux"; isRaspberryPi = true; - nixosModule = { config, inputs, lib, ... }: { + nixosModule = { + config, + inputs, + lib, + ... + }: { # imports = [ "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" ]; lab = { storage.profile = "pi"; @@ -17,7 +22,7 @@ v4l-utils ]; - boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; + boot.extraModulePackages = with config.boot.kernelPackages; [v4l2loopback]; }; }; } diff --git a/machines/talos.nix b/machines/talos.nix index 0fa0311..56ada95 100644 --- a/machines/talos.nix +++ b/machines/talos.nix @@ -2,7 +2,7 @@ machines.talos = { arch = "x86_64-linux"; - nixosModule = { lib, ... }: { + nixosModule = {lib, ...}: { lab.storage.profile = "normal"; # boot.loader.systemd-boot.enable = lib.mkForce false; diff --git a/modules/backups.nix b/modules/backups.nix index bf1c9a5..18e7240 100644 --- a/modules/backups.nix +++ b/modules/backups.nix @@ -1,12 +1,16 @@ -{ pkgs, lib, config, ... }: -let +{ + pkgs, + lib, + config, + ... +}: let cfg = config.lab.backups; borgmaticConfig = pkgs.writeTextFile { name = "borgmatic-config.yaml"; - text = lib.generators.toYAML { } { - source_directories = [ "/mnt/longhorn/persistent/longhorn-backup" ]; + text = lib.generators.toYAML {} { + source_directories = ["/mnt/longhorn/persistent/longhorn-backup"]; repositories = [ { @@ -27,8 +31,7 @@ let encryption_passcommand = "${pkgs.coreutils}/bin/cat ${config.sops.secrets."borg/borgPassphrase".path}"; }; }; -in -{ +in { options.lab.backups = { enable = lib.mkOption { default = false; @@ -48,13 +51,13 @@ in }; config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; [ borgbackup ]; + environment.systemPackages = with pkgs; [borgbackup]; # Converted from: # https://github.com/borgmatic-collective/borgmatic/tree/84823dfb912db650936e3492f6ead7e0e0d32a0f/sample/systemd systemd.services.borgmatic = { description = "borgmatic backup"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; + wants = ["network-online.target"]; + after = ["network-online.target"]; unitConfig.ConditionACPower = true; preStart = "${pkgs.coreutils}/bin/sleep 10s"; @@ -75,7 +78,7 @@ in systemd.timers.borgmatic = { description = "Run borgmatic backup"; - wantedBy = [ "timers.target" ]; + wantedBy = ["timers.target"]; timerConfig = { OnCalendar = "*-*-* 3:00:00"; Persistent = true; @@ -84,8 +87,8 @@ in }; sops.secrets = { - "borg/borgPassphrase" = { }; - "borg/borgbasePrivateKey" = { }; + "borg/borgPassphrase" = {}; + "borg/borgbasePrivateKey" = {}; }; }; } diff --git a/modules/data-sharing.nix b/modules/data-sharing.nix index ac6c456..8fe6c37 100644 --- a/modules/data-sharing.nix +++ b/modules/data-sharing.nix @@ -1,5 +1,8 @@ -{ lib, config, ... }: -let +{ + lib, + config, + ... +}: let cfg = config.lab.data-sharing; nfsShares = [ @@ -13,13 +16,12 @@ let nfsExports = lib.strings.concatLines ( builtins.map - (share: - "${share} 192.168.30.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1/8(rw,sync,no_subtree_check,no_root_squash) 10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)" - ) - nfsShares + ( + share: "${share} 192.168.30.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1/8(rw,sync,no_subtree_check,no_root_squash) 10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)" + ) + nfsShares ); -in -{ +in { options.lab.data-sharing = { enable = lib.mkOption { default = false; diff --git a/modules/default.nix b/modules/default.nix index 7628bdb..8749267 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,17 +1,27 @@ -{ self, pkgs, config, lib, inputs, machine, ... }: { - imports = [ - ./storage.nix - ./backups.nix - ./networking - ./data-sharing.nix - ./monitoring - ./k3s - ./tailscale.nix - machine.nixosModule - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - inputs.nix-snapshotter.nixosModules.nix-snapshotter - ] ++ lib.lists.optional (machine.isRaspberryPi) inputs.nixos-hardware.nixosModules.raspberry-pi-4; +{ + self, + pkgs, + config, + lib, + inputs, + machine, + ... +}: { + imports = + [ + ./storage.nix + ./backups.nix + ./networking + ./data-sharing.nix + ./monitoring + ./k3s + ./tailscale.nix + machine.nixosModule + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + inputs.nix-snapshotter.nixosModules.nix-snapshotter + ] + ++ lib.lists.optional (machine.isRaspberryPi) inputs.nixos-hardware.nixosModules.raspberry-pi-4; config = { time.timeZone = "Europe/Amsterdam"; @@ -31,7 +41,9 @@ i18n = { defaultLocale = "en_US.UTF-8"; - extraLocaleSettings = let extraLocale = "nl_NL.UTF-8"; in { + extraLocaleSettings = let + extraLocale = "nl_NL.UTF-8"; + in { LC_ADDRESS = extraLocale; LC_IDENTIFICATION = extraLocale; LC_MEASUREMENT = extraLocale; @@ -97,12 +109,12 @@ ]; boot = lib.mkIf (! machine.isRaspberryPi) { - kernelModules = [ "kvm-intel" ]; - extraModulePackages = [ ]; + kernelModules = ["kvm-intel"]; + extraModulePackages = []; kernel.sysctl."fs.inotify.max_user_instances" = 256; initrd = { - kernelModules = [ ]; + kernelModules = []; availableKernelModules = [ "ahci" diff --git a/modules/k3s/bootstrap.nix b/modules/k3s/bootstrap.nix index 28a8aa9..e49770b 100644 --- a/modules/k3s/bootstrap.nix +++ b/modules/k3s/bootstrap.nix @@ -1,5 +1,5 @@ -{ kubenix, ... }: { - imports = [ kubenix.modules.k8s ]; +{kubenix, ...}: { + imports = [kubenix.modules.k8s]; kubernetes.resources.clusterRoleBindings.cluster-admins = { roleRef = { apiGroup = "rbac.authorization.k8s.io"; diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index d638c81..9b00024 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -1,8 +1,13 @@ -{ self, inputs, pkgs, lib, config, ... }: -let - cfg = config.lab.k3s; -in { + self, + inputs, + pkgs, + lib, + config, + ... +}: let + cfg = config.lab.k3s; +in { options.lab.k3s = { enable = lib.mkOption { default = false; @@ -62,68 +67,66 @@ in address = "/run/nix-snapshotter/nix-snapshotter.sock"; }; - plugins = - let - k3s-cni-plugins = pkgs.buildEnv { - name = "k3s-cni-plugins"; - paths = with pkgs; [ - cni-plugins - cni-plugin-flannel - ]; - }; - in - { - "io.containerd.grpc.v1.cri" = { - stream_server_address = "127.0.0.1"; - stream_server_port = "10010"; - enable_selinux = false; - enable_unprivileged_ports = true; - enable_unprivileged_icmp = true; - disable_apparmor = true; - disable_cgroup = true; - restrict_oom_score_adj = true; - sandbox_image = "rancher/mirrored-pause:3.6"; - containerd.snapshotter = "nix"; + plugins = let + k3s-cni-plugins = pkgs.buildEnv { + name = "k3s-cni-plugins"; + paths = with pkgs; [ + cni-plugins + cni-plugin-flannel + ]; + }; + in { + "io.containerd.grpc.v1.cri" = { + stream_server_address = "127.0.0.1"; + stream_server_port = "10010"; + enable_selinux = false; + enable_unprivileged_ports = true; + enable_unprivileged_icmp = true; + disable_apparmor = true; + disable_cgroup = true; + restrict_oom_score_adj = true; + sandbox_image = "rancher/mirrored-pause:3.6"; + containerd.snapshotter = "nix"; - cni = { - conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d/"; - bin_dir = "${k3s-cni-plugins}/bin"; - }; + cni = { + conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d/"; + bin_dir = "${k3s-cni-plugins}/bin"; }; + }; - "io.containerd.transfer.v1.local".unpack_config = [{ + "io.containerd.transfer.v1.local".unpack_config = [ + { platform = "linux/amd64"; snapshotter = "nix"; - }]; - }; + } + ]; + }; }; }; services = { nix-snapshotter.enable = true; - k3s = - let - serverFlagList = [ - "--image-service-endpoint=unix:///run/nix-snapshotter/nix-snapshotter.sock" - "--snapshotter=overlayfs" - "--container-runtime-endpoint=unix:///run/containerd/containerd.sock" - "--tls-san=${config.networking.fqdn}" - "--disable=servicelb" - "--cluster-cidr=10.42.0.0/16,2001:cafe:42::/56" - "--service-cidr=10.43.0.0/16,2001:cafe:43::/112" - ]; + k3s = let + serverFlagList = [ + "--image-service-endpoint=unix:///run/nix-snapshotter/nix-snapshotter.sock" + "--snapshotter=overlayfs" + "--container-runtime-endpoint=unix:///run/containerd/containerd.sock" + "--tls-san=${config.networking.fqdn}" + "--disable=servicelb" + "--cluster-cidr=10.42.0.0/16,2001:cafe:42::/56" + "--service-cidr=10.43.0.0/16,2001:cafe:43::/112" + ]; - serverFlags = builtins.concatStringsSep " " serverFlagList; - in - { - enable = true; - role = cfg.role; - tokenFile = config.sops.secrets."k3s/serverToken".path; - extraFlags = lib.mkIf (cfg.role == "server") (lib.mkForce serverFlags); - clusterInit = cfg.clusterInit; - serverAddr = lib.mkIf (! (cfg.serverAddr == null)) cfg.serverAddr; - }; + serverFlags = builtins.concatStringsSep " " serverFlagList; + in { + enable = true; + role = cfg.role; + tokenFile = config.sops.secrets."k3s/serverToken".path; + extraFlags = lib.mkIf (cfg.role == "server") (lib.mkForce serverFlags); + clusterInit = cfg.clusterInit; + serverAddr = lib.mkIf (! (cfg.serverAddr == null)) cfg.serverAddr; + }; # Required for Longhorn openiscsi = { @@ -143,11 +146,14 @@ in k3s-bootstrap = lib.mkIf (cfg.role == "server") { text = ( let - k3sBootstrapFile = (inputs.kubenix.evalModules.x86_64-linux { - module = import ./bootstrap.nix; - }).config.kubernetes.result; - in - '' + k3sBootstrapFile = + (inputs.kubenix.evalModules.x86_64-linux { + module = import ./bootstrap.nix; + }) + .config + .kubernetes + .result; + in '' mkdir -p /var/lib/rancher/k3s/server/manifests ln -sf ${k3sBootstrapFile} /var/lib/rancher/k3s/server/manifests/k3s-bootstrap.json '' @@ -166,18 +172,16 @@ in }; }; - sops.secrets = - let - keyPathBase = "/var/lib/rancher/k3s/server/tls"; - in - { - "k3s/serverToken" = { }; - "k3s/keys/clientCAKey".path = "${keyPathBase}/client-ca.key"; - "k3s/keys/requestHeaderCAKey".path = "${keyPathBase}/request-header-ca.key"; - "k3s/keys/serverCAKey".path = "${keyPathBase}/server-ca.key"; - "k3s/keys/serviceKey".path = "${keyPathBase}/service.key"; - "k3s/keys/etcd/peerCAKey".path = "${keyPathBase}/etcd/peer-ca.key"; - "k3s/keys/etcd/serverCAKey".path = "${keyPathBase}/etcd/server-ca.key"; - }; + sops.secrets = let + keyPathBase = "/var/lib/rancher/k3s/server/tls"; + in { + "k3s/serverToken" = {}; + "k3s/keys/clientCAKey".path = "${keyPathBase}/client-ca.key"; + "k3s/keys/requestHeaderCAKey".path = "${keyPathBase}/request-header-ca.key"; + "k3s/keys/serverCAKey".path = "${keyPathBase}/server-ca.key"; + "k3s/keys/serviceKey".path = "${keyPathBase}/service.key"; + "k3s/keys/etcd/peerCAKey".path = "${keyPathBase}/etcd/peer-ca.key"; + "k3s/keys/etcd/serverCAKey".path = "${keyPathBase}/etcd/server-ca.key"; + }; }; } diff --git a/modules/monitoring/default.nix b/modules/monitoring/default.nix index 2d6560d..a67b12e 100644 --- a/modules/monitoring/default.nix +++ b/modules/monitoring/default.nix @@ -1,8 +1,11 @@ -{ lib, config, machines, ... }: -let - cfg = config.lab.monitoring; -in { + lib, + config, + machines, + ... +}: let + cfg = config.lab.monitoring; +in { options = { lab.monitoring = { enable = lib.mkOption { @@ -18,8 +21,9 @@ in }; config = lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [ config.services.prometheus.exporters.node.port ] - ++ lib.lists.optionals cfg.server.enable [ 80 ]; + networking.firewall.allowedTCPPorts = + [config.services.prometheus.exporters.node.port] + ++ lib.lists.optionals cfg.server.enable [80]; services.prometheus = { enable = cfg.server.enable; @@ -32,12 +36,15 @@ in scrapeConfigs = lib.mkIf cfg.server.enable ( let - generated = lib.attrsets.mapAttrsToList + generated = + lib.attrsets.mapAttrsToList (name: machine: { job_name = name; - static_configs = [{ - targets = [ "${name}.dmz:${toString config.services.prometheus.exporters.node.port}" ]; - }]; + static_configs = [ + { + targets = ["${name}.dmz:${toString config.services.prometheus.exporters.node.port}"]; + } + ]; }) machines; @@ -53,12 +60,14 @@ in password = "admin"; }; - static_configs = [{ - targets = [ "pikvm.dmz" ]; - }]; + static_configs = [ + { + targets = ["pikvm.dmz"]; + } + ]; }; in - generated ++ [ pikvm ] + generated ++ [pikvm] ); }; diff --git a/modules/networking/default.nix b/modules/networking/default.nix index df36440..0f235cc 100644 --- a/modules/networking/default.nix +++ b/modules/networking/default.nix @@ -1,4 +1,8 @@ -{ lib, machine, ... }: { +{ + lib, + machine, + ... +}: { config = { networking = { domain = "dmz"; diff --git a/modules/storage.nix b/modules/storage.nix index 670cb7f..d9e5529 100644 --- a/modules/storage.nix +++ b/modules/storage.nix @@ -1,5 +1,8 @@ -{ lib, config, ... }: -let +{ + lib, + config, + ... +}: let cfg = config.lab.storage; modules = [ { @@ -7,7 +10,7 @@ let fileSystems."/" = { device = "/dev/disk/by-label/NIXOS_SD"; fsType = "ext4"; - options = [ "noatime" ]; + options = ["noatime"]; }; }; } @@ -87,7 +90,7 @@ let type = "filesystem"; format = "ext4"; mountpoint = "/"; - mountOptions = [ "defaults" ]; + mountOptions = ["defaults"]; }; }; @@ -145,7 +148,7 @@ let type = "filesystem"; format = "ext4"; mountpoint = "/"; - mountOptions = [ "defaults" ]; + mountOptions = ["defaults"]; }; }; }; @@ -155,8 +158,7 @@ let }; } ]; -in -{ +in { imports = modules; options.lab.storage = { diff --git a/modules/tailscale.nix b/modules/tailscale.nix index d50408e..d24c4d7 100644 --- a/modules/tailscale.nix +++ b/modules/tailscale.nix @@ -1,8 +1,10 @@ -{ lib, config, ... }: -let - cfg = config.lab.tailscale; -in { + lib, + config, + ... +}: let + cfg = config.lab.tailscale; +in { options = { lab.tailscale = { enable = lib.mkEnableOption "tailscale"; @@ -21,15 +23,17 @@ in useRoutingFeatures = "server"; openFirewall = true; - extraUpFlags = [ - "--accept-dns=false" - "--hostname=${config.networking.hostName}" - ] ++ lib.lists.optional cfg.advertiseExitNode "--advertise-exit-node" - ++ lib.lists.optional cfg.advertiseExitNode "--advertise-routes=192.168.30.0/24"; + extraUpFlags = + [ + "--accept-dns=false" + "--hostname=${config.networking.hostName}" + ] + ++ lib.lists.optional cfg.advertiseExitNode "--advertise-exit-node" + ++ lib.lists.optional cfg.advertiseExitNode "--advertise-routes=192.168.30.0/24"; }; - sops.secrets."tailscale/authKey" = { }; + sops.secrets."tailscale/authKey" = {}; - systemd.network.wait-online.ignoredInterfaces = [ "tailscale0" ]; + systemd.network.wait-online.ignoredInterfaces = ["tailscale0"]; }; } diff --git a/nixos.nix b/nixos.nix index 21c0023..4d2d0ad 100644 --- a/nixos.nix +++ b/nixos.nix @@ -1,23 +1,26 @@ -{ self, nixpkgs, ... }@inputs: -let +{ + self, + nixpkgs, + ... +} @ inputs: let deployArch = "x86_64-linux"; machines = self.machines.${deployArch}; mkNixosSystems = systemDef: builtins.mapAttrs - (name: machine: + ( + name: machine: nixpkgs.lib.nixosSystem (systemDef name machine) - ) - machines; -in -{ + ) + machines; +in { nixosConfigurations = mkNixosSystems (name: machine: { system = machine.arch; - specialArgs = { inherit self inputs machine machines; }; + specialArgs = {inherit self inputs machine machines;}; modules = [ "${self}/modules" - { networking.hostName = name; } + {networking.hostName = name;} ]; }); } diff --git a/scripts/default.nix b/scripts/default.nix index e1ffbbc..5386881 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -1,23 +1,31 @@ -{ nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: -let +{ + nixpkgs, + flake-utils, + ... +}: +flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - createScript = { name, runtimeInputs, scriptPath, extraWrapperFlags ? "", ... }: - let - script = (pkgs.writeScriptBin name (builtins.readFile scriptPath)).overrideAttrs (old: { - buildCommand = "${old.buildCommand}\n patchShebangs $out"; - }); - in + createScript = { + name, + runtimeInputs, + scriptPath, + extraWrapperFlags ? "", + ... + }: let + script = (pkgs.writeScriptBin name (builtins.readFile scriptPath)).overrideAttrs (old: { + buildCommand = "${old.buildCommand}\n patchShebangs $out"; + }); + in pkgs.symlinkJoin { inherit name; - paths = [ script ] ++ runtimeInputs; - buildInputs = [ pkgs.makeWrapper ]; + paths = [script] ++ runtimeInputs; + buildInputs = [pkgs.makeWrapper]; postBuild = "wrapProgram $out/bin/${name} --set PATH $out/bin ${extraWrapperFlags}"; }; -in -{ +in { packages.bootstrap = createScript { name = "bootstrap"; - runtimeInputs = with pkgs; [ sops coreutils nixos-anywhere ]; + runtimeInputs = with pkgs; [sops coreutils nixos-anywhere]; scriptPath = ./bootstrap.sh; }; }) diff --git a/shell.nix b/shell.nix index 67e7b03..072adef 100644 --- a/shell.nix +++ b/shell.nix @@ -1,9 +1,12 @@ -{ flake-utils, nixpkgs, ... }: flake-utils.lib.eachDefaultSystem (system: -let - pkgs = nixpkgs.legacyPackages.${system}; -in { + flake-utils, + nixpkgs, + ... +}: +flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; +in { devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ ansible ]; + buildInputs = with pkgs; [ansible]; }; }) diff --git a/utils/default.nix b/utils/default.nix index 297fc3c..e73e360 100644 --- a/utils/default.nix +++ b/utils/default.nix @@ -1,14 +1,14 @@ -{ nixpkgs, flake-utils, ... }: - -let - systemAttrs = flake-utils.lib.eachDefaultSystem (system: - let - pkgs = nixpkgs.legacypackages.${system}; - lib = pkgs.lib; - in - { - net = import ./net.nix lib; - }); +{ + nixpkgs, + flake-utils, + ... +}: let + systemAttrs = flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacypackages.${system}; + lib = pkgs.lib; + in { + net = import ./net.nix lib; + }); nonSystemAttrs = { globals = import ./globals.nix; @@ -16,4 +16,4 @@ let allAttrs = systemAttrs // nonSystemAttrs; in -allAttrs + allAttrs diff --git a/utils/net.nix b/utils/net.nix index 9f5b0e5..d5b15a1 100644 --- a/utils/net.nix +++ b/utils/net.nix @@ -1,367 +1,347 @@ # IP address arithmetic and validation in Nix by @duairc: # https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba - -lib: - -let - - net = { - ip = { - - # add :: (ip | mac | integer) -> ip -> ip - # - # Examples: - # - # Adding integer to IPv4: - # > net.ip.add 100 "10.0.0.1" - # "10.0.0.101" - # - # Adding IPv4 to IPv4: - # > net.ip.add "127.0.0.1" "10.0.0.1" - # "137.0.0.2" - # - # Adding IPv6 to IPv4: - # > net.ip.add "::cafe:beef" "10.0.0.1" - # "212.254.186.191" - # - # Adding MAC to IPv4 (overflows): - # > net.ip.add "fe:ed:fa:ce:f0:0d" "10.0.0.1" - # "4.206.240.14" - # - # Adding integer to IPv6: - # > net.ip.add 100 "dead:cafe:beef::" - # "dead:cafe:beef::64" - # - # Adding IPv4 to to IPv6: - # > net.ip.add "127.0.0.1" "dead:cafe:beef::" - # "dead:cafe:beef::7f00:1" - # - # Adding MAC to IPv6: - # > net.ip.add "fe:ed:fa:ce:f0:0d" "dead:cafe:beef::" - # "dead:cafe:beef::feed:face:f00d" - add = delta: ip: - let +lib: let + net = + { + ip = { + # add :: (ip | mac | integer) -> ip -> ip + # + # Examples: + # + # Adding integer to IPv4: + # > net.ip.add 100 "10.0.0.1" + # "10.0.0.101" + # + # Adding IPv4 to IPv4: + # > net.ip.add "127.0.0.1" "10.0.0.1" + # "137.0.0.2" + # + # Adding IPv6 to IPv4: + # > net.ip.add "::cafe:beef" "10.0.0.1" + # "212.254.186.191" + # + # Adding MAC to IPv4 (overflows): + # > net.ip.add "fe:ed:fa:ce:f0:0d" "10.0.0.1" + # "4.206.240.14" + # + # Adding integer to IPv6: + # > net.ip.add 100 "dead:cafe:beef::" + # "dead:cafe:beef::64" + # + # Adding IPv4 to to IPv6: + # > net.ip.add "127.0.0.1" "dead:cafe:beef::" + # "dead:cafe:beef::7f00:1" + # + # Adding MAC to IPv6: + # > net.ip.add "fe:ed:fa:ce:f0:0d" "dead:cafe:beef::" + # "dead:cafe:beef::feed:face:f00d" + add = delta: ip: let function = "net.ip.add"; delta' = typechecks.numeric function "delta" delta; ip' = typechecks.ip function "ip" ip; in - builders.ip (implementations.ip.add delta' ip'); + builders.ip (implementations.ip.add delta' ip'); - # diff :: ip -> ip -> (integer | ipv6) - # - # net.ip.diff is the reverse of net.ip.add: - # - # net.ip.diff (net.ip.add a b) a = b - # net.ip.diff (net.ip.add a b) b = a - # - # The difference between net.ip.diff and net.ip.subtract is that - # net.ip.diff will try its best to return an integer (falling back - # to an IPv6 if the result is too big to fit in an integer). This is - # useful if you have two hosts that you know are on the same network - # and you just want to calculate the offset between them — a result - # like "0.0.0.10" is not very useful (which is what you would get - # from net.ip.subtract). - diff = minuend: subtrahend: - let + # diff :: ip -> ip -> (integer | ipv6) + # + # net.ip.diff is the reverse of net.ip.add: + # + # net.ip.diff (net.ip.add a b) a = b + # net.ip.diff (net.ip.add a b) b = a + # + # The difference between net.ip.diff and net.ip.subtract is that + # net.ip.diff will try its best to return an integer (falling back + # to an IPv6 if the result is too big to fit in an integer). This is + # useful if you have two hosts that you know are on the same network + # and you just want to calculate the offset between them — a result + # like "0.0.0.10" is not very useful (which is what you would get + # from net.ip.subtract). + diff = minuend: subtrahend: let function = "net.ip.diff"; minuend' = typechecks.ip function "minuend" minuend; subtrahend' = typechecks.ip function "subtrahend" subtrahend; result = implementations.ip.diff minuend' subtrahend'; in - if result ? ipv6 - then builders.ipv6 result - else result; + if result ? ipv6 + then builders.ipv6 result + else result; - # subtract :: (ip | mac | integer) -> ip -> ip - # - # net.ip.subtract is also the reverse of net.ip.add: - # - # net.ip.subtract a (net.ip.add a b) = b - # net.ip.subtract b (net.ip.add a b) = a - # - # The difference between net.ip.subtract and net.ip.diff is that - # net.ip.subtract will always return the same type as its "ip" - # parameter. Its implementation takes the "delta" parameter, - # coerces it to be the same type as the "ip" paramter, negates it - # (using two's complement), and then adds it to "ip". - subtract = delta: ip: - let + # subtract :: (ip | mac | integer) -> ip -> ip + # + # net.ip.subtract is also the reverse of net.ip.add: + # + # net.ip.subtract a (net.ip.add a b) = b + # net.ip.subtract b (net.ip.add a b) = a + # + # The difference between net.ip.subtract and net.ip.diff is that + # net.ip.subtract will always return the same type as its "ip" + # parameter. Its implementation takes the "delta" parameter, + # coerces it to be the same type as the "ip" paramter, negates it + # (using two's complement), and then adds it to "ip". + subtract = delta: ip: let function = "net.ip.subtract"; delta' = typechecks.numeric function "delta" delta; ip' = typechecks.ip function "ip" ip; in - builders.ip (implementations.ip.subtract delta' ip'); - }; + builders.ip (implementations.ip.subtract delta' ip'); + }; - mac = { - - # add :: (ip | mac | integer) -> mac -> mac - # - # Examples: - # - # Adding integer to MAC: - # > net.mac.add 100 "fe:ed:fa:ce:f0:0d" - # "fe:ed:fa:ce:f0:71" - # - # Adding IPv4 to MAC: - # > net.mac.add "127.0.0.1" "fe:ed:fa:ce:f0:0d" - # "fe:ee:79:ce:f0:0e" - # - # Adding IPv6 to MAC: - # > net.mac.add "::cafe:beef" "fe:ed:fa:ce:f0:0d" - # "fe:ee:c5:cd:aa:cb - # - # Adding MAC to MAC: - # > net.mac.add "fe:ed:fa:00:00:00" "00:00:00:ce:f0:0d" - # "fe:ed:fa:ce:f0:0d" - add = delta: mac: - let + mac = { + # add :: (ip | mac | integer) -> mac -> mac + # + # Examples: + # + # Adding integer to MAC: + # > net.mac.add 100 "fe:ed:fa:ce:f0:0d" + # "fe:ed:fa:ce:f0:71" + # + # Adding IPv4 to MAC: + # > net.mac.add "127.0.0.1" "fe:ed:fa:ce:f0:0d" + # "fe:ee:79:ce:f0:0e" + # + # Adding IPv6 to MAC: + # > net.mac.add "::cafe:beef" "fe:ed:fa:ce:f0:0d" + # "fe:ee:c5:cd:aa:cb + # + # Adding MAC to MAC: + # > net.mac.add "fe:ed:fa:00:00:00" "00:00:00:ce:f0:0d" + # "fe:ed:fa:ce:f0:0d" + add = delta: mac: let function = "net.mac.add"; delta' = typechecks.numeric function "delta" delta; mac' = typechecks.mac function "mac" mac; in - builders.mac (implementations.mac.add delta' mac'); + builders.mac (implementations.mac.add delta' mac'); - # diff :: mac -> mac -> integer - # - # net.mac.diff is the reverse of net.mac.add: - # - # net.mac.diff (net.mac.add a b) a = b - # net.mac.diff (net.mac.add a b) b = a - # - # The difference between net.mac.diff and net.mac.subtract is that - # net.mac.diff will always return an integer. - diff = minuend: subtrahend: - let + # diff :: mac -> mac -> integer + # + # net.mac.diff is the reverse of net.mac.add: + # + # net.mac.diff (net.mac.add a b) a = b + # net.mac.diff (net.mac.add a b) b = a + # + # The difference between net.mac.diff and net.mac.subtract is that + # net.mac.diff will always return an integer. + diff = minuend: subtrahend: let function = "net.mac.diff"; minuend' = typechecks.mac function "minuend" minuend; subtrahend' = typechecks.mac function "subtrahend" subtrahend; in - implementations.mac.diff minuend' subtrahend'; + implementations.mac.diff minuend' subtrahend'; - # subtract :: (ip | mac | integer) -> mac -> mac - # - # net.mac.subtract is also the reverse of net.ip.add: - # - # net.mac.subtract a (net.mac.add a b) = b - # net.mac.subtract b (net.mac.add a b) = a - # - # The difference between net.mac.subtract and net.mac.diff is that - # net.mac.subtract will always return a MAC address. - subtract = delta: mac: - let + # subtract :: (ip | mac | integer) -> mac -> mac + # + # net.mac.subtract is also the reverse of net.ip.add: + # + # net.mac.subtract a (net.mac.add a b) = b + # net.mac.subtract b (net.mac.add a b) = a + # + # The difference between net.mac.subtract and net.mac.diff is that + # net.mac.subtract will always return a MAC address. + subtract = delta: mac: let function = "net.mac.subtract"; delta' = typechecks.numeric function "delta" delta; mac' = typechecks.mac function "mac" mac; in - builders.mac (implementations.mac.subtract delta' mac'); - }; + builders.mac (implementations.mac.subtract delta' mac'); + }; - cidr = { - # add :: (ip | mac | integer) -> cidr -> cidr - # - # > net.cidr.add 2 "127.0.0.0/8" - # "129.0.0.0/8" - # - # > net.cidr.add (-2) "127.0.0.0/8" - # "125.0.0.0/8" - add = delta: cidr: - let + cidr = { + # add :: (ip | mac | integer) -> cidr -> cidr + # + # > net.cidr.add 2 "127.0.0.0/8" + # "129.0.0.0/8" + # + # > net.cidr.add (-2) "127.0.0.0/8" + # "125.0.0.0/8" + add = delta: cidr: let function = "net.cidr.add"; delta' = typechecks.numeric function "delta" delta; cidr' = typechecks.cidr function "cidr" cidr; in - builders.cidr (implementations.cidr.add delta' cidr'); + builders.cidr (implementations.cidr.add delta' cidr'); - # child :: cidr -> cidr -> bool - # - # > net.cidr.child "10.10.10.0/24" "10.0.0.0/8" - # true - # - # > net.cidr.child "127.0.0.0/8" "10.0.0.0/8" - # false - child = subcidr: cidr: - let + # child :: cidr -> cidr -> bool + # + # > net.cidr.child "10.10.10.0/24" "10.0.0.0/8" + # true + # + # > net.cidr.child "127.0.0.0/8" "10.0.0.0/8" + # false + child = subcidr: cidr: let function = "net.cidr.child"; subcidr' = typechecks.cidr function "subcidr" subcidr; cidr' = typechecks.cidr function "cidr" cidr; in - implementations.cidr.child subcidr' cidr'; + implementations.cidr.child subcidr' cidr'; - # contains :: ip -> cidr -> bool - # - # > net.cidr.contains "127.0.0.1" "127.0.0.0/8" - # true - # - # > net.cidr.contains "127.0.0.1" "192.168.0.0/16" - # false - contains = ip: cidr: - let + # contains :: ip -> cidr -> bool + # + # > net.cidr.contains "127.0.0.1" "127.0.0.0/8" + # true + # + # > net.cidr.contains "127.0.0.1" "192.168.0.0/16" + # false + contains = ip: cidr: let function = "net.cidr.contains"; ip' = typechecks.ip function "ip" ip; cidr' = typechecks.cidr function "cidr" cidr; in - implementations.cidr.contains ip' cidr'; + implementations.cidr.contains ip' cidr'; - # capacity :: cidr -> integer - # - # > net.cidr.capacity "172.16.0.0/12" - # 1048576 - # - # > net.cidr.capacity "dead:cafe:beef::/96" - # 4294967296 - # - # > net.cidr.capacity "dead:cafe:beef::/48" (saturates to maxBound) - # 9223372036854775807 - capacity = cidr: - let + # capacity :: cidr -> integer + # + # > net.cidr.capacity "172.16.0.0/12" + # 1048576 + # + # > net.cidr.capacity "dead:cafe:beef::/96" + # 4294967296 + # + # > net.cidr.capacity "dead:cafe:beef::/48" (saturates to maxBound) + # 9223372036854775807 + capacity = cidr: let function = "net.cidr.capacity"; cidr' = typechecks.cidr function "cidr" cidr; in - implementations.cidr.capacity cidr'; + implementations.cidr.capacity cidr'; - # host :: (ip | mac | integer) -> cidr -> ip - # - # > net.cidr.host 10000 "10.0.0.0/8" - # 10.0.39.16 - # - # > net.cidr.host 10000 "dead:cafe:beef::/64" - # "dead:cafe:beef::2710" - # - # net.cidr.host "127.0.0.1" "dead:cafe:beef::/48" - # > "dead:cafe:beef::7f00:1" - # - # Inpsired by: - # https://www.terraform.io/docs/configuration/functions/cidrhost.html - host = hostnum: cidr: - let + # host :: (ip | mac | integer) -> cidr -> ip + # + # > net.cidr.host 10000 "10.0.0.0/8" + # 10.0.39.16 + # + # > net.cidr.host 10000 "dead:cafe:beef::/64" + # "dead:cafe:beef::2710" + # + # net.cidr.host "127.0.0.1" "dead:cafe:beef::/48" + # > "dead:cafe:beef::7f00:1" + # + # Inpsired by: + # https://www.terraform.io/docs/configuration/functions/cidrhost.html + host = hostnum: cidr: let function = "net.cidr.host"; hostnum' = typechecks.numeric function "hostnum" hostnum; cidr' = typechecks.cidr function "cidr" cidr; in - builders.ip (implementations.cidr.host hostnum' cidr'); + builders.ip (implementations.cidr.host hostnum' cidr'); - # length :: cidr -> integer - # - # > net.cidr.prefix "127.0.0.0/8" - # 8 - # - # > net.cidr.prefix "dead:cafe:beef::/48" - # 48 - length = cidr: - let + # length :: cidr -> integer + # + # > net.cidr.prefix "127.0.0.0/8" + # 8 + # + # > net.cidr.prefix "dead:cafe:beef::/48" + # 48 + length = cidr: let function = "net.cidr.length"; cidr' = typechecks.cidr function "cidr" cidr; in - implementations.cidr.length cidr'; + implementations.cidr.length cidr'; - # make :: integer -> ip -> cidr - # - # > net.cidr.make 24 "192.168.0.150" - # "192.168.0.0/24" - # - # > net.cidr.make 40 "dead:cafe:beef::feed:face:f00d" - # "dead:cafe:be00::/40" - make = length: base: - let + # make :: integer -> ip -> cidr + # + # > net.cidr.make 24 "192.168.0.150" + # "192.168.0.0/24" + # + # > net.cidr.make 40 "dead:cafe:beef::feed:face:f00d" + # "dead:cafe:be00::/40" + make = length: base: let function = "net.cidr.make"; length' = typechecks.int function "length" length; base' = typechecks.ip function "base" base; in - builders.cidr (implementations.cidr.make length' base'); + builders.cidr (implementations.cidr.make length' base'); - # netmask :: cidr -> ip - # - # > net.cidr.netmask "192.168.0.0/24" - # "255.255.255.0" - # - # > net.cidr.netmask "dead:cafe:beef::/64" - # "ffff:ffff:ffff:ffff::" - netmask = cidr: - let + # netmask :: cidr -> ip + # + # > net.cidr.netmask "192.168.0.0/24" + # "255.255.255.0" + # + # > net.cidr.netmask "dead:cafe:beef::/64" + # "ffff:ffff:ffff:ffff::" + netmask = cidr: let function = "net.cidr.netmask"; cidr' = typechecks.cidr function "cidr" cidr; in - builders.ip (implementations.cidr.netmask cidr'); + builders.ip (implementations.cidr.netmask cidr'); - # size :: cidr -> integer - # - # > net.cidr.prefix "127.0.0.0/8" - # 24 - # - # > net.cidr.prefix "dead:cafe:beef::/48" - # 80 - size = cidr: - let + # size :: cidr -> integer + # + # > net.cidr.prefix "127.0.0.0/8" + # 24 + # + # > net.cidr.prefix "dead:cafe:beef::/48" + # 80 + size = cidr: let function = "net.cidr.size"; cidr' = typechecks.cidr function "cidr" cidr; in - implementations.cidr.size cidr'; + implementations.cidr.size cidr'; - # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr - # - # > net.cidr.subnet 4 2 "172.16.0.0/12" - # "172.18.0.0/16" - # - # > net.cidr.subnet 4 15 "10.1.2.0/24" - # "10.1.2.240/28" - # - # > net.cidr.subnet 16 162 "fd00:fd12:3456:7890::/56" - # "fd00:fd12:3456:7800:a200::/72" - # - # Inspired by: - # https://www.terraform.io/docs/configuration/functions/cidrsubnet.html - subnet = length: netnum: cidr: - let + # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr + # + # > net.cidr.subnet 4 2 "172.16.0.0/12" + # "172.18.0.0/16" + # + # > net.cidr.subnet 4 15 "10.1.2.0/24" + # "10.1.2.240/28" + # + # > net.cidr.subnet 16 162 "fd00:fd12:3456:7890::/56" + # "fd00:fd12:3456:7800:a200::/72" + # + # Inspired by: + # https://www.terraform.io/docs/configuration/functions/cidrsubnet.html + subnet = length: netnum: cidr: let function = "net.cidr.subnet"; length' = typechecks.int function "length" length; netnum' = typechecks.numeric function "netnum" netnum; cidr' = typechecks.cidr function "cidr" cidr; in - builders.cidr (implementations.cidr.subnet length' netnum' cidr'); - - }; - } // ({ - types = - let - - mkParsedOptionType = { name, description, parser, builder }: - let - normalize = def: def // { + builders.cidr (implementations.cidr.subnet length' netnum' cidr'); + }; + } + // { + types = let + mkParsedOptionType = { + name, + description, + parser, + builder, + }: let + normalize = def: + def + // { value = builder (parser def.value); }; - in + in lib.mkOptionType { inherit name description; check = x: builtins.isString x && parser x != null; merge = loc: defs: lib.mergeEqualOption loc (map normalize defs); }; - dependent-ip = type: cidr: - let - cidrs = - if builtins.isList cidr - then cidr - else [ cidr ]; - in - lib.types.addCheck type (i: lib.any (net.cidr.contains i) cidrs) // { + dependent-ip = type: cidr: let + cidrs = + if builtins.isList cidr + then cidr + else [cidr]; + in + lib.types.addCheck type (i: lib.any (net.cidr.contains i) cidrs) + // { description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; }; - dependent-cidr = type: cidr: - let - cidrs = - if builtins.isList cidr - then cidr - else [ cidr ]; - in - lib.types.addCheck type (i: lib.any (net.cidr.child i) cidrs) // { + dependent-cidr = type: cidr: let + cidrs = + if builtins.isList cidr + then cidr + else [cidr]; + in + lib.types.addCheck type (i: lib.any (net.cidr.child i) cidrs) + // { description = type.description + " in ${builtins.concatStringsSep " or " cidrs}"; }; - - in - rec { - + in rec { ip = mkParsedOptionType { name = "ip"; description = "IPv4 or IPv6 address"; @@ -422,46 +402,44 @@ let parser = parsers.mac; builder = builders.mac; }; - }; - } - ); + }; list = { - cons = a: b: [ a ] ++ b; + cons = a: b: [a] ++ b; }; - bit = - let - shift = n: x: - if n < 0 - then x * math.pow 2 (-n) - else - let - safeDiv = n: d: if d == 0 then 0 else n / d; - d = math.pow 2 n; - in - if x < 0 - then not (safeDiv (not x) d) - else safeDiv x d; + bit = let + shift = n: x: + if n < 0 + then x * math.pow 2 (-n) + else let + safeDiv = n: d: + if d == 0 + then 0 + else n / d; + d = math.pow 2 n; + in + if x < 0 + then not (safeDiv (not x) d) + else safeDiv x d; - left = n: shift (-n); + left = n: shift (-n); - right = shift; + right = shift; - and = builtins.bitAnd; + and = builtins.bitAnd; - or = builtins.bitOr; + or = builtins.bitOr; - xor = builtins.bitXor; + xor = builtins.bitXor; - not = xor (-1); + not = xor (-1); - mask = n: and (left n 1 - 1); - in - { - inherit left right and or xor not mask; - }; + mask = n: and (left n 1 - 1); + in { + inherit left right and or xor not mask; + }; math = rec { max = a: b: @@ -484,89 +462,88 @@ let else pow (x * x) (n / 2); }; - parsers = - let + parsers = let + # fmap :: (a -> b) -> parser a -> parser b + fmap = f: ma: bind ma (a: pure (f a)); - # fmap :: (a -> b) -> parser a -> parser b - fmap = f: ma: bind ma (a: pure (f a)); + # pure :: a -> parser a + pure = a: string: { + leftovers = string; + result = a; + }; - # pure :: a -> parser a - pure = a: string: { - leftovers = string; - result = a; + # liftA2 :: (a -> b -> c) -> parser a -> parser b -> parser c + liftA2 = f: ma: mb: bind ma (a: bind mb (b: pure (f a b))); + liftA3 = f: a: b: ap (liftA2 f a b); + liftA4 = f: a: b: c: ap (liftA3 f a b c); + liftA5 = f: a: b: c: d: ap (liftA4 f a b c d); + liftA6 = f: a: b: c: d: e: ap (liftA5 f a b c d e); + + # ap :: parser (a -> b) -> parser a -> parser b + ap = liftA2 (a: a); + + # then_ :: parser a -> parser b -> parser b + then_ = liftA2 (a: b: b); + + # empty :: parser a + empty = string: null; + + # alt :: parser a -> parser a -> parser a + alt = left: right: string: let + result = left string; + in + if builtins.isNull result + then right string + else result; + + # guard :: bool -> parser {} + guard = condition: + if condition + then pure {} + else empty; + + # mfilter :: (a -> bool) -> parser a -> parser a + mfilter = f: parser: bind parser (a: then_ (guard (f a)) (pure a)); + + # some :: parser a -> parser [a] + some = v: liftA2 list.cons v (many v); + + # many :: parser a -> parser [a] + many = v: alt (some v) (pure []); + + # bind :: parser a -> (a -> parser b) -> parser b + bind = parser: f: string: let + a = parser string; + in + if builtins.isNull a + then null + else f a.result a.leftovers; + + # run :: parser a -> string -> maybe a + run = parser: string: let + result = parser string; + in + if builtins.isNull result || result.leftovers != "" + then null + else result.result; + + next = string: + if string == "" + then null + else { + leftovers = builtins.substring 1 (-1) string; + result = builtins.substring 0 1 string; }; - # liftA2 :: (a -> b -> c) -> parser a -> parser b -> parser c - liftA2 = f: ma: mb: bind ma (a: bind mb (b: pure (f a b))); - liftA3 = f: a: b: ap (liftA2 f a b); - liftA4 = f: a: b: c: ap (liftA3 f a b c); - liftA5 = f: a: b: c: d: ap (liftA4 f a b c d); - liftA6 = f: a: b: c: d: e: ap (liftA5 f a b c d e); - - # ap :: parser (a -> b) -> parser a -> parser b - ap = liftA2 (a: a); - - # then_ :: parser a -> parser b -> parser b - then_ = liftA2 (a: b: b); - - # empty :: parser a - empty = string: null; - - # alt :: parser a -> parser a -> parser a - alt = left: right: string: - let - result = left string; - in - if builtins.isNull result - then right string - else result; - - # guard :: bool -> parser {} - guard = condition: if condition then pure { } else empty; - - # mfilter :: (a -> bool) -> parser a -> parser a - mfilter = f: parser: bind parser (a: then_ (guard (f a)) (pure a)); - - # some :: parser a -> parser [a] - some = v: liftA2 list.cons v (many v); - - # many :: parser a -> parser [a] - many = v: alt (some v) (pure [ ]); - - # bind :: parser a -> (a -> parser b) -> parser b - bind = parser: f: string: - let - a = parser string; - in - if builtins.isNull a - then null - else f a.result a.leftovers; - - # run :: parser a -> string -> maybe a - run = parser: string: - let - result = parser string; - in - if builtins.isNull result || result.leftovers != "" - then null - else result.result; - - next = string: - if string == "" - then null - else { - leftovers = builtins.substring 1 (-1) string; - result = builtins.substring 0 1 string; - }; - - # Count how many characters were consumed by a parser - count = parser: string: - let - result = parser string; - in - if builtins.isNull result - then null - else result // { + # Count how many characters were consumed by a parser + count = parser: string: let + result = parser string; + in + if builtins.isNull result + then null + else + result + // { result = { inherit (result) result; count = with result; @@ -574,46 +551,49 @@ let }; }; - # Limit the parser to n characters at most - limit = n: parser: - fmap (a: a.result) (mfilter (a: a.count <= n) (count parser)); + # Limit the parser to n characters at most + limit = n: parser: + fmap (a: a.result) (mfilter (a: a.count <= n) (count parser)); - # Ensure the parser consumes exactly n characters - exactly = n: parser: - fmap (a: a.result) (mfilter (a: a.count == n) (count parser)); + # Ensure the parser consumes exactly n characters + exactly = n: parser: + fmap (a: a.result) (mfilter (a: a.count == n) (count parser)); - char = c: bind next (c': guard (c == c')); + char = c: bind next (c': guard (c == c')); - string = css: - if css == "" - then pure { } - else - let - c = builtins.substring 0 1 css; - cs = builtins.substring 1 (-1) css; - in - then_ (char c) (string cs); + string = css: + if css == "" + then pure {} + else let + c = builtins.substring 0 1 css; + cs = builtins.substring 1 (-1) css; + in + then_ (char c) (string cs); - digit = set: bind next ( - c: then_ + digit = set: + bind next ( + c: + then_ (guard (builtins.hasAttr c set)) (pure (builtins.getAttr c set)) ); - decimalDigits = { - "0" = 0; - "1" = 1; - "2" = 2; - "3" = 3; - "4" = 4; - "5" = 5; - "6" = 6; - "7" = 7; - "8" = 8; - "9" = 9; - }; + decimalDigits = { + "0" = 0; + "1" = 1; + "2" = 2; + "3" = 3; + "4" = 4; + "5" = 5; + "6" = 6; + "7" = 7; + "8" = 8; + "9" = 9; + }; - hexadecimalDigits = decimalDigits // { + hexadecimalDigits = + decimalDigits + // { "a" = 10; "b" = 11; "c" = 12; @@ -628,328 +608,293 @@ let "F" = 15; }; - fromDecimalDigits = builtins.foldl' (a: c: a * 10 + c) 0; - fromHexadecimalDigits = builtins.foldl' (a: bit.or (bit.left 4 a)) 0; + fromDecimalDigits = builtins.foldl' (a: c: a * 10 + c) 0; + fromHexadecimalDigits = builtins.foldl' (a: bit.or (bit.left 4 a)) 0; - # disallow leading zeros - decimal = bind (digit decimalDigits) ( - n: + # disallow leading zeros + decimal = bind (digit decimalDigits) ( + n: if n == 0 then pure 0 else fmap - (ns: fromDecimalDigits (list.cons n ns)) - (many (digit decimalDigits)) - ); + (ns: fromDecimalDigits (list.cons n ns)) + (many (digit decimalDigits)) + ); - hexadecimal = fmap fromHexadecimalDigits (some (digit hexadecimalDigits)); + hexadecimal = fmap fromHexadecimalDigits (some (digit hexadecimalDigits)); - ipv4 = - let - dot = char "."; + ipv4 = let + dot = char "."; - octet = mfilter (n: n < 256) decimal; + octet = mfilter (n: n < 256) decimal; - octet' = then_ dot octet; + octet' = then_ dot octet; - fromOctets = a: b: c: d: { - ipv4 = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d; + fromOctets = a: b: c: d: { + ipv4 = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d; + }; + in + liftA4 fromOctets octet octet' octet' octet'; + + # This is more or less a literal translation of + # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#parser + ipv6 = let + colon = char ":"; + + hextet = limit 4 hexadecimal; + + fromHextets = hextets: + if builtins.length hextets != 8 + then empty + else let + a = builtins.elemAt hextets 0; + b = builtins.elemAt hextets 1; + c = builtins.elemAt hextets 2; + d = builtins.elemAt hextets 3; + e = builtins.elemAt hextets 4; + f = builtins.elemAt hextets 5; + g = builtins.elemAt hextets 6; + h = builtins.elemAt hextets 7; + in + pure { + ipv6 = { + a = bit.or (bit.left 16 a) b; + b = bit.or (bit.left 16 c) d; + c = bit.or (bit.left 16 e) f; + d = bit.or (bit.left 16 g) h; + }; }; - in - liftA4 fromOctets octet octet' octet' octet'; - # This is more or less a literal translation of - # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#parser - ipv6 = - let - colon = char ":"; + ipv4' = + fmap + ( + address: let + upper = bit.right 16 address.ipv4; + lower = bit.mask 16 address.ipv4; + in [upper lower] + ) + ipv4; - hextet = limit 4 hexadecimal; - - fromHextets = hextets: - if builtins.length hextets != 8 - then empty - else - let - a = builtins.elemAt hextets 0; - b = builtins.elemAt hextets 1; - c = builtins.elemAt hextets 2; - d = builtins.elemAt hextets 3; - e = builtins.elemAt hextets 4; - f = builtins.elemAt hextets 5; - g = builtins.elemAt hextets 6; - h = builtins.elemAt hextets 7; - in - pure { - ipv6 = { - a = bit.or (bit.left 16 a) b; - b = bit.or (bit.left 16 c) d; - c = bit.or (bit.left 16 e) f; - d = bit.or (bit.left 16 g) h; - }; - }; - - ipv4' = fmap + part = n: let + n' = n + 1; + hex = + liftA2 list.cons hextet + ( + then_ colon ( - address: - let - upper = bit.right 16 address.ipv4; - lower = bit.mask 16 address.ipv4; - in - [ upper lower ] + alt + (then_ colon (doubleColon n')) + (part n') ) - ipv4; + ); + in + if n == 7 + then fmap (a: [a]) hextet + else if n == 6 + then alt ipv4' hex + else hex; - part = n: - let - n' = n + 1; - hex = liftA2 list.cons hextet - ( - then_ colon - ( - alt - (then_ colon (doubleColon n')) - (part n') - ) - ); - in - if n == 7 - then fmap (a: [ a ]) hextet - else - if n == 6 - then alt ipv4' hex - else hex; + doubleColon = n: + bind (alt afterDoubleColon (pure [])) ( + rest: let + missing = 8 - n - builtins.length rest; + in + if missing < 0 + then empty + else pure (builtins.genList (_: 0) missing ++ rest) + ); - doubleColon = n: - bind (alt afterDoubleColon (pure [ ])) ( - rest: - let - missing = 8 - n - builtins.length rest; - in - if missing < 0 - then empty - else pure (builtins.genList (_: 0) missing ++ rest) - ); - - afterDoubleColon = - alt ipv4' - ( - liftA2 list.cons hextet - ( - alt - (then_ colon afterDoubleColon) - (pure [ ]) - ) - ); - - in - bind + afterDoubleColon = + alt ipv4' + ( + liftA2 list.cons hextet ( alt - ( - then_ - (string "::") - (doubleColon 0) - ) - (part 0) + (then_ colon afterDoubleColon) + (pure []) ) - fromHextets; - - cidrv4 = - liftA2 - (base: length: implementations.cidr.make length base) - ipv4 - (then_ (char "/") (mfilter (n: n <= 32) decimal)); - - cidrv6 = - liftA2 - (base: length: implementations.cidr.make length base) - ipv6 - (then_ (char "/") (mfilter (n: n <= 128) decimal)); - - mac = - let - colon = char ":"; - - octet = exactly 2 hexadecimal; - - octet' = then_ colon octet; - - fromOctets = a: b: c: d: e: f: { - mac = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d)) e)) f; - }; - in - liftA6 fromOctets octet octet' octet' octet' octet' octet'; - + ); in - { - ipv4 = run ipv4; - ipv6 = run ipv6; - ip = run (alt ipv4 ipv6); - cidrv4 = run cidrv4; - cidrv6 = run cidrv6; - cidr = run (alt cidrv4 cidrv6); - mac = run mac; - numeric = run (alt (alt ipv4 ipv6) mac); - }; + bind + ( + alt + ( + then_ + (string "::") + (doubleColon 0) + ) + (part 0) + ) + fromHextets; - builders = - let + cidrv4 = + liftA2 + (base: length: implementations.cidr.make length base) + ipv4 + (then_ (char "/") (mfilter (n: n <= 32) decimal)); - ipv4 = address: - let - abcd = address.ipv4; - abc = bit.right 8 abcd; - ab = bit.right 8 abc; - a = bit.right 8 ab; - b = bit.mask 8 ab; - c = bit.mask 8 abc; - d = bit.mask 8 abcd; - in - builtins.concatStringsSep "." (map toString [ a b c d ]); + cidrv6 = + liftA2 + (base: length: implementations.cidr.make length base) + ipv6 + (then_ (char "/") (mfilter (n: n <= 128) decimal)); - # This is more or less a literal translation of - # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#encode - ipv6 = address: - let + mac = let + colon = char ":"; - digits = "0123456789abcdef"; + octet = exactly 2 hexadecimal; - toHexString = n: - let - rest = bit.right 4 n; - current = bit.mask 4 n; - prefix = - if rest == 0 - then "" - else toHexString rest; - in - "${prefix}${builtins.substring current 1 digits}"; - - in - if (with address.ipv6; a == 0 && b == 0 && c == 0 && d > 65535) - then "::${ipv4 { ipv4 = address.ipv6.d; }}" - else - if (with address.ipv6; a == 0 && b == 0 && c == 65535) - then "::ffff:${ipv4 { ipv4 = address.ipv6.d; }}" - else - let - - a = bit.right 16 address.ipv6.a; - b = bit.mask 16 address.ipv6.a; - c = bit.right 16 address.ipv6.b; - d = bit.mask 16 address.ipv6.b; - e = bit.right 16 address.ipv6.c; - f = bit.mask 16 address.ipv6.c; - g = bit.right 16 address.ipv6.d; - h = bit.mask 16 address.ipv6.d; - - hextets = [ a b c d e f g h ]; - - # calculate the position and size of the longest sequence of - # zeroes within the list of hextets - longest = - let - go = i: current: best: - if i < builtins.length hextets - then - let - n = builtins.elemAt hextets i; - - current' = - if n == 0 - then - if builtins.isNull current - then { - size = 1; - position = i; - } - else current // { - size = current.size + 1; - } - else null; - - best' = - if n == 0 - then - if builtins.isNull best - then current' - else - if current'.size > best.size - then current' - else best - else best; - in - go (i + 1) current' best' - else best; - in - go 0 null null; - - format = hextets: - builtins.concatStringsSep ":" (map toHexString hextets); - in - if builtins.isNull longest - then format hextets - else - let - sublist = i: length: xs: - map - (builtins.elemAt xs) - (builtins.genList (x: x + i) length); - - end = longest.position + longest.size; - - before = sublist 0 longest.position hextets; - - after = sublist end (builtins.length hextets - end) hextets; - in - "${format before}::${format after}"; - - ip = address: - if address ? ipv4 - then ipv4 address - else ipv6 address; - - cidrv4 = cidr: - "${ipv4 cidr.base}/${toString cidr.length}"; - - cidrv6 = cidr: - "${ipv6 cidr.base}/${toString cidr.length}"; - - cidr = cidr: - "${ip cidr.base}/${toString cidr.length}"; - - mac = address: - let - digits = "0123456789abcdef"; - octet = n: - let - upper = bit.right 4 n; - lower = bit.mask 4 n; - in - "${builtins.substring upper 1 digits}${builtins.substring lower 1 digits}"; - in - let - a = bit.mask 8 (bit.right 40 address.mac); - b = bit.mask 8 (bit.right 32 address.mac); - c = bit.mask 8 (bit.right 24 address.mac); - d = bit.mask 8 (bit.right 16 address.mac); - e = bit.mask 8 (bit.right 8 address.mac); - f = bit.mask 8 (bit.right 0 address.mac); - in - "${octet a}:${octet b}:${octet c}:${octet d}:${octet e}:${octet f}"; + octet' = then_ colon octet; + fromOctets = a: b: c: d: e: f: { + mac = bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 (bit.or (bit.left 8 a) b)) c)) d)) e)) f; + }; in - { - inherit ipv4 ipv6 ip cidrv4 cidrv6 cidr mac; - }; + liftA6 fromOctets octet octet' octet' octet' octet' octet'; + in { + ipv4 = run ipv4; + ipv6 = run ipv6; + ip = run (alt ipv4 ipv6); + cidrv4 = run cidrv4; + cidrv6 = run cidrv6; + cidr = run (alt cidrv4 cidrv6); + mac = run mac; + numeric = run (alt (alt ipv4 ipv6) mac); + }; + + builders = let + ipv4 = address: let + abcd = address.ipv4; + abc = bit.right 8 abcd; + ab = bit.right 8 abc; + a = bit.right 8 ab; + b = bit.mask 8 ab; + c = bit.mask 8 abc; + d = bit.mask 8 abcd; + in + builtins.concatStringsSep "." (map toString [a b c d]); + + # This is more or less a literal translation of + # https://hackage.haskell.org/package/ip/docs/src/Net.IPv6.html#encode + ipv6 = address: let + digits = "0123456789abcdef"; + + toHexString = n: let + rest = bit.right 4 n; + current = bit.mask 4 n; + prefix = + if rest == 0 + then "" + else toHexString rest; + in "${prefix}${builtins.substring current 1 digits}"; + in + if (with address.ipv6; a == 0 && b == 0 && c == 0 && d > 65535) + then "::${ipv4 {ipv4 = address.ipv6.d;}}" + else if (with address.ipv6; a == 0 && b == 0 && c == 65535) + then "::ffff:${ipv4 {ipv4 = address.ipv6.d;}}" + else let + a = bit.right 16 address.ipv6.a; + b = bit.mask 16 address.ipv6.a; + c = bit.right 16 address.ipv6.b; + d = bit.mask 16 address.ipv6.b; + e = bit.right 16 address.ipv6.c; + f = bit.mask 16 address.ipv6.c; + g = bit.right 16 address.ipv6.d; + h = bit.mask 16 address.ipv6.d; + + hextets = [a b c d e f g h]; + + # calculate the position and size of the longest sequence of + # zeroes within the list of hextets + longest = let + go = i: current: best: + if i < builtins.length hextets + then let + n = builtins.elemAt hextets i; + + current' = + if n == 0 + then + if builtins.isNull current + then { + size = 1; + position = i; + } + else + current + // { + size = current.size + 1; + } + else null; + + best' = + if n == 0 + then + if builtins.isNull best + then current' + else if current'.size > best.size + then current' + else best + else best; + in + go (i + 1) current' best' + else best; + in + go 0 null null; + + format = hextets: + builtins.concatStringsSep ":" (map toHexString hextets); + in + if builtins.isNull longest + then format hextets + else let + sublist = i: length: xs: + map + (builtins.elemAt xs) + (builtins.genList (x: x + i) length); + + end = longest.position + longest.size; + + before = sublist 0 longest.position hextets; + + after = sublist end (builtins.length hextets - end) hextets; + in "${format before}::${format after}"; + + ip = address: + if address ? ipv4 + then ipv4 address + else ipv6 address; + + cidrv4 = cidr: "${ipv4 cidr.base}/${toString cidr.length}"; + + cidrv6 = cidr: "${ipv6 cidr.base}/${toString cidr.length}"; + + cidr = cidr: "${ip cidr.base}/${toString cidr.length}"; + + mac = address: let + digits = "0123456789abcdef"; + octet = n: let + upper = bit.right 4 n; + lower = bit.mask 4 n; + in "${builtins.substring upper 1 digits}${builtins.substring lower 1 digits}"; + in let + a = bit.mask 8 (bit.right 40 address.mac); + b = bit.mask 8 (bit.right 32 address.mac); + c = bit.mask 8 (bit.right 24 address.mac); + d = bit.mask 8 (bit.right 16 address.mac); + e = bit.mask 8 (bit.right 8 address.mac); + f = bit.mask 8 (bit.right 0 address.mac); + in "${octet a}:${octet b}:${octet c}:${octet d}:${octet e}:${octet f}"; + in { + inherit ipv4 ipv6 ip cidrv4 cidrv6 cidr mac; + }; arithmetic = rec { # or :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - or = a_: b: - let - a = coerce b a_; - in + or = a_: b: let + a = coerce b a_; + in if a ? ipv6 then { ipv6 = { @@ -970,10 +915,9 @@ let else bit.or a b; # and :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - and = a_: b: - let - a = coerce b a_; - in + and = a_: b: let + a = coerce b a_; + in if a ? ipv6 then { ipv6 = { @@ -1015,33 +959,29 @@ let else bit.not a; # add :: (ip | mac | integer) -> (ip | mac | integer) -> (ip | mac | integer) - add = - let - split = a: { - fst = bit.mask 32 (bit.right 32 a); - snd = bit.mask 32 a; - }; + add = let + split = a: { + fst = bit.mask 32 (bit.right 32 a); + snd = bit.mask 32 a; + }; + in + a_: b: let + a = coerce b a_; in - a_: b: - let - a = coerce b a_; - in if a ? ipv6 - then - let - a' = split (a.ipv6.a + b.ipv6.a + b'.fst); - b' = split (a.ipv6.b + b.ipv6.b + c'.fst); - c' = split (a.ipv6.c + b.ipv6.c + d'.fst); - d' = split (a.ipv6.d + b.ipv6.d); - in - { - ipv6 = { - a = a'.snd; - b = b'.snd; - c = c'.snd; - d = d'.snd; - }; - } + then let + a' = split (a.ipv6.a + b.ipv6.a + b'.fst); + b' = split (a.ipv6.b + b.ipv6.b + c'.fst); + c' = split (a.ipv6.c + b.ipv6.c + d'.fst); + d' = split (a.ipv6.d + b.ipv6.d); + in { + ipv6 = { + a = a'.snd; + b = b'.snd; + c = c'.snd; + d = d'.snd; + }; + } else if a ? ipv4 then { ipv4 = bit.mask 32 (a.ipv4 + b.ipv4); @@ -1056,12 +996,11 @@ let subtract = a: b: add (add 1 (not (coerce b a))) b; # diff :: (ip | mac | integer) -> (ip | mac | integer) -> (ipv6 | integer) - diff = a: b: - let - toIPv6 = coerce ({ ipv6.a = 0; }); - result = (subtract b (toIPv6 a)).ipv6; - max32 = bit.left 32 1 - 1; - in + diff = a: b: let + toIPv6 = coerce {ipv6.a = 0;}; + result = (subtract b (toIPv6 a)).ipv6; + max32 = bit.left 32 1 - 1; + in if result.a == 0 && result.b == 0 && bit.right 31 result.c == 0 || result.a == max32 && result.b == max32 && bit.right 31 result.c == 1 then bit.or (bit.left 32 result.c) result.d else { @@ -1072,36 +1011,33 @@ let left = i: right (-i); # right :: integer -> (ip | mac | integer) -> (ip | mac | integer) - right = - let - step = i: x: { - _1 = bit.mask 32 (bit.right (i + 96) x); - _2 = bit.mask 32 (bit.right (i + 64) x); - _3 = bit.mask 32 (bit.right (i + 32) x); - _4 = bit.mask 32 (bit.right i x); - _5 = bit.mask 32 (bit.right (i - 32) x); - _6 = bit.mask 32 (bit.right (i - 64) x); - _7 = bit.mask 32 (bit.right (i - 96) x); - }; - ors = builtins.foldl' bit.or 0; - in + right = let + step = i: x: { + _1 = bit.mask 32 (bit.right (i + 96) x); + _2 = bit.mask 32 (bit.right (i + 64) x); + _3 = bit.mask 32 (bit.right (i + 32) x); + _4 = bit.mask 32 (bit.right i x); + _5 = bit.mask 32 (bit.right (i - 32) x); + _6 = bit.mask 32 (bit.right (i - 64) x); + _7 = bit.mask 32 (bit.right (i - 96) x); + }; + ors = builtins.foldl' bit.or 0; + in i: x: if x ? ipv6 - then - let - a' = step i x.ipv6.a; - b' = step i x.ipv6.b; - c' = step i x.ipv6.c; - d' = step i x.ipv6.d; - in - { - ipv6 = { - a = ors [ a'._4 b'._3 c'._2 d'._1 ]; - b = ors [ a'._5 b'._4 c'._3 d'._2 ]; - c = ors [ a'._6 b'._5 c'._4 d'._3 ]; - d = ors [ a'._7 b'._6 c'._5 d'._4 ]; - }; - } + then let + a' = step i x.ipv6.a; + b' = step i x.ipv6.b; + c' = step i x.ipv6.c; + d' = step i x.ipv6.d; + in { + ipv6 = { + a = ors [a'._4 b'._3 c'._2 d'._1]; + b = ors [a'._5 b'._4 c'._3 d'._2]; + c = ors [a'._6 b'._5 c'._4 d'._3]; + d = ors [a'._7 b'._6 c'._5 d'._4]; + }; + } else if x ? ipv4 then { ipv4 = bit.mask 32 (bit.right i x.ipv4); @@ -1180,21 +1116,20 @@ let else { mac = bit.mask 48 value; } - else - if value ? ipv6 - then - builtins.foldl' bit.or 0 - [ - (bit.left 96 value.ipv6.a) - (bit.left 64 value.ipv6.b) - (bit.left 32 value.ipv6.c) - value.ipv6.d - ] - else if value ? ipv4 - then value.ipv4 - else if value ? mac - then value.mac - else value; + else if value ? ipv6 + then + builtins.foldl' bit.or 0 + [ + (bit.left 96 value.ipv6.a) + (bit.left 64 value.ipv6.b) + (bit.left 32 value.ipv6.c) + value.ipv6.d + ] + else if value ? ipv4 + then value.ipv4 + else if value ? mac + then value.mac + else value; }; implementations = { @@ -1222,20 +1157,17 @@ let cidr = rec { # add :: (ip | mac | integer) -> cidr -> cidr - add = delta: cidr: - let - size' = size cidr; - in - { - base = arithmetic.left size' (arithmetic.add delta (arithmetic.right size' cidr.base)); - inherit (cidr) length; - }; + add = delta: cidr: let + size' = size cidr; + in { + base = arithmetic.left size' (arithmetic.add delta (arithmetic.right size' cidr.base)); + inherit (cidr) length; + }; # capacity :: cidr -> integer - capacity = cidr: - let - size' = size cidr; - in + capacity = cidr: let + size' = size cidr; + in if size' > 62 then 9223372036854775807 # maxBound to prevent overflow else bit.left size' 1; @@ -1248,10 +1180,9 @@ let contains = ip: cidr: host 0 (make cidr.length ip) == host 0 cidr; # host :: (ip | mac | integer) -> cidr -> ip - host = index: cidr: - let - index' = arithmetic.coerce cidr.base index; - in + host = index: cidr: let + index' = arithmetic.coerce cidr.base index; + in arithmetic.or (arithmetic.shadow cidr.length index') cidr.base; # length :: cidr -> integer @@ -1261,63 +1192,71 @@ let netmask = cidr: arithmetic.coshadow cidr.length (arithmetic.coerce cidr.base (-1)); # size :: cidr -> integer - size = cidr: (if cidr.base ? ipv6 then 128 else 32) - cidr.length; + size = cidr: + ( + if cidr.base ? ipv6 + then 128 + else 32 + ) + - cidr.length; # subnet :: integer -> (ip | mac | integer) -> cidr -> cidr - subnet = length: index: cidr: - let - length' = cidr.length + length; - index' = arithmetic.coerce cidr.base index; - size = (if cidr.base ? ipv6 then 128 else 32) - length'; - in + subnet = length: index: cidr: let + length' = cidr.length + length; + index' = arithmetic.coerce cidr.base index; + size = + ( + if cidr.base ? ipv6 + then 128 + else 32 + ) + - length'; + in make length' (host (arithmetic.left size index') cidr); # make :: integer -> ip -> cidr - make = length: base: - let - length' = math.clamp 0 (if base ? ipv6 then 128 else 32) length; - in - { - base = arithmetic.coshadow length' base; - length = length'; - }; + make = length: base: let + length' = + math.clamp 0 ( + if base ? ipv6 + then 128 + else 32 + ) + length; + in { + base = arithmetic.coshadow length' base; + length = length'; + }; }; }; - typechecks = - let - - fail = description: function: argument: - builtins.throw "${function}: ${argument} parameter must be ${description}"; - - meta = parser: description: function: argument: input: - let - error = fail description function argument; - in - if !builtins.isString input - then error - else - let - result = parser input; - in - if builtins.isNull result - then error - else result; + typechecks = let + fail = description: function: argument: + builtins.throw "${function}: ${argument} parameter must be ${description}"; + meta = parser: description: function: argument: input: let + error = fail description function argument; in - { - int = function: argument: input: - if builtins.isInt input - then input - else fail "an integer" function argument; - ip = meta parsers.ip "an IPv4 or IPv6 address"; - cidr = meta parsers.cidr "an IPv4 or IPv6 address range in CIDR notation"; - mac = meta parsers.mac "a MAC address"; - numeric = function: argument: input: - if builtins.isInt input - then input - else meta parsers.numeric "an integer or IPv4, IPv6 or MAC address" function argument input; - }; - + if !builtins.isString input + then error + else let + result = parser input; + in + if builtins.isNull result + then error + else result; + in { + int = function: argument: input: + if builtins.isInt input + then input + else fail "an integer" function argument; + ip = meta parsers.ip "an IPv4 or IPv6 address"; + cidr = meta parsers.cidr "an IPv4 or IPv6 address range in CIDR notation"; + mac = meta parsers.mac "a MAC address"; + numeric = function: argument: input: + if builtins.isInt input + then input + else meta parsers.numeric "an integer or IPv4, IPv6 or MAC address" function argument input; + }; in -net + net From 591df62e582dd0cfc2d081f1529f1579a2e62ea7 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 28 Oct 2024 14:42:21 +0100 Subject: [PATCH 093/108] Add commit hook and flake check for formatting --- .envrc | 1 + .pre-commit-config.yaml | 1 + formatter.nix | 15 ++++++++++++++- shell.nix | 4 +++- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 .envrc create mode 120000 .pre-commit-config.yaml diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 120000 index 0000000..b104519 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1 @@ +/nix/store/aimf4r2pn4gapwcm87hbwx73r40cj89i-pre-commit-config.json \ No newline at end of file diff --git a/formatter.nix b/formatter.nix index 0d42f9c..3cef74a 100644 --- a/formatter.nix +++ b/formatter.nix @@ -1,14 +1,27 @@ { + self, nixpkgs, treefmt-nix, flake-utils, + pre-commit-hooks, ... }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = nixpkgs.legacyPackages.${system}; treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; + treefmtWrapper = treefmtEval.config.build.wrapper; in { - formatter = treefmtEval.config.build.wrapper; + packages.formatter = treefmtWrapper; + formatter = self.packages.${system}.formatter; + checks.pre-commit-check = pre-commit-hooks.lib.${system}.run { + src = ./.; + hooks = { + treefmt = { + enable = true; + package = treefmtWrapper; + }; + }; + }; } ) diff --git a/shell.nix b/shell.nix index 072adef..261ea16 100644 --- a/shell.nix +++ b/shell.nix @@ -1,4 +1,5 @@ { + self, flake-utils, nixpkgs, ... @@ -7,6 +8,7 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; in { devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ansible]; + inherit (self.checks.${system}.pre-commit-check) shellHook; + buildInputs = self.checks.${system}.pre-commit-check.enabledPackages ++ [pkgs.ansible]; }; }) From da78282a5ccc225b7d6ac2cebdff7ac23f5ee6b9 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 28 Oct 2024 14:43:32 +0100 Subject: [PATCH 094/108] Git ignore .pre-commit-config.yaml --- .gitignore | 1 + .pre-commit-config.yaml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 120000 .pre-commit-config.yaml diff --git a/.gitignore b/.gitignore index 446c3c0..d2273ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .direnv .deploy-gc/ +.pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 120000 index b104519..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1 +0,0 @@ -/nix/store/aimf4r2pn4gapwcm87hbwx73r40cj89i-pre-commit-config.json \ No newline at end of file From 14872a2e6b009767d71a5f6b5fcc7f3ac43bfe4a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 30 Oct 2024 21:17:03 +0100 Subject: [PATCH 095/108] Update git-hooks --- flake.lock | 66 +++++++++++++++++++++++++-------------------------- flake.nix | 2 +- formatter.nix | 4 ++-- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/flake.lock b/flake.lock index 074e833..4a4950d 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "flake-compat_2": { "flake": false, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { @@ -96,11 +96,11 @@ "flake-compat_3": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { @@ -179,10 +179,33 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat_2", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs-unstable" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1730302582, + "narHash": "sha256-W1MIJpADXQCgosJZT8qBYLRuZls2KSiKdpnTVdKBuvU=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "af8a16fe5c264f5e9e18bcee2859b40a656876cf", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ - "pre-commit-hooks", + "git-hooks", "nixpkgs" ] }, @@ -202,7 +225,7 @@ }, "kubenix": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "nixpkgs": [ "nixpkgs-unstable" ], @@ -225,7 +248,7 @@ }, "nix-snapshotter": { "inputs": { - "flake-compat": "flake-compat_3", + "flake-compat": "flake-compat_4", "flake-parts": "flake-parts", "nixpkgs": [ "nixpkgs-unstable" @@ -378,42 +401,19 @@ "type": "github" } }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat_4", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs-unstable" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1729104314, - "narHash": "sha256-pZRZsq5oCdJt3upZIU4aslS9XwFJ+/nVtALHIciX/BI=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, "root": { "inputs": { "deploy-rs": "deploy-rs", "disko": "disko", "dns": "dns", "flake-utils": "flake-utils_2", + "git-hooks": "git-hooks", "kubenix": "kubenix", "nix-snapshotter": "nix-snapshotter", "nixng": "nixng", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", - "pre-commit-hooks": "pre-commit-hooks", "sops-nix": "sops-nix", "treefmt-nix": "treefmt-nix" } diff --git a/flake.nix b/flake.nix index 0238d94..9ad4f55 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ flake-utils.url = "github:numtide/flake-utils"; treefmt-nix.url = "github:numtide/treefmt-nix"; - pre-commit-hooks = { + git-hooks = { url = "github:cachix/git-hooks.nix"; inputs.nixpkgs.follows = "nixpkgs-unstable"; }; diff --git a/formatter.nix b/formatter.nix index 3cef74a..dc0826b 100644 --- a/formatter.nix +++ b/formatter.nix @@ -3,7 +3,7 @@ nixpkgs, treefmt-nix, flake-utils, - pre-commit-hooks, + git-hooks, ... }: flake-utils.lib.eachDefaultSystem ( @@ -14,7 +14,7 @@ flake-utils.lib.eachDefaultSystem ( in { packages.formatter = treefmtWrapper; formatter = self.packages.${system}.formatter; - checks.pre-commit-check = pre-commit-hooks.lib.${system}.run { + checks.pre-commit-check = git-hooks.lib.${system}.run { src = ./.; hooks = { treefmt = { From a423fd024e97e517b8af32d04da1339b3eb4ce85 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 2 Nov 2024 23:55:25 +0100 Subject: [PATCH 096/108] Use nixos-facter --- flake.lock | 16 + flake.nix | 1 + machines/{atlas.nix => atlas/default.nix} | 1 + machines/atlas/facter.json | 3758 +++++++++++ machines/default.nix | 17 +- machines/{jefke.nix => jefke/default.nix} | 1 + machines/jefke/facter.json | 3593 +++++++++++ machines/{lewis.nix => lewis/default.nix} | 1 + machines/lewis/facter.json | 5507 +++++++++++++++++ machines/{warwick.nix => warwick/default.nix} | 1 + machines/warwick/facter.json | 1372 ++++ modules/default.nix | 3 + 12 files changed, 14266 insertions(+), 5 deletions(-) rename machines/{atlas.nix => atlas/default.nix} (88%) create mode 100644 machines/atlas/facter.json rename machines/{jefke.nix => jefke/default.nix} (88%) create mode 100644 machines/jefke/facter.json rename machines/{lewis.nix => lewis/default.nix} (91%) create mode 100644 machines/lewis/facter.json rename machines/{warwick.nix => warwick/default.nix} (87%) create mode 100644 machines/warwick/facter.json diff --git a/flake.lock b/flake.lock index 4a4950d..9796810 100644 --- a/flake.lock +++ b/flake.lock @@ -289,6 +289,21 @@ "type": "github" } }, + "nixos-facter-modules": { + "locked": { + "lastModified": 1730026316, + "narHash": "sha256-AzP+trH/ykBJGTx3twkpuwbkhFSmsY1PJDQtRmK4k4c=", + "owner": "numtide", + "repo": "nixos-facter-modules", + "rev": "15b6531d44aa6f0bbd2fd8309cd2a6d7f183ba32", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nixos-facter-modules", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1729742320, @@ -411,6 +426,7 @@ "kubenix": "kubenix", "nix-snapshotter": "nix-snapshotter", "nixng": "nixng", + "nixos-facter-modules": "nixos-facter-modules", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", diff --git a/flake.nix b/flake.nix index 9ad4f55..423acc0 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,7 @@ nixos-hardware.url = "github:NixOS/nixos-hardware/master"; flake-utils.url = "github:numtide/flake-utils"; treefmt-nix.url = "github:numtide/treefmt-nix"; + nixos-facter-modules.url = "github:numtide/nixos-facter-modules"; git-hooks = { url = "github:cachix/git-hooks.nix"; diff --git a/machines/atlas.nix b/machines/atlas/default.nix similarity index 88% rename from machines/atlas.nix rename to machines/atlas/default.nix index a6bf86f..a0845e0 100644 --- a/machines/atlas.nix +++ b/machines/atlas/default.nix @@ -2,6 +2,7 @@ machines.atlas = { arch = "x86_64-linux"; kubernetesNodeLabels.storageType = "slow"; + facterReportPath = ./facter.json; nixosModule.lab = { storage.profile = "kubernetes"; diff --git a/machines/atlas/facter.json b/machines/atlas/facter.json new file mode 100644 index 0000000..28cf32c --- /dev/null +++ b/machines/atlas/facter.json @@ -0,0 +1,3758 @@ +{ + "version": 1, + "system": "x86_64-linux", + "virtualisation": "none", + "hardware": { + "bios": { + "apm_info": { + "supported": false, + "enabled": false, + "version": 0, + "sub_version": 0, + "bios_flags": 0 + }, + "vbe_info": { + "version": 0, + "video_memory": 0 + }, + "pnp": false, + "pnp_id": 0, + "lba_support": false, + "low_memory_size": 0, + "smbios_version": 770 + }, + "bluetooth": [ + { + "index": 45, + "attached_to": 46, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.0", + "sysfs_bus_id": "1-3:1.0", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in00" + }, + { + "index": 47, + "attached_to": 46, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.1", + "sysfs_bus_id": "1-3:1.1", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 1, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in01" + } + ], + "bridge": [ + { + "index": 10, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "ISA bridge", + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12776 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel ISA bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.0", + "sysfs_bus_id": "0000:00:1f.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031E8sv00001458sd00001000bc06sc01i00", + "label": "Onboard - Other" + }, + { + "index": 11, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12762 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2", + "sysfs_bus_id": "0000:00:13.2", + "resources": [ + { + "type": "irq", + "base": 123, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 2, + "command": 1031, + "header_type": 1, + "secondary_bus": 2, + "irq": 123, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DAsv00001458sd00001000bc06sc04i00" + }, + { + "index": 13, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12760 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0", + "sysfs_bus_id": "0000:00:13.0", + "resources": [ + { + "type": "irq", + "base": 122, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 1, + "secondary_bus": 1, + "irq": 122, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031D8sv00001458sd00001000bc06sc04i00" + }, + { + "index": 17, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "Host bridge", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12784 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Host bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:00.0", + "sysfs_bus_id": "0000:00:00.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031F0sv00001458sd00001000bc06sc00i00", + "label": "Onboard - Other" + }, + { + "index": 20, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12763 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3", + "sysfs_bus_id": "0000:00:13.3", + "resources": [ + { + "type": "irq", + "base": 124, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 3, + "command": 1031, + "header_type": 1, + "secondary_bus": 3, + "irq": 124, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DBsv00001458sd00001000bc06sc04i00" + } + ], + "cpu": [ + { + "architecture": "x86_64", + "vendor_name": "GenuineIntel", + "family": 6, + "model": 122, + "stepping": 1, + "features": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "dts", + "acpi", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "ht", + "tm", + "pbe", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "art", + "arch_perfmon", + "pebs", + "bts", + "rep_good", + "nopl", + "xtopology", + "nonstop_tsc", + "cpuid", + "aperfmperf", + "tsc_known_freq", + "pni", + "pclmulqdq", + "dtes64", + "monitor", + "ds_cpl", + "vmx", + "est", + "tm2", + "ssse3", + "sdbg", + "cx16", + "xtpr", + "pdcm", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "rdrand", + "lahf_lm", + "3dnowprefetch", + "cpuid_fault", + "cat_l2", + "pti", + "cdp_l2", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "ibrs_enhanced", + "tpr_shadow", + "flexpriority", + "ept", + "vpid", + "ept_ad", + "fsgsbase", + "tsc_adjust", + "smep", + "erms", + "mpx", + "rdt_a", + "rdseed", + "smap", + "clflushopt", + "intel_pt", + "sha_ni", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "dtherm", + "ida", + "arat", + "pln", + "pts", + "vnmi", + "umip", + "rdpid", + "md_clear", + "arch_capabilities" + ], + "bugs": [ + "cpu_meltdown", + "spectre_v1", + "spectre_v2", + "spec_store_bypass", + "rfds", + "bhi" + ], + "bogo": 2995.2, + "cache": 4096, + "units": 64, + "physical_id": 0, + "siblings": 4, + "cores": 4, + "fpu": true, + "fpu_exception": true, + "cpuid_level": 24, + "write_protect": false, + "clflush_size": 64, + "cache_alignment": 64, + "address_sizes": { + "physical": 39, + "virtual": 48 + } + } + ], + "disk": [ + { + "index": 25, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 7, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf61", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdf", + "sysfs_bus_id": "7:0:0:1", + "sysfs_device_link": "/devices/platform/host7/session47/target7:0:0/7:0:0:1", + "unix_device_name": "/dev/sdf", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 80, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/62", + "/dev/disk/by-id/scsi-360000000000000000e00000000060001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000060001", + "/dev/disk/by-path/ip-10.42.1.180:3260-iscsi-iqn.2019-10.io.longhorn:pvc-9a1d2ca8-edce-416c-b41b-42bcd3380887-lun-1", + "/dev/disk/by-uuid/35036532-23d4-4038-bfe6-15a86e793ed5", + "/dev/sdf" + ], + "unix_device_name2": "/dev/sg14", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 14, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1018, + "heads": 166, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 10485760, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 26, + "attached_to": 14, + "bus_type": { + "name": "NVME", + "value": 150 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "name": "KINGSTON SNV2S1000G", + "value": 20503 + }, + "sub_device": { + "value": 20503 + }, + "serial": "50026B7784EB3FFB", + "model": "KINGSTON SNV2S1000G", + "sysfs_id": "/class/block/nvme0n1", + "sysfs_bus_id": "nvme0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0/nvme/nvme0", + "unix_device_name": "/dev/nvme0n1", + "unix_device_number": { + "type": 98, + "major": 259, + "minor": 0, + "range": 0 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/1", + "/dev/disk/by-id/nvme-KINGSTON_SNV2S1000G_50026B7784EB3FFB", + "/dev/disk/by-id/nvme-KINGSTON_SNV2S1000G_50026B7784EB3FFB_1", + "/dev/disk/by-id/nvme-eui.00000000000000000026b7784eb3ffb5", + "/dev/disk/by-path/pci-0000:01:00.0-nvme-1", + "/dev/nvme0n1" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 953869, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1953525168, + "value_2": 512 + } + ], + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ] + }, + { + "index": 27, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 5, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf41", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdd", + "sysfs_bus_id": "5:0:0:1", + "sysfs_device_link": "/devices/platform/host5/session46/target5:0:0/5:0:0:1", + "unix_device_name": "/dev/sdd", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 48, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/61", + "/dev/disk/by-id/scsi-360000000000000000e00000000040001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000040001", + "/dev/disk/by-path/ip-10.42.1.180:3260-iscsi-iqn.2019-10.io.longhorn:radicale-lun-1", + "/dev/disk/by-uuid/6378cbe8-6c3e-4a9c-8397-9530d32668fb", + "/dev/sdd" + ], + "unix_device_name2": "/dev/sg12", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 12, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1008, + "heads": 7, + "sectors": 58, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 409600, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 28, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf31", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdb", + "sysfs_bus_id": "3:0:0:1", + "sysfs_device_link": "/devices/platform/host3/session31/target3:0:0/3:0:0:1", + "unix_device_name": "/dev/sdb", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 16, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/46", + "/dev/disk/by-id/scsi-360000000000000000e00000000030001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000030001", + "/dev/disk/by-path/ip-10.42.1.148:3260-iscsi-iqn.2019-10.io.longhorn:freshrss-lun-1", + "/dev/disk/by-uuid/dd58e1cc-0b35-43e8-b267-c899b93bfb58", + "/dev/sdb" + ], + "unix_device_name2": "/dev/sg4", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 4, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1011, + "heads": 34, + "sectors": 61, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 2097152, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 29, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf51", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdk", + "sysfs_bus_id": "11:0:0:1", + "sysfs_device_link": "/devices/platform/host11/session45/target11:0:0/11:0:0:1", + "unix_device_name": "/dev/sdk", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 160, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/60", + "/dev/disk/by-id/scsi-360000000000000000e00000000050001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000050001", + "/dev/disk/by-path/ip-10.42.1.180:3260-iscsi-iqn.2019-10.io.longhorn:atuin-db-lun-1", + "/dev/disk/by-uuid/2f56d1b7-45ad-4a6f-b1f7-fcfa01ef03af", + "/dev/sdk" + ], + "unix_device_name2": "/dev/sg10", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 10, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 10, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 614400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 30, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf21", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdi", + "sysfs_bus_id": "2:0:0:1", + "sysfs_device_link": "/devices/platform/host2/session37/target2:0:0/2:0:0:1", + "unix_device_name": "/dev/sdi", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 128, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/52", + "/dev/disk/by-path/ip-10.42.1.180:3260-iscsi-iqn.2019-10.io.longhorn:attic-lun-1", + "/dev/disk/by-uuid/bd47a75f-71d2-4e73-85e1-65997fcef2c2", + "/dev/sdi" + ], + "unix_device_name2": "/dev/sg6", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 6, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 15360, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 31457280, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 31, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdg", + "sysfs_bus_id": "8:0:0:1", + "sysfs_device_link": "/devices/platform/host8/session48/target8:0:0/8:0:0:1", + "unix_device_name": "/dev/sdg", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 96, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/63", + "/dev/disk/by-id/scsi-360000000000000000e00000000010001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000010001", + "/dev/disk/by-path/ip-10.42.1.5:3260-iscsi-iqn.2019-10.io.longhorn:prowlarr-lun-1", + "/dev/disk/by-uuid/485930ae-2fe2-4470-b99a-dc61a93d921c", + "/dev/sdg" + ], + "unix_device_name2": "/dev/sg16", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 16, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 5, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 307200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 32, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 6, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sde", + "sysfs_bus_id": "6:0:0:1", + "sysfs_device_link": "/devices/platform/host6/session42/target6:0:0/6:0:0:1", + "unix_device_name": "/dev/sde", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 64, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/57", + "/dev/disk/by-path/ip-10.42.1.180:3260-iscsi-iqn.2019-10.io.longhorn:forgejo-lun-1", + "/dev/disk/by-uuid/0448fef2-ca9e-4a75-9d21-e148e3e9fe34", + "/dev/sde" + ], + "unix_device_name2": "/dev/sg8", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 8, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 20480, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 41943040, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 33, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf21", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdc", + "sysfs_bus_id": "4:0:0:1", + "sysfs_device_link": "/devices/platform/host4/session29/target4:0:0/4:0:0:1", + "unix_device_name": "/dev/sdc", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 32, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/44", + "/dev/disk/by-path/ip-10.42.1.148:3260-iscsi-iqn.2019-10.io.longhorn:atuin-lun-1", + "/dev/disk/by-uuid/f4def3ee-1977-48a5-8c34-badb13c8e3b1", + "/dev/sdc" + ], + "unix_device_name2": "/dev/sg2", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 2, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 10, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 614400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 34, + "attached_to": 18, + "bus_type": { + "name": "IDE", + "value": 133 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "Hitachi", + "value": 0 + }, + "device": { + "name": "HTS72755", + "value": 0 + }, + "revision": { + "name": "A0E0", + "value": 0 + }, + "serial": "J33B0084GPB4PB", + "model": "Hitachi HTS72755", + "sysfs_id": "/class/block/sda", + "sysfs_bus_id": "0:0:0:0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:12.0/ata1/host0/target0:0:0/0:0:0:0", + "unix_device_name": "/dev/sda", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/2", + "/dev/disk/by-id/ata-Hitachi_HTS727550A9E364_J33B0084GPB4PB", + "/dev/disk/by-id/wwn-0x5000cca68cc9b5a7", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1.0", + "/dev/sda" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 60801, + "heads": 255, + "sectors": 63, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 976773168, + "value_2": 512 + } + ], + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci", + "sd" + ], + "driver_modules": [ + "ahci", + "sd_mod" + ] + }, + { + "index": 35, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 9, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf21", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdh", + "sysfs_bus_id": "9:0:0:1", + "sysfs_device_link": "/devices/platform/host9/session50/target9:0:0/9:0:0:1", + "unix_device_name": "/dev/sdh", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 112, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/65", + "/dev/disk/by-id/scsi-360000000000000000e00000000020001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000020001", + "/dev/disk/by-path/ip-10.42.1.5:3260-iscsi-iqn.2019-10.io.longhorn:paperless-data-lun-1", + "/dev/disk/by-uuid/682d7efc-356e-4180-aff9-e5e6a7792702", + "/dev/sdh" + ], + "unix_device_name2": "/dev/sg18", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 18, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 10240, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 20971520, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + } + ], + "graphics_card": [ + { + "index": 23, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 2 + }, + "base_class": { + "name": "Display controller", + "value": 3 + }, + "sub_class": { + "name": "VGA compatible controller", + "value": 0 + }, + "pci_interface": { + "name": "VGA", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12677 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel VGA compatible controller", + "sysfs_id": "/devices/pci0000:00/0000:00:02.0", + "sysfs_bus_id": "0000:00:02.0", + "resources": [ + { + "type": "io", + "base": 61440, + "range": 64, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 134, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2415919104, + "range": 268435456, + "enabled": true, + "access": "read_only", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2684354560, + "range": 16777216, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 786432, + "range": 131072, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 134, + "prog_if": 0 + }, + "driver": "i915", + "driver_module": "i915", + "drivers": [ + "i915" + ], + "driver_modules": [ + "i915" + ], + "module_alias": "pci:v00008086d00003185sv00001458sd00001000bc03sc00i00", + "label": "Onboard - Video" + } + ], + "hub": [ + { + "index": 46, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.43 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 2 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.43 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-0:1.0", + "sysfs_bus_id": "1-0:1.0", + "resources": [ + { + "type": "baud", + "speed": 480000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 1, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0002d0606dc09dsc00dp01ic09isc00ip00in00" + }, + { + "index": 48, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.43 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 3 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.43 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb2/2-0:1.0", + "sysfs_bus_id": "2-0:1.0", + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 3, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0003d0606dc09dsc00dp03ic09isc00ip00in00" + } + ], + "memory": [ + { + "index": 7, + "attached_to": 0, + "base_class": { + "name": "Internally Used Class", + "value": 257 + }, + "sub_class": { + "name": "Main Memory", + "value": 2 + }, + "model": "Main Memory", + "resources": [ + { + "type": "mem", + "base": 0, + "range": 25008361472, + "enabled": true, + "access": "read_write", + "prefetch": "unknown" + }, + { + "type": "phys_mem", + "range": 25769803776 + } + ] + } + ], + "network_controller": [ + { + "index": 8, + "attached_to": 20, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Ethernet controller", + "value": 0 + }, + "vendor": { + "value": 4332 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 33128 + }, + "sub_device": { + "value": 57344 + }, + "revision": { + "value": 21 + }, + "model": "Ethernet controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "sysfs_bus_id": "0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "io", + "base": 57344, + "range": 256, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 21, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2701131776, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2701148160, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 21, + "prog_if": 0 + }, + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ], + "module_alias": "pci:v000010ECd00008168sv00001458sd0000E000bc02sc00i00" + }, + { + "index": 12, + "attached_to": 11, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Network controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "device": { + "value": 9467 + }, + "sub_device": { + "value": 8464 + }, + "revision": { + "value": 16 + }, + "model": "Intel Network controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2/0000:02:00.0", + "sysfs_bus_id": "0000:02:00.0", + "resources": [ + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2702180352, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 2, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000024FBsv00008086sd00002110bc02sc80i00", + "label": "Onboard - RTK Ethernet" + } + ], + "network_interface": [ + { + "index": 59, + "attached_to": 0, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Loopback", + "value": 0 + }, + "model": "Loopback network interface", + "sysfs_id": "/class/net/lo", + "unix_device_name": "lo", + "unix_device_names": [ + "lo" + ] + }, + { + "index": 90, + "attached_to": 8, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Ethernet", + "value": 1 + }, + "model": "Ethernet network interface", + "sysfs_id": "/class/net/enp3s0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ] + } + ], + "storage_controller": [ + { + "index": 14, + "attached_to": 13, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 1, + "number": 0 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 8 + }, + "pci_interface": { + "value": 2 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "value": 20503 + }, + "sub_device": { + "value": 20503 + }, + "revision": { + "value": 3 + }, + "model": "Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0", + "sysfs_bus_id": "0000:01:00.0", + "resources": [ + { + "type": "irq", + "base": 22, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2703228928, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 22, + "prog_if": 2 + }, + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ], + "module_alias": "pci:v00002646d00005017sv00002646sd00005017bc01sc08i02" + }, + { + "index": 18, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 18 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 6 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12771 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:12.0", + "sysfs_bus_id": "0000:00:12.0", + "resources": [ + { + "type": "io", + "base": 61536, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61568, + "range": 4, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61584, + "range": 8, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 131, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704343040, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704371712, + "range": 2048, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704375808, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 131, + "prog_if": 1 + }, + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci" + ], + "driver_modules": [ + "ahci" + ], + "module_alias": "pci:v00008086d000031E3sv00001458sd00001000bc01sc06i01", + "label": "Onboard - SATA" + } + ], + "system": { + "form_factor": "desktop" + }, + "unknown": [ + { + "index": 9, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 28 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12748 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1c.0", + "sysfs_bus_id": "0000:00:1c.0", + "resources": [ + { + "type": "irq", + "base": 39, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704363520, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704367616, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 39, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031CCsv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 15, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 30 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12752 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1e.0", + "sysfs_bus_id": "0000:00:1e.0", + "resources": [ + { + "type": "irq", + "base": 42, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704355328, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704359424, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 42, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031D0sv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 16, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 15 + }, + "base_class": { + "name": "Communication controller", + "value": 7 + }, + "sub_class": { + "name": "Communication controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12698 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Communication controller", + "sysfs_id": "/devices/pci0000:00/0000:00:0f.0", + "sysfs_bus_id": "0000:00:0f.0", + "resources": [ + { + "type": "irq", + "base": 132, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704379904, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 132, + "prog_if": 0 + }, + "driver": "mei_me", + "driver_module": "mei_me", + "drivers": [ + "mei_me" + ], + "driver_modules": [ + "mei_me" + ], + "module_alias": "pci:v00008086d0000319Asv00001458sd00001000bc07sc80i00", + "label": "Onboard - Other" + }, + { + "index": 19, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "SMBus", + "value": 5 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12756 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel SMBus", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.1", + "sysfs_bus_id": "0000:00:1f.1", + "resources": [ + { + "type": "io", + "base": 61504, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704351232, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 1, + "command": 3, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "driver": "i801_smbus", + "driver_module": "i2c_i801", + "drivers": [ + "i801_smbus" + ], + "driver_modules": [ + "i2c_i801" + ], + "module_alias": "pci:v00008086d000031D4sv00001458sd00001000bc0Csc05i00", + "label": "Onboard - Other" + }, + { + "index": 22, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "name": "System peripheral", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12688 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel System peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:00.3", + "sysfs_bus_id": "0000:00:00.3", + "resources": [ + { + "type": "irq", + "base": 23, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704384000, + "range": 4096, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 3, + "command": 0, + "header_type": 0, + "secondary_bus": 0, + "irq": 23, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d00003190sv00001458sd00001000bc08sc80i00", + "label": "Onboard - Other" + }, + { + "index": 24, + "attached_to": 0, + "base_class": { + "name": "Communication controller", + "value": 7 + }, + "sub_class": { + "name": "Serial controller", + "value": 0 + }, + "pci_interface": { + "name": "16550", + "value": 2 + }, + "device": { + "name": "16550A", + "value": 0 + }, + "model": "16550A", + "unix_device_name": "/dev/ttyS0", + "unix_device_names": [ + "/dev/ttyS0" + ], + "resources": [ + { + "type": "io", + "base": 1016, + "range": 0, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 4, + "triggered": 0, + "enabled": true + } + ] + }, + { + "index": 36, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg9", + "sysfs_bus_id": "11:0:0:0", + "unix_device_name": "/dev/sg9", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 9, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg9" + ] + }, + { + "index": 37, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 6, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg7", + "sysfs_bus_id": "6:0:0:0", + "unix_device_name": "/dev/sg7", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 7, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg7" + ] + }, + { + "index": 38, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 9, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg17", + "sysfs_bus_id": "9:0:0:0", + "unix_device_name": "/dev/sg17", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 17, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg17" + ] + }, + { + "index": 39, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg5", + "sysfs_bus_id": "2:0:0:0", + "unix_device_name": "/dev/sg5", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 5, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg5" + ] + }, + { + "index": 40, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg15", + "sysfs_bus_id": "8:0:0:0", + "unix_device_name": "/dev/sg15", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 15, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg15" + ] + }, + { + "index": 41, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg3", + "sysfs_bus_id": "3:0:0:0", + "unix_device_name": "/dev/sg3", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 3, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg3" + ] + }, + { + "index": 42, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 7, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg13", + "sysfs_bus_id": "7:0:0:0", + "unix_device_name": "/dev/sg13", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 13, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg13" + ] + }, + { + "index": 43, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg1", + "sysfs_bus_id": "4:0:0:0", + "unix_device_name": "/dev/sg1", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 1, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg1" + ] + }, + { + "index": 44, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 5, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg11", + "sysfs_bus_id": "5:0:0:0", + "unix_device_name": "/dev/sg11", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 11, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg11" + ] + } + ], + "usb_controller": [ + { + "index": 21, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 21 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "USB Controller", + "value": 3 + }, + "pci_interface": { + "value": 48 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12712 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel USB Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0", + "sysfs_bus_id": "0000:00:15.0", + "resources": [ + { + "type": "irq", + "base": 125, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704277504, + "range": 65536, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 125, + "prog_if": 48 + }, + "driver": "xhci_hcd", + "driver_module": "xhci_pci", + "drivers": [ + "xhci_hcd" + ], + "driver_modules": [ + "xhci_pci" + ], + "module_alias": "pci:v00008086d000031A8sv00001458sd00001000bc0Csc03i30", + "label": "Onboard - Other" + } + ] + }, + "smbios": { + "bios": { + "handle": 0, + "vendor": "American Megatrends Inc.", + "version": "F8", + "date": "12/13/2019", + "features": [ + "PCI supported", + "BIOS flashable", + "BIOS shadowing allowed", + "CD boot supported", + "Selectable boot supported", + "BIOS ROM socketed", + "EDD spec supported", + "1.2MB Floppy supported", + "720kB Floppy supported", + "2.88MB Floppy supported", + "Print Screen supported", + "8042 Keyboard Services supported", + "Serial Services supported", + "Printer Services supported", + "ACPI supported", + "USB Legacy supported", + "BIOS Boot Spec supported" + ], + "start_address": "0xf0000", + "rom_size": 6291456 + }, + "board": { + "handle": 2, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "board_type": { + "name": "Motherboard", + "value": 10 + }, + "features": [ + "Hosting Board", + "Replaceable" + ], + "location": "Default string", + "chassis": 3 + }, + "cache": [ + { + "handle": 47, + "socket": "CPU Internal L1", + "size_max": 224, + "size_current": 224, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 0, + "ecc": { + "name": "Parity", + "value": 4 + }, + "cache_type": { + "name": "Other", + "value": 1 + }, + "associativity": { + "name": "Other", + "value": 1 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + }, + { + "handle": 48, + "socket": "CPU Internal L2", + "size_max": 4096, + "size_current": 4096, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 1, + "ecc": { + "name": "Single-bit", + "value": 5 + }, + "cache_type": { + "name": "Unified", + "value": 5 + }, + "associativity": { + "name": "16-way Set-Associative", + "value": 8 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + } + ], + "chassis": { + "handle": 3, + "manufacturer": "Default string", + "version": "Default string", + "chassis_type": { + "name": "Desktop", + "value": 3 + }, + "lock_present": false, + "bootup_state": { + "name": "Safe", + "value": 3 + }, + "power_state": { + "name": "Safe", + "value": 3 + }, + "thermal_state": { + "name": "Safe", + "value": 3 + }, + "security_state": { + "name": "None", + "value": 3 + }, + "oem": "0x0" + }, + "config": { + "handle": 34, + "options": [ + "Default string" + ] + }, + "language": [ + { + "handle": 63, + "languages": [ + "en|US|iso8859-1" + ] + } + ], + "memory_array": [ + { + "handle": 35, + "location": { + "name": "Motherboard", + "value": 3 + }, + "usage": { + "name": "System memory", + "value": 3 + }, + "ecc": { + "name": "None", + "value": 3 + }, + "max_size": 33554432, + "error_handle": 65534, + "slots": 2 + } + ], + "memory_array_mapped_address": [ + { + "handle": 36, + "array_handle": 35, + "start_address": 0, + "end_address": 25769803776, + "part_width": 2 + } + ], + "memory_device": [ + { + "handle": 37, + "location": "A1_DIMM0", + "bank_location": "A1_BANK0", + "manufacturer": "Crucial", + "part_number": "CT16G4SFD824A.M16F", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 16777216, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + }, + { + "handle": 39, + "location": "A1_DIMM1", + "bank_location": "A1_BANK1", + "manufacturer": "Crucial", + "part_number": "CT8G4SFS824A.M8FJ", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 8388608, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + } + ], + "memory_device_mapped_address": [ + { + "handle": 38, + "memory_device_handle": 37, + "array_map_handle": 36, + "start_address": 0, + "end_address": 17179869184, + "row_position": 255, + "interleave_position": 1, + "interleave_depth": 2 + }, + { + "handle": 40, + "memory_device_handle": 39, + "array_map_handle": 36, + "start_address": 17179869184, + "end_address": 25769803776, + "row_position": 255, + "interleave_position": 2, + "interleave_depth": 2 + } + ], + "onboard": [ + { + "handle": 32, + "devices": [ + { + "name": "To Be Filled By O.E.M.", + "type": { + "name": "Video", + "value": 3 + }, + "enabled": true + } + ] + } + ], + "port_connector": [ + { + "handle": 8, + "port_type": { + "name": "Mouse Port", + "value": 14 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "PS2Mouse" + }, + { + "handle": 9, + "port_type": { + "name": "Keyboard Port", + "value": 13 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "Keyboard" + }, + { + "handle": 10, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2A1", + "external_connector_type": { + "name": "Mini-Centronics Type-14", + "value": 29 + }, + "external_reference_designator": "TV Out" + }, + { + "handle": 11, + "port_type": { + "name": "Serial Port 16550A Compatible", + "value": 9 + }, + "internal_reference_designator": "J2A2A", + "external_connector_type": { + "name": "DB-9 pin male", + "value": 8 + }, + "external_reference_designator": "COM A" + }, + { + "handle": 12, + "port_type": { + "name": "Video Port", + "value": 28 + }, + "internal_reference_designator": "J2A2B", + "external_connector_type": { + "name": "DB-15 pin female", + "value": 7 + }, + "external_reference_designator": "Video" + }, + { + "handle": 13, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB1" + }, + { + "handle": 14, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB2" + }, + { + "handle": 15, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB3" + }, + { + "handle": 16, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9A1 - TPM HDR" + }, + { + "handle": 17, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9C1 - PCIE DOCKING CONN" + }, + { + "handle": 18, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2B3 - CPU FAN" + }, + { + "handle": 19, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6C2 - EXT HDMI" + }, + { + "handle": 20, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J3C1 - GMCH FAN" + }, + { + "handle": 21, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1D1 - ITP" + }, + { + "handle": 22, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E2 - MDC INTPSR" + }, + { + "handle": 23, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E4 - MDC INTPSR" + }, + { + "handle": 24, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E3 - LPC HOT DOCKING" + }, + { + "handle": 25, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E1 - SCAN MATRIX" + }, + { + "handle": 26, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9G1 - LPC SIDE BAND" + }, + { + "handle": 27, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J8F1 - UNIFIED" + }, + { + "handle": 28, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6F1 - LVDS" + }, + { + "handle": 29, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2F1 - LAI FAN" + }, + { + "handle": 30, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2G1 - GFX VID" + }, + { + "handle": 31, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1G6 - AC JACK" + } + ], + "processor": [ + { + "handle": 49, + "socket": "SOCKET 0", + "socket_type": { + "name": "Other", + "value": 1 + }, + "socket_populated": true, + "manufacturer": "Intel", + "version": "Intel(R) Celeron(R) J4105 CPU @ 1.50GHz", + "part": "Fill By OEM", + "processor_type": { + "name": "CPU", + "value": 3 + }, + "processor_family": { + "name": "Celeron", + "value": 15 + }, + "processor_status": { + "name": "Enabled", + "value": 1 + }, + "clock_ext": 100, + "clock_max": 2700, + "cache_handle_l1": 47, + "cache_handle_l2": 48, + "cache_handle_l3": 0 + } + ], + "slot": [ + { + "handle": 64, + "designation": "J7H1", + "slot_type": { + "name": "Other", + "value": 174 + }, + "bus_width": { + "name": "Other", + "value": 10 + }, + "usage": { + "name": "In Use", + "value": 4 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 0, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + }, + { + "handle": 65, + "designation": "J8H1", + "slot_type": { + "name": "Other", + "value": 173 + }, + "bus_width": { + "name": "Other", + "value": 9 + }, + "usage": { + "name": "Available", + "value": 3 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 1, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + } + ], + "system": { + "handle": 1, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "wake_up": { + "name": "Power Switch", + "value": 6 + } + } + } +} \ No newline at end of file diff --git a/machines/default.nix b/machines/default.nix index 261980b..9a0c0c8 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -17,6 +17,14 @@ flake-utils.lib.eachDefaultSystem (system: let ''; }; + facterReportPath = lib.mkOption { + default = null; + type = with lib.types; nullOr path; + description = '' + Path to the nixos-facter report JSON for this machine. + ''; + }; + isRaspberryPi = lib.mkOption { default = false; type = lib.types.bool; @@ -52,12 +60,11 @@ in { (lib.modules.evalModules { modules = [ allOpts - ./warwick.nix - ./atlas.nix - ./jefke.nix - ./lewis.nix + ./warwick + ./atlas + ./jefke + ./lewis # ./talos.nix - # ./pikvm.nix ]; }) .config diff --git a/machines/jefke.nix b/machines/jefke/default.nix similarity index 88% rename from machines/jefke.nix rename to machines/jefke/default.nix index 096be8c..f423c08 100644 --- a/machines/jefke.nix +++ b/machines/jefke/default.nix @@ -2,6 +2,7 @@ machines.jefke = { arch = "x86_64-linux"; kubernetesNodeLabels.storageType = "fast"; + facterReportPath = ./facter.json; nixosModule.lab = { storage.profile = "kubernetes"; diff --git a/machines/jefke/facter.json b/machines/jefke/facter.json new file mode 100644 index 0000000..d08cfd4 --- /dev/null +++ b/machines/jefke/facter.json @@ -0,0 +1,3593 @@ +{ + "version": 1, + "system": "x86_64-linux", + "virtualisation": "none", + "hardware": { + "bios": { + "apm_info": { + "supported": false, + "enabled": false, + "version": 0, + "sub_version": 0, + "bios_flags": 0 + }, + "vbe_info": { + "version": 0, + "video_memory": 0 + }, + "pnp": false, + "pnp_id": 0, + "lba_support": false, + "low_memory_size": 0, + "smbios_version": 770 + }, + "bluetooth": [ + { + "index": 42, + "attached_to": 43, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.0", + "sysfs_bus_id": "1-3:1.0", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in00" + }, + { + "index": 44, + "attached_to": 43, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.1", + "sysfs_bus_id": "1-3:1.1", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 1, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in01" + } + ], + "bridge": [ + { + "index": 10, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "ISA bridge", + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12776 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel ISA bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.0", + "sysfs_bus_id": "0000:00:1f.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031E8sv00001458sd00001000bc06sc01i00", + "label": "Onboard - Other" + }, + { + "index": 11, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12762 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2", + "sysfs_bus_id": "0000:00:13.2", + "resources": [ + { + "type": "irq", + "base": 123, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 2, + "command": 1031, + "header_type": 1, + "secondary_bus": 2, + "irq": 123, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DAsv00001458sd00001000bc06sc04i00" + }, + { + "index": 13, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12760 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0", + "sysfs_bus_id": "0000:00:13.0", + "resources": [ + { + "type": "irq", + "base": 122, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 1, + "secondary_bus": 1, + "irq": 122, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031D8sv00001458sd00001000bc06sc04i00" + }, + { + "index": 17, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "Host bridge", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12784 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Host bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:00.0", + "sysfs_bus_id": "0000:00:00.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031F0sv00001458sd00001000bc06sc00i00", + "label": "Onboard - Other" + }, + { + "index": 20, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12763 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3", + "sysfs_bus_id": "0000:00:13.3", + "resources": [ + { + "type": "irq", + "base": 124, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 3, + "command": 1031, + "header_type": 1, + "secondary_bus": 3, + "irq": 124, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DBsv00001458sd00001000bc06sc04i00" + } + ], + "cpu": [ + { + "architecture": "x86_64", + "vendor_name": "GenuineIntel", + "family": 6, + "model": 122, + "stepping": 1, + "features": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "dts", + "acpi", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "ht", + "tm", + "pbe", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "art", + "arch_perfmon", + "pebs", + "bts", + "rep_good", + "nopl", + "xtopology", + "nonstop_tsc", + "cpuid", + "aperfmperf", + "tsc_known_freq", + "pni", + "pclmulqdq", + "dtes64", + "monitor", + "ds_cpl", + "vmx", + "est", + "tm2", + "ssse3", + "sdbg", + "cx16", + "xtpr", + "pdcm", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "rdrand", + "lahf_lm", + "3dnowprefetch", + "cpuid_fault", + "cat_l2", + "pti", + "cdp_l2", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "ibrs_enhanced", + "tpr_shadow", + "flexpriority", + "ept", + "vpid", + "ept_ad", + "fsgsbase", + "tsc_adjust", + "smep", + "erms", + "mpx", + "rdt_a", + "rdseed", + "smap", + "clflushopt", + "intel_pt", + "sha_ni", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "dtherm", + "ida", + "arat", + "pln", + "pts", + "vnmi", + "umip", + "rdpid", + "md_clear", + "arch_capabilities" + ], + "bugs": [ + "cpu_meltdown", + "spectre_v1", + "spectre_v2", + "spec_store_bypass", + "rfds", + "bhi" + ], + "bogo": 2995.2, + "cache": 4096, + "units": 64, + "physical_id": 0, + "siblings": 4, + "cores": 4, + "fpu": true, + "fpu_exception": true, + "cpuid_level": 24, + "write_protect": false, + "clflush_size": 64, + "cache_alignment": 64, + "address_sizes": { + "physical": 39, + "virtual": 48 + } + } + ], + "disk": [ + { + "index": 24, + "attached_to": 14, + "bus_type": { + "name": "NVME", + "value": 150 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "name": "KINGSTON SA2000M8500G", + "value": 8803 + }, + "sub_device": { + "value": 8803 + }, + "serial": "50026B7282414E01", + "model": "KINGSTON SA2000M8500G", + "sysfs_id": "/class/block/nvme0n1", + "sysfs_bus_id": "nvme0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0/nvme/nvme0", + "unix_device_name": "/dev/nvme0n1", + "unix_device_number": { + "type": 98, + "major": 259, + "minor": 0, + "range": 0 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/1", + "/dev/disk/by-id/nvme-KINGSTON_SA2000M8500G_50026B7282414E01", + "/dev/disk/by-id/nvme-KINGSTON_SA2000M8500G_50026B7282414E01_1", + "/dev/disk/by-id/nvme-eui.0026b7282414e015", + "/dev/disk/by-path/pci-0000:01:00.0-nvme-1", + "/dev/nvme0n1" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 476940, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 976773168, + "value_2": 512 + } + ], + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ] + }, + { + "index": 25, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 15, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf141", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdo", + "sysfs_bus_id": "15:0:0:1", + "sysfs_device_link": "/devices/platform/host15/session111/target15:0:0/15:0:0:1", + "unix_device_name": "/dev/sdo", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 224, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/124", + "/dev/disk/by-id/scsi-360000000000000000e000000000e0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000e0001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:kitchenowl-lun-1", + "/dev/disk/by-uuid/8946a256-09b8-4ca5-b18a-fbde2f0bd674", + "/dev/sdo" + ], + "unix_device_name2": "/dev/sg12", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 12, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 4, + "sectors": 50, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 204800, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 26, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf31", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdd", + "sysfs_bus_id": "4:0:0:1", + "sysfs_device_link": "/devices/platform/host4/session23/target4:0:0/4:0:0:1", + "unix_device_name": "/dev/sdd", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 48, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/36", + "/dev/disk/by-id/scsi-360000000000000000e00000000030001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000030001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:bazarr-lun-1", + "/dev/sdd" + ], + "unix_device_name2": "/dev/sg6", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 6, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 1, + "sectors": 52, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 53248, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 27, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdb", + "sysfs_bus_id": "2:0:0:1", + "sysfs_device_link": "/devices/platform/host2/session1/target2:0:0/2:0:0:1", + "unix_device_name": "/dev/sdb", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 16, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/14", + "/dev/disk/by-id/scsi-360000000000000000e00000000010001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000010001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:pvc-9701d2f8-4cf0-490b-a0ad-2c1151bbf15f-lun-1", + "/dev/sdb" + ], + "unix_device_name2": "/dev/sg2", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 2, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1018, + "heads": 166, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 10485760, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 28, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf101", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdk", + "sysfs_bus_id": "11:0:0:1", + "sysfs_device_link": "/devices/platform/host11/session83/target11:0:0/11:0:0:1", + "unix_device_name": "/dev/sdk", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 160, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/96", + "/dev/disk/by-id/scsi-360000000000000000e000000000a0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000a0001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:pihole-dnsmasq-lun-1", + "/dev/disk/by-uuid/636d77cf-0418-43fb-b86c-22cde408cf08", + "/dev/sdk" + ], + "unix_device_name2": "/dev/sg10", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 10, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 1, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 32768, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 29, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 17, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf161", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdq", + "sysfs_bus_id": "17:0:0:1", + "sysfs_device_link": "/devices/platform/host17/session113/target17:0:0/17:0:0:1", + "unix_device_name": "/dev/sdq", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/126", + "/dev/disk/by-id/scsi-360000000000000000e00000000100001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000100001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:nextcloud-db-lun-1", + "/dev/disk/by-uuid/751984ab-5b1a-4109-9c75-2babdccede30", + "/dev/sdq" + ], + "unix_device_name2": "/dev/sg14", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 14, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1016, + "heads": 13, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 819200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 30, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf21", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdc", + "sysfs_bus_id": "3:0:0:1", + "sysfs_device_link": "/devices/platform/host3/session15/target3:0:0/3:0:0:1", + "unix_device_name": "/dev/sdc", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 32, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/28", + "/dev/disk/by-id/scsi-360000000000000000e00000000020001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000020001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:radicale-lun-1", + "/dev/sdc" + ], + "unix_device_name2": "/dev/sg4", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 4, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1008, + "heads": 7, + "sectors": 58, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 409600, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 31, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 20, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf191", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdt", + "sysfs_bus_id": "20:0:0:1", + "sysfs_device_link": "/devices/platform/host20/session116/target20:0:0/20:0:0:1", + "unix_device_name": "/dev/sdt", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 48, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/129", + "/dev/disk/by-id/scsi-360000000000000000e00000000130001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000130001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:hedgedoc-db-lun-1", + "/dev/disk/by-uuid/758d3a46-6501-432f-b839-8dfb3767bf03", + "/dev/sdt" + ], + "unix_device_name2": "/dev/sg16", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 16, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 4, + "sectors": 50, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 204800, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 32, + "attached_to": 18, + "bus_type": { + "name": "IDE", + "value": 133 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "Samsung", + "value": 0 + }, + "device": { + "name": "SSD 860", + "value": 0 + }, + "revision": { + "name": "4B6Q", + "value": 0 + }, + "serial": "S3YJNB0K486420W", + "model": "Samsung SSD 860", + "sysfs_id": "/class/block/sda", + "sysfs_bus_id": "0:0:0:0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:12.0/ata1/host0/target0:0:0/0:0:0:0", + "unix_device_name": "/dev/sda", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/2", + "/dev/disk/by-id/ata-Samsung_SSD_860_EVO_250GB_S3YJNB0K486420W", + "/dev/disk/by-id/wwn-0x5002538e40364c21", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1.0", + "/dev/sda" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 30401, + "heads": 255, + "sectors": 63, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 488397168, + "value_2": 512 + } + ], + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci", + "sd" + ], + "driver_modules": [ + "ahci", + "sd_mod" + ] + }, + { + "index": 33, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf71", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdh", + "sysfs_bus_id": "8:0:0:1", + "sysfs_device_link": "/devices/platform/host8/session82/target8:0:0/8:0:0:1", + "unix_device_name": "/dev/sdh", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 112, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/95", + "/dev/disk/by-id/scsi-360000000000000000e00000000070001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000070001", + "/dev/disk/by-path/ip-10.42.0.177:3260-iscsi-iqn.2019-10.io.longhorn:pihole-data-lun-1", + "/dev/disk/by-uuid/c323da21-9775-4c9d-8825-89b981680747", + "/dev/sdh" + ], + "unix_device_name2": "/dev/sg8", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 8, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 25, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1536000, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + } + ], + "graphics_card": [ + { + "index": 23, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 2 + }, + "base_class": { + "name": "Display controller", + "value": 3 + }, + "sub_class": { + "name": "VGA compatible controller", + "value": 0 + }, + "pci_interface": { + "name": "VGA", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12677 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel VGA compatible controller", + "sysfs_id": "/devices/pci0000:00/0000:00:02.0", + "sysfs_bus_id": "0000:00:02.0", + "resources": [ + { + "type": "io", + "base": 61440, + "range": 64, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 134, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2415919104, + "range": 268435456, + "enabled": true, + "access": "read_only", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2684354560, + "range": 16777216, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 786432, + "range": 131072, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 134, + "prog_if": 0 + }, + "driver": "i915", + "driver_module": "i915", + "drivers": [ + "i915" + ], + "driver_modules": [ + "i915" + ], + "module_alias": "pci:v00008086d00003185sv00001458sd00001000bc03sc00i00", + "label": "Onboard - Video" + } + ], + "hub": [ + { + "index": 43, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.32 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 2 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.32 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-0:1.0", + "sysfs_bus_id": "1-0:1.0", + "resources": [ + { + "type": "baud", + "speed": 480000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 1, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0002d0606dc09dsc00dp01ic09isc00ip00in00" + }, + { + "index": 45, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.32 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 3 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.32 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb2/2-0:1.0", + "sysfs_bus_id": "2-0:1.0", + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 3, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0003d0606dc09dsc00dp03ic09isc00ip00in00" + } + ], + "memory": [ + { + "index": 7, + "attached_to": 0, + "base_class": { + "name": "Internally Used Class", + "value": 257 + }, + "sub_class": { + "name": "Main Memory", + "value": 2 + }, + "model": "Main Memory", + "resources": [ + { + "type": "mem", + "base": 0, + "range": 16577695744, + "enabled": true, + "access": "read_write", + "prefetch": "unknown" + }, + { + "type": "phys_mem", + "range": 16106127360 + } + ] + } + ], + "network_controller": [ + { + "index": 8, + "attached_to": 20, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Ethernet controller", + "value": 0 + }, + "vendor": { + "value": 4332 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 33128 + }, + "sub_device": { + "value": 57344 + }, + "revision": { + "value": 21 + }, + "model": "Ethernet controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "sysfs_bus_id": "0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 98 + }, + { + "type": "io", + "base": 57344, + "range": 256, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 21, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2701131776, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2701148160, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "phwaddr", + "address": 98 + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 21, + "prog_if": 0 + }, + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ], + "module_alias": "pci:v000010ECd00008168sv00001458sd0000E000bc02sc00i00" + }, + { + "index": 12, + "attached_to": 11, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Network controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "device": { + "value": 9467 + }, + "sub_device": { + "value": 8464 + }, + "revision": { + "value": 16 + }, + "model": "Intel Network controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2/0000:02:00.0", + "sysfs_bus_id": "0000:02:00.0", + "resources": [ + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2702180352, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 2, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000024FBsv00008086sd00002110bc02sc80i00", + "label": "Onboard - RTK Ethernet" + } + ], + "network_interface": [ + { + "index": 52, + "attached_to": 8, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Ethernet", + "value": 1 + }, + "model": "Ethernet network interface", + "sysfs_id": "/class/net/enp3s0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 98 + }, + { + "type": "phwaddr", + "address": 98 + } + ], + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ] + }, + { + "index": 75, + "attached_to": 0, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Loopback", + "value": 0 + }, + "model": "Loopback network interface", + "sysfs_id": "/class/net/lo", + "unix_device_name": "lo", + "unix_device_names": [ + "lo" + ] + } + ], + "storage_controller": [ + { + "index": 14, + "attached_to": 13, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 1, + "number": 0 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 8 + }, + "pci_interface": { + "value": 2 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "value": 8803 + }, + "sub_device": { + "value": 8803 + }, + "revision": { + "value": 3 + }, + "model": "Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0", + "sysfs_bus_id": "0000:01:00.0", + "resources": [ + { + "type": "irq", + "base": 22, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2703228928, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 22, + "prog_if": 2 + }, + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ], + "module_alias": "pci:v00002646d00002263sv00002646sd00002263bc01sc08i02" + }, + { + "index": 18, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 18 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 6 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12771 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:12.0", + "sysfs_bus_id": "0000:00:12.0", + "resources": [ + { + "type": "io", + "base": 61536, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61568, + "range": 4, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61584, + "range": 8, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 131, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704343040, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704371712, + "range": 2048, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704375808, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 131, + "prog_if": 1 + }, + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci" + ], + "driver_modules": [ + "ahci" + ], + "module_alias": "pci:v00008086d000031E3sv00001458sd00001000bc01sc06i01", + "label": "Onboard - SATA" + } + ], + "system": { + "form_factor": "desktop" + }, + "unknown": [ + { + "index": 9, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 28 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12748 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1c.0", + "sysfs_bus_id": "0000:00:1c.0", + "resources": [ + { + "type": "irq", + "base": 39, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704363520, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704367616, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 39, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031CCsv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 15, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 30 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12752 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1e.0", + "sysfs_bus_id": "0000:00:1e.0", + "resources": [ + { + "type": "irq", + "base": 42, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704355328, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704359424, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 42, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031D0sv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 16, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 15 + }, + "base_class": { + "name": "Communication controller", + "value": 7 + }, + "sub_class": { + "name": "Communication controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12698 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Communication controller", + "sysfs_id": "/devices/pci0000:00/0000:00:0f.0", + "sysfs_bus_id": "0000:00:0f.0", + "resources": [ + { + "type": "irq", + "base": 132, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704379904, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 132, + "prog_if": 0 + }, + "driver": "mei_me", + "driver_module": "mei_me", + "drivers": [ + "mei_me" + ], + "driver_modules": [ + "mei_me" + ], + "module_alias": "pci:v00008086d0000319Asv00001458sd00001000bc07sc80i00", + "label": "Onboard - Other" + }, + { + "index": 19, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "SMBus", + "value": 5 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12756 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel SMBus", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.1", + "sysfs_bus_id": "0000:00:1f.1", + "resources": [ + { + "type": "io", + "base": 61504, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704351232, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 1, + "command": 3, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "driver": "i801_smbus", + "driver_module": "i2c_i801", + "drivers": [ + "i801_smbus" + ], + "driver_modules": [ + "i2c_i801" + ], + "module_alias": "pci:v00008086d000031D4sv00001458sd00001000bc0Csc05i00", + "label": "Onboard - Other" + }, + { + "index": 22, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "name": "System peripheral", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12688 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel System peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:00.3", + "sysfs_bus_id": "0000:00:00.3", + "resources": [ + { + "type": "irq", + "base": 23, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704384000, + "range": 4096, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 3, + "command": 0, + "header_type": 0, + "secondary_bus": 0, + "irq": 23, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d00003190sv00001458sd00001000bc08sc80i00", + "label": "Onboard - Other" + }, + { + "index": 34, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg9", + "sysfs_bus_id": "11:0:0:0", + "unix_device_name": "/dev/sg9", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 9, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg9" + ] + }, + { + "index": 35, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg7", + "sysfs_bus_id": "8:0:0:0", + "unix_device_name": "/dev/sg7", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 7, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg7" + ] + }, + { + "index": 36, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg5", + "sysfs_bus_id": "4:0:0:0", + "unix_device_name": "/dev/sg5", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 5, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg5" + ] + }, + { + "index": 37, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 20, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg15", + "sysfs_bus_id": "20:0:0:0", + "unix_device_name": "/dev/sg15", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 15, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg15" + ] + }, + { + "index": 38, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg3", + "sysfs_bus_id": "3:0:0:0", + "unix_device_name": "/dev/sg3", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 3, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg3" + ] + }, + { + "index": 39, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 17, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg13", + "sysfs_bus_id": "17:0:0:0", + "unix_device_name": "/dev/sg13", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 13, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg13" + ] + }, + { + "index": 40, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg1", + "sysfs_bus_id": "2:0:0:0", + "unix_device_name": "/dev/sg1", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 1, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg1" + ] + }, + { + "index": 41, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 15, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg11", + "sysfs_bus_id": "15:0:0:0", + "unix_device_name": "/dev/sg11", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 11, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg11" + ] + } + ], + "usb_controller": [ + { + "index": 21, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 21 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "USB Controller", + "value": 3 + }, + "pci_interface": { + "value": 48 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12712 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel USB Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0", + "sysfs_bus_id": "0000:00:15.0", + "resources": [ + { + "type": "irq", + "base": 130, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704277504, + "range": 65536, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 130, + "prog_if": 48 + }, + "driver": "xhci_hcd", + "driver_module": "xhci_pci", + "drivers": [ + "xhci_hcd" + ], + "driver_modules": [ + "xhci_pci" + ], + "module_alias": "pci:v00008086d000031A8sv00001458sd00001000bc0Csc03i30", + "label": "Onboard - Other" + } + ] + }, + "smbios": { + "bios": { + "handle": 0, + "vendor": "American Megatrends Inc.", + "version": "F8", + "date": "12/13/2019", + "features": [ + "PCI supported", + "BIOS flashable", + "BIOS shadowing allowed", + "CD boot supported", + "Selectable boot supported", + "BIOS ROM socketed", + "EDD spec supported", + "1.2MB Floppy supported", + "720kB Floppy supported", + "2.88MB Floppy supported", + "Print Screen supported", + "8042 Keyboard Services supported", + "Serial Services supported", + "Printer Services supported", + "ACPI supported", + "USB Legacy supported", + "BIOS Boot Spec supported" + ], + "start_address": "0xf0000", + "rom_size": 6291456 + }, + "board": { + "handle": 2, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "board_type": { + "name": "Motherboard", + "value": 10 + }, + "features": [ + "Hosting Board", + "Replaceable" + ], + "location": "Default string", + "chassis": 3 + }, + "cache": [ + { + "handle": 47, + "socket": "CPU Internal L1", + "size_max": 224, + "size_current": 224, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 0, + "ecc": { + "name": "Parity", + "value": 4 + }, + "cache_type": { + "name": "Other", + "value": 1 + }, + "associativity": { + "name": "Other", + "value": 1 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + }, + { + "handle": 48, + "socket": "CPU Internal L2", + "size_max": 4096, + "size_current": 4096, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 1, + "ecc": { + "name": "Single-bit", + "value": 5 + }, + "cache_type": { + "name": "Unified", + "value": 5 + }, + "associativity": { + "name": "16-way Set-Associative", + "value": 8 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + } + ], + "chassis": { + "handle": 3, + "manufacturer": "Default string", + "version": "Default string", + "chassis_type": { + "name": "Desktop", + "value": 3 + }, + "lock_present": false, + "bootup_state": { + "name": "Safe", + "value": 3 + }, + "power_state": { + "name": "Safe", + "value": 3 + }, + "thermal_state": { + "name": "Safe", + "value": 3 + }, + "security_state": { + "name": "None", + "value": 3 + }, + "oem": "0x0" + }, + "config": { + "handle": 34, + "options": [ + "Default string" + ] + }, + "language": [ + { + "handle": 63, + "languages": [ + "en|US|iso8859-1" + ] + } + ], + "memory_array": [ + { + "handle": 35, + "location": { + "name": "Motherboard", + "value": 3 + }, + "usage": { + "name": "System memory", + "value": 3 + }, + "ecc": { + "name": "None", + "value": 3 + }, + "max_size": 33554432, + "error_handle": 65534, + "slots": 2 + } + ], + "memory_array_mapped_address": [ + { + "handle": 36, + "array_handle": 35, + "start_address": 0, + "end_address": 17179869184, + "part_width": 2 + } + ], + "memory_device": [ + { + "handle": 37, + "location": "A1_DIMM0", + "bank_location": "A1_BANK0", + "manufacturer": "Crucial", + "part_number": "CT8G4SFS824A.M8FR", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 8388608, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + }, + { + "handle": 39, + "location": "A1_DIMM1", + "bank_location": "A1_BANK1", + "manufacturer": "Crucial", + "part_number": "CT8G4SFS824A.M8FR", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 8388608, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + } + ], + "memory_device_mapped_address": [ + { + "handle": 38, + "memory_device_handle": 37, + "array_map_handle": 36, + "start_address": 0, + "end_address": 8589934592, + "row_position": 255, + "interleave_position": 1, + "interleave_depth": 2 + }, + { + "handle": 40, + "memory_device_handle": 39, + "array_map_handle": 36, + "start_address": 8589934592, + "end_address": 17179869184, + "row_position": 255, + "interleave_position": 2, + "interleave_depth": 2 + } + ], + "onboard": [ + { + "handle": 32, + "devices": [ + { + "name": "To Be Filled By O.E.M.", + "type": { + "name": "Video", + "value": 3 + }, + "enabled": true + } + ] + } + ], + "port_connector": [ + { + "handle": 8, + "port_type": { + "name": "Mouse Port", + "value": 14 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "PS2Mouse" + }, + { + "handle": 9, + "port_type": { + "name": "Keyboard Port", + "value": 13 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "Keyboard" + }, + { + "handle": 10, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2A1", + "external_connector_type": { + "name": "Mini-Centronics Type-14", + "value": 29 + }, + "external_reference_designator": "TV Out" + }, + { + "handle": 11, + "port_type": { + "name": "Serial Port 16550A Compatible", + "value": 9 + }, + "internal_reference_designator": "J2A2A", + "external_connector_type": { + "name": "DB-9 pin male", + "value": 8 + }, + "external_reference_designator": "COM A" + }, + { + "handle": 12, + "port_type": { + "name": "Video Port", + "value": 28 + }, + "internal_reference_designator": "J2A2B", + "external_connector_type": { + "name": "DB-15 pin female", + "value": 7 + }, + "external_reference_designator": "Video" + }, + { + "handle": 13, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB1" + }, + { + "handle": 14, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB2" + }, + { + "handle": 15, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB3" + }, + { + "handle": 16, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9A1 - TPM HDR" + }, + { + "handle": 17, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9C1 - PCIE DOCKING CONN" + }, + { + "handle": 18, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2B3 - CPU FAN" + }, + { + "handle": 19, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6C2 - EXT HDMI" + }, + { + "handle": 20, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J3C1 - GMCH FAN" + }, + { + "handle": 21, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1D1 - ITP" + }, + { + "handle": 22, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E2 - MDC INTPSR" + }, + { + "handle": 23, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E4 - MDC INTPSR" + }, + { + "handle": 24, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E3 - LPC HOT DOCKING" + }, + { + "handle": 25, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E1 - SCAN MATRIX" + }, + { + "handle": 26, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9G1 - LPC SIDE BAND" + }, + { + "handle": 27, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J8F1 - UNIFIED" + }, + { + "handle": 28, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6F1 - LVDS" + }, + { + "handle": 29, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2F1 - LAI FAN" + }, + { + "handle": 30, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2G1 - GFX VID" + }, + { + "handle": 31, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1G6 - AC JACK" + } + ], + "processor": [ + { + "handle": 49, + "socket": "SOCKET 0", + "socket_type": { + "name": "Other", + "value": 1 + }, + "socket_populated": true, + "manufacturer": "Intel", + "version": "Intel(R) Celeron(R) J4105 CPU @ 1.50GHz", + "part": "Fill By OEM", + "processor_type": { + "name": "CPU", + "value": 3 + }, + "processor_family": { + "name": "Celeron", + "value": 15 + }, + "processor_status": { + "name": "Enabled", + "value": 1 + }, + "clock_ext": 100, + "clock_max": 2700, + "cache_handle_l1": 47, + "cache_handle_l2": 48, + "cache_handle_l3": 0 + } + ], + "slot": [ + { + "handle": 64, + "designation": "J7H1", + "slot_type": { + "name": "Other", + "value": 174 + }, + "bus_width": { + "name": "Other", + "value": 10 + }, + "usage": { + "name": "In Use", + "value": 4 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 0, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + }, + { + "handle": 65, + "designation": "J8H1", + "slot_type": { + "name": "Other", + "value": 173 + }, + "bus_width": { + "name": "Other", + "value": 9 + }, + "usage": { + "name": "Available", + "value": 3 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 1, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + } + ], + "system": { + "handle": 1, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "wake_up": { + "name": "Power Switch", + "value": 6 + } + } + } +} \ No newline at end of file diff --git a/machines/lewis.nix b/machines/lewis/default.nix similarity index 91% rename from machines/lewis.nix rename to machines/lewis/default.nix index c20bbb2..5b6f580 100644 --- a/machines/lewis.nix +++ b/machines/lewis/default.nix @@ -5,6 +5,7 @@ storageType = "fast"; hasMedia = "true"; }; + facterReportPath = ./facter.json; nixosModule.lab = { storage.profile = "kubernetes"; diff --git a/machines/lewis/facter.json b/machines/lewis/facter.json new file mode 100644 index 0000000..ef4139b --- /dev/null +++ b/machines/lewis/facter.json @@ -0,0 +1,5507 @@ +{ + "version": 1, + "system": "x86_64-linux", + "virtualisation": "none", + "hardware": { + "bios": { + "apm_info": { + "supported": false, + "enabled": false, + "version": 0, + "sub_version": 0, + "bios_flags": 0 + }, + "vbe_info": { + "version": 0, + "video_memory": 0 + }, + "pnp": false, + "pnp_id": 0, + "lba_support": false, + "low_memory_size": 0, + "smbios_version": 770 + }, + "bluetooth": [ + { + "index": 72, + "attached_to": 73, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.0", + "sysfs_bus_id": "1-3:1.0", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in00" + }, + { + "index": 74, + "attached_to": 73, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bluetooth Device", + "value": 277 + }, + "vendor": { + "value": 32903 + }, + "device": { + "value": 2727 + }, + "revision": { + "name": "0.01", + "value": 0 + }, + "model": "Bluetooth Device", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3:1.1", + "sysfs_bus_id": "1-3:1.1", + "resources": [ + { + "type": "baud", + "speed": 12000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "wireless", + "value": 224 + }, + "device_subclass": { + "name": "audio", + "value": 1 + }, + "device_protocol": 1, + "interface_class": { + "name": "wireless", + "value": 224 + }, + "interface_subclass": { + "name": "audio", + "value": 1 + }, + "interface_protocol": 1, + "interface_number": 1, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "btusb", + "driver_module": "btusb", + "drivers": [ + "btusb" + ], + "driver_modules": [ + "btusb" + ], + "module_alias": "usb:v8087p0AA7d0001dcE0dsc01dp01icE0isc01ip01in01" + } + ], + "bridge": [ + { + "index": 10, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "ISA bridge", + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12776 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel ISA bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.0", + "sysfs_bus_id": "0000:00:1f.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031E8sv00001458sd00001000bc06sc01i00", + "label": "Onboard - Other" + }, + { + "index": 11, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12762 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2", + "sysfs_bus_id": "0000:00:13.2", + "resources": [ + { + "type": "irq", + "base": 123, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 2, + "command": 1031, + "header_type": 1, + "secondary_bus": 2, + "irq": 123, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DAsv00001458sd00001000bc06sc04i00" + }, + { + "index": 13, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12760 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0", + "sysfs_bus_id": "0000:00:13.0", + "resources": [ + { + "type": "irq", + "base": 122, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 1, + "secondary_bus": 1, + "irq": 122, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031D8sv00001458sd00001000bc06sc04i00" + }, + { + "index": 17, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "Host bridge", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12784 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Host bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:00.0", + "sysfs_bus_id": "0000:00:00.0", + "detail": { + "function": 0, + "command": 7, + "header_type": 0, + "secondary_bus": 0, + "irq": 0, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000031F0sv00001458sd00001000bc06sc00i00", + "label": "Onboard - Other" + }, + { + "index": 20, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 19 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12763 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 243 + }, + "model": "Intel PCI bridge", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3", + "sysfs_bus_id": "0000:00:13.3", + "resources": [ + { + "type": "irq", + "base": 124, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 3, + "command": 1031, + "header_type": 1, + "secondary_bus": 3, + "irq": 124, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v00008086d000031DBsv00001458sd00001000bc06sc04i00" + } + ], + "cpu": [ + { + "architecture": "x86_64", + "vendor_name": "GenuineIntel", + "family": 6, + "model": 122, + "stepping": 1, + "features": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "dts", + "acpi", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "ht", + "tm", + "pbe", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "art", + "arch_perfmon", + "pebs", + "bts", + "rep_good", + "nopl", + "xtopology", + "nonstop_tsc", + "cpuid", + "aperfmperf", + "tsc_known_freq", + "pni", + "pclmulqdq", + "dtes64", + "monitor", + "ds_cpl", + "vmx", + "est", + "tm2", + "ssse3", + "sdbg", + "cx16", + "xtpr", + "pdcm", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "rdrand", + "lahf_lm", + "3dnowprefetch", + "cpuid_fault", + "cat_l2", + "pti", + "cdp_l2", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "ibrs_enhanced", + "tpr_shadow", + "flexpriority", + "ept", + "vpid", + "ept_ad", + "fsgsbase", + "tsc_adjust", + "smep", + "erms", + "mpx", + "rdt_a", + "rdseed", + "smap", + "clflushopt", + "intel_pt", + "sha_ni", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "dtherm", + "ida", + "arat", + "pln", + "pts", + "vnmi", + "umip", + "rdpid", + "md_clear", + "arch_capabilities" + ], + "bugs": [ + "cpu_meltdown", + "spectre_v1", + "spectre_v2", + "spec_store_bypass", + "rfds", + "bhi" + ], + "bogo": 2995.2, + "cache": 4096, + "units": 64, + "physical_id": 0, + "siblings": 4, + "cores": 4, + "fpu": true, + "fpu_exception": true, + "cpuid_level": 24, + "write_protect": false, + "clflush_size": 64, + "cache_alignment": 64, + "address_sizes": { + "physical": 39, + "virtual": 48 + } + } + ], + "disk": [ + { + "index": 24, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 25, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf231", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdy", + "sysfs_bus_id": "25:0:0:1", + "sysfs_device_link": "/devices/platform/host25/session163/target25:0:0/25:0:0:1", + "unix_device_name": "/dev/sdy", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 128, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/176", + "/dev/disk/by-id/scsi-360000000000000000e00000000170001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000170001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:ntfy-lun-1", + "/dev/disk/by-uuid/7ae09e5a-8909-416c-903e-faeaf8b9ebf7", + "/dev/sdy" + ], + "unix_device_name2": "/dev/sg36", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 36, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 10, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 614400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 25, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 6, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf31", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdf", + "sysfs_bus_id": "6:0:0:1", + "sysfs_device_link": "/devices/platform/host6/session521/target6:0:0/6:0:0:1", + "unix_device_name": "/dev/sdf", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 80, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/552", + "/dev/disk/by-id/scsi-360000000000000000e00000000030001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000030001", + "/dev/disk/by-path/ip-10.42.2.229:3260-iscsi-iqn.2019-10.io.longhorn:nextcloud-lun-1", + "/dev/disk/by-uuid/9ad442ea-127e-4f66-8cf8-4f7a69932806", + "/dev/sdf" + ], + "unix_device_name2": "/dev/sg40", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 40, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 51200, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 104857600, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 26, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 28, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf271", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdab", + "sysfs_bus_id": "28:0:0:1", + "sysfs_device_link": "/devices/platform/host28/session123/target28:0:0/28:0:0:1", + "unix_device_name": "/dev/sdab", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 176, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/136", + "/dev/disk/by-id/scsi-360000000000000000e000000001b0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000001b0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:attic-db-lun-1", + "/dev/disk/by-uuid/6940ecd4-614f-41db-a4f5-9171f5498519", + "/dev/sdab" + ], + "unix_device_name2": "/dev/sg10", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 10, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 5, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 307200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 27, + "attached_to": 14, + "bus_type": { + "name": "NVME", + "value": 150 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "name": "KINGSTON SNV2S1000G", + "value": 20503 + }, + "sub_device": { + "value": 20503 + }, + "serial": "50026B76862833F0", + "model": "KINGSTON SNV2S1000G", + "sysfs_id": "/class/block/nvme0n1", + "sysfs_bus_id": "nvme0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0/nvme/nvme0", + "unix_device_name": "/dev/nvme0n1", + "unix_device_number": { + "type": 98, + "major": 259, + "minor": 0, + "range": 0 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/1", + "/dev/disk/by-id/nvme-KINGSTON_SNV2S1000G_50026B76862833F0", + "/dev/disk/by-id/nvme-KINGSTON_SNV2S1000G_50026B76862833F0_1", + "/dev/disk/by-id/nvme-eui.00000000000000000026b76862833f05", + "/dev/disk/by-path/pci-0000:01:00.0-nvme-1", + "/dev/nvme0n1" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 953869, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1953525168, + "value_2": 512 + } + ], + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ] + }, + { + "index": 28, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 15, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf181", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdo", + "sysfs_bus_id": "15:0:0:1", + "sysfs_device_link": "/devices/platform/host15/session141/target15:0:0/15:0:0:1", + "unix_device_name": "/dev/sdo", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 224, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/154", + "/dev/disk/by-id/scsi-360000000000000000e00000000120001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000120001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:hedgedoc-uploads-lun-1", + "/dev/disk/by-uuid/a852f0d1-e4fa-43c4-9789-270d29a24025", + "/dev/sdo" + ], + "unix_device_name2": "/dev/sg12", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 12, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 2, + "sectors": 50, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 102400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 29, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 23, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf211", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdw", + "sysfs_bus_id": "23:0:0:1", + "sysfs_device_link": "/devices/platform/host23/session161/target23:0:0/23:0:0:1", + "unix_device_name": "/dev/sdw", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 96, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/174", + "/dev/disk/by-id/scsi-360000000000000000e00000000150001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000150001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:pvc-8562af07-b250-4e87-9ebd-3bcad23a3b54-lun-1", + "/dev/disk/by-uuid/614ccde9-d82f-4b8d-bffe-f427743618de", + "/dev/sdw" + ], + "unix_device_name2": "/dev/sg32", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 32, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1020, + "heads": 17, + "sectors": 59, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1024000, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 30, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf151", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdd", + "sysfs_bus_id": "4:0:0:1", + "sysfs_device_link": "/devices/platform/host4/session37/target4:0:0/4:0:0:1", + "unix_device_name": "/dev/sdd", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 48, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/50", + "/dev/disk/by-id/scsi-360000000000000000e000000000f0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000f0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:hedgedoc-db-lun-1", + "/dev/sdd" + ], + "unix_device_name2": "/dev/sg6", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 6, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 4, + "sectors": 50, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 204800, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 31, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 13, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf121", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdm", + "sysfs_bus_id": "13:0:0:1", + "sysfs_device_link": "/devices/platform/host13/session156/target13:0:0/13:0:0:1", + "unix_device_name": "/dev/sdm", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 192, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/169", + "/dev/disk/by-id/scsi-360000000000000000e000000000c0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000c0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:prowlarr-lun-1", + "/dev/disk/by-uuid/485930ae-2fe2-4470-b99a-dc61a93d921c", + "/dev/sdm" + ], + "unix_device_name2": "/dev/sg24", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 24, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 5, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 307200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 32, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 21, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf191", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdu", + "sysfs_bus_id": "21:0:0:1", + "sysfs_device_link": "/devices/platform/host21/session159/target21:0:0/21:0:0:1", + "unix_device_name": "/dev/sdu", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 64, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/172", + "/dev/disk/by-id/scsi-360000000000000000e00000000130001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000130001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:pvc-2848b393-989a-4a12-b155-59d67313c20b-lun-1", + "/dev/disk/by-uuid/4ffb4dc3-e48b-4e74-9678-5693227cb1cf", + "/dev/sdu" + ], + "unix_device_name2": "/dev/sg30", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 30, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 10, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 614400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 33, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdb", + "sysfs_bus_id": "2:0:0:1", + "sysfs_device_link": "/devices/platform/host2/session1/target2:0:0/2:0:0:1", + "unix_device_name": "/dev/sdb", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 16, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/14", + "/dev/disk/by-id/scsi-360000000000000000e00000000010001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000010001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:pvc-09c264fc-dace-4bbe-88ae-555d96e6c956-lun-1", + "/dev/sdb" + ], + "unix_device_name2": "/dev/sg2", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 2, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 20480, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 41943040, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 34, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf101", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdk", + "sysfs_bus_id": "11:0:0:1", + "sysfs_device_link": "/devices/platform/host11/session51/target11:0:0/11:0:0:1", + "unix_device_name": "/dev/sdk", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 160, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/64", + "/dev/disk/by-id/scsi-360000000000000000e000000000a0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000a0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:immich-db-lun-1", + "/dev/disk/by-uuid/b2aeda75-49fa-4d68-8949-9effd8931753", + "/dev/sdk" + ], + "unix_device_name2": "/dev/sg8", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 8, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1018, + "heads": 166, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 10485760, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 35, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 19, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf161", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sds", + "sysfs_bus_id": "19:0:0:1", + "sysfs_device_link": "/devices/platform/host19/session158/target19:0:0/19:0:0:1", + "unix_device_name": "/dev/sds", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 32, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/171", + "/dev/disk/by-id/scsi-360000000000000000e00000000100001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000100001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:jellyseerr-lun-1", + "/dev/disk/by-uuid/2fbc120d-0631-4d48-814a-49fa1c91c607", + "/dev/sds" + ], + "unix_device_name2": "/dev/sg28", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 28, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1017, + "heads": 3, + "sectors": 51, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 155648, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 36, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 9, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf71", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdi", + "sysfs_bus_id": "9:0:0:1", + "sysfs_device_link": "/devices/platform/host9/session153/target9:0:0/9:0:0:1", + "unix_device_name": "/dev/sdi", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 128, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/166", + "/dev/disk/by-id/scsi-360000000000000000e00000000070001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000070001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:paperless-redisdata-lun-1", + "/dev/disk/by-uuid/0f49df82-6a76-453d-bdaf-0a9332d204b8", + "/dev/sdi" + ], + "unix_device_name2": "/dev/sg20", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 20, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 1, + "sectors": 40, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 40960, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 37, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 17, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf131", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdq", + "sysfs_bus_id": "17:0:0:1", + "sysfs_device_link": "/devices/platform/host17/session157/target17:0:0/17:0:0:1", + "unix_device_name": "/dev/sdq", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/170", + "/dev/disk/by-id/scsi-360000000000000000e000000000d0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000d0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:bazarr-lun-1", + "/dev/disk/by-uuid/358898d4-e920-414a-b1c8-3e2a6af401ab", + "/dev/sdq" + ], + "unix_device_name2": "/dev/sg26", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 26, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 1, + "sectors": 52, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 53248, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 38, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 7, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf51", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdg", + "sysfs_bus_id": "7:0:0:1", + "sysfs_device_link": "/devices/platform/host7/session151/target7:0:0/7:0:0:1", + "unix_device_name": "/dev/sdg", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 96, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/164", + "/dev/disk/by-id/scsi-360000000000000000e00000000050001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000050001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:deluge-lun-1", + "/dev/disk/by-uuid/84cc595f-a85d-4aea-a9b6-b2f2ac5e402e", + "/dev/sdg" + ], + "unix_device_name2": "/dev/sg18", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 18, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1020, + "heads": 17, + "sectors": 59, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1024000, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 39, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 24, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf221", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdx", + "sysfs_bus_id": "24:0:0:1", + "sysfs_device_link": "/devices/platform/host24/session162/target24:0:0/24:0:0:1", + "unix_device_name": "/dev/sdx", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 112, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/175", + "/dev/disk/by-id/scsi-360000000000000000e00000000160001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000160001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:paperless-db-lun-1", + "/dev/disk/by-uuid/6a149153-655e-4561-a8c0-c7d19074cce9", + "/dev/sdx" + ], + "unix_device_name2": "/dev/sg34", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 34, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 5, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 307200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 40, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 5, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf31", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sde", + "sysfs_bus_id": "5:0:0:1", + "sysfs_device_link": "/devices/platform/host5/session147/target5:0:0/5:0:0:1", + "unix_device_name": "/dev/sde", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 64, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/160", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:pvc-1251134d-6da6-4aae-9b7c-770aa76fffd9-lun-1", + "/dev/disk/by-uuid/d0342ab1-820d-4fa8-baf9-d1cfd6441b8e", + "/dev/sde" + ], + "unix_device_name2": "/dev/sg16", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 16, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 20480, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 41943040, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 41, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 14, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdn", + "sysfs_bus_id": "14:0:0:1", + "sysfs_device_link": "/devices/platform/host14/session759/target14:0:0/14:0:0:1", + "unix_device_name": "/dev/sdn", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 208, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/790", + "/dev/disk/by-path/ip-10.42.2.68:3260-iscsi-iqn.2019-10.io.longhorn:forgejo-lun-1", + "/dev/disk/by-uuid/0448fef2-ca9e-4a75-9d21-e148e3e9fe34", + "/dev/sdn" + ], + "unix_device_name2": "/dev/sg46", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 46, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 20480, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 41943040, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 42, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 22, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf61", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdv", + "sysfs_bus_id": "22:0:0:1", + "sysfs_device_link": "/devices/platform/host22/session587/target22:0:0/22:0:0:1", + "unix_device_name": "/dev/sdv", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 80, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/618", + "/dev/disk/by-id/scsi-360000000000000000e00000000060001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000060001", + "/dev/disk/by-path/ip-10.42.2.229:3260-iscsi-iqn.2019-10.io.longhorn:sonarr-lun-1", + "/dev/disk/by-uuid/b362beb2-a0d6-4fad-97e6-9d234c122aa9", + "/dev/sdv" + ], + "unix_device_name2": "/dev/sg44", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 44, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 5, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 307200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 43, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf21", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdc", + "sysfs_bus_id": "3:0:0:1", + "sysfs_device_link": "/devices/platform/host3/session146/target3:0:0/3:0:0:1", + "unix_device_name": "/dev/sdc", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 32, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/159", + "/dev/disk/by-id/scsi-360000000000000000e00000000020001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000020001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:jellyfin-lun-1", + "/dev/disk/by-uuid/48bef742-1b0e-4417-bfac-3d0d59e4baeb", + "/dev/sdc" + ], + "unix_device_name2": "/dev/sg14", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 14, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1018, + "heads": 166, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 10485760, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 44, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 12, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf111", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdl", + "sysfs_bus_id": "12:0:0:1", + "sysfs_device_link": "/devices/platform/host12/session155/target12:0:0/12:0:0:1", + "unix_device_name": "/dev/sdl", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 176, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/168", + "/dev/disk/by-id/scsi-360000000000000000e000000000b0001", + "/dev/disk/by-id/wwn-0x60000000000000000e000000000b0001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:radarr-lun-1", + "/dev/disk/by-uuid/ec9d35c0-6ee7-4b3f-8b87-3fc1703c62ce", + "/dev/sdl" + ], + "unix_device_name2": "/dev/sg22", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 22, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1024, + "heads": 10, + "sectors": 60, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 614400, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 45, + "attached_to": 18, + "bus_type": { + "name": "IDE", + "value": 133 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "Samsung", + "value": 0 + }, + "device": { + "name": "SSD 870", + "value": 0 + }, + "revision": { + "name": "2B6Q", + "value": 0 + }, + "serial": "S5RRNF0W629236X", + "model": "Samsung SSD 870", + "sysfs_id": "/class/block/sda", + "sysfs_bus_id": "0:0:0:0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:12.0/ata1/host0/target0:0:0/0:0:0:0", + "unix_device_name": "/dev/sda", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/2", + "/dev/disk/by-id/ata-Samsung_SSD_870_QVO_1TB_S5RRNF0W629236X", + "/dev/disk/by-id/wwn-0x5002538f43621654", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1", + "/dev/disk/by-path/pci-0000:00:12.0-ata-1.0", + "/dev/sda" + ], + "resources": [ + { + "type": "disk_geo", + "cylinders": 121601, + "heads": 255, + "sectors": 63, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 1953525168, + "value_2": 512 + } + ], + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci", + "sd" + ], + "driver_modules": [ + "ahci", + "sd_mod" + ] + }, + { + "index": 46, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 10, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf41", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdj", + "sysfs_bus_id": "10:0:0:1", + "sysfs_device_link": "/devices/platform/host10/session522/target10:0:0/10:0:0:1", + "unix_device_name": "/dev/sdj", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 144, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/553", + "/dev/disk/by-id/scsi-360000000000000000e00000000040001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000040001", + "/dev/disk/by-path/ip-10.42.2.229:3260-iscsi-iqn.2019-10.io.longhorn:syncthing-lun-1", + "/dev/disk/by-uuid/6cbd7d44-7471-42f0-a325-7fefe1f63960", + "/dev/sdj" + ], + "unix_device_name2": "/dev/sg42", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 42, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1016, + "heads": 13, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 819200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 47, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 18, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf171", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdr", + "sysfs_bus_id": "18:0:0:1", + "sysfs_device_link": "/devices/platform/host18/session35/target18:0:0/18:0:0:1", + "unix_device_name": "/dev/sdr", + "unix_device_number": { + "type": 98, + "major": 65, + "minor": 16, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/48", + "/dev/disk/by-id/scsi-360000000000000000e00000000110001", + "/dev/disk/by-id/wwn-0x60000000000000000e00000000110001", + "/dev/disk/by-path/ip-10.42.2.244:3260-iscsi-iqn.2019-10.io.longhorn:nextcloud-db-lun-1", + "/dev/sdr" + ], + "unix_device_name2": "/dev/sg4", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 4, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 1016, + "heads": 13, + "sectors": 62, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 819200, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + }, + { + "index": 48, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "VIRTUAL-DISK", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "serial": "beaf11", + "model": "IET VIRTUAL-DISK", + "sysfs_id": "/class/block/sdh", + "sysfs_bus_id": "8:0:0:1", + "sysfs_device_link": "/devices/platform/host8/session519/target8:0:0/8:0:0:1", + "unix_device_name": "/dev/sdh", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 112, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/550", + "/dev/disk/by-path/ip-10.42.2.229:3260-iscsi-iqn.2019-10.io.longhorn:immich-lun-1", + "/dev/disk/by-uuid/a274d2e4-c595-48ae-be32-15f7084aedce", + "/dev/sdh" + ], + "unix_device_name2": "/dev/sg38", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 38, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 51200, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 104857600, + "value_2": 512 + } + ], + "driver": "sd", + "driver_module": "sd_mod", + "drivers": [ + "sd" + ], + "driver_modules": [ + "sd_mod" + ] + } + ], + "graphics_card": [ + { + "index": 23, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 2 + }, + "base_class": { + "name": "Display controller", + "value": 3 + }, + "sub_class": { + "name": "VGA compatible controller", + "value": 0 + }, + "pci_interface": { + "name": "VGA", + "value": 0 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12677 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel VGA compatible controller", + "sysfs_id": "/devices/pci0000:00/0000:00:02.0", + "sysfs_bus_id": "0000:00:02.0", + "resources": [ + { + "type": "io", + "base": 61440, + "range": 64, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 134, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2415919104, + "range": 268435456, + "enabled": true, + "access": "read_only", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2684354560, + "range": 16777216, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 786432, + "range": 131072, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 134, + "prog_if": 0 + }, + "driver": "i915", + "driver_module": "i915", + "drivers": [ + "i915" + ], + "driver_modules": [ + "i915" + ], + "module_alias": "pci:v00008086d00003185sv00001458sd00001000bc03sc00i00", + "label": "Onboard - Video" + } + ], + "hub": [ + { + "index": 73, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.32 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 2 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.32 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb1/1-0:1.0", + "sysfs_bus_id": "1-0:1.0", + "resources": [ + { + "type": "baud", + "speed": 480000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 1, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0002d0606dc09dsc00dp01ic09isc00ip00in00" + }, + { + "index": 75, + "attached_to": 21, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.6.32 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 3 + }, + "revision": { + "name": "6.06", + "value": 0 + }, + "serial": "0000:00:15.0", + "model": "Linux 6.6.32 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0/usb2/2-0:1.0", + "sysfs_bus_id": "2-0:1.0", + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 3, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "drivers": [ + "hub" + ], + "module_alias": "usb:v1D6Bp0003d0606dc09dsc00dp03ic09isc00ip00in00" + } + ], + "memory": [ + { + "index": 7, + "attached_to": 0, + "base_class": { + "name": "Internally Used Class", + "value": 257 + }, + "sub_class": { + "name": "Main Memory", + "value": 2 + }, + "model": "Main Memory", + "resources": [ + { + "type": "mem", + "base": 0, + "range": 25008177152, + "enabled": true, + "access": "read_write", + "prefetch": "unknown" + }, + { + "type": "phys_mem", + "range": 25769803776 + } + ] + } + ], + "network_controller": [ + { + "index": 8, + "attached_to": 20, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Ethernet controller", + "value": 0 + }, + "vendor": { + "value": 4332 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 33128 + }, + "sub_device": { + "value": 57344 + }, + "revision": { + "value": 21 + }, + "model": "Ethernet controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "sysfs_bus_id": "0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "io", + "base": 57344, + "range": 256, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 21, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2701131776, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2701148160, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 21, + "prog_if": 0 + }, + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ], + "module_alias": "pci:v000010ECd00008168sv00001458sd0000E000bc02sc00i00" + }, + { + "index": 12, + "attached_to": 11, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Network controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "device": { + "value": 9467 + }, + "sub_device": { + "value": 8464 + }, + "revision": { + "value": 16 + }, + "model": "Intel Network controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.2/0000:02:00.0", + "sysfs_bus_id": "0000:02:00.0", + "resources": [ + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2702180352, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 2, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d000024FBsv00008086sd00002110bc02sc80i00", + "label": "Onboard - RTK Ethernet" + } + ], + "network_interface": [ + { + "index": 91, + "attached_to": 8, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Ethernet", + "value": 1 + }, + "model": "Ethernet network interface", + "sysfs_id": "/class/net/enp3s0", + "sysfs_device_link": "/devices/pci0000:00/0000:00:13.3/0000:03:00.0", + "unix_device_name": "enp3s0", + "unix_device_names": [ + "enp3s0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "driver": "r8169", + "driver_module": "r8169", + "drivers": [ + "r8169" + ], + "driver_modules": [ + "r8169" + ] + }, + { + "index": 100, + "attached_to": 0, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Loopback", + "value": 0 + }, + "model": "Loopback network interface", + "sysfs_id": "/class/net/lo", + "unix_device_name": "lo", + "unix_device_names": [ + "lo" + ] + } + ], + "storage_controller": [ + { + "index": 14, + "attached_to": 13, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 1, + "number": 0 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 8 + }, + "pci_interface": { + "value": 2 + }, + "vendor": { + "value": 9798 + }, + "sub_vendor": { + "value": 9798 + }, + "device": { + "value": 20503 + }, + "sub_device": { + "value": 20503 + }, + "revision": { + "value": 3 + }, + "model": "Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:13.0/0000:01:00.0", + "sysfs_bus_id": "0000:01:00.0", + "resources": [ + { + "type": "irq", + "base": 22, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2703228928, + "range": 16384, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 22, + "prog_if": 2 + }, + "driver": "nvme", + "driver_module": "nvme", + "drivers": [ + "nvme" + ], + "driver_modules": [ + "nvme" + ], + "module_alias": "pci:v00002646d00005017sv00002646sd00005017bc01sc08i02" + }, + { + "index": 18, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 18 + }, + "base_class": { + "name": "Mass storage controller", + "value": 1 + }, + "sub_class": { + "value": 6 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12771 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Mass storage controller", + "sysfs_id": "/devices/pci0000:00/0000:00:12.0", + "sysfs_bus_id": "0000:00:12.0", + "resources": [ + { + "type": "io", + "base": 61536, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61568, + "range": 4, + "enabled": true, + "access": "read_write" + }, + { + "type": "io", + "base": 61584, + "range": 8, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 131, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704343040, + "range": 8192, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704371712, + "range": 2048, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704375808, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1031, + "header_type": 0, + "secondary_bus": 0, + "irq": 131, + "prog_if": 1 + }, + "driver": "ahci", + "driver_module": "ahci", + "drivers": [ + "ahci" + ], + "driver_modules": [ + "ahci" + ], + "module_alias": "pci:v00008086d000031E3sv00001458sd00001000bc01sc06i01", + "label": "Onboard - SATA" + } + ], + "system": { + "form_factor": "desktop" + }, + "unknown": [ + { + "index": 9, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 28 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12748 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1c.0", + "sysfs_bus_id": "0000:00:1c.0", + "resources": [ + { + "type": "irq", + "base": 39, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704363520, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704367616, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 39, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031CCsv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 15, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 30 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "value": 5 + }, + "pci_interface": { + "value": 1 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12752 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Generic system peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:1e.0", + "sysfs_bus_id": "0000:00:1e.0", + "resources": [ + { + "type": "irq", + "base": 42, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704355328, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + }, + { + "type": "mem", + "base": 2704359424, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 0, + "secondary_bus": 0, + "irq": 42, + "prog_if": 1 + }, + "driver": "sdhci-pci", + "driver_module": "sdhci_pci", + "drivers": [ + "sdhci-pci" + ], + "driver_modules": [ + "sdhci_pci" + ], + "module_alias": "pci:v00008086d000031D0sv00001458sd00001000bc08sc05i01", + "label": "Onboard - Other" + }, + { + "index": 16, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 15 + }, + "base_class": { + "name": "Communication controller", + "value": 7 + }, + "sub_class": { + "name": "Communication controller", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12698 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel Communication controller", + "sysfs_id": "/devices/pci0000:00/0000:00:0f.0", + "sysfs_bus_id": "0000:00:0f.0", + "resources": [ + { + "type": "irq", + "base": 132, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704379904, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 132, + "prog_if": 0 + }, + "driver": "mei_me", + "driver_module": "mei_me", + "drivers": [ + "mei_me" + ], + "driver_modules": [ + "mei_me" + ], + "module_alias": "pci:v00008086d0000319Asv00001458sd00001000bc07sc80i00", + "label": "Onboard - Other" + }, + { + "index": 19, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 31 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "SMBus", + "value": 5 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12756 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel SMBus", + "sysfs_id": "/devices/pci0000:00/0000:00:1f.1", + "sysfs_bus_id": "0000:00:1f.1", + "resources": [ + { + "type": "io", + "base": 61504, + "range": 32, + "enabled": true, + "access": "read_write" + }, + { + "type": "irq", + "base": 20, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704351232, + "range": 256, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 1, + "command": 3, + "header_type": 0, + "secondary_bus": 0, + "irq": 20, + "prog_if": 0 + }, + "driver": "i801_smbus", + "driver_module": "i2c_i801", + "drivers": [ + "i801_smbus" + ], + "driver_modules": [ + "i2c_i801" + ], + "module_alias": "pci:v00008086d000031D4sv00001458sd00001000bc0Csc05i00", + "label": "Onboard - Other" + }, + { + "index": 22, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Generic system peripheral", + "value": 8 + }, + "sub_class": { + "name": "System peripheral", + "value": 128 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12688 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel System peripheral", + "sysfs_id": "/devices/pci0000:00/0000:00:00.3", + "sysfs_bus_id": "0000:00:00.3", + "resources": [ + { + "type": "irq", + "base": 23, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704384000, + "range": 4096, + "enabled": false, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 3, + "command": 0, + "header_type": 0, + "secondary_bus": 0, + "irq": 23, + "prog_if": 0 + }, + "module_alias": "pci:v00008086d00003190sv00001458sd00001000bc08sc80i00", + "label": "Onboard - Other" + }, + { + "index": 49, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 6, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg39", + "sysfs_bus_id": "6:0:0:0", + "unix_device_name": "/dev/sg39", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 39, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg39" + ] + }, + { + "index": 50, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 21, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg29", + "sysfs_bus_id": "21:0:0:0", + "unix_device_name": "/dev/sg29", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 29, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg29" + ] + }, + { + "index": 51, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 28, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg9", + "sysfs_bus_id": "28:0:0:0", + "unix_device_name": "/dev/sg9", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 9, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg9" + ] + }, + { + "index": 52, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 9, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg19", + "sysfs_bus_id": "9:0:0:0", + "unix_device_name": "/dev/sg19", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 19, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg19" + ] + }, + { + "index": 53, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 8, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg37", + "sysfs_bus_id": "8:0:0:0", + "unix_device_name": "/dev/sg37", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 37, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg37" + ] + }, + { + "index": 54, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 19, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg27", + "sysfs_bus_id": "19:0:0:0", + "unix_device_name": "/dev/sg27", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 27, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg27" + ] + }, + { + "index": 55, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 11, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg7", + "sysfs_bus_id": "11:0:0:0", + "unix_device_name": "/dev/sg7", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 7, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg7" + ] + }, + { + "index": 56, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 7, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg17", + "sysfs_bus_id": "7:0:0:0", + "unix_device_name": "/dev/sg17", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 17, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg17" + ] + }, + { + "index": 57, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 14, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg45", + "sysfs_bus_id": "14:0:0:0", + "unix_device_name": "/dev/sg45", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 45, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg45" + ] + }, + { + "index": 58, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 25, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg35", + "sysfs_bus_id": "25:0:0:0", + "unix_device_name": "/dev/sg35", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 35, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg35" + ] + }, + { + "index": 59, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 17, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg25", + "sysfs_bus_id": "17:0:0:0", + "unix_device_name": "/dev/sg25", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 25, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg25" + ] + }, + { + "index": 60, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 4, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg5", + "sysfs_bus_id": "4:0:0:0", + "unix_device_name": "/dev/sg5", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 5, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg5" + ] + }, + { + "index": 61, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 5, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg15", + "sysfs_bus_id": "5:0:0:0", + "unix_device_name": "/dev/sg15", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 15, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg15" + ] + }, + { + "index": 62, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 22, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg43", + "sysfs_bus_id": "22:0:0:0", + "unix_device_name": "/dev/sg43", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 43, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg43" + ] + }, + { + "index": 63, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 24, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg33", + "sysfs_bus_id": "24:0:0:0", + "unix_device_name": "/dev/sg33", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 33, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg33" + ] + }, + { + "index": 64, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 13, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg23", + "sysfs_bus_id": "13:0:0:0", + "unix_device_name": "/dev/sg23", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 23, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg23" + ] + }, + { + "index": 65, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 18, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg3", + "sysfs_bus_id": "18:0:0:0", + "unix_device_name": "/dev/sg3", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 3, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg3" + ] + }, + { + "index": 66, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 3, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg13", + "sysfs_bus_id": "3:0:0:0", + "unix_device_name": "/dev/sg13", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 13, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg13" + ] + }, + { + "index": 67, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 10, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg41", + "sysfs_bus_id": "10:0:0:0", + "unix_device_name": "/dev/sg41", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 41, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg41" + ] + }, + { + "index": 68, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 23, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg31", + "sysfs_bus_id": "23:0:0:0", + "unix_device_name": "/dev/sg31", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 31, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg31" + ] + }, + { + "index": 69, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 12, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg21", + "sysfs_bus_id": "12:0:0:0", + "unix_device_name": "/dev/sg21", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 21, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg21" + ] + }, + { + "index": 70, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 2, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg1", + "sysfs_bus_id": "2:0:0:0", + "unix_device_name": "/dev/sg1", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 1, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg1" + ] + }, + { + "index": 71, + "attached_to": 0, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 15, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Storage Device", + "value": 128 + }, + "vendor": { + "name": "IET", + "value": 0 + }, + "device": { + "name": "Controller", + "value": 0 + }, + "revision": { + "name": "0001", + "value": 0 + }, + "model": "IET Controller", + "sysfs_id": "/class/scsi_generic/sg11", + "sysfs_bus_id": "15:0:0:0", + "unix_device_name": "/dev/sg11", + "unix_device_number": { + "type": 99, + "major": 21, + "minor": 11, + "range": 1 + }, + "unix_device_names": [ + "/dev/sg11" + ] + } + ], + "usb_controller": [ + { + "index": 21, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 21 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "USB Controller", + "value": 3 + }, + "pci_interface": { + "value": 48 + }, + "vendor": { + "name": "Intel Corporation", + "value": 32902 + }, + "sub_vendor": { + "value": 5208 + }, + "device": { + "value": 12712 + }, + "sub_device": { + "value": 4096 + }, + "revision": { + "value": 3 + }, + "model": "Intel USB Controller", + "sysfs_id": "/devices/pci0000:00/0000:00:15.0", + "sysfs_bus_id": "0000:00:15.0", + "resources": [ + { + "type": "irq", + "base": 125, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 2704277504, + "range": 65536, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1030, + "header_type": 0, + "secondary_bus": 0, + "irq": 125, + "prog_if": 48 + }, + "driver": "xhci_hcd", + "driver_module": "xhci_pci", + "drivers": [ + "xhci_hcd" + ], + "driver_modules": [ + "xhci_pci" + ], + "module_alias": "pci:v00008086d000031A8sv00001458sd00001000bc0Csc03i30", + "label": "Onboard - Other" + } + ] + }, + "smbios": { + "bios": { + "handle": 0, + "vendor": "American Megatrends Inc.", + "version": "F8", + "date": "12/13/2019", + "features": [ + "PCI supported", + "BIOS flashable", + "BIOS shadowing allowed", + "CD boot supported", + "Selectable boot supported", + "BIOS ROM socketed", + "EDD spec supported", + "1.2MB Floppy supported", + "720kB Floppy supported", + "2.88MB Floppy supported", + "Print Screen supported", + "8042 Keyboard Services supported", + "Serial Services supported", + "Printer Services supported", + "ACPI supported", + "USB Legacy supported", + "BIOS Boot Spec supported" + ], + "start_address": "0xf0000", + "rom_size": 6291456 + }, + "board": { + "handle": 2, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "board_type": { + "name": "Motherboard", + "value": 10 + }, + "features": [ + "Hosting Board", + "Replaceable" + ], + "location": "Default string", + "chassis": 3 + }, + "cache": [ + { + "handle": 47, + "socket": "CPU Internal L1", + "size_max": 224, + "size_current": 224, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 0, + "ecc": { + "name": "Parity", + "value": 4 + }, + "cache_type": { + "name": "Other", + "value": 1 + }, + "associativity": { + "name": "Other", + "value": 1 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + }, + { + "handle": 48, + "socket": "CPU Internal L2", + "size_max": 4096, + "size_current": 4096, + "speed": 0, + "mode": { + "name": "Write Back", + "value": 1 + }, + "enabled": true, + "location": { + "name": "Internal", + "value": 0 + }, + "socketed": false, + "level": 1, + "ecc": { + "name": "Single-bit", + "value": 5 + }, + "cache_type": { + "name": "Unified", + "value": 5 + }, + "associativity": { + "name": "16-way Set-Associative", + "value": 8 + }, + "sram_type_current": [ + "Synchronous" + ], + "sram_type_supported": [ + "Synchronous" + ] + } + ], + "chassis": { + "handle": 3, + "manufacturer": "Default string", + "version": "Default string", + "chassis_type": { + "name": "Desktop", + "value": 3 + }, + "lock_present": false, + "bootup_state": { + "name": "Safe", + "value": 3 + }, + "power_state": { + "name": "Safe", + "value": 3 + }, + "thermal_state": { + "name": "Safe", + "value": 3 + }, + "security_state": { + "name": "None", + "value": 3 + }, + "oem": "0x0" + }, + "config": { + "handle": 34, + "options": [ + "Default string" + ] + }, + "language": [ + { + "handle": 63, + "languages": [ + "en|US|iso8859-1" + ] + } + ], + "memory_array": [ + { + "handle": 35, + "location": { + "name": "Motherboard", + "value": 3 + }, + "usage": { + "name": "System memory", + "value": 3 + }, + "ecc": { + "name": "None", + "value": 3 + }, + "max_size": 33554432, + "error_handle": 65534, + "slots": 2 + } + ], + "memory_array_mapped_address": [ + { + "handle": 36, + "array_handle": 35, + "start_address": 0, + "end_address": 25769803776, + "part_width": 2 + } + ], + "memory_device": [ + { + "handle": 37, + "location": "A1_DIMM0", + "bank_location": "A1_BANK0", + "manufacturer": "Crucial", + "part_number": "CT8G4SFS824A.M8FJ", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 8388608, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + }, + { + "handle": 39, + "location": "A1_DIMM1", + "bank_location": "A1_BANK1", + "manufacturer": "Crucial", + "part_number": "CT16G4SFD824A.M16F", + "array_handle": 35, + "error_handle": 65534, + "width": 64, + "ecc_bits": 0, + "size": 16777216, + "form_factor": { + "name": "SODIMM", + "value": 13 + }, + "set": 0, + "memory_type": { + "name": "Other", + "value": 26 + }, + "memory_type_details": [ + "Synchronous" + ], + "speed": 2400 + } + ], + "memory_device_mapped_address": [ + { + "handle": 38, + "memory_device_handle": 37, + "array_map_handle": 36, + "start_address": 0, + "end_address": 8589934592, + "row_position": 255, + "interleave_position": 1, + "interleave_depth": 2 + }, + { + "handle": 40, + "memory_device_handle": 39, + "array_map_handle": 36, + "start_address": 8589934592, + "end_address": 25769803776, + "row_position": 255, + "interleave_position": 2, + "interleave_depth": 2 + } + ], + "onboard": [ + { + "handle": 32, + "devices": [ + { + "name": "To Be Filled By O.E.M.", + "type": { + "name": "Video", + "value": 3 + }, + "enabled": true + } + ] + } + ], + "port_connector": [ + { + "handle": 8, + "port_type": { + "name": "Mouse Port", + "value": 14 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "PS2Mouse" + }, + { + "handle": 9, + "port_type": { + "name": "Keyboard Port", + "value": 13 + }, + "internal_reference_designator": "J1A1", + "external_connector_type": { + "name": "PS/2", + "value": 15 + }, + "external_reference_designator": "Keyboard" + }, + { + "handle": 10, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2A1", + "external_connector_type": { + "name": "Mini-Centronics Type-14", + "value": 29 + }, + "external_reference_designator": "TV Out" + }, + { + "handle": 11, + "port_type": { + "name": "Serial Port 16550A Compatible", + "value": 9 + }, + "internal_reference_designator": "J2A2A", + "external_connector_type": { + "name": "DB-9 pin male", + "value": 8 + }, + "external_reference_designator": "COM A" + }, + { + "handle": 12, + "port_type": { + "name": "Video Port", + "value": 28 + }, + "internal_reference_designator": "J2A2B", + "external_connector_type": { + "name": "DB-15 pin female", + "value": 7 + }, + "external_reference_designator": "Video" + }, + { + "handle": 13, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB1" + }, + { + "handle": 14, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB2" + }, + { + "handle": 15, + "port_type": { + "name": "USB", + "value": 16 + }, + "internal_reference_designator": "J3A1", + "external_connector_type": { + "name": "Access Bus [USB]", + "value": 18 + }, + "external_reference_designator": "USB3" + }, + { + "handle": 16, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9A1 - TPM HDR" + }, + { + "handle": 17, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9C1 - PCIE DOCKING CONN" + }, + { + "handle": 18, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2B3 - CPU FAN" + }, + { + "handle": 19, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6C2 - EXT HDMI" + }, + { + "handle": 20, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J3C1 - GMCH FAN" + }, + { + "handle": 21, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1D1 - ITP" + }, + { + "handle": 22, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E2 - MDC INTPSR" + }, + { + "handle": 23, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E4 - MDC INTPSR" + }, + { + "handle": 24, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E3 - LPC HOT DOCKING" + }, + { + "handle": 25, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9E1 - SCAN MATRIX" + }, + { + "handle": 26, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J9G1 - LPC SIDE BAND" + }, + { + "handle": 27, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J8F1 - UNIFIED" + }, + { + "handle": 28, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J6F1 - LVDS" + }, + { + "handle": 29, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2F1 - LAI FAN" + }, + { + "handle": 30, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J2G1 - GFX VID" + }, + { + "handle": 31, + "port_type": { + "name": "Other", + "value": 255 + }, + "internal_connector_type": { + "name": "Other", + "value": 255 + }, + "internal_reference_designator": "J1G6 - AC JACK" + } + ], + "processor": [ + { + "handle": 49, + "socket": "SOCKET 0", + "socket_type": { + "name": "Other", + "value": 1 + }, + "socket_populated": true, + "manufacturer": "Intel", + "version": "Intel(R) Celeron(R) J4105 CPU @ 1.50GHz", + "part": "Fill By OEM", + "processor_type": { + "name": "CPU", + "value": 3 + }, + "processor_family": { + "name": "Celeron", + "value": 15 + }, + "processor_status": { + "name": "Enabled", + "value": 1 + }, + "clock_ext": 100, + "clock_max": 2700, + "cache_handle_l1": 47, + "cache_handle_l2": 48, + "cache_handle_l3": 0 + } + ], + "slot": [ + { + "handle": 64, + "designation": "J7H1", + "slot_type": { + "name": "Other", + "value": 174 + }, + "bus_width": { + "name": "Other", + "value": 10 + }, + "usage": { + "name": "In Use", + "value": 4 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 0, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + }, + { + "handle": 65, + "designation": "J8H1", + "slot_type": { + "name": "Other", + "value": 173 + }, + "bus_width": { + "name": "Other", + "value": 9 + }, + "usage": { + "name": "Available", + "value": 3 + }, + "length": { + "name": "Short", + "value": 3 + }, + "id": 1, + "features": [ + "3.3 V", + "Shared", + "PME#" + ] + } + ], + "system": { + "handle": 1, + "manufacturer": "GIGABYTE", + "product": "MZGLKAP-00", + "version": "1.x", + "wake_up": { + "name": "Power Switch", + "value": 6 + } + } + } +} \ No newline at end of file diff --git a/machines/warwick.nix b/machines/warwick/default.nix similarity index 87% rename from machines/warwick.nix rename to machines/warwick/default.nix index 15e276d..ac0caaa 100644 --- a/machines/warwick.nix +++ b/machines/warwick/default.nix @@ -2,6 +2,7 @@ machines.warwick = { arch = "aarch64-linux"; isRaspberryPi = true; + facterReportPath = ./facter.json; nixosModule.lab = { storage.profile = "pi"; diff --git a/machines/warwick/facter.json b/machines/warwick/facter.json new file mode 100644 index 0000000..1415f3d --- /dev/null +++ b/machines/warwick/facter.json @@ -0,0 +1,1372 @@ +{ + "version": 1, + "system": "aarch64-linux", + "virtualisation": "none", + "hardware": { + "bridge": [ + { + "index": 8, + "attached_to": 0, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Bridge", + "value": 6 + }, + "sub_class": { + "name": "PCI bridge", + "value": 4 + }, + "pci_interface": { + "name": "Normal decode", + "value": 0 + }, + "vendor": { + "name": "Broadcom", + "value": 5348 + }, + "device": { + "value": 10001 + }, + "revision": { + "value": 32 + }, + "model": "Broadcom PCI bridge", + "sysfs_id": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0", + "sysfs_bus_id": "0000:00:00.0", + "resources": [ + { + "type": "irq", + "base": 30, + "triggered": 0, + "enabled": true + } + ], + "detail": { + "function": 0, + "command": 6, + "header_type": 1, + "secondary_bus": 1, + "irq": 30, + "prog_if": 0 + }, + "driver": "pcieport", + "drivers": [ + "pcieport" + ], + "module_alias": "pci:v000014E4d00002711sv00000000sd00000000bc06sc04i00" + } + ], + "cpu": [ + { + "architecture": "aarch64", + "vendor_name": "ARM Limited", + "family": 0, + "model": 3, + "stepping": 0, + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "bogo": 108, + "physical_id": 0, + "fpu": false, + "fpu_exception": false, + "write_protect": false, + "address_sizes": {} + } + ], + "disk": [ + { + "index": 14, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram2", + "unix_device_name": "/dev/ram2", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 2, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram2" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 15, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram0", + "unix_device_name": "/dev/ram0", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 0, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram0" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 16, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram9", + "unix_device_name": "/dev/ram9", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 9, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram9" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 17, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram14", + "unix_device_name": "/dev/ram14", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 14, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram14" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 18, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram7", + "unix_device_name": "/dev/ram7", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 7, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram7" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 19, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram12", + "unix_device_name": "/dev/ram12", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 12, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram12" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 20, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram5", + "unix_device_name": "/dev/ram5", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 5, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram5" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 21, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram10", + "unix_device_name": "/dev/ram10", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 10, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram10" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 22, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram3", + "unix_device_name": "/dev/ram3", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 3, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram3" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 23, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram1", + "unix_device_name": "/dev/ram1", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 1, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram1" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 24, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram15", + "unix_device_name": "/dev/ram15", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 15, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram15" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 25, + "attached_to": 7, + "bus_type": { + "name": "SCSI", + "value": 132 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "vendor": { + "name": "Samsung", + "value": 2316 + }, + "device": { + "name": "Flash Drive", + "value": 4096 + }, + "revision": { + "name": "1100", + "value": 0 + }, + "serial": "AA00000000000489", + "model": "Samsung Flash Drive", + "sysfs_id": "/class/block/sda", + "sysfs_bus_id": "0:0:0:0", + "sysfs_device_link": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb2/2-1/2-1:1.0/host0/target0:0:0/0:0:0:0", + "unix_device_name": "/dev/sda", + "unix_device_number": { + "type": 98, + "major": 8, + "minor": 0, + "range": 16 + }, + "unix_device_names": [ + "/dev/disk/by-diskseq/25", + "/dev/disk/by-id/usb-Samsung_Flash_Drive_0374021110005452-0:0", + "/dev/disk/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1:1.0-scsi-0:0:0:0", + "/dev/disk/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usbv3-0:1:1.0-scsi-0:0:0:0", + "/dev/sda" + ], + "unix_device_name2": "/dev/sg0", + "unix_device_number2": { + "type": 99, + "major": 21, + "minor": 0, + "range": 1 + }, + "resources": [ + { + "type": "disk_geo", + "cylinders": 61188, + "heads": 64, + "sectors": 32, + "size": 0, + "geo_type": "logical" + }, + { + "type": "size", + "unit": "sectors", + "value_1": 125313283, + "value_2": 512 + } + ], + "driver": "usb-storage", + "driver_module": "usb_storage", + "drivers": [ + "sd", + "usb-storage" + ], + "driver_modules": [ + "usb_storage" + ], + "module_alias": "usb:v090Cp1000d1100dc00dsc00dp00ic08isc06ip50in00" + }, + { + "index": 26, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram8", + "unix_device_name": "/dev/ram8", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 8, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram8" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 27, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram13", + "unix_device_name": "/dev/ram13", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 13, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram13" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 28, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram6", + "unix_device_name": "/dev/ram6", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 6, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram6" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 29, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram11", + "unix_device_name": "/dev/ram11", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 11, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram11" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + }, + { + "index": 30, + "attached_to": 0, + "base_class": { + "name": "Mass Storage Device", + "value": 262 + }, + "sub_class": { + "name": "Disk", + "value": 0 + }, + "model": "Disk", + "sysfs_id": "/class/block/ram4", + "unix_device_name": "/dev/ram4", + "unix_device_number": { + "type": 98, + "major": 1, + "minor": 4, + "range": 1 + }, + "unix_device_names": [ + "/dev/ram4" + ], + "resources": [ + { + "type": "size", + "unit": "sectors", + "value_1": 8192, + "value_2": 512 + } + ] + } + ], + "hub": [ + { + "index": 32, + "attached_to": 7, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.1.63 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 2 + }, + "revision": { + "name": "6.01", + "value": 0 + }, + "serial": "0000:01:00.0", + "model": "Linux 6.1.63 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-0:1.0", + "sysfs_bus_id": "1-0:1.0", + "resources": [ + { + "type": "baud", + "speed": 480000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 1, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "driver_module": "usbcore", + "drivers": [ + "hub" + ], + "driver_modules": [ + "usbcore" + ], + "module_alias": "usb:v1D6Bp0002d0601dc09dsc00dp01ic09isc00ip00in00" + }, + { + "index": 33, + "attached_to": 32, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "value": 8457 + }, + "device": { + "name": "USB2.0 Hub", + "value": 13361 + }, + "revision": { + "name": "4.21", + "value": 0 + }, + "model": "USB2.0 Hub", + "sysfs_id": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1:1.0", + "sysfs_bus_id": "1-1:1.0", + "resources": [ + { + "type": "baud", + "speed": 480000000, + "bits": 0, + "stop_bits": 0, + "parity": 0, + "handshake": 0 + } + ], + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 1, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "driver_module": "usbcore", + "drivers": [ + "hub" + ], + "driver_modules": [ + "usbcore" + ], + "module_alias": "usb:v2109p3431d0421dc09dsc00dp01ic09isc00ip00in00" + }, + { + "index": 34, + "attached_to": 7, + "bus_type": { + "name": "USB", + "value": 134 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Hub", + "value": 266 + }, + "vendor": { + "name": "Linux 6.1.63 xhci-hcd", + "value": 7531 + }, + "device": { + "name": "xHCI Host Controller", + "value": 3 + }, + "revision": { + "name": "6.01", + "value": 0 + }, + "serial": "0000:01:00.0", + "model": "Linux 6.1.63 xhci-hcd xHCI Host Controller", + "sysfs_id": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb2/2-0:1.0", + "sysfs_bus_id": "2-0:1.0", + "detail": { + "device_class": { + "name": "hub", + "value": 9 + }, + "device_subclass": { + "name": "per_interface", + "value": 0 + }, + "device_protocol": 3, + "interface_class": { + "name": "hub", + "value": 9 + }, + "interface_subclass": { + "name": "per_interface", + "value": 0 + }, + "interface_protocol": 0, + "interface_number": 0, + "interface_alternate_setting": 0 + }, + "hotplug": "usb", + "driver": "hub", + "driver_module": "usbcore", + "drivers": [ + "hub" + ], + "driver_modules": [ + "usbcore" + ], + "module_alias": "usb:v1D6Bp0003d0601dc09dsc00dp03ic09isc00ip00in00" + } + ], + "memory": [ + { + "index": 6, + "attached_to": 0, + "base_class": { + "name": "Internally Used Class", + "value": 257 + }, + "sub_class": { + "name": "Main Memory", + "value": 2 + }, + "model": "Main Memory", + "resources": [ + { + "type": "mem", + "base": 0, + "range": 3964207104, + "enabled": true, + "access": "read_write", + "prefetch": "unknown" + }, + { + "type": "phys_mem", + "range": 4026531840 + } + ] + } + ], + "mmc_controller": [ + { + "index": 10, + "attached_to": 0, + "bus_type": { + "name": "MMC", + "value": 147 + }, + "slot": { + "bus": 0, + "number": 1 + }, + "base_class": { + "name": "MMC Controller", + "value": 279 + }, + "vendor": "", + "device": "SDIO Controller 1", + "model": "SDIO Controller 1", + "sysfs_id": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001", + "sysfs_bus_id": "mmc1:0001" + } + ], + "network_controller": [ + { + "index": 9, + "attached_to": 0, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "WLAN controller", + "value": 130 + }, + "vendor": { + "name": "Bogus Corp.", + "value": 1337 + }, + "device": { + "name": "ARM Ethernet controller", + "value": 0 + }, + "model": "ARM Ethernet controller", + "sysfs_id": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:1", + "sysfs_bus_id": "mmc1:0001:1", + "unix_device_name": "wlan0", + "unix_device_names": [ + "wlan0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "phwaddr", + "address": 100 + }, + { + "type": "wlan", + "channels": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "34", + "36", + "38", + "40", + "42", + "44", + "46", + "48", + "52", + "56", + "60", + "64", + "100", + "104", + "108", + "112", + "116", + "120" + ], + "frequencies": [ + "2.412", + "2.417", + "2.422", + "2.427", + "2.432", + "2.437", + "2.442", + "2.447", + "2.452", + "2.457", + "2.462", + "2.467", + "2.472", + "2.484", + "5.17", + "5.18", + "5.19", + "5.2", + "5.21", + "5.22", + "5.23", + "5.24", + "5.26", + "5.28", + "5.3", + "5.32", + "5.5", + "5.52", + "5.54", + "5.56", + "5.58", + "5.6" + ], + "auth_modes": [ + "open", + "sharedkey", + "wpa-psk", + "wpa-eap" + ], + "enc_modes": [ + "WEP40", + "WEP104", + "TKIP", + "CCMP" + ] + } + ], + "driver": "brcmfmac", + "driver_module": "brcmfmac", + "drivers": [ + "brcmfmac" + ], + "driver_modules": [ + "brcmfmac", + "brcmfmac", + "brcmfmac" + ], + "module_alias": "of:NmmcnrT(null)Cbrcm,bcm2835-mmcCbrcm,bcm2835-sdhci" + }, + { + "index": 12, + "attached_to": 10, + "bus_type": { + "name": "SDIO", + "value": 148 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Network controller", + "value": 2 + }, + "sub_class": { + "name": "Network controller", + "value": 128 + }, + "vendor": { + "name": "Broadcom Corp.", + "value": 720 + }, + "device": { + "name": "BCM43430 WLAN card", + "value": 43430 + }, + "model": "Broadcom BCM43430 WLAN card", + "sysfs_id": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:1", + "sysfs_bus_id": "mmc1:0001:1", + "driver": "brcmfmac", + "driver_module": "brcmfmac", + "drivers": [ + "brcmfmac" + ], + "driver_modules": [ + "brcmfmac", + "brcmfmac", + "brcmfmac" + ], + "module_alias": "sdio:c00v02D0dA9A6" + } + ], + "network_interface": [ + { + "index": 36, + "attached_to": 0, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Ethernet", + "value": 1 + }, + "model": "Ethernet network interface", + "sysfs_id": "/class/net/end0", + "sysfs_device_link": "/devices/platform/scb/fd580000.ethernet", + "unix_device_name": "end0", + "unix_device_names": [ + "end0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "driver": "bcmgenet", + "drivers": [ + "bcmgenet" + ] + }, + { + "index": 37, + "attached_to": 0, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "Loopback", + "value": 0 + }, + "model": "Loopback network interface", + "sysfs_id": "/class/net/lo", + "unix_device_name": "lo", + "unix_device_names": [ + "lo" + ] + }, + { + "index": 38, + "attached_to": 9, + "base_class": { + "name": "Network Interface", + "value": 263 + }, + "sub_class": { + "name": "WLAN", + "value": 10 + }, + "model": "WLAN network interface", + "sysfs_id": "/class/net/wlan0", + "sysfs_device_link": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:1", + "unix_device_name": "wlan0", + "unix_device_names": [ + "wlan0" + ], + "resources": [ + { + "type": "hwaddr", + "address": 100 + }, + { + "type": "phwaddr", + "address": 100 + } + ], + "driver": "brcmfmac", + "driver_module": "brcmfmac", + "drivers": [ + "brcmfmac" + ], + "driver_modules": [ + "brcmfmac", + "brcmfmac", + "brcmfmac" + ] + } + ], + "system": {}, + "unknown": [ + { + "index": 11, + "attached_to": 10, + "bus_type": { + "name": "SDIO", + "value": 148 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Unclassified device", + "value": 0 + }, + "sub_class": { + "name": "Unclassified device", + "value": 0 + }, + "vendor": { + "name": "Broadcom Corp.", + "value": 720 + }, + "device": { + "name": "BCM43430 WLAN card", + "value": 43430 + }, + "model": "Broadcom BCM43430 WLAN card", + "sysfs_id": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:3", + "sysfs_bus_id": "mmc1:0001:3", + "module_alias": "sdio:c02v02D0dA9A6" + }, + { + "index": 13, + "attached_to": 10, + "bus_type": { + "name": "SDIO", + "value": 148 + }, + "slot": { + "bus": 0, + "number": 0 + }, + "base_class": { + "name": "Unclassified device", + "value": 0 + }, + "sub_class": { + "name": "Unclassified device", + "value": 0 + }, + "vendor": { + "name": "Broadcom Corp.", + "value": 720 + }, + "device": { + "name": "BCM43430 WLAN card", + "value": 43430 + }, + "model": "Broadcom BCM43430 WLAN card", + "sysfs_id": "/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:2", + "sysfs_bus_id": "mmc1:0001:2", + "driver": "brcmfmac", + "driver_module": "brcmfmac", + "drivers": [ + "brcmfmac" + ], + "driver_modules": [ + "brcmfmac", + "brcmfmac", + "brcmfmac" + ], + "module_alias": "sdio:c00v02D0dA9A6" + } + ], + "usb_controller": [ + { + "index": 7, + "attached_to": 8, + "bus_type": { + "name": "PCI", + "value": 4 + }, + "slot": { + "bus": 1, + "number": 0 + }, + "base_class": { + "name": "Serial bus controller", + "value": 12 + }, + "sub_class": { + "name": "USB Controller", + "value": 3 + }, + "pci_interface": { + "value": 48 + }, + "vendor": { + "value": 4358 + }, + "sub_vendor": { + "value": 4358 + }, + "device": { + "value": 13443 + }, + "sub_device": { + "value": 13443 + }, + "revision": { + "value": 1 + }, + "model": "USB Controller", + "sysfs_id": "/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0", + "sysfs_bus_id": "0000:01:00.0", + "resources": [ + { + "type": "irq", + "base": 37, + "triggered": 0, + "enabled": true + }, + { + "type": "mem", + "base": 25769803776, + "range": 4096, + "enabled": true, + "access": "read_write", + "prefetch": "no" + } + ], + "detail": { + "function": 0, + "command": 1350, + "header_type": 0, + "secondary_bus": 0, + "irq": 37, + "prog_if": 48 + }, + "driver": "xhci_hcd", + "driver_module": "xhci_pci", + "drivers": [ + "xhci_hcd" + ], + "driver_modules": [ + "xhci_pci" + ], + "module_alias": "pci:v00001106d00003483sv00001106sd00003483bc0Csc03i30" + } + ] + }, + "smbios": {} +} diff --git a/modules/default.nix b/modules/default.nix index 8749267..2448041 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -20,6 +20,7 @@ inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops inputs.nix-snapshotter.nixosModules.nix-snapshotter + inputs.nixos-facter-modules.nixosModules.facter ] ++ lib.lists.optional (machine.isRaspberryPi) inputs.nixos-hardware.nixosModules.raspberry-pi-4; @@ -162,5 +163,7 @@ age.keyFile = "/root/.config/sops/age/keys.txt"; defaultSopsFile = "${self}/secrets/nixos.yaml"; }; + + facter.reportPath = machine.facterReportPath; }; } From 7a8a7f88dda2a23f724162bd25326df51e5870f9 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 2 Nov 2024 23:58:22 +0100 Subject: [PATCH 097/108] Add formatter for JSON documents --- machines/atlas/facter.json | 2 +- machines/jefke/facter.json | 2 +- machines/lewis/facter.json | 2 +- treefmt.nix | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/machines/atlas/facter.json b/machines/atlas/facter.json index 28cf32c..200d9bd 100644 --- a/machines/atlas/facter.json +++ b/machines/atlas/facter.json @@ -3755,4 +3755,4 @@ } } } -} \ No newline at end of file +} diff --git a/machines/jefke/facter.json b/machines/jefke/facter.json index d08cfd4..c38ac98 100644 --- a/machines/jefke/facter.json +++ b/machines/jefke/facter.json @@ -3590,4 +3590,4 @@ } } } -} \ No newline at end of file +} diff --git a/machines/lewis/facter.json b/machines/lewis/facter.json index ef4139b..3c634c5 100644 --- a/machines/lewis/facter.json +++ b/machines/lewis/facter.json @@ -5504,4 +5504,4 @@ } } } -} \ No newline at end of file +} diff --git a/treefmt.nix b/treefmt.nix index e6da195..0a59d44 100644 --- a/treefmt.nix +++ b/treefmt.nix @@ -1,4 +1,5 @@ {...}: { projectRootFile = "flake.nix"; programs.alejandra.enable = true; + programs.jsonfmt.enable = true; } From 806e6c1d03e564e4c5c7c874db431929b96d61cd Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 21:08:57 +0100 Subject: [PATCH 098/108] update nixos-facter-modules --- flake.lock | 6 +++--- machines/warwick/facter.json | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 9796810..cba988c 100644 --- a/flake.lock +++ b/flake.lock @@ -291,11 +291,11 @@ }, "nixos-facter-modules": { "locked": { - "lastModified": 1730026316, - "narHash": "sha256-AzP+trH/ykBJGTx3twkpuwbkhFSmsY1PJDQtRmK4k4c=", + "lastModified": 1730737399, + "narHash": "sha256-PzJrTMhHb9f46uMxmRD4GjnyVuNqxeyEvxaq7OierUQ=", "owner": "numtide", "repo": "nixos-facter-modules", - "rev": "15b6531d44aa6f0bbd2fd8309cd2a6d7f183ba32", + "rev": "c22b916f629fee6941a2976c62247b0bec68082b", "type": "github" }, "original": { diff --git a/machines/warwick/facter.json b/machines/warwick/facter.json index 1415f3d..b30a26a 100644 --- a/machines/warwick/facter.json +++ b/machines/warwick/facter.json @@ -959,10 +959,6 @@ "name": "WLAN controller", "value": 130 }, - "vendor": { - "name": "Bogus Corp.", - "value": 1337 - }, "device": { "name": "ARM Ethernet controller", "value": 0 From 4d7e81fd63e2275fed1eace87a809792a955c585 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 21:34:04 +0100 Subject: [PATCH 099/108] Remove options already populated by nixos-facter Remove pikvm machine --- machines/pikvm.nix | 28 ---------------------------- modules/default.nix | 20 -------------------- nixos.nix | 2 -- 3 files changed, 50 deletions(-) delete mode 100644 machines/pikvm.nix diff --git a/machines/pikvm.nix b/machines/pikvm.nix deleted file mode 100644 index d384897..0000000 --- a/machines/pikvm.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - machines.pikvm = { - arch = "aarch64-linux"; - isRaspberryPi = true; - - nixosModule = { - config, - inputs, - lib, - ... - }: { - # imports = [ "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" ]; - lab = { - storage.profile = "pi"; - }; - - environment.systemPackages = with inputs.nixpkgs.legacyPackages.aarch64-linux; [ - (mplayer.override { - v4lSupport = true; - }) - ffmpeg - v4l-utils - ]; - - boot.extraModulePackages = with config.boot.kernelPackages; [v4l2loopback]; - }; - }; -} diff --git a/modules/default.nix b/modules/default.nix index 2448041..a595904 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -26,8 +26,6 @@ config = { time.timeZone = "Europe/Amsterdam"; - hardware.cpu.intel.updateMicrocode = lib.mkIf (! machine.isRaspberryPi) config.hardware.enableRedistributableFirmware; - nixpkgs = { config.allowUnfree = true; overlays = [ @@ -110,24 +108,6 @@ ]; boot = lib.mkIf (! machine.isRaspberryPi) { - kernelModules = ["kvm-intel"]; - extraModulePackages = []; - kernel.sysctl."fs.inotify.max_user_instances" = 256; - - initrd = { - kernelModules = []; - - availableKernelModules = [ - "ahci" - "xhci_pci" - "nvme" - "usbhid" - "usb_storage" - "sd_mod" - "sdhci_pci" - ]; - }; - loader = { systemd-boot.enable = lib.mkDefault true; efi.canTouchEfiVariables = true; diff --git a/nixos.nix b/nixos.nix index 4d2d0ad..34f3fb8 100644 --- a/nixos.nix +++ b/nixos.nix @@ -14,8 +14,6 @@ machines; in { nixosConfigurations = mkNixosSystems (name: machine: { - system = machine.arch; - specialArgs = {inherit self inputs machine machines;}; modules = [ From 2a63bee83b70e8d963fff451a02323772c736cf5 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 22:27:24 +0100 Subject: [PATCH 100/108] Implement raspberry pi check using nixos-facter --- machines/default.nix | 5 ----- machines/warwick/default.nix | 19 ++++++++++++------- modules/default.nix | 34 ++++++++++++++++------------------ modules/facter.nix | 15 +++++++++++++++ modules/networking/default.nix | 5 +++-- 5 files changed, 46 insertions(+), 32 deletions(-) create mode 100644 modules/facter.nix diff --git a/machines/default.nix b/machines/default.nix index 9a0c0c8..c32a0b4 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -25,11 +25,6 @@ flake-utils.lib.eachDefaultSystem (system: let ''; }; - isRaspberryPi = lib.mkOption { - default = false; - type = lib.types.bool; - }; - nixosModule = lib.mkOption { default = {...}: {}; type = lib.types.anything; diff --git a/machines/warwick/default.nix b/machines/warwick/default.nix index ac0caaa..0035e27 100644 --- a/machines/warwick/default.nix +++ b/machines/warwick/default.nix @@ -1,16 +1,21 @@ { machines.warwick = { arch = "aarch64-linux"; - isRaspberryPi = true; facterReportPath = ./facter.json; - nixosModule.lab = { - storage.profile = "pi"; - monitoring.server.enable = true; + nixosModule = {inputs, ...}: { + imports = [inputs.nixos-hardware.nixosModules.raspberry-pi-4]; - tailscale = { - advertiseExitNode = true; - enable = true; + config = { + lab = { + storage.profile = "pi"; + monitoring.server.enable = true; + + tailscale = { + advertiseExitNode = true; + enable = true; + }; + }; }; }; }; diff --git a/modules/default.nix b/modules/default.nix index a595904..99e0605 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,28 +1,26 @@ { self, pkgs, - config, lib, inputs, machine, + config, ... }: { - imports = - [ - ./storage.nix - ./backups.nix - ./networking - ./data-sharing.nix - ./monitoring - ./k3s - ./tailscale.nix - machine.nixosModule - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - inputs.nix-snapshotter.nixosModules.nix-snapshotter - inputs.nixos-facter-modules.nixosModules.facter - ] - ++ lib.lists.optional (machine.isRaspberryPi) inputs.nixos-hardware.nixosModules.raspberry-pi-4; + imports = [ + ./storage.nix + ./backups.nix + ./networking + ./data-sharing.nix + ./monitoring + ./k3s + ./tailscale.nix + ./facter.nix + machine.nixosModule + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + inputs.nix-snapshotter.nixosModules.nix-snapshotter + ]; config = { time.timeZone = "Europe/Amsterdam"; @@ -107,7 +105,7 @@ fastfetch ]; - boot = lib.mkIf (! machine.isRaspberryPi) { + boot = lib.mkIf (! config.facter.lab.isRaspberryPi) { loader = { systemd-boot.enable = lib.mkDefault true; efi.canTouchEfiVariables = true; diff --git a/modules/facter.nix b/modules/facter.nix new file mode 100644 index 0000000..2ee214d --- /dev/null +++ b/modules/facter.nix @@ -0,0 +1,15 @@ +{ + inputs, + lib, + config, + ... +}: { + imports = [inputs.nixos-facter-modules.nixosModules.facter]; + + options.facter.lab = { + isRaspberryPi = lib.mkOption { + type = lib.types.bool; + default = config.facter.report.system == "aarch64-linux"; + }; + }; +} diff --git a/modules/networking/default.nix b/modules/networking/default.nix index 0f235cc..ef68c4e 100644 --- a/modules/networking/default.nix +++ b/modules/networking/default.nix @@ -1,5 +1,6 @@ { lib, + config, machine, ... }: { @@ -16,7 +17,7 @@ enable = true; networks = lib.attrsets.mergeAttrsList [ - (lib.optionalAttrs (! machine.isRaspberryPi) { + (lib.optionalAttrs (! config.facter.lab.isRaspberryPi) { "30-main-nic" = { matchConfig.Name = "en*"; @@ -25,7 +26,7 @@ }; }; }) - (lib.optionalAttrs machine.isRaspberryPi { + (lib.optionalAttrs config.facter.lab.isRaspberryPi { "30-main-nic" = { matchConfig.Name = "end*"; networkConfig = { From 6b804382434ffbac16314f6fde0e837d91418368 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 22:44:26 +0100 Subject: [PATCH 101/108] Use system architecture reported by nixos-facter --- deploy.nix | 5 +++-- machines/atlas/default.nix | 1 - machines/default.nix | 8 -------- machines/jefke/default.nix | 1 - machines/lewis/default.nix | 1 - machines/talos.nix | 2 -- machines/warwick/default.nix | 1 - modules/default.nix | 2 +- modules/k3s/default.nix | 1 - 9 files changed, 4 insertions(+), 18 deletions(-) diff --git a/deploy.nix b/deploy.nix index e8886c7..dcfa2a2 100644 --- a/deploy.nix +++ b/deploy.nix @@ -15,11 +15,12 @@ in { nodes = mkDeployNodes (name: machine: let nixosConfiguration = self.nixosConfigurations.${name}; + machineArch = nixosConfiguration.config.facter.report.system; in { hostname = nixosConfiguration.config.networking.fqdn; profiles.system = { - remoteBuild = machine.arch != deployArch; - path = deploy-rs.lib.${machine.arch}.activate.nixos nixosConfiguration; + remoteBuild = machineArch != deployArch; + path = deploy-rs.lib.${machineArch}.activate.nixos nixosConfiguration; }; }); }; diff --git a/machines/atlas/default.nix b/machines/atlas/default.nix index a0845e0..aae82bc 100644 --- a/machines/atlas/default.nix +++ b/machines/atlas/default.nix @@ -1,6 +1,5 @@ { machines.atlas = { - arch = "x86_64-linux"; kubernetesNodeLabels.storageType = "slow"; facterReportPath = ./facter.json; diff --git a/machines/default.nix b/machines/default.nix index c32a0b4..5aab827 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -9,14 +9,6 @@ flake-utils.lib.eachDefaultSystem (system: let machineOpts = {config, ...}: { options = { - arch = lib.mkOption { - default = null; - type = with lib.types; nullOr str; - description = '' - CPU architecture of this machine. - ''; - }; - facterReportPath = lib.mkOption { default = null; type = with lib.types; nullOr path; diff --git a/machines/jefke/default.nix b/machines/jefke/default.nix index f423c08..ffab64b 100644 --- a/machines/jefke/default.nix +++ b/machines/jefke/default.nix @@ -1,6 +1,5 @@ { machines.jefke = { - arch = "x86_64-linux"; kubernetesNodeLabels.storageType = "fast"; facterReportPath = ./facter.json; diff --git a/machines/lewis/default.nix b/machines/lewis/default.nix index 5b6f580..2dcf470 100644 --- a/machines/lewis/default.nix +++ b/machines/lewis/default.nix @@ -1,6 +1,5 @@ { machines.lewis = { - arch = "x86_64-linux"; kubernetesNodeLabels = { storageType = "fast"; hasMedia = "true"; diff --git a/machines/talos.nix b/machines/talos.nix index 56ada95..cbcc0b1 100644 --- a/machines/talos.nix +++ b/machines/talos.nix @@ -1,7 +1,5 @@ { machines.talos = { - arch = "x86_64-linux"; - nixosModule = {lib, ...}: { lab.storage.profile = "normal"; diff --git a/machines/warwick/default.nix b/machines/warwick/default.nix index 0035e27..a9e740b 100644 --- a/machines/warwick/default.nix +++ b/machines/warwick/default.nix @@ -1,6 +1,5 @@ { machines.warwick = { - arch = "aarch64-linux"; facterReportPath = ./facter.json; nixosModule = {inputs, ...}: { diff --git a/modules/default.nix b/modules/default.nix index 99e0605..ef7de1c 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -29,7 +29,7 @@ overlays = [ (final: _prev: { unstable = import inputs.nixpkgs-unstable { - system = machine.arch; + system = config.nixpkgs.hostPlatform.system; }; }) ]; diff --git a/modules/k3s/default.nix b/modules/k3s/default.nix index 9b00024..e193271 100644 --- a/modules/k3s/default.nix +++ b/modules/k3s/default.nix @@ -1,5 +1,4 @@ { - self, inputs, pkgs, lib, From ed550eafb115c78def25f2c88b54ce3f70daa6a6 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 22:56:26 +0100 Subject: [PATCH 102/108] Improve setting facter report path --- machines/atlas/default.nix | 17 ++++++++++------- machines/default.nix | 8 -------- machines/jefke/default.nix | 17 ++++++++++------- machines/lewis/default.nix | 21 ++++++++++++--------- machines/warwick/default.nix | 4 ++-- modules/default.nix | 2 -- 6 files changed, 34 insertions(+), 35 deletions(-) diff --git a/machines/atlas/default.nix b/machines/atlas/default.nix index aae82bc..c2d4f98 100644 --- a/machines/atlas/default.nix +++ b/machines/atlas/default.nix @@ -1,15 +1,18 @@ { machines.atlas = { kubernetesNodeLabels.storageType = "slow"; - facterReportPath = ./facter.json; - nixosModule.lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; + nixosModule = { + facter.reportPath = ./facter.json; - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; + lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; + + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; + }; }; }; }; diff --git a/machines/default.nix b/machines/default.nix index 5aab827..fdbae99 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -9,14 +9,6 @@ flake-utils.lib.eachDefaultSystem (system: let machineOpts = {config, ...}: { options = { - facterReportPath = lib.mkOption { - default = null; - type = with lib.types; nullOr path; - description = '' - Path to the nixos-facter report JSON for this machine. - ''; - }; - nixosModule = lib.mkOption { default = {...}: {}; type = lib.types.anything; diff --git a/machines/jefke/default.nix b/machines/jefke/default.nix index ffab64b..742e9b1 100644 --- a/machines/jefke/default.nix +++ b/machines/jefke/default.nix @@ -1,15 +1,18 @@ { machines.jefke = { kubernetesNodeLabels.storageType = "fast"; - facterReportPath = ./facter.json; - nixosModule.lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; + nixosModule = { + facter.reportPath = ./facter.json; - k3s = { - enable = true; - clusterInit = true; + lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; + + k3s = { + enable = true; + clusterInit = true; + }; }; }; }; diff --git a/machines/lewis/default.nix b/machines/lewis/default.nix index 2dcf470..790041f 100644 --- a/machines/lewis/default.nix +++ b/machines/lewis/default.nix @@ -4,17 +4,20 @@ storageType = "fast"; hasMedia = "true"; }; - facterReportPath = ./facter.json; - nixosModule.lab = { - storage.profile = "kubernetes"; - backups.enable = true; - data-sharing.enable = true; - tailscale.enable = true; + nixosModule = { + facter.reportPath = ./facter.json; - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; + lab = { + storage.profile = "kubernetes"; + backups.enable = true; + data-sharing.enable = true; + tailscale.enable = true; + + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; + }; }; }; }; diff --git a/machines/warwick/default.nix b/machines/warwick/default.nix index a9e740b..81bd94f 100644 --- a/machines/warwick/default.nix +++ b/machines/warwick/default.nix @@ -1,11 +1,11 @@ { machines.warwick = { - facterReportPath = ./facter.json; - nixosModule = {inputs, ...}: { imports = [inputs.nixos-hardware.nixosModules.raspberry-pi-4]; config = { + facter.reportPath = ./facter.json; + lab = { storage.profile = "pi"; monitoring.server.enable = true; diff --git a/modules/default.nix b/modules/default.nix index ef7de1c..fe31225 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -141,7 +141,5 @@ age.keyFile = "/root/.config/sops/age/keys.txt"; defaultSopsFile = "${self}/secrets/nixos.yaml"; }; - - facter.reportPath = machine.facterReportPath; }; } From fd423b8237384c1718180fd1b177a625ddde0ca3 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 23:17:39 +0100 Subject: [PATCH 103/108] Move kubernetes node labels to k8s repo --- machines/atlas/default.nix | 2 -- machines/default.nix | 8 -------- machines/jefke/default.nix | 2 -- machines/lewis/default.nix | 5 ----- 4 files changed, 17 deletions(-) diff --git a/machines/atlas/default.nix b/machines/atlas/default.nix index c2d4f98..bea4f2c 100644 --- a/machines/atlas/default.nix +++ b/machines/atlas/default.nix @@ -1,7 +1,5 @@ { machines.atlas = { - kubernetesNodeLabels.storageType = "slow"; - nixosModule = { facter.reportPath = ./facter.json; diff --git a/machines/default.nix b/machines/default.nix index fdbae99..59d4f2e 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -16,14 +16,6 @@ flake-utils.lib.eachDefaultSystem (system: let Customized configuration for this machine in the form of a NixOS module. ''; }; - - kubernetesNodeLabels = lib.mkOption { - default = null; - type = with lib.types; nullOr attrs; - description = '' - Any labels to add to the Kubernetes node. - ''; - }; }; }; diff --git a/machines/jefke/default.nix b/machines/jefke/default.nix index 742e9b1..3502ab1 100644 --- a/machines/jefke/default.nix +++ b/machines/jefke/default.nix @@ -1,7 +1,5 @@ { machines.jefke = { - kubernetesNodeLabels.storageType = "fast"; - nixosModule = { facter.reportPath = ./facter.json; diff --git a/machines/lewis/default.nix b/machines/lewis/default.nix index 790041f..47aef36 100644 --- a/machines/lewis/default.nix +++ b/machines/lewis/default.nix @@ -1,10 +1,5 @@ { machines.lewis = { - kubernetesNodeLabels = { - storageType = "fast"; - hasMedia = "true"; - }; - nixosModule = { facter.reportPath = ./facter.json; From 1e80b3603777ce600ef8374d12d823c909e92408 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Mon, 4 Nov 2024 23:35:04 +0100 Subject: [PATCH 104/108] Refactor machine logic --- deploy.nix | 6 ++--- machines/atlas/default.nix | 18 +++++-------- machines/default.nix | 49 +++++----------------------------- machines/jefke/default.nix | 18 +++++-------- machines/lewis/default.nix | 22 +++++++-------- machines/talos.nix | 9 ------- machines/warwick/default.nix | 24 +++++++---------- modules/default.nix | 2 -- modules/monitoring/default.nix | 2 +- modules/networking/default.nix | 1 - nixos.nix | 16 ++++++----- 11 files changed, 53 insertions(+), 114 deletions(-) delete mode 100644 machines/talos.nix diff --git a/deploy.nix b/deploy.nix index dcfa2a2..7547945 100644 --- a/deploy.nix +++ b/deploy.nix @@ -6,14 +6,14 @@ deployArch = "x86_64-linux"; mkDeployNodes = nodeDef: builtins.mapAttrs - (name: machine: nodeDef name machine) - self.machines.${deployArch}; + (name: module: nodeDef name module) + self.machines; in { deploy = { sshUser = "root"; user = "root"; - nodes = mkDeployNodes (name: machine: let + nodes = mkDeployNodes (name: _module: let nixosConfiguration = self.nixosConfigurations.${name}; machineArch = nixosConfiguration.config.facter.report.system; in { diff --git a/machines/atlas/default.nix b/machines/atlas/default.nix index bea4f2c..8f55a09 100644 --- a/machines/atlas/default.nix +++ b/machines/atlas/default.nix @@ -1,17 +1,13 @@ { - machines.atlas = { - nixosModule = { - facter.reportPath = ./facter.json; + facter.reportPath = ./facter.json; - lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; + lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; - }; - }; + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; }; }; } diff --git a/machines/default.nix b/machines/default.nix index 59d4f2e..74151fb 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -1,43 +1,8 @@ -{ - nixpkgs, - flake-utils, - ... -}: -flake-utils.lib.eachDefaultSystem (system: let - pkgs = nixpkgs.legacyPackages.${system}; - lib = pkgs.lib; - - machineOpts = {config, ...}: { - options = { - nixosModule = lib.mkOption { - default = {...}: {}; - type = lib.types.anything; - description = '' - Customized configuration for this machine in the form of a NixOS module. - ''; - }; - }; +{...}: { + machines = { + atlas = import ./atlas; + jefke = import ./jefke; + lewis = import ./lewis; + warwick = import ./warwick; }; - - allOpts = { - options = { - machines = lib.mkOption { - type = with lib.types; attrsOf (submodule machineOpts); - }; - }; - }; -in { - machines = - (lib.modules.evalModules { - modules = [ - allOpts - ./warwick - ./atlas - ./jefke - ./lewis - # ./talos.nix - ]; - }) - .config - .machines; -}) +} diff --git a/machines/jefke/default.nix b/machines/jefke/default.nix index 3502ab1..dd0e03f 100644 --- a/machines/jefke/default.nix +++ b/machines/jefke/default.nix @@ -1,17 +1,13 @@ { - machines.jefke = { - nixosModule = { - facter.reportPath = ./facter.json; + facter.reportPath = ./facter.json; - lab = { - storage.profile = "kubernetes"; - tailscale.enable = true; + lab = { + storage.profile = "kubernetes"; + tailscale.enable = true; - k3s = { - enable = true; - clusterInit = true; - }; - }; + k3s = { + enable = true; + clusterInit = true; }; }; } diff --git a/machines/lewis/default.nix b/machines/lewis/default.nix index 47aef36..9cabbcf 100644 --- a/machines/lewis/default.nix +++ b/machines/lewis/default.nix @@ -1,19 +1,15 @@ { - machines.lewis = { - nixosModule = { - facter.reportPath = ./facter.json; + facter.reportPath = ./facter.json; - lab = { - storage.profile = "kubernetes"; - backups.enable = true; - data-sharing.enable = true; - tailscale.enable = true; + lab = { + storage.profile = "kubernetes"; + backups.enable = true; + data-sharing.enable = true; + tailscale.enable = true; - k3s = { - enable = true; - serverAddr = "https://jefke.dmz:6443"; - }; - }; + k3s = { + enable = true; + serverAddr = "https://jefke.dmz:6443"; }; }; } diff --git a/machines/talos.nix b/machines/talos.nix deleted file mode 100644 index cbcc0b1..0000000 --- a/machines/talos.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - machines.talos = { - nixosModule = {lib, ...}: { - lab.storage.profile = "normal"; - - # boot.loader.systemd-boot.enable = lib.mkForce false; - }; - }; -} diff --git a/machines/warwick/default.nix b/machines/warwick/default.nix index 81bd94f..b3daee7 100644 --- a/machines/warwick/default.nix +++ b/machines/warwick/default.nix @@ -1,20 +1,16 @@ -{ - machines.warwick = { - nixosModule = {inputs, ...}: { - imports = [inputs.nixos-hardware.nixosModules.raspberry-pi-4]; +{inputs, ...}: { + imports = [inputs.nixos-hardware.nixosModules.raspberry-pi-4]; - config = { - facter.reportPath = ./facter.json; + config = { + facter.reportPath = ./facter.json; - lab = { - storage.profile = "pi"; - monitoring.server.enable = true; + lab = { + storage.profile = "pi"; + monitoring.server.enable = true; - tailscale = { - advertiseExitNode = true; - enable = true; - }; - }; + tailscale = { + advertiseExitNode = true; + enable = true; }; }; }; diff --git a/modules/default.nix b/modules/default.nix index fe31225..da36e7d 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -3,7 +3,6 @@ pkgs, lib, inputs, - machine, config, ... }: { @@ -16,7 +15,6 @@ ./k3s ./tailscale.nix ./facter.nix - machine.nixosModule inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops inputs.nix-snapshotter.nixosModules.nix-snapshotter diff --git a/modules/monitoring/default.nix b/modules/monitoring/default.nix index a67b12e..58aa4aa 100644 --- a/modules/monitoring/default.nix +++ b/modules/monitoring/default.nix @@ -38,7 +38,7 @@ in { let generated = lib.attrsets.mapAttrsToList - (name: machine: { + (name: _module: { job_name = name; static_configs = [ { diff --git a/modules/networking/default.nix b/modules/networking/default.nix index ef68c4e..41c0174 100644 --- a/modules/networking/default.nix +++ b/modules/networking/default.nix @@ -1,7 +1,6 @@ { lib, config, - machine, ... }: { config = { diff --git a/nixos.nix b/nixos.nix index 34f3fb8..d00b9a5 100644 --- a/nixos.nix +++ b/nixos.nix @@ -3,22 +3,24 @@ nixpkgs, ... } @ inputs: let - deployArch = "x86_64-linux"; - machines = self.machines.${deployArch}; mkNixosSystems = systemDef: builtins.mapAttrs ( - name: machine: - nixpkgs.lib.nixosSystem (systemDef name machine) + name: module: + nixpkgs.lib.nixosSystem (systemDef name module) ) - machines; + self.machines; in { - nixosConfigurations = mkNixosSystems (name: machine: { - specialArgs = {inherit self inputs machine machines;}; + nixosConfigurations = mkNixosSystems (name: module: { + specialArgs = { + inherit self inputs; + inherit (self) machines; + }; modules = [ "${self}/modules" {networking.hostName = name;} + module ]; }); } From 52264d4a1f2288b4dfdf5a9447941e87ccda9817 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 30 Nov 2024 22:53:01 +0100 Subject: [PATCH 105/108] Remove migrated Warwick server --- machines/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/machines/default.nix b/machines/default.nix index 74151fb..eb60ba5 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -3,6 +3,5 @@ atlas = import ./atlas; jefke = import ./jefke; lewis = import ./lewis; - warwick = import ./warwick; }; } From 01bb809384accf086c3a4894ea1470fa8d237dce Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 1 Dec 2024 14:36:26 +0100 Subject: [PATCH 106/108] Remove migrated Atlas server --- machines/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/machines/default.nix b/machines/default.nix index eb60ba5..f809200 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -1,6 +1,5 @@ {...}: { machines = { - atlas = import ./atlas; jefke = import ./jefke; lewis = import ./lewis; }; From 863ce8d4d097f7ebd8e582dcf6510d8e37d166ca Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 1 Dec 2024 15:41:11 +0100 Subject: [PATCH 107/108] Remove migrated machine Jefke --- machines/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/machines/default.nix b/machines/default.nix index f809200..a9ef5ab 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -1,6 +1,5 @@ {...}: { machines = { - jefke = import ./jefke; lewis = import ./lewis; }; } From 68b79e086c4cc6b850ba12c60f3a978d18bd41b1 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 1 Dec 2024 16:50:32 +0100 Subject: [PATCH 108/108] Add deprecation notice --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d18af32..b218f6d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # nixos-servers +> [!CAUTION] +> This repository has been deprecated in favor of [pim/nixos-configs](https://git.kun.is/pim/nixos-configs). + Nix definitions to configure our servers at home. ## Acknowledgements