From 1f0dc9090e016e1a6853cba82fd1627f3587409c Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 20:03:36 +0200 Subject: [PATCH 01/63] WIP headscale --- kubenix-modules/bootstrap-default.nix | 2 + kubenix-modules/headscale.nix | 411 ++++++++++++++++++++++++++ 2 files changed, 413 insertions(+) create mode 100644 kubenix-modules/headscale.nix diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index 4f5d9ba..31eeb14 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -47,6 +47,7 @@ dns = { }; media = { }; minecraft = { }; + headscale = { }; tailscale = { }; }; @@ -154,6 +155,7 @@ sonarr.storage = "150Mi"; bazarr.storage = "25Mi"; minecraft.storage = "1Gi"; + headscale.storage = "1Gi"; }; }; } diff --git a/kubenix-modules/headscale.nix b/kubenix-modules/headscale.nix new file mode 100644 index 0000000..c0ca798 --- /dev/null +++ b/kubenix-modules/headscale.nix @@ -0,0 +1,411 @@ +{ lib, ... }: { + kubernetes.resources = { + secrets.headscale.stringData.config = lib.generators.toYAML { } { + #--- + ## headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order: + ## + ## - `/etc/headscale` + ## - `~/.headscale` + ## - current working directory + + ## The url clients will connect to. + ## Typically this will be a domain like: + ## + ## https://myheadscale.example.com:443 + ## + #server_url: http://127.0.0.1:8080 + server_url = "https://headscale.kun.is"; + + ## Address to listen to / bind to on the server + ## + ## For production: + ## listen_addr: 0.0.0.0:8080 + #listen_addr: 127.0.0.1:8080 + listen_addr = "0.0.0.0:8080"; + + ## Address to listen to /metrics, you may want + ## to keep this endpoint private to your internal + ## network + ## + #metrics_listen_addr: 127.0.0.1:9090 + metrics_listen_addr = "0.0.0.0:9090"; + + ## Address to listen for gRPC. + ## gRPC is used for controlling a headscale server + ## remotely with the CLI + ## Note: Remote access _only_ works if you have + ## valid certificates. + ## + ## For production: + ## grpc_listen_addr: 0.0.0.0:50443 + #grpc_listen_addr: 127.0.0.1:50443 + + ## Allow the gRPC admin interface to run in INSECURE + ## mode. This is not recommended as the traffic will + ## be unencrypted. Only enable if you know what you + ## are doing. + #grpc_allow_insecure: false + + ## The Noise section includes specific configuration for the + ## TS2021 Noise protocol + #noise: + noise = { + # # The Noise private key is used to encrypt the + # # traffic between headscale and Tailscale clients when + # # using the new Noise-based protocol. + # private_key_path: /var/lib/headscale/noise_private.key + # TODO + private_key_path = "/etc/headscale/noise_private.key"; + }; + + ## List of IP prefixes to allocate tailaddresses from. + ## Each prefix consists of either an IPv4 or IPv6 address, + ## and the associated prefix length, delimited by a slash. + ## It must be within IP ranges supported by the Tailscale + ## client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48. + ## See below: + ## IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71 + ## IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33 + ## Any other range is NOT supported, and it will cause unexpected issues. + #prefixes: + # v6: fd7a:115c:a1e0::/48 + # v4: 100.64.0.0/10 + + prefixes = { + v6 = "fd7a:115c:a1e0::/48"; + v4 = "100.64.0.0/10"; + + # # Strategy used for allocation of IPs to nodes, available options: + # # - sequential (default): assigns the next free IP from the previous given IP. + # # - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand). + allocation = "sequential"; + }; + + ## DERP is a relay system that Tailscale uses when a direct + ## connection cannot be established. + ## https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp + ## + ## headscale needs a list of DERP servers that can be presented + ## to the clients. + #derp: + # server: + # # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config + # # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place + # enabled: false + + # # Region ID to use for the embedded DERP server. + # # The local DERP prevails if the region ID collides with other region ID coming from + # # the regular DERP config. + # region_id: 999 + + # # Region code and name are displayed in the Tailscale UI to identify a DERP region + # region_code: "headscale" + # region_name: "Headscale Embedded DERP" + + # # Listens over UDP at the configured address for STUN connections - to help with NAT traversal. + # # When the embedded DERP server is enabled stun_listen_addr MUST be defined. + # # + # # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/ + # stun_listen_addr: "0.0.0.0:3478" + + # # Private key used to encrypt the traffic between headscale DERP + # # and Tailscale clients. + # # The private key file will be autogenerated if it's missing. + # # + # private_key_path: /var/lib/headscale/derp_server_private.key + + # # This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically, + # # it enables the creation of your very own DERP map entry using a locally available file with the parameter DERP.paths + # # If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using DERP.paths + # automatically_add_embedded_derp_region: true + + # # For better connection stability (especially when using an Exit-Node and DNS is not working), + # # it is possible to optionally add the public IPv4 and IPv6 address to the Derp-Map using: + # ipv4: 1.2.3.4 + # ipv6: 2001:db8::1 + + # # List of externally available DERP maps encoded in JSON + # urls: + # - https://controlplane.tailscale.com/derpmap/default + + # # Locally available DERP map files encoded in YAML + # # + # # This option is mostly interesting for people hosting + # # their own DERP servers: + # # https://tailscale.com/kb/1118/custom-derp-servers/ + # # + # # paths: + # # - /etc/headscale/derp-example.yaml + # paths: [] + + # # If enabled, a worker will be set up to periodically + # # refresh the given sources and update the derpmap + # # will be set up. + # auto_update_enabled: true + + # # How often should we check for DERP updates? + # update_frequency: 24h + + derp = { + server.enabled = false; + urls = [ "https://controlplane.tailscale.com/derpmap/default" ]; + auto_update_enabled = true; + }; + + ## Disables the automatic check for headscale updates on startup + #disable_check_updates: false + + ## Time before an inactive ephemeral node is deleted? + #ephemeral_node_inactivity_timeout: 30m + + #database: + # type: sqlite + + # # SQLite config + # sqlite: + # path: /var/lib/headscale/db.sqlite + + # # Enable WAL mode for SQLite. This is recommended for production environments. + # # https://www.sqlite.org/wal.html + # write_ahead_log: true + + # # # Postgres config + # # postgres: + # # # If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank. + # # host: localhost + # # port: 5432 + # # name: headscale + # # user: foo + # # pass: bar + # # max_open_conns: 10 + # # max_idle_conns: 10 + # # conn_max_idle_time_secs: 3600 + + # # # If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need + # # # in the 'ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1. + # # ssl: false + + database = { + type = "sqlite"; + sqlite = { + path = "/var/lib/headscale/db.sqlite"; + write_ahead_log = true; + }; + }; + + #### TLS configuration + ## + ### Let's encrypt / ACME + ## + ## headscale supports automatically requesting and setting up + ## TLS for a domain with Let's Encrypt. + ## + ## URL to ACME directory + #acme_url: https://acme-v02.api.letsencrypt.org/directory + + ## Email to register with ACME provider + #acme_email: "" + + ## Domain name to request a TLS certificate for: + #tls_letsencrypt_hostname: "" + + ## Path to store certificates and metadata needed by + ## letsencrypt + ## For production: + #tls_letsencrypt_cache_dir: /var/lib/headscale/cache + + ## Type of ACME challenge to use, currently supported types: + ## HTTP-01 or TLS-ALPN-01 + ## See [docs/tls.md](docs/tls.md) for more information + #tls_letsencrypt_challenge_type: HTTP-01 + ## When HTTP-01 challenge is chosen, letsencrypt must set up a + ## verification endpoint, and it will be listening on: + ## :http = port 80 + #tls_letsencrypt_listen: ":http" + + ### Use already defined certificates: + #tls_cert_path: "" + #tls_key_path: "" + + #log: + # # Output formatting for logs: text or json + # format: text + # level: info + log = { + format = "text"; + level = "info"; + }; + + ### Policy + ## headscale supports Tailscale's ACL policies. + ## Please have a look to their KB to better + ## understand the concepts: https://tailscale.com/kb/1018/acls/ + #policy: + # # The mode can be "file" or "database" that defines + # # where the ACL policies are stored and read from. + # mode: file + # # If the mode is set to "file", the + # # path to a file containing ACL policies. + # # The file can be in YAML or HuJSON format. + # path: "" + policy.mode = "database"; + + ### DNS + ## + ## headscale supports Tailscale's DNS configuration and MagicDNS. + ## Please have a look to their KB to better understand the concepts: + ## + ## - https://tailscale.com/kb/1054/dns/ + ## - https://tailscale.com/kb/1081/magicdns/ + ## - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/ + ## + #dns_config: + # # Whether to prefer using Headscale provided DNS or use local. + # override_local_dns: true + + # # List of DNS servers to expose to clients. + # nameservers: + # - 1.1.1.1 + + # # NextDNS (see https://tailscale.com/kb/1218/nextdns/). + # # "abc123" is example NextDNS ID, replace with yours. + # # + # # With metadata sharing: + # # nameservers: + # # - https://dns.nextdns.io/abc123 + # # + # # Without metadata sharing: + # # nameservers: + # # - 2a07:a8c0::ab:c123 + # # - 2a07:a8c1::ab:c123 + + # # Split DNS (see https://tailscale.com/kb/1054/dns/), + # # list of search domains and the DNS to query for each one. + # # + # # restricted_nameservers: + # # foo.bar.com: + # # - 1.1.1.1 + # # darp.headscale.net: + # # - 1.1.1.1 + # # - 8.8.8.8 + + # # Search domains to inject. + # domains: [] + + # # Extra DNS records + # # so far only A-records are supported (on the tailscale side) + # # See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations + # # extra_records: + # # - name: "grafana.myvpn.example.com" + # # type: "A" + # # value: "100.64.0.3" + # # + # # # you can also put it in one line + # # - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" } + + # # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). + # # Only works if there is at least a nameserver defined. + # magic_dns: true + + # # DEPRECATED + # # Use the username as part of the DNS name for nodes, with this option enabled: + # # node1.username.example.com + # # while when this is disabled: + # # node1.example.com + # # This is a legacy option as Headscale has have this wrongly implemented + # # while in upstream Tailscale, the username is not included. + # use_username_in_magic_dns: false + + # # Defines the base domain to create the hostnames for MagicDNS. + # # `base_domain` must be a FQDNs, without the trailing dot. + # # The FQDN of the hosts will be + # # `hostname.user.base_domain` (e.g., _myhost.myuser.example.com_). + # base_domain: example.com + + ## Unix socket used for the CLI to connect without authentication + ## Note: for production you will want to set this to something like: + #unix_socket: /var/run/headscale/headscale.sock + #unix_socket_permission: "0770" + ## + ## headscale supports experimental OpenID connect support, + ## it is still being tested and might have some bugs, please + ## help us test it. + ## OpenID Connect + ## oidc: + ## only_start_if_oidc_is_available: true + ## issuer: "https://your-oidc.issuer.com/path" + ## client_id: "your-oidc-client-id" + ## client_secret: "your-oidc-client-secret" + ## # Alternatively, set `client_secret_path` to read the secret from the file. + ## # It resolves environment variables, making integration to systemd's + ## # `LoadCredential` straightforward: + ## client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret" + ## # client_secret and client_secret_path are mutually exclusive. + ## + ## # The amount of time from a node is authenticated with OpenID until it + ## # expires and needs to reauthenticate. + ## # Setting the value to "0" will mean no expiry. + ## expiry: 180d + ## + ## # Use the expiry from the token received from OpenID when the user logged + ## # in, this will typically lead to frequent need to reauthenticate and should + ## # only been enabled if you know what you are doing. + ## # Note: enabling this will cause `oidc.expiry` to be ignored. + ## use_expiry_from_token: false + ## + ## # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query + ## # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email". + ## + ## scope: ["openid", "profile", "email", "custom"] + ## extra_params: + ## domain_hint: example.com + ## + ## # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the + ## # authentication request will be rejected. + ## + ## allowed_domains: + ## - example.com + ## # Note: Groups from keycloak have a leading '/' + ## allowed_groups: + ## - /headscale + ## allowed_users: + ## - alice@example.com + ## + ## # If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed. + ## # This will transform `first-name.last-name@example.com` to the user `first-name.last-name` + ## # If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following + ## user: `first-name.last-name.example.com` + ## + ## strip_email_domain: true + + ## Logtail configuration + ## Logtail is Tailscales logging and auditing infrastructure, it allows the control panel + ## to instruct tailscale nodes to log their activity to a remote server. + #logtail: + # # Enable logtail for this headscales clients. + # # As there is currently no support for overriding the log server in headscale, this is + # # disabled by default. Enabling this will make your clients send logs to Tailscale Inc. + # enabled: false + + ## Enabling this option makes devices prefer a random port for WireGuard traffic over the + ## default static port 41641. This option is intended as a workaround for some buggy + ## firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information. + #randomize_client_port: false + }; + + deployments.headscale.spec = { + selector.matchLabels.app = "headscale"; + + template = { + metadata.labels.app = "headscale"; + + spec = { + containers.headscale = { + image = "headscale/headscale:v0.23.0-alpha12"; + imagePullPolicy = "Always"; + }; + }; + }; + }; + }; +} From 6152ce4577186fc68c4856e7d9f688009d255796 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 20:30:47 +0200 Subject: [PATCH 02/63] 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 03/63] 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 04/63] 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 05/63] 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 06/63] 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 07/63] 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 08/63] 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 09/63] 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 10/63] 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 11/63] 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 12/63] 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 13/63] 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 14/63] 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 15/63] 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 16/63] 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 17/63] 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 18/63] 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 19/63] 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 20/63] 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 21/63] 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 22/63] 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 23/63] 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 24/63] 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 25/63] 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 26/63] 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 27/63] 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 28/63] 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 29/63] 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 30/63] 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 31/63] 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 32/63] 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 33/63] 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 34/63] 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 35/63] 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 36/63] 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 37/63] 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 38/63] 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 39/63] 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 40/63] 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 41/63] 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 42/63] 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 43/63] 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 44/63] 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 45/63] 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 46/63] 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 47/63] 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 48/63] 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 49/63] 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 50/63] 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 51/63] 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 52/63] 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 53/63] 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 54/63] 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 55/63] 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 56/63] 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 57/63] 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 58/63] 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 59/63] 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 60/63] 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 61/63] 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 62/63] 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 63/63] 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