From 5c975a5eef3e09841dd713bbb24f3b98eef2a212 Mon Sep 17 00:00:00 2001 From: Qubasa Date: Mon, 9 Sep 2024 15:51:31 +0200 Subject: [PATCH] clanCore: init machineId and diskId v2 --- checks/borgbackup/default.nix | 1 + checks/container/default.nix | 1 + checks/installation/flake-module.nix | 4 + checks/lib/age/privkey | 1 + checks/lib/age/pubkey | 1 + checks/mumble/default.nix | 1 + checks/nixos-documentation/flake-module.nix | 4 +- clanModules/factless/README.md | 5 + clanModules/factless/default.nix | 33 ++ clanModules/factless/roles/default.nix | 1 + clanModules/flake-module.nix | 1 + clanModules/single-disk/default.nix | 83 +++-- docs/mkdocs.yml | 2 + docs/site/getting-started/disk-encryption.md | 319 +++++++++--------- docs/site/getting-started/installer.md | 4 +- inventory.json | 28 ++ lib/eval-clan-modules/default.nix | 3 + lib/inventory/build-inventory/interface.nix | 34 +- nixosModules/clanCore/default.nix | 2 + nixosModules/clanCore/disk_id.nix | 48 +++ nixosModules/clanCore/machine_id.nix | 59 ++++ nixosModules/clanCore/uuid4.sh | 20 ++ pkgs/clan-cli/clan_cli/inventory/classes.py | 34 ++ pkgs/clan-cli/clan_cli/inventory/update.sh | 4 + pkgs/installer/flake-module.nix | 82 +++-- .../app/src/routes/machines/details.tsx | 6 +- templates/flake-parts/modules/disko.nix | 7 +- templates/new-clan/modules/disko.nix | 7 +- 28 files changed, 543 insertions(+), 252 deletions(-) create mode 100644 checks/lib/age/privkey create mode 100644 checks/lib/age/pubkey create mode 100644 clanModules/factless/README.md create mode 100644 clanModules/factless/default.nix create mode 100644 clanModules/factless/roles/default.nix create mode 100644 nixosModules/clanCore/disk_id.nix create mode 100644 nixosModules/clanCore/machine_id.nix create mode 100644 nixosModules/clanCore/uuid4.sh create mode 100755 pkgs/clan-cli/clan_cli/inventory/update.sh diff --git a/checks/borgbackup/default.nix b/checks/borgbackup/default.nix index d376b354b..0bbb0927b 100644 --- a/checks/borgbackup/default.nix +++ b/checks/borgbackup/default.nix @@ -18,6 +18,7 @@ { clan.core.machineName = "machine"; clan.core.clanDir = ./.; + clan.core.state.testState.folders = [ "/etc/state" ]; environment.etc.state.text = "hello world"; systemd.tmpfiles.settings."vmsecrets" = { diff --git a/checks/container/default.nix b/checks/container/default.nix index 61c75a0e9..4b265559c 100644 --- a/checks/container/default.nix +++ b/checks/container/default.nix @@ -9,6 +9,7 @@ networking.hostName = "machine"; services.openssh.enable = true; services.openssh.startWhenNeeded = false; + }; testScript = '' start_all() diff --git a/checks/installation/flake-module.nix b/checks/installation/flake-module.nix index ecfcd7b2d..83ff01e35 100644 --- a/checks/installation/flake-module.nix +++ b/checks/installation/flake-module.nix @@ -13,10 +13,14 @@ { imports = [ self.clanModules.single-disk + self.clanModules.factless (modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests (modulesPath + "/profiles/qemu-guest.nix") ]; clan.single-disk.device = "/dev/vdb"; + clan.factless = { + diskId = "ac51e4623c804dcbbce0144ed8e16e55"; + }; environment.etc."install-successful".text = "ok"; diff --git a/checks/lib/age/privkey b/checks/lib/age/privkey new file mode 100644 index 000000000..f707304a7 --- /dev/null +++ b/checks/lib/age/privkey @@ -0,0 +1 @@ +AGE-SECRET-KEY-1KF8E3SR3TTGL6M476SKF7EEMR4H9NF7ZWYSLJUAK8JX276JC7KUSSURKFK \ No newline at end of file diff --git a/checks/lib/age/pubkey b/checks/lib/age/pubkey new file mode 100644 index 000000000..80b46d53c --- /dev/null +++ b/checks/lib/age/pubkey @@ -0,0 +1 @@ +age1dhwqzkah943xzc34tc3dlmfayyevcmdmxzjezdgdy33euxwf59vsp3vk3c \ No newline at end of file diff --git a/checks/mumble/default.nix b/checks/mumble/default.nix index d29c8a7ae..d73828c9a 100644 --- a/checks/mumble/default.nix +++ b/checks/mumble/default.nix @@ -32,6 +32,7 @@ common { clan.core.machineName = "peer1"; + environment.etc = { "mumble-key".source = ./peer_1/peer_1_test_key; "mumble-cert".source = ./peer_1/peer_1_test_cert; diff --git a/checks/nixos-documentation/flake-module.nix b/checks/nixos-documentation/flake-module.nix index 743d97c19..463e301a6 100644 --- a/checks/nixos-documentation/flake-module.nix +++ b/checks/nixos-documentation/flake-module.nix @@ -8,7 +8,9 @@ let self.nixosModules.clanCore # This is the only option that is not part of the # module because it is usually set by flake-parts - { clan.core.clanDir = ./.; } + { + clan.core.clanDir = ./.; + } ]; }; in diff --git a/clanModules/factless/README.md b/clanModules/factless/README.md new file mode 100644 index 000000000..66ac34dbd --- /dev/null +++ b/clanModules/factless/README.md @@ -0,0 +1,5 @@ +--- +description = "Disables early fact generation in clanCore" +--- + +This module isn't meant for everyone. It's made for internal use or for those who prefer not to create facts for a machine. \ No newline at end of file diff --git a/clanModules/factless/default.nix b/clanModules/factless/default.nix new file mode 100644 index 000000000..90098f7b4 --- /dev/null +++ b/clanModules/factless/default.nix @@ -0,0 +1,33 @@ +{ + config, + lib, + ... +}: +let + + cfg = config.clan.factless; +in +{ + # These options are reexported here to allow the inventory to set them + options.clan.factless = { + machineId = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "A machine id based on the UUID v4 format"; + default = null; + }; + diskId = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "The disk id, changing this will require a new installation"; + default = null; + }; + }; + + config = { + clan.core.machine = { + generateMachineId = false; + generateDiskId = false; + machineId = cfg.machineId; + diskId = cfg.diskId; + }; + }; +} diff --git a/clanModules/factless/roles/default.nix b/clanModules/factless/roles/default.nix new file mode 100644 index 000000000..ffcd4415b --- /dev/null +++ b/clanModules/factless/roles/default.nix @@ -0,0 +1 @@ +{ } diff --git a/clanModules/flake-module.nix b/clanModules/flake-module.nix index 648e91b47..c57ab0830 100644 --- a/clanModules/flake-module.nix +++ b/clanModules/flake-module.nix @@ -7,6 +7,7 @@ deltachat = ./deltachat; dyndns = ./dyndns; ergochat = ./ergochat; + factless = ./factless; garage = ./garage; golem-provider = ./golem-provider; heisenbridge = ./heisenbridge; diff --git a/clanModules/single-disk/default.nix b/clanModules/single-disk/default.nix index 6a9d8e01a..88d7b2e5c 100644 --- a/clanModules/single-disk/default.nix +++ b/clanModules/single-disk/default.nix @@ -1,53 +1,66 @@ { lib, config, ... }: +let + cfg = config.clan.single-disk; + suffix = config.clan.core.machine.diskId; +in { options.clan.single-disk = { device = lib.mkOption { default = null; type = lib.types.nullOr lib.types.str; description = "The primary disk device to install the system on"; - # Question: should we set a default here? - # default = "/dev/null"; }; }; - config = { - boot.loader.grub.efiSupport = lib.mkDefault true; - boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; - disko.devices = { - disk = { - main = { - type = "disk"; - # This is set through the UI - device = config.clan.single-disk.device; + config = lib.mkMerge [ + ({ + assertions = [ + { + assertion = suffix != null; + message = "Please run `clan facts generate` or import `clanModules.factless`"; + } + ]; + }) + (lib.mkIf (suffix != null) { + boot.loader.grub.efiSupport = lib.mkDefault true; + boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; + disko.devices = { + disk = { + "main" = { + name = suffix; + type = "disk"; + # This is set through the UI + device = cfg.device; - content = { - type = "gpt"; - partitions = { - "${config.networking.hostName}-boot" = { - size = "1M"; - type = "EF02"; # for grub MBR - priority = 1; - }; - "${config.networking.hostName}-ESP" = { - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; + content = { + type = "gpt"; + partitions = { + "boot" = { + size = "1M"; + type = "EF02"; # for grub MBR + priority = 1; }; - }; - "${config.networking.hostName}-root" = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; + "ESP" = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + "root" = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; }; }; }; }; }; }; - }; - }; + }) + ]; } diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index eaee14bac..536b01ae6 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -63,6 +63,7 @@ nav: - reference/clanModules/nginx.md - reference/clanModules/vaultwarden.md - reference/clanModules/ergochat.md + - reference/clanModules/factless.md - reference/clanModules/garage.md - reference/clanModules/golem-provider.md - reference/clanModules/index.md @@ -108,6 +109,7 @@ nav: - reference/clan-core/sops.md - reference/clan-core/state.md - reference/clan-core/deployment.md + - reference/clan-core/machine.md - reference/clan-core/networking.md - Nix API: - reference/nix-api/index.md diff --git a/docs/site/getting-started/disk-encryption.md b/docs/site/getting-started/disk-encryption.md index 8217ef761..7d5cbb3d6 100644 --- a/docs/site/getting-started/disk-encryption.md +++ b/docs/site/getting-started/disk-encryption.md @@ -14,183 +14,192 @@ lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT === "**Single Disk**" Below is the configuration for `disko.nix` - ```nix hl_lines="14 40" - { lib, ... }: - let - mirrorBoot = idx: { - type = "disk"; - device = "/dev/disk/by-id/${idx}"; - content = { - type = "gpt"; - partitions = { - "${config.networking.hostName}-boot" = { - size = "1M"; - type = "EF02"; # for grub MBR - priority = 1; - }; - "${config.networking.hostName}-ESP" = lib.mkIf (idx == "nvme-eui.002538b931b59865") { - size = "1G"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "nofail" ]; - }; - }; - "${config.networking.hostName}-root" = { - size = "100%"; - content = { - type = "zfs"; - pool = "zroot"; - }; - }; - }; + ```nix hl_lines="16 43" +{ lib, ... }: +let + suffix = config.clan.core.machine.diskId; + mirrorBoot = idx: { + name = suffix; + type = "disk"; + device = "/dev/disk/by-id/${idx}"; + content = { + type = "gpt"; + partitions = { + "boot" = { + size = "1M"; + type = "EF02"; # for grub MBR + priority = 1; }; + "ESP" = lib.mkIf (idx == "nvme-eui.002538b931b59865") { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "nofail" ]; + }; + }; + "root" = { + size = "100%"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; }; - in - { + }; +in +{ + config = { boot.loader.systemd-boot.enable = true; disko.devices = { - disk = { - x = mirrorBoot "nvme-eui.002538b931b59865"; - }; - zpool = { - zroot = { - type = "zpool"; - rootFsOptions = { - compression = "lz4"; - acltype = "posixacl"; - xattr = "sa"; - "com.sun:auto-snapshot" = "true"; - mountpoint = "none"; - }; - datasets = { - "root" = { - type = "zfs_fs"; - options = { - mountpoint = "none"; - encryption = "aes-256-gcm"; - keyformat = "passphrase"; - keylocation = "file:///tmp/secret.key"; - }; - }; - "root/nixos" = { - type = "zfs_fs"; - options.mountpoint = "/"; - mountpoint = "/"; - }; - "root/home" = { - type = "zfs_fs"; - options.mountpoint = "/home"; - mountpoint = "/home"; - }; - "root/tmp" = { - type = "zfs_fs"; - mountpoint = "/tmp"; - options = { - mountpoint = "/tmp"; - sync = "disabled"; - }; - }; - }; + disk = { + x = mirrorBoot "nvme-eui.002538b931b59865"; + }; + zpool = { + zroot = { + type = "zpool"; + rootFsOptions = { + compression = "lz4"; + acltype = "posixacl"; + xattr = "sa"; + "com.sun:auto-snapshot" = "true"; + mountpoint = "none"; + }; + datasets = { + "root" = { + type = "zfs_fs"; + options = { + mountpoint = "none"; + encryption = "aes-256-gcm"; + keyformat = "passphrase"; + keylocation = "file:///tmp/secret.key"; + }; }; + "root/nixos" = { + type = "zfs_fs"; + options.mountpoint = "/"; + mountpoint = "/"; + }; + "root/home" = { + type = "zfs_fs"; + options.mountpoint = "/home"; + mountpoint = "/home"; + }; + "root/tmp" = { + type = "zfs_fs"; + mountpoint = "/tmp"; + options = { + mountpoint = "/tmp"; + sync = "disabled"; + }; + }; + }; }; + }; }; - } + }; +} + ``` === "**Raid 1**" Below is the configuration for `disko.nix` - ```nix hl_lines="14 40 41" - { lib, ... }: - let - mirrorBoot = idx: { - type = "disk"; - device = "/dev/disk/by-id/${idx}"; - content = { - type = "gpt"; - partitions = { - boot = { - size = "1M"; - type = "EF02"; # for grub MBR - priority = 1; - }; - ESP = lib.mkIf (idx == "nvme-eui.002538b931b59865") { - size = "1G"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "nofail" ]; - }; - }; - zfs = { - size = "100%"; - content = { - type = "zfs"; - pool = "zroot"; - }; - }; - }; + ```nix hl_lines="16 43 44" +{ lib, ... }: +let + suffix = config.clan.core.machine.diskId; + mirrorBoot = idx: { + name = suffix; + type = "disk"; + device = "/dev/disk/by-id/${idx}"; + content = { + type = "gpt"; + partitions = { + "boot" = { + size = "1M"; + type = "EF02"; # for grub MBR + priority = 1; }; + "ESP" = lib.mkIf (idx == "nvme-eui.002538b931b59865") { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "nofail" ]; + }; + }; + "root" = { + size = "100%"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; }; - in - { + }; +in +{ + config = { boot.loader.systemd-boot.enable = true; disko.devices = { - disk = { - x = mirrorBoot "nvme-eui.002538b931b59865"; - y = mirrorBoot "myOtherDrive" - }; - zpool = { - zroot = { - type = "zpool"; - rootFsOptions = { - compression = "lz4"; - acltype = "posixacl"; - xattr = "sa"; - "com.sun:auto-snapshot" = "true"; - mountpoint = "none"; - }; - datasets = { - "root" = { - type = "zfs_fs"; - options = { - mountpoint = "none"; - encryption = "aes-256-gcm"; - keyformat = "passphrase"; - keylocation = "file:///tmp/secret.key"; - }; - }; - "root/nixos" = { - type = "zfs_fs"; - options.mountpoint = "/"; - mountpoint = "/"; - }; - "root/home" = { - type = "zfs_fs"; - options.mountpoint = "/home"; - mountpoint = "/home"; - }; - "root/tmp" = { - type = "zfs_fs"; - mountpoint = "/tmp"; - options = { - mountpoint = "/tmp"; - sync = "disabled"; - }; - }; - }; + disk = { + x = mirrorBoot "nvme-eui.002538b931b59865"; + y = mirrorBoot "my-other-disk"; + }; + zpool = { + zroot = { + type = "zpool"; + rootFsOptions = { + compression = "lz4"; + acltype = "posixacl"; + xattr = "sa"; + "com.sun:auto-snapshot" = "true"; + mountpoint = "none"; + }; + datasets = { + "root" = { + type = "zfs_fs"; + options = { + mountpoint = "none"; + encryption = "aes-256-gcm"; + keyformat = "passphrase"; + keylocation = "file:///tmp/secret.key"; + }; }; + "root/nixos" = { + type = "zfs_fs"; + options.mountpoint = "/"; + mountpoint = "/"; + }; + "root/home" = { + type = "zfs_fs"; + options.mountpoint = "/home"; + mountpoint = "/home"; + }; + "root/tmp" = { + type = "zfs_fs"; + mountpoint = "/tmp"; + options = { + mountpoint = "/tmp"; + sync = "disabled"; + }; + }; + }; }; + }; }; - } + }; +} ``` Below is the configuration for `initrd.nix`. diff --git a/docs/site/getting-started/installer.md b/docs/site/getting-started/installer.md index d4d7f2ab8..dc0562c4d 100644 --- a/docs/site/getting-started/installer.md +++ b/docs/site/getting-started/installer.md @@ -72,13 +72,13 @@ sudo umount /dev/sdb1 ``` clan flash asd --list-keymaps ``` - + !!! Note You can get a list of all languages with the following command: ``` clan flash asd --list-languages ``` - + diff --git a/inventory.json b/inventory.json index 028bc4112..1edd84f86 100644 --- a/inventory.json +++ b/inventory.json @@ -68,6 +68,34 @@ } } }, + "factless": { + "default": { + "meta": { + "name": "factless", + "description": null, + "icon": null + }, + "roles": { + "default": { + "config": {}, + "imports": [], + "machines": ["test-inventory-machine"], + "tags": [] + } + }, + "config": {}, + "imports": [], + "machines": { + "test-inventory-machine": { + "config": { + "diskId": "910662", + "machineId": "fe7f3ff75c844d36ac4e5383b55b5a76" + }, + "imports": [] + } + } + } + }, "single-disk": { "default": { "meta": { diff --git a/lib/eval-clan-modules/default.nix b/lib/eval-clan-modules/default.nix index ccef35868..c984270d3 100644 --- a/lib/eval-clan-modules/default.nix +++ b/lib/eval-clan-modules/default.nix @@ -25,6 +25,9 @@ let evaled = lib.evalModules { modules = [ baseModule + ({ + clan.core.clanDir = ./.; + }) clan-core.nixosModules.clanCore ] ++ (map (name: clanModules.${name}) modulenames); }; diff --git a/lib/inventory/build-inventory/interface.nix b/lib/inventory/build-inventory/interface.nix index 133e65c58..d4b26338d 100644 --- a/lib/inventory/build-inventory/interface.nix +++ b/lib/inventory/build-inventory/interface.nix @@ -23,27 +23,27 @@ let description = '' List of imported '.nix' files. - Each filename must be a string and is interpreted relative to the 'directory' passed to buildClan. - The import only happens if the machine is part of the service or role. + Each filename must be a string and is interpreted relative to the 'directory' passed to buildClan. + The import only happens if the machine is part of the service or role. - ## Example + ## Example - To import the `special.nix` file + To import the `special.nix` file - ``` - . Clan Directory - ├── flake.nix - ... - └── modules - ├── special.nix - └── ... - ``` + ``` + . Clan Directory + ├── flake.nix + ... + └── modules + ├── special.nix + └── ... + ``` - ```nix - { - imports = [ "modules/special.nix" ]; - } - ``` + ```nix + { + imports = [ "modules/special.nix" ]; + } + ``` ''; default = [ ]; diff --git a/nixosModules/clanCore/default.nix b/nixosModules/clanCore/default.nix index cb469bee3..6529b5683 100644 --- a/nixosModules/clanCore/default.nix +++ b/nixosModules/clanCore/default.nix @@ -18,5 +18,7 @@ ./vm.nix ./wayland-proxy-virtwl.nix ./zerotier + ./machine_id.nix + ./disk_id.nix ]; } diff --git a/nixosModules/clanCore/disk_id.nix b/nixosModules/clanCore/disk_id.nix new file mode 100644 index 000000000..a69f43740 --- /dev/null +++ b/nixosModules/clanCore/disk_id.nix @@ -0,0 +1,48 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.clan.core.machine; + facts = config.clan.core.facts.services.diskId.public or { }; +in +{ + options.clan.core.machine = { + diskId = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "The disk id"; + }; + generateDiskId = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Generate a new disk id"; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf ((facts.diskId.value or null) != null) { + clan.core.machine.diskId = lib.mkDefault facts.diskId.value; + }) + (lib.mkIf cfg.generateDiskId { + clan.core.facts.services.diskId = { + public.diskId = { }; + generator.path = [ + pkgs.coreutils + pkgs.bash + ]; + generator.script = '' + uuid=$(bash ${./uuid4.sh}) + + # Remove the hyphens from the UUID + uuid_no_hyphens=$(echo -n "$uuid" | tr -d '-') + + echo -n "$uuid_no_hyphens" > "$facts/diskId" + ''; + }; + }) + ]; +} diff --git a/nixosModules/clanCore/machine_id.nix b/nixosModules/clanCore/machine_id.nix new file mode 100644 index 000000000..f6bbe0224 --- /dev/null +++ b/nixosModules/clanCore/machine_id.nix @@ -0,0 +1,59 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.clan.core.machine; + facts = config.clan.core.facts.services.machineId.public or { }; +in +{ + options.clan.core.machine = { + machineId = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "A machine id based on the UUID v4 format"; + }; + generateMachineId = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Generate a new machine id"; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf (cfg.machineId != null) { + assertions = [ + { + assertion = lib.stringLength cfg.machineId == 32; + message = "machineId must be exactly 32 characters long."; + } + ]; + boot.kernelParams = [ + ''systemd.machine_id=${cfg.machineId}'' + ]; + }) + (lib.mkIf ((facts.machineId.value or null) != null) { + clan.core.machine.machineId = lib.mkDefault facts.machineId.value; + }) + (lib.mkIf cfg.generateMachineId { + clan.core.facts.services.machineId = { + public.machineId = { }; + generator.path = [ + pkgs.coreutils + pkgs.bash + ]; + generator.script = '' + uuid=$(bash ${./uuid4.sh}) + + # Remove the hyphens from the UUID + uuid_no_hyphens=$(echo -n "$uuid" | tr -d '-') + + echo -n "$uuid_no_hyphens" > "$facts/machineId" + ''; + }; + }) + ]; +} diff --git a/nixosModules/clanCore/uuid4.sh b/nixosModules/clanCore/uuid4.sh new file mode 100644 index 000000000..ca3a7c47e --- /dev/null +++ b/nixosModules/clanCore/uuid4.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Read 16 bytes from /dev/urandom +uuid=$(dd if=/dev/urandom bs=1 count=16 2>/dev/null | od -An -tx1 | tr -d ' \n') + +# Break the UUID into pieces and apply the required modifications +byte6=${uuid:12:2} +byte8=${uuid:16:2} + +# Construct the correct version and variant +hex_byte6=$(printf "%x" $((0x$byte6 & 0x0F | 0x40))) +hex_byte8=$(printf "%x" $((0x$byte8 & 0x3F | 0x80))) + +# Rebuild the UUID with the correct fields +uuid_v4="${uuid:0:12}${hex_byte6}${uuid:14:2}${hex_byte8}${uuid:18:14}" + +# Format the UUID correctly 8-4-4-4-12 +uuid_formatted="${uuid_v4:0:8}-${uuid_v4:8:4}-${uuid_v4:12:4}-${uuid_v4:16:4}-${uuid_v4:20:12}" + +echo -n "$uuid_formatted" \ No newline at end of file diff --git a/pkgs/clan-cli/clan_cli/inventory/classes.py b/pkgs/clan-cli/clan_cli/inventory/classes.py index c0c31e9ae..9de6ef139 100644 --- a/pkgs/clan-cli/clan_cli/inventory/classes.py +++ b/pkgs/clan-cli/clan_cli/inventory/classes.py @@ -117,6 +117,39 @@ class ServiceBorgbackup: machines: dict[str, ServiceBorgbackupMachine] = field(default_factory = dict) +@dataclass +class FactlessConfig: + diskId: None | str = field(default = None) + machineId: None | str = field(default = None) + + +@dataclass +class ServiceFactlesMachine: + config: FactlessConfig = field(default_factory = FactlessConfig) + imports: list[str] = field(default_factory = list) + + +@dataclass +class ServiceFactlesRoleDefault: + config: FactlessConfig = field(default_factory = FactlessConfig) + imports: list[str] = field(default_factory = list) + machines: list[str] = field(default_factory = list) + tags: list[str] = field(default_factory = list) + + +@dataclass +class ServiceFactlesRole: + default: ServiceFactlesRoleDefault + + +@dataclass +class ServiceFactles: + meta: ServiceMeta + roles: ServiceFactlesRole + config: FactlessConfig = field(default_factory = FactlessConfig) + machines: dict[str, ServiceFactlesMachine] = field(default_factory = dict) + + @dataclass class IwdConfigNetwork: ssid: str @@ -222,6 +255,7 @@ class ServiceSingleDisk: class Service: admin: dict[str, ServiceAdmin] = field(default_factory = dict) borgbackup: dict[str, ServiceBorgbackup] = field(default_factory = dict) + factless: dict[str, ServiceFactles] = field(default_factory = dict) iwd: dict[str, ServiceIwd] = field(default_factory = dict) packages: dict[str, ServicePackage] = field(default_factory = dict) single_disk: dict[str, ServiceSingleDisk] = field(default_factory = dict, metadata = {"alias": "single-disk"}) diff --git a/pkgs/clan-cli/clan_cli/inventory/update.sh b/pkgs/clan-cli/clan_cli/inventory/update.sh new file mode 100755 index 000000000..5d1bf5214 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/inventory/update.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +jsonSchema=$(nix build .#inventory-schema --print-out-paths)/schema.json +nix run .#classgen "$jsonSchema" "$PKG_ROOT/clan_cli/inventory/classes.py" \ No newline at end of file diff --git a/pkgs/installer/flake-module.nix b/pkgs/installer/flake-module.nix index 04cfb96ce..6c0be2bc8 100644 --- a/pkgs/installer/flake-module.nix +++ b/pkgs/installer/flake-module.nix @@ -1,54 +1,62 @@ -{ self, lib, ... }: +{ + self, + lib, + ... +}: let - flashInstallerModule = { config, ... }: + let + suffix = config.clan.core.machine.diskId; + in { imports = [ ./iwd.nix self.nixosModules.installer - # Allow to download pre-build binaries from our nix caches self.clanModules.trusted-nix-caches + self.clanModules.factless ]; + clan.factless = { + diskId = "ac51e4623c804dcbbce0144ed8e16e55"; + }; + system.stateVersion = config.system.nixos.version; nixpkgs.pkgs = self.inputs.nixpkgs.legacyPackages.x86_64-linux; - } - // flashDiskoConfig; - # Important: The partition names need to be different to the clan install - flashDiskoConfig = { - boot.loader.grub.efiSupport = lib.mkDefault true; - boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; - disko.devices = { - disk = { - main = { - type = "disk"; - device = lib.mkDefault "/dev/null"; - content = { - type = "gpt"; - partitions = { - installer-boot = { - size = "1M"; - type = "EF02"; # for grub MBR - priority = 1; - }; - installer-ESP = { - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; + boot.loader.grub.efiSupport = lib.mkDefault true; + boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; + disko.devices = { + disk = { + "main" = { + name = suffix; + type = "disk"; + device = lib.mkDefault "/dev/null"; + content = { + type = "gpt"; + partitions = { + "boot" = { + size = "1M"; + type = "EF02"; # for grub MBR + priority = 1; }; - }; - installer-root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; + "ESP" = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + "root" = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; }; }; }; @@ -56,7 +64,7 @@ let }; }; }; - }; + in { clan = { diff --git a/pkgs/webview-ui/app/src/routes/machines/details.tsx b/pkgs/webview-ui/app/src/routes/machines/details.tsx index 821e9cea6..97444d434 100644 --- a/pkgs/webview-ui/app/src/routes/machines/details.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/details.tsx @@ -112,15 +112,15 @@ const InstallMachine = (props: InstallMachineProps) => { e.preventDefault(); const curr_uri = activeURI(); const disk = getValue(formStore, "disk"); - const disk_id = props.disks.find((d) => d.name === disk)?.id_link; - if (!curr_uri || !disk_id || !props.name) { + const diskId = props.disks.find((d) => d.name === disk)?.id_link; + if (!curr_uri || !diskId || !props.name) { return; } const r = await callApi("set_single_disk_uuid", { base_path: curr_uri, machine_name: props.name, - disk_uuid: disk_id, + disk_uuid: diskId, }); if (r.status === "error") { toast.error("Failed to set disk"); diff --git a/templates/flake-parts/modules/disko.nix b/templates/flake-parts/modules/disko.nix index 474a31c39..6c6ad8790 100644 --- a/templates/flake-parts/modules/disko.nix +++ b/templates/flake-parts/modules/disko.nix @@ -1,10 +1,15 @@ { lib, ... }: + +let + suffix = config.clan.core.machine.diskId; +in { boot.loader.grub.efiSupport = lib.mkDefault true; boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; disko.devices = { disk = { - main = { + "main" = { + name = suffix; type = "disk"; # Set the following in flake.nix for each maschine: # device = ; diff --git a/templates/new-clan/modules/disko.nix b/templates/new-clan/modules/disko.nix index b98423bc5..7a8b8ebc8 100644 --- a/templates/new-clan/modules/disko.nix +++ b/templates/new-clan/modules/disko.nix @@ -1,4 +1,8 @@ { lib, ... }: + +let + suffix = config.clan.core.machine.diskId; +in { # TO NOT EDIT THIS FILE AFTER INSTALLATION of a machine # Otherwise your system might not boot because of missing partitions / filesystems @@ -6,7 +10,8 @@ boot.loader.grub.efiInstallAsRemovable = lib.mkDefault true; disko.devices = { disk = { - main = { + "main" = { + name = suffix; type = "disk"; # Set the following in flake.nix for each maschine: # device = ;