From 8666475b74ecd15bcf546f554c0587f496cd9c8f Mon Sep 17 00:00:00 2001 From: lassulus Date: Fri, 21 Oct 2022 14:43:55 +0200 Subject: tests: pass lib to examples --- example/boot-raid1.nix | 2 +- example/btrfs-subvolumes.nix | 2 +- example/complex.nix | 2 +- example/gpt-bios-compat.nix | 2 +- example/luks-lvm.nix | 2 +- example/lvm-raid.nix | 2 +- example/mdadm.nix | 2 +- example/with-lib.nix | 35 +++++++++++++++++++++++++++++++++++ example/zfs-over-legacy.nix | 2 +- example/zfs.nix | 2 +- tests/lib.nix | 8 ++++---- tests/with-lib.nix | 11 +++++++++++ 12 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 example/with-lib.nix create mode 100644 tests/with-lib.nix diff --git a/example/boot-raid1.nix b/example/boot-raid1.nix index c930eb5..dfd2e6c 100644 --- a/example/boot-raid1.nix +++ b/example/boot-raid1.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { one = { type = "disk"; diff --git a/example/btrfs-subvolumes.nix b/example/btrfs-subvolumes.nix index 9a22861..02ce2a4 100644 --- a/example/btrfs-subvolumes.nix +++ b/example/btrfs-subvolumes.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" ] }: { +{ disks ? [ "/dev/vdb" ], ... }: { disk = { vdb = { type = "disk"; diff --git a/example/complex.nix b/example/complex.nix index 7ee9282..f2204a6 100644 --- a/example/complex.nix +++ b/example/complex.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { disk0 = { type = "disk"; diff --git a/example/gpt-bios-compat.nix b/example/gpt-bios-compat.nix index 72886a0..7275e26 100644 --- a/example/gpt-bios-compat.nix +++ b/example/gpt-bios-compat.nix @@ -1,5 +1,5 @@ # Example to create a bios compatible gpt partition -{ disks ? [ "/dev/vdb" ] }: { +{ disks ? [ "/dev/vdb" ], ... }: { disk = { vdb = { device = builtins.elemAt disks 0; diff --git a/example/luks-lvm.nix b/example/luks-lvm.nix index fdaba8c..8ffb273 100644 --- a/example/luks-lvm.nix +++ b/example/luks-lvm.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" ] }: { +{ disks ? [ "/dev/vdb" ], ... }: { disk = { vdb = { type = "disk"; diff --git a/example/lvm-raid.nix b/example/lvm-raid.nix index 9d0c9d7..8622238 100644 --- a/example/lvm-raid.nix +++ b/example/lvm-raid.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { one = { type = "disk"; diff --git a/example/mdadm.nix b/example/mdadm.nix index 8093698..132ead5 100644 --- a/example/mdadm.nix +++ b/example/mdadm.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { vdb = { type = "disk"; diff --git a/example/with-lib.nix b/example/with-lib.nix new file mode 100644 index 0000000..e746f5b --- /dev/null +++ b/example/with-lib.nix @@ -0,0 +1,35 @@ +# Example to create a bios compatible gpt partition +{ disks ? [ "/dev/vdb" ], lib, ... }: { + disk = lib.traceValSeq (lib.genAttrs [ (lib.head disks) ] (device: { + device = device; + type = "disk"; + content = { + type = "table"; + format = "gpt"; + partitions = [ + { + name = "boot"; + type = "partition"; + start = "0"; + end = "1M"; + part-type = "primary"; + flags = ["bios_grub"]; + } + { + name = "root"; + type = "partition"; + # leave space for the grub aka BIOS boot + start = "1M"; + end = "100%"; + part-type = "primary"; + bootable = true; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + } + ]; + }; + })); +} diff --git a/example/zfs-over-legacy.nix b/example/zfs-over-legacy.nix index 9943278..974af35 100644 --- a/example/zfs-over-legacy.nix +++ b/example/zfs-over-legacy.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { vdb = { type = "disk"; diff --git a/example/zfs.nix b/example/zfs.nix index 92ed688..59c3f24 100644 --- a/example/zfs.nix +++ b/example/zfs.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { disk = { x = { type = "disk"; diff --git a/tests/lib.nix b/tests/lib.nix index fb9d1e9..b3b3009 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -21,10 +21,10 @@ inherit (pkgs) system; }; disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ]; - tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (disko-config { disks = builtins.tail disks; })); - tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (disko-config { disks = builtins.tail disks; })); - tsp-config = (pkgs.callPackage ../. { }).config (disko-config { inherit disks; }); - num-disks = builtins.length (lib.attrNames (disko-config {}).disk); + tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-config = (pkgs.callPackage ../. { }).config (disko-config { inherit disks; inherit lib; }); + num-disks = builtins.length (lib.attrNames (disko-config { inherit lib; }).disk); installed-system = { modulesPath, ... }: { imports = [ tsp-config diff --git a/tests/with-lib.nix b/tests/with-lib.nix new file mode 100644 index 0000000..e94cf00 --- /dev/null +++ b/tests/with-lib.nix @@ -0,0 +1,11 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/with-lib.nix; + extraTestScript = '' + machine.succeed("mountpoint /"); + ''; + efi = false; + grub-devices = [ "/dev/vdb" ]; +} -- cgit v1.2.3 From 89cc8978eb819ee0405e1998ddc02317652fdb3a Mon Sep 17 00:00:00 2001 From: lassulus Date: Fri, 21 Oct 2022 14:44:17 +0200 Subject: types: meta.dependencies -> meta.deviceDependencies --- types.nix | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/types.nix b/types.nix index e830c8d..6d3fcda 100644 --- a/types.nix +++ b/types.nix @@ -81,15 +81,15 @@ rec { }; in valueType; - /* Given a attrset of dependencies and a devices attrset - returns a sorted list by dependencies. aborts if a loop is found + /* Given a attrset of deviceDependencies and a devices attrset + returns a sorted list by deviceDependencies. aborts if a loop is found sortDevicesByDependencies :: AttrSet -> AttrSet -> [ [ str str ] ] */ - sortDevicesByDependencies = dependencies: devices: + sortDevicesByDependencies = deviceDependencies: devices: let dependsOn = a: b: - elem a (attrByPath b [] dependencies); + elem a (attrByPath b [] deviceDependencies); maybeSortedDevices = toposort dependsOn (diskoLib.deviceList devices); in if (hasAttr "cycle" maybeSortedDevices) then @@ -182,7 +182,7 @@ rec { config.devices.mdadm config.devices.zpool ])) // { - sortedDeviceList = diskoLib.sortDevicesByDependencies config.meta.dependencies config.devices; + sortedDeviceList = diskoLib.sortDevicesByDependencies config.meta.deviceDependencies config.devices; }; }; create = mkOption { @@ -514,7 +514,7 @@ rec { readOnly = true; type = types.functionTo diskoLib.jsonType; default = dev: { - dependencies.lvm_vg.${config.vg} = [ dev ]; + deviceDependencies.lvm_vg.${config.vg} = [ dev ]; }; }; _create = mkOption { @@ -673,7 +673,7 @@ rec { readOnly = true; type = types.functionTo diskoLib.jsonType; default = dev: { - dependencies.zpool.${config.pool} = [ dev ]; + deviceDependencies.zpool.${config.pool} = [ dev ]; }; }; _create = mkOption { @@ -957,7 +957,7 @@ rec { readOnly = true; type = types.functionTo diskoLib.jsonType; default = dev: { - dependencies.mdadm.${config.name} = [ dev ]; + deviceDependencies.mdadm.${config.name} = [ dev ]; }; }; _create = mkOption { -- cgit v1.2.3 From 271b00593ff11a36081f5cbbacc3aa4fdc0f5b1a Mon Sep 17 00:00:00 2001 From: lassulus Date: Fri, 21 Oct 2022 22:25:20 +0200 Subject: types: add packages output --- default.nix | 1 + types.nix | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 112 insertions(+), 11 deletions(-) diff --git a/default.nix b/default.nix index 98f5213..00333a8 100644 --- a/default.nix +++ b/default.nix @@ -17,4 +17,5 @@ in { create = cfg: (eval cfg).config.topLevel.create; mount = cfg: (eval cfg).config.topLevel.mount; config = cfg: (eval cfg).config.topLevel.config; + packages = cfg: (eval cfg).config.topLevel.packages; } diff --git a/types.nix b/types.nix index 6d3fcda..818defb 100644 --- a/types.nix +++ b/types.nix @@ -223,6 +223,16 @@ rec { config.devices.zpool ])));}; }; + packages = mkOption { + readOnly = true; + # type = types.functionTo (types.listOf types.package); + default = pkgs: unique (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues [ + config.devices.disk + config.devices.lvm_vg + config.devices.mdadm + config.devices.zpool + ])))); + }; }; }); @@ -290,6 +300,12 @@ rec { }; }]; }; + _pkgs= mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: []; + }; }; }); @@ -358,6 +374,18 @@ rec { }; }]; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + # type = types.functionTo (types.listOf types.package); + default = pkgs: + # TODO add many more + if (config.format == "xfs") then [ pkgs.xfsprogs ] + else if (config.format == "btrfs") then [ pkgs.btrfs-progs ] + else if (config.format == "vfat") then [ pkgs.dosfstools ] + else if (config.format == "ext2") then [ pkgs.e2fsprogs ] + else []; + }; }; }); @@ -411,6 +439,13 @@ rec { default = dev: map (partition: partition._config dev) config.partitions; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: + [ pkgs.parted ] ++ flatten (map (partition: partition._pkgs pkgs) config.partitions); + }; }; }); @@ -497,6 +532,12 @@ rec { default = dev: optional (!isNull config.content) (config.content._config (diskoLib.deviceNumbering dev config.index)); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: optionals (!isNull config.content) (config.content._pkgs pkgs); + }; }; }); @@ -538,6 +579,12 @@ rec { readOnly = true; default = dev: []; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: [ pkgs.lvm2 ]; + }; }; }); @@ -591,6 +638,12 @@ rec { default = map (lv: lv._config config.name) (attrValues config.lvs); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: flatten (map (lv: lv._pkgs pkgs) (attrValues config.lvs)); + }; }; }); @@ -656,6 +709,12 @@ rec { }) ]; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: lib.optionals (!isNull config.content) (config.content._pkgs pkgs); + }; }; }); @@ -696,6 +755,12 @@ rec { readOnly = true; default = dev: []; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: [ pkgs.zfs ]; + }; }; }); @@ -779,17 +844,22 @@ rec { _config = mkOption { internal = true; readOnly = true; - default = - [ - (map (dataset: dataset._config config.name) (attrValues config.datasets)) - (optional (!isNull config.mountpoint) { - fileSystems.${config.mountpoint} = { - device = config.name; - fsType = "zfs"; - options = lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil"; - }; - }) - ]; + default = [ + (map (dataset: dataset._config config.name) (attrValues config.datasets)) + (optional (!isNull config.mountpoint) { + fileSystems.${config.mountpoint} = { + device = config.name; + fsType = "zfs"; + options = lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil"; + }; + }) + ]; + }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: flatten (map (dataset: dataset._pkgs pkgs) (attrValues config.datasets)); }; }; }); @@ -880,6 +950,12 @@ rec { }; }); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: lib.optionals (!isNull config.content) (config.content._pkgs pkgs); + }; }; }); @@ -939,6 +1015,12 @@ rec { default = optional (!isNull config.content) (config.content._config "/dev/md/${config.name}"); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: (lib.optionals (!isNull config.content) (config.content._pkgs pkgs)); + }; }; }); @@ -981,6 +1063,12 @@ rec { readOnly = true; default = dev: []; }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: [ pkgs.mdadm ]; + }; }; }); @@ -1045,6 +1133,12 @@ rec { { boot.initrd.luks.devices.${config.name}.device = dev; } ] ++ (optional (!isNull config.content) (config.content._config "/dev/mapper/${config.name}")); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: [ pkgs.cryptsetup ] ++ (lib.optionals (!isNull config.content) (config.content._pkgs pkgs)); + }; }; }); @@ -1087,6 +1181,12 @@ rec { default = optional (!isNull config.content) (config.content._config config.device); }; + _pkgs = mkOption { + internal = true; + readOnly = true; + type = types.functionTo (types.listOf types.package); + default = pkgs: lib.optionals (!isNull config.content) (config.content._pkgs pkgs); + }; }; }); } -- cgit v1.2.3 From 5aa3ebcb998c1d489926e4f702ee98f5175240e6 Mon Sep 17 00:00:00 2001 From: lassulus Date: Sat, 22 Oct 2022 23:35:16 +0200 Subject: types: refactor topLevel into devices, move output generators to lib --- default.nix | 14 +++---- types.nix | 135 ++++++++++++++++++++++++++---------------------------------- 2 files changed, 66 insertions(+), 83 deletions(-) diff --git a/default.nix b/default.nix index 00333a8..3fe2bbb 100644 --- a/default.nix +++ b/default.nix @@ -4,18 +4,18 @@ let eval = cfg: lib.evalModules { modules = lib.singleton { # _file = toString input; - imports = lib.singleton { topLevel.devices = cfg; }; + imports = lib.singleton { devices = cfg; }; options = { - topLevel = lib.mkOption { - type = types.topLevel; + devices = lib.mkOption { + type = types.devices; }; }; }; }; in { types = types; - create = cfg: (eval cfg).config.topLevel.create; - mount = cfg: (eval cfg).config.topLevel.mount; - config = cfg: (eval cfg).config.topLevel.config; - packages = cfg: (eval cfg).config.topLevel.packages; + create = cfg: types.diskoLib.create (eval cfg).config.devices; + mount = cfg: types.diskoLib.mount (eval cfg).config.devices; + config = cfg: types.diskoLib.config (eval cfg).config.devices; + packages = cfg: types.diskoLib.packages (eval cfg).config.devices; } diff --git a/types.nix b/types.nix index 818defb..db70ede 100644 --- a/types.nix +++ b/types.nix @@ -119,6 +119,51 @@ rec { => "hello world" */ maybeStr = x: optionalString (!isNull x) x; + + /* Takes a disko device specification, returns an attrset with metadata + + meta :: types.devices -> AttrSet + */ + meta = devices: diskoLib.deepMergeMap (dev: dev._meta) (flatten (map attrValues (attrValues devices))); + /* Takes a disko device specification and returns a string which formats the disks + + create :: types.devices -> str + */ + create = devices: let + sortedDeviceList = diskoLib.sortDevicesByDependencies (diskoLib.meta devices).deviceDependencies devices; + in '' + set -efux + ${concatStrings (map (dev: attrByPath (dev ++ [ "_create" ]) "" devices) sortedDeviceList)} + ''; + /* Takes a disko device specification and returns a string which mounts the disks + + mount :: types.devices -> str + */ + mount = devices: let + fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or {}) (flatten (map attrValues (attrValues devices))); + sortedDeviceList = diskoLib.sortDevicesByDependencies (diskoLib.meta devices).deviceDependencies devices; + in '' + set -efux + # first create the neccessary devices + ${concatStrings (map (dev: attrByPath (dev ++ [ "_mount" "dev" ]) "" devices) sortedDeviceList)} + + # and then mount the filesystems in alphabetical order + # attrValues returns values sorted by name. This is important, because it + # ensures that "/" is processed before "/foo" etc. + ${concatStrings (attrValues fsMounts)} + ''; + /* Takes a disko device specification and returns a nixos configuration + + config :: types.devices -> nixosConfig + */ + config = devices: { + imports = flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); + }; + /* Takes a disko device specification and returns a function to get the needed packages to format/mount the disks + + packages :: types.devices -> pkgs -> [ derivation ] + */ + packages = devices: pkgs: unique (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))); }; optionTypes = rec { @@ -152,89 +197,27 @@ rec { }; /* topLevel type of the disko config, takes attrsets of disks mdadms zpools and lvm vgs. - exports create, mount, meta and config */ - topLevel = types.submodule ({ config, ... }: { + devices = types.submodule { options = { - devices = { - disk = mkOption { - type = types.attrsOf disk; - default = {}; - }; - mdadm = mkOption { - type = types.attrsOf mdadm; - default = {}; - }; - zpool = mkOption { - type = types.attrsOf zpool; - default = {}; - }; - lvm_vg = mkOption { - type = types.attrsOf lvm_vg; - default = {}; - }; - }; - meta = mkOption { - readOnly = true; - default = diskoLib.deepMergeMap (dev: dev._meta) (flatten (map attrValues [ - config.devices.disk - config.devices.lvm_vg - config.devices.mdadm - config.devices.zpool - ])) // { - sortedDeviceList = diskoLib.sortDevicesByDependencies config.meta.deviceDependencies config.devices; - }; - }; - create = mkOption { - readOnly = true; - type = types.str; - default = '' - set -efux - ${concatStrings (map (dev: attrByPath (dev ++ [ "_create" ]) "" config.devices) config.meta.sortedDeviceList)} - ''; + disk = mkOption { + type = types.attrsOf disk; + default = {}; }; - mount = mkOption { - readOnly = true; - type = types.str; - default = let - fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or {}) (flatten (map attrValues [ - config.devices.disk - config.devices.lvm_vg - config.devices.mdadm - config.devices.zpool - ])); - in '' - set -efux - # first create the neccessary devices - ${concatStrings (map (dev: attrByPath (dev ++ [ "_mount" "dev" ]) "" config.devices) config.meta.sortedDeviceList)} - - # and then mount the filesystems in alphabetical order - # attrValues returns values sorted by name. This is important, because it - # ensures that "/" is processed before "/foo" etc. - ${concatStrings (attrValues fsMounts)} - ''; + mdadm = mkOption { + type = types.attrsOf mdadm; + default = {}; }; - config = mkOption { - readOnly = true; - default = { imports = flatten (map (dev: dev._config) (flatten (map attrValues [ - config.devices.disk - config.devices.lvm_vg - config.devices.mdadm - config.devices.zpool - ])));}; + zpool = mkOption { + type = types.attrsOf zpool; + default = {}; }; - packages = mkOption { - readOnly = true; - # type = types.functionTo (types.listOf types.package); - default = pkgs: unique (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues [ - config.devices.disk - config.devices.lvm_vg - config.devices.mdadm - config.devices.zpool - ])))); + lvm_vg = mkOption { + type = types.attrsOf lvm_vg; + default = {}; }; }; - }); + }; btrfs = types.submodule ({ config, ... }: { options = { -- cgit v1.2.3 From 3c4cc930077f88fd1bb6331e26dcbcf7efa7478e Mon Sep 17 00:00:00 2001 From: lassulus Date: Sun, 23 Oct 2022 11:30:08 +0200 Subject: export config list in types --- default.nix | 2 +- types.nix | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/default.nix b/default.nix index 3fe2bbb..4a81f03 100644 --- a/default.nix +++ b/default.nix @@ -16,6 +16,6 @@ in { types = types; create = cfg: types.diskoLib.create (eval cfg).config.devices; mount = cfg: types.diskoLib.mount (eval cfg).config.devices; - config = cfg: types.diskoLib.config (eval cfg).config.devices; + config = cfg: { imports = types.diskoLib.config (eval cfg).config.devices; }; packages = cfg: types.diskoLib.packages (eval cfg).config.devices; } diff --git a/types.nix b/types.nix index db70ede..6c35de6 100644 --- a/types.nix +++ b/types.nix @@ -156,9 +156,7 @@ rec { config :: types.devices -> nixosConfig */ - config = devices: { - imports = flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); - }; + config = devices: flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); /* Takes a disko device specification and returns a function to get the needed packages to format/mount the disks packages :: types.devices -> pkgs -> [ derivation ] -- cgit v1.2.3 From 87e93073ac762993a0bf27bc65af570226586ae5 Mon Sep 17 00:00:00 2001 From: lassulus Date: Sun, 23 Oct 2022 11:30:50 +0200 Subject: example complex: fix default value --- example/complex.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/complex.nix b/example/complex.nix index f2204a6..b3fb951 100644 --- a/example/complex.nix +++ b/example/complex.nix @@ -1,4 +1,4 @@ -{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: { +{ disks ? [ "/dev/vdb" "/dev/vdc" "/dev/vdd" ], ... }: { disk = { disk0 = { type = "disk"; -- cgit v1.2.3 From c777d1ca4ff0f759a6517eb2a4d7e9bae1fa9fd2 Mon Sep 17 00:00:00 2001 From: lassulus Date: Sun, 23 Oct 2022 12:29:13 +0200 Subject: tests: add simple-efi --- example/simple-efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ tests/simple-efi.nix | 9 +++++++++ 2 files changed, 49 insertions(+) create mode 100644 example/simple-efi.nix create mode 100644 tests/simple-efi.nix diff --git a/example/simple-efi.nix b/example/simple-efi.nix new file mode 100644 index 0000000..c69c847 --- /dev/null +++ b/example/simple-efi.nix @@ -0,0 +1,40 @@ +{ disks ? [ "/dev/vdb" ], ... }: { + disk = { + vdb = { + device = builtins.elemAt disks 0; + type = "disk"; + content = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + name = "ESP"; + start = "1MiB"; + end = "100MiB"; + bootable = true; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + } + { + name = "root"; + type = "partition"; + start = "100MiB"; + end = "100%"; + part-type = "primary"; + bootable = true; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + } + ]; + }; + }; + }; +} + diff --git a/tests/simple-efi.nix b/tests/simple-efi.nix new file mode 100644 index 0000000..2d3b92d --- /dev/null +++ b/tests/simple-efi.nix @@ -0,0 +1,9 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = import ../example/simple-efi.nix; + extraTestScript = '' + machine.succeed("mountpoint /"); + ''; +} -- cgit v1.2.3 From 4184cbcd037b79ed627aca20798810518cb328ac Mon Sep 17 00:00:00 2001 From: lassulus Date: Sun, 23 Oct 2022 12:29:30 +0200 Subject: add module --- README.md | 194 ++++++++++++++++++++++++++++++++++++++++--------------------- flake.nix | 1 + module.nix | 43 ++++++++++++++ 3 files changed, 171 insertions(+), 67 deletions(-) create mode 100644 module.nix diff --git a/README.md b/README.md index eb06ac8..f448455 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,140 @@ -disko -===== +# disko -nix-powered automatic disk partitioning +nix-powered automatic disk partitioning. partition your disks declaratively NixOS style. -Usage -===== +## Installing NixOS module -Master Boot Record ------------------- -This is how your iso configuation may look like +You can use the NixOS module in one of the following ways: + +### Flakes + +If you use nix flakes support: + +``` nix +{ + inputs.disko.url = "github:nix-community/disko"; + inputs.disko.inputs.nixpkgs.follows = "nixpkgs"; + + outputs = { self, nixpkgs, disko }: { + # change `yourhostname` to your actual hostname + nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem { + # change to your system: + system = "x86_64-linux"; + modules = [ + ./configuration.nix + disko.nixosModules.disko + ]; + }; + }; +} +``` + +### [niv](https://github.com/nmattia/niv) (Current recommendation) + First add it to niv: + +```console +$ niv add nix-community/disko +``` + + Then add the following to your configuration.nix in the `imports` list: -/etc/nixos/configuration.nix ```nix -{ pkgs, modulesPath, ... }: -let - disko = pkgs.callPackage (builtins.fetchGit { - url = "https://github.com/nix-community/disko"; - ref = "master"; - }) {}; - cfg = { - disk = { - sda = { - device = "/dev/sda"; - type = "device"; - content = { - type = "table"; - format = "msdos"; - partitions = [ - { - name = "root"; - type = "partition"; - part-type = "primary"; - start = "1M"; - end = "100%"; - bootable = true; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - } - ]; - }; +{ + imports = [ "${(import ./nix/sources.nix).disko}/modules/disko.nix" ]; +} +``` + +### nix-channel + + As root run: + +```console +$ nix-channel --add https://github.com/nix-community/disko/archive/main.tar.gz disko +$ nix-channel --update +``` + + Then add the following to your configuration.nix in the `imports` list: + +```nix +{ + imports = [ ]; +} +``` + +### fetchTarball + + Add the following to your configuration.nix: + +``` nix +{ + imports = [ "${builtins.fetchTarball "https://github.com/nix-community/disko/archive/main.tar.gz"}/modules/disko.nix" ]; +} +``` + + or with pinning: + +```nix +{ + imports = let + # replace this with an actual commit id or tag + commit = "f2783a8ef91624b375a3cf665c3af4ac60b7c278"; + in [ + "${builtins.fetchTarball { + url = "https://github.com/nix-community/disko/archive/${commit}.tar.gz"; + # replace this with an actual hash + sha256 = "0000000000000000000000000000000000000000000000000000"; + }}/module.nix" + ]; +} +``` + +## Using the NixOS module + +```nix +{ + # checkout the example folder for how to configure different diska layouts + disko.devices = { + disk.sda = { + device = "/dev/sda"; + type = "disk"; + content = { + type = "table"; + format = "gpt"; + partitions = [ + { + type = "partition"; + name = "ESP"; + start = "1MiB"; + end = "100MiB"; + bootable = true; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + } + { + name = "root"; + type = "partition"; + start = "100MiB"; + end = "100%"; + part-type = "primary"; + bootable = true; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + } + ]; }; }; }; -in { - imports = [ - (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") - ]; - environment.systemPackages = with pkgs;[ - (pkgs.writeScriptBin "tsp-create" (disko.create cfg)) - (pkgs.writeScriptBin "tsp-mount" (disko.mount cfg)) - ]; - ## Optional: Automatically creates a service which runs at startup to perform the partitioning - #systemd.services.install-to-hd = { - # enable = true; - # wantedBy = ["multi-user.target"]; - # after = ["getty@tty1.service" ]; - # serviceConfig = { - # Type = "oneshot"; - # ExecStart = [ (disko.create cfg) (disk.mount cfg) ]; - # StandardInput = "null"; - # StandardOutput = "journal+console"; - # StandardError = "inherit"; - # }; - #}; } ``` -After `nixos-rebuild switch` this will add a `tsp-create` and a `tsp-mount` -command: +this will configure `fileSystems` and other required NixOS options to boot the specified configuration. -- **tsp-create**: creates & formats the partitions according to `tsp-disk.json` -- **tsp-mount**: mounts the partitions to `/mnt` +If you are on an installer, you probably want to disable `enableConfig`. -GUID Partition Table, LVM and dm-crypt --------------------------------------- -See `examples/` +disko will create the scripts `disko-create` and `disko-mount` which can be used to create/mount the configured disk layout. diff --git a/flake.nix b/flake.nix index cdc5a4c..c06834f 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,7 @@ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; outputs = { self, nixpkgs, ... }: { + nixosModules.disko = import ./module.nix; lib = import ./. { inherit (nixpkgs) lib; }; diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..611d681 --- /dev/null +++ b/module.nix @@ -0,0 +1,43 @@ +{ config, lib, pkgs, ... }: +let + types = import ./types.nix { inherit lib; }; + cfg = config.disko; +in { + options.disko = { + devices = lib.mkOption { + type = types.devices; + }; + enableConfig = lib.mkOption { + description = '' + configure nixos with the specified devices + should be true if the system is booted with those devices + should be false on an installer image etc. + ''; + type = lib.types.bool; + default = true; + }; + addScripts = lib.mkOption { + description = '' + add disko-create and disko-mount scripts to systemPackages. + ''; + type = lib.types.bool; + default = true; + }; + }; + config = { + environment.systemPackages = (lib.optionals cfg.addScripts [ + (pkgs.writers.writeDashBin "disko-create" '' + export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)} + ${types.diskoLib.create cfg.devices} + '') + (pkgs.writers.writeDashBin "disko-mount" '' + export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)} + ${types.diskoLib.mount cfg.devices} + '') + ]) ++ lib.optionals cfg.enableConfig (types.diskoLib.packages cfg.devices pkgs); + + # Remember to add config keys here if they are added to types + fileSystems = lib.mkIf cfg.enableConfig (lib.mkMerge (lib.catAttrs "fileSystems" (types.diskoLib.config cfg.devices))); + boot = lib.mkIf cfg.enableConfig (lib.mkMerge (lib.catAttrs "boot" (types.diskoLib.config cfg.devices))); + }; +} -- cgit v1.2.3 From 324a8d5347a18e0c74625903c3bb13144370fbf2 Mon Sep 17 00:00:00 2001 From: lassulus Date: Thu, 27 Oct 2022 00:02:37 +0200 Subject: disko: add scripts with pkgs --- default.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/default.nix b/default.nix index 4a81f03..fdbe43d 100644 --- a/default.nix +++ b/default.nix @@ -15,7 +15,15 @@ let in { types = types; create = cfg: types.diskoLib.create (eval cfg).config.devices; + createScript = pkgs: cfg: pkgs.writeScript "disko-create" '' + export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)} + ${types.diskoLib.create (eval cfg).config.devices} + ''; mount = cfg: types.diskoLib.mount (eval cfg).config.devices; + mountScript = pkgs: cfg: pkgs.writeScript "disko-mount" '' + export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)} + ${types.diskoLib.mount (eval cfg).config.devices} + ''; config = cfg: { imports = types.diskoLib.config (eval cfg).config.devices; }; packages = cfg: types.diskoLib.packages (eval cfg).config.devices; } -- cgit v1.2.3 From f1531fb4f3f8052181964d17891fbb3ce1f918f7 Mon Sep 17 00:00:00 2001 From: lassulus Date: Thu, 27 Oct 2022 00:02:49 +0200 Subject: add disko cli --- cli.nix | 15 ++++++++++++++ default.nix | 4 ++-- disko | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 cli.nix create mode 100755 disko diff --git a/cli.nix b/cli.nix new file mode 100644 index 0000000..76e0971 --- /dev/null +++ b/cli.nix @@ -0,0 +1,15 @@ +{ pkgs ? import {} +, mode ? "mount" +, diskoFile +, ... }@args: +let + disko = import ./. {}; + diskFormat = import diskoFile args; + diskoEval = if (mode == "create") then + disko.createScript diskFormat pkgs + else if (mode == "mount") then + disko.mountScript diskFormat pkgs + else + builtins.abort "invalid mode" + ; +in diskoEval diff --git a/default.nix b/default.nix index fdbe43d..8d91e7c 100644 --- a/default.nix +++ b/default.nix @@ -15,12 +15,12 @@ let in { types = types; create = cfg: types.diskoLib.create (eval cfg).config.devices; - createScript = pkgs: cfg: pkgs.writeScript "disko-create" '' + createScript = cfg: pkgs: pkgs.writeScript "disko-create" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)} ${types.diskoLib.create (eval cfg).config.devices} ''; mount = cfg: types.diskoLib.mount (eval cfg).config.devices; - mountScript = pkgs: cfg: pkgs.writeScript "disko-mount" '' + mountScript = cfg: pkgs: pkgs.writeScript "disko-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)} ${types.diskoLib.mount (eval cfg).config.devices} ''; diff --git a/disko b/disko new file mode 100755 index 0000000..c5b9d49 --- /dev/null +++ b/disko @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail +set -x + +readonly libexec_dir="${0%/*}" + +# mount was chosen as the default mode because it's less destructive +mode=mount +nix_args=() + +showUsage() { + cat <&2 + exit 1 +} + +## Main ## + +while [[ $# -gt 0 ]]; do + case "$1" in + -m | --mode) + mode=$2 + shift + ;; + --argstr | --arg) + nix_args+=("$1" "$2" "$3") + shift + shift + ;; + --help) + showUsage + exit 0 + ;; + *) + if [ -z ${disko_config+x} ] && [ -e $1 ]; then + disko_config=$1 + else + showUsage + fi + ;; + esac + shift +done + +if ! ([[ $mode = "create" ]] || [[ $mode = "mount" ]]); then + abort "mode must be either create or mount" +fi + +script=$(nix-build "${libexec_dir}"/cli.nix \ + --arg diskoFile "$disko_config" \ + --argstr mode "$mode" \ + "${nix_args[@]}" +) +exec "$script" -- cgit v1.2.3 From fec0b14fb5b9204bbc92eb5fa0f0f60bba2815f6 Mon Sep 17 00:00:00 2001 From: lassulus Date: Sat, 29 Oct 2022 13:19:29 +0200 Subject: add tests for module and cli --- tests/boot-raid1.nix | 2 +- tests/btrfs-subvolumes.nix | 2 +- tests/cli.nix | 28 +++++++++++++++++++++++ tests/complex.nix | 2 +- tests/gpt-bios-compat.nix | 2 +- tests/lib.nix | 56 +++++++++++++++++++++++++++++++++++++++------- tests/luks-lvm.nix | 2 +- tests/lvm-raid.nix | 2 +- tests/mdadm.nix | 2 +- tests/module.nix | 28 +++++++++++++++++++++++ tests/simple-efi.nix | 2 +- tests/with-lib.nix | 2 +- tests/zfs-over-legacy.nix | 2 +- tests/zfs.nix | 2 +- 14 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 tests/cli.nix create mode 100644 tests/module.nix diff --git a/tests/boot-raid1.nix b/tests/boot-raid1.nix index 6d0a563..bea9adb 100644 --- a/tests/boot-raid1.nix +++ b/tests/boot-raid1.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/boot-raid1.nix; + disko-config = ../example/boot-raid1.nix; extraTestScript = '' machine.succeed("test -b /dev/md/boot"); machine.succeed("mountpoint /boot"); diff --git a/tests/btrfs-subvolumes.nix b/tests/btrfs-subvolumes.nix index e53cf34..1a62702 100644 --- a/tests/btrfs-subvolumes.nix +++ b/tests/btrfs-subvolumes.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/btrfs-subvolumes.nix; + disko-config = ../example/btrfs-subvolumes.nix; extraTestScript = '' machine.succeed("test -e /test"); machine.succeed("btrfs subvolume list / | grep -qs 'path test$'"); diff --git a/tests/cli.nix b/tests/cli.nix new file mode 100644 index 0000000..24eb24c --- /dev/null +++ b/tests/cli.nix @@ -0,0 +1,28 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = ../example/complex.nix; + extraConfig = { + fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this! + }; + testMode = "cli"; + extraTestScript = '' + machine.succeed("test -b /dev/zroot/zfs_testvolume"); + machine.succeed("test -b /dev/md/raid1p1"); + + + machine.succeed("mountpoint /zfs_fs"); + machine.succeed("mountpoint /zfs_legacy_fs"); + machine.succeed("mountpoint /ext4onzfs"); + machine.succeed("mountpoint /ext4_on_lvm"); + ''; + enableOCR = true; + bootCommands = '' + machine.wait_for_text("Passphrase for") + machine.send_chars("secret\n") + ''; + extraConfig = { + boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + }; +} diff --git a/tests/complex.nix b/tests/complex.nix index cd87b3b..5fe5efa 100644 --- a/tests/complex.nix +++ b/tests/complex.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/complex.nix; + disko-config = ../example/complex.nix; extraConfig = { fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this! }; diff --git a/tests/gpt-bios-compat.nix b/tests/gpt-bios-compat.nix index d9317f9..e19c49a 100644 --- a/tests/gpt-bios-compat.nix +++ b/tests/gpt-bios-compat.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/gpt-bios-compat.nix; + disko-config = ../example/gpt-bios-compat.nix; extraTestScript = '' machine.succeed("mountpoint /"); ''; diff --git a/tests/lib.nix b/tests/lib.nix index b3b3009..b9e75dd 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -12,6 +12,7 @@ , grub-devices ? [ "nodev" ] , efi ? true , enableOCR ? false + , testMode ? "direct" # can be one of direct module cli }: let lib = pkgs.lib; @@ -21,13 +22,21 @@ inherit (pkgs) system; }; disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ]; - tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-config = (pkgs.callPackage ../. { }).config (disko-config { inherit disks; inherit lib; }); - num-disks = builtins.length (lib.attrNames (disko-config { inherit lib; }).disk); + tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (import disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (import disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-config = (pkgs.callPackage ../. { }).config (import disko-config { inherit disks; inherit lib; }); + num-disks = builtins.length (lib.attrNames (import disko-config { inherit lib; }).disk); installed-system = { modulesPath, ... }: { imports = [ - tsp-config + (lib.optionalAttrs (testMode == "direct" || testMode == "cli") tsp-config) + (lib.optionalAttrs (testMode == "module") { + imports = [ ../module.nix ]; + disko = { + addScripts = false; + enableConfig = true; + devices = import disko-config { inherit disks lib; }; + }; + }) (modulesPath + "/testing/test-instrumentation.nix") (modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/profiles/minimal.nix") @@ -63,6 +72,21 @@ inherit enableOCR; nodes.machine = { config, pkgs, modulesPath, ... }: { imports = [ + (lib.optionalAttrs (testMode == "module") { + imports = [ ../module.nix ]; + disko = { + addScripts = true; + enableConfig = false; + devices = import disko-config { disks = builtins.tail disks; inherit lib; }; + }; + }) + (lib.optionalAttrs (testMode == "cli") { + imports = [ (modulesPath + "/installer/cd-dvd/channel.nix") ]; + system.extraDependencies = [ + ((pkgs.callPackage ../. { }).createScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ((pkgs.callPackage ../. { }).mountScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ]; + }) (modulesPath + "/profiles/base.nix") (modulesPath + "/profiles/minimal.nix") extraConfig @@ -97,9 +121,25 @@ machine.start() machine.succeed("echo -n 'secret' > /tmp/secret.key") - machine.succeed("${tsp-create}") - machine.succeed("${tsp-mount}") - machine.succeed("${tsp-mount}") # verify that the command is idempotent + ${lib.optionalString (testMode == "direct") '' + machine.succeed("${tsp-create}") + machine.succeed("${tsp-mount}") + machine.succeed("${tsp-mount}") # verify that the command is idempotent + ''} + ${lib.optionalString (testMode == "module") '' + machine.succeed("disko-create") + machine.succeed("disko-mount") + machine.succeed("disko-mount") # verify that the command is idempotent + ''} + ${lib.optionalString (testMode == "cli") '' + # TODO use the disko cli here + # machine.succeed("${../.}/disko --no-pkgs --mode create ${disko-config}") + # machine.succeed("${../.}/disko --no-pkgs --mode mount ${disko-config}") + # machine.succeed("${../.}/disko --no-pkgs --mode mount ${disko-config}") # verify that the command is idempotent + machine.succeed("${tsp-create}") + machine.succeed("${tsp-mount}") + machine.succeed("${tsp-mount}") # verify that the command is idempotent + ''} # mount nix-store in /mnt machine.succeed("mkdir -p /mnt/nix/store") diff --git a/tests/luks-lvm.nix b/tests/luks-lvm.nix index 1a3dc66..05d3362 100644 --- a/tests/luks-lvm.nix +++ b/tests/luks-lvm.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/luks-lvm.nix; + disko-config = ../example/luks-lvm.nix; extraTestScript = '' machine.succeed("cryptsetup isLuks /dev/vda2"); machine.succeed("mountpoint /home"); diff --git a/tests/lvm-raid.nix b/tests/lvm-raid.nix index 1249b7b..cc73e61 100644 --- a/tests/lvm-raid.nix +++ b/tests/lvm-raid.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/lvm-raid.nix; + disko-config = ../example/lvm-raid.nix; extraTestScript = '' machine.succeed("mountpoint /home"); ''; diff --git a/tests/mdadm.nix b/tests/mdadm.nix index 74a7d5d..2b4442a 100644 --- a/tests/mdadm.nix +++ b/tests/mdadm.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/mdadm.nix; + disko-config = ../example/mdadm.nix; extraTestScript = '' machine.succeed("test -b /dev/md/raid1"); machine.succeed("mountpoint /"); diff --git a/tests/module.nix b/tests/module.nix new file mode 100644 index 0000000..ef3b88e --- /dev/null +++ b/tests/module.nix @@ -0,0 +1,28 @@ +{ pkgs ? (import { }) +, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest +}: +makeDiskoTest { + disko-config = ../example/complex.nix; + extraConfig = { + fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this! + }; + testMode = "module"; + extraTestScript = '' + machine.succeed("test -b /dev/zroot/zfs_testvolume"); + machine.succeed("test -b /dev/md/raid1p1"); + + + machine.succeed("mountpoint /zfs_fs"); + machine.succeed("mountpoint /zfs_legacy_fs"); + machine.succeed("mountpoint /ext4onzfs"); + machine.succeed("mountpoint /ext4_on_lvm"); + ''; + enableOCR = true; + bootCommands = '' + machine.wait_for_text("Passphrase for") + machine.send_chars("secret\n") + ''; + extraConfig = { + boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + }; +} diff --git a/tests/simple-efi.nix b/tests/simple-efi.nix index 2d3b92d..920920f 100644 --- a/tests/simple-efi.nix +++ b/tests/simple-efi.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/simple-efi.nix; + disko-config = ../example/simple-efi.nix; extraTestScript = '' machine.succeed("mountpoint /"); ''; diff --git a/tests/with-lib.nix b/tests/with-lib.nix index e94cf00..18c422b 100644 --- a/tests/with-lib.nix +++ b/tests/with-lib.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/with-lib.nix; + disko-config = ../example/with-lib.nix; extraTestScript = '' machine.succeed("mountpoint /"); ''; diff --git a/tests/zfs-over-legacy.nix b/tests/zfs-over-legacy.nix index 50e3796..09505e5 100644 --- a/tests/zfs-over-legacy.nix +++ b/tests/zfs-over-legacy.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/zfs-over-legacy.nix; + disko-config = ../example/zfs-over-legacy.nix; extraTestScript = '' machine.succeed("test -e /zfs_fs"); machine.succeed("mountpoint /zfs_fs"); diff --git a/tests/zfs.nix b/tests/zfs.nix index 78b64bd..d88070e 100644 --- a/tests/zfs.nix +++ b/tests/zfs.nix @@ -2,7 +2,7 @@ , makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest }: makeDiskoTest { - disko-config = import ../example/zfs.nix; + disko-config = ../example/zfs.nix; extraConfig = { fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this! }; -- cgit v1.2.3 From 1ddeb716b6dc3f609c87f6d672ae6977fb0b74e0 Mon Sep 17 00:00:00 2001 From: lassulus Date: Sat, 29 Oct 2022 13:19:39 +0200 Subject: types: add more packages --- types.nix | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/types.nix b/types.nix index 6c35de6..2dd2151 100644 --- a/types.nix +++ b/types.nix @@ -360,12 +360,16 @@ rec { readOnly = true; # type = types.functionTo (types.listOf types.package); default = pkgs: - # TODO add many more - if (config.format == "xfs") then [ pkgs.xfsprogs ] - else if (config.format == "btrfs") then [ pkgs.btrfs-progs ] - else if (config.format == "vfat") then [ pkgs.dosfstools ] - else if (config.format == "ext2") then [ pkgs.e2fsprogs ] - else []; + [ pkgs.util-linux ] ++ ( + # TODO add many more + if (config.format == "xfs") then [ pkgs.xfsprogs ] + else if (config.format == "btrfs") then [ pkgs.btrfs-progs ] + else if (config.format == "vfat") then [ pkgs.dosfstools ] + else if (config.format == "ext2") then [ pkgs.e2fsprogs ] + else if (config.format == "ext3") then [ pkgs.e2fsprogs ] + else if (config.format == "ext4") then [ pkgs.e2fsprogs ] + else [] + ); }; }; }); @@ -425,7 +429,7 @@ rec { readOnly = true; type = types.functionTo (types.listOf types.package); default = pkgs: - [ pkgs.parted ] ++ flatten (map (partition: partition._pkgs pkgs) config.partitions); + [ pkgs.parted pkgs.systemdMinimal ] ++ flatten (map (partition: partition._pkgs pkgs) config.partitions); }; }; }); @@ -840,7 +844,7 @@ rec { internal = true; readOnly = true; type = types.functionTo (types.listOf types.package); - default = pkgs: flatten (map (dataset: dataset._pkgs pkgs) (attrValues config.datasets)); + default = pkgs: [ pkgs.util-linux ] ++ flatten (map (dataset: dataset._pkgs pkgs) (attrValues config.datasets)); }; }; }); @@ -935,7 +939,7 @@ rec { internal = true; readOnly = true; type = types.functionTo (types.listOf types.package); - default = pkgs: lib.optionals (!isNull config.content) (config.content._pkgs pkgs); + default = pkgs: [ pkgs.util-linux ] ++ lib.optionals (!isNull config.content) (config.content._pkgs pkgs); }; }; }); -- cgit v1.2.3 From f82656afbd5dafe1a0f762bdb7678a62203158b0 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Wed, 2 Nov 2022 18:58:36 +0100 Subject: WIP docs Based on https://documentation.divio.com/ --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f448455..20dea6f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,48 @@ -# disko +# disko - declarative disk partitioning -nix-powered automatic disk partitioning. partition your disks declaratively NixOS style. +Disko takes the NixOS module system and makes it work for disk partitioning +as well. + +I wanted to write a curses NixOS installer, and that was the first step that I +hit; the disk formatting is a manual process. Once that's done, the NixOS +system itself is declarative, but the actual formatting of disks is manual. + +## Features + +* supports LVM, ZFS, btrfs, GPT, mdadm, ext4, ... +* supports recursive layouts +* outputs a NixOS-compatible module +* CLI + +## How-to guides + +### NixOS installation + +During the NixOS installation process, replace the [Partitioning and +formatting](https://nixos.org/manual/nixos/stable/index.html#sec-installation-partitioning) +steps with the following: + +1. Find a disk layout in ./examples that you like. +2. Write the config based on the example and your disk layout. +4. Run the CLI (`nix run github:nix-community/disko`) to apply the changes. +5. FIXME: Copy the disko module and disk layout around. +6. Continue the NixOS installation. + +### Using without NixOS + +## Reference + +### Module options + +TODO: link to generated module options + +### Examples + +./examples + +### CLI + +TODO: output of the cli --help ## Installing NixOS module -- cgit v1.2.3 From 2a59af78a8e2e7ab6fc7a4be3671da0c19a8806c Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sat, 5 Nov 2022 14:25:08 -0500 Subject: fix: add package build and fix disko --- Makefile | 15 +++++++++++++++ disko | 12 ++++++++++-- flake.nix | 9 +++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d01f5bf --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +PREFIX ?= /usr/local +SHARE ?= $(PREFIX)/share/disko + +all: + +SOURCES = disko cli.nix default.nix types.nix + +install: + mkdir -p $(PREFIX)/bin $(SHARE) + sed \ + -e "s|libexec_dir=\".*\"|libexec_dir=\"$(SHARE)\"|" \ + -e "s|#!/usr/bin/env.*|#!/usr/bin/env bash|" \ + disko > $(PREFIX)/bin/disko + chmod 755 $(PREFIX)/bin/disko + cp -r $(SOURCES) $(SHARE) diff --git a/disko b/disko index c5b9d49..f51339e 100755 --- a/disko +++ b/disko @@ -1,9 +1,11 @@ #!/usr/bin/env bash set -euo pipefail -set -x readonly libexec_dir="${0%/*}" +# a file with the disko config +declare disko_config + # mount was chosen as the default mode because it's less destructive mode=mount nix_args=() @@ -30,6 +32,11 @@ abort() { ## Main ## +[[ $# -eq 0 ]] && { + showUsage + exit 1 +} + while [[ $# -gt 0 ]]; do case "$1" in -m | --mode) @@ -46,10 +53,11 @@ while [[ $# -gt 0 ]]; do exit 0 ;; *) - if [ -z ${disko_config+x} ] && [ -e $1 ]; then + if [ -z ${disko_config+x} ] && [ -e "$1" ]; then disko_config=$1 else showUsage + exit 1 fi ;; esac diff --git a/flake.nix b/flake.nix index c06834f..adb2add 100644 --- a/flake.nix +++ b/flake.nix @@ -8,6 +8,15 @@ lib = import ./. { inherit (nixpkgs) lib; }; + packages.x86_64-linux.disko = let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + in pkgs.stdenv.mkDerivation { + name = "disko"; + src = ./.; + meta.description = "Format disks with nix-config"; + installFlags = [ "PREFIX=$(out)" ]; + }; + packages.x86_64-linux.default = self.packages.x86_64-linux.disko; checks.x86_64-linux = let pkgs = nixpkgs.legacyPackages.x86_64-linux; in -- cgit v1.2.3 From 15b62fd7a1b6500cc4ee039550297640e86c8383 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sat, 5 Nov 2022 22:29:28 -0500 Subject: fix: expect normal disko-config module files --- cli.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli.nix b/cli.nix index 76e0971..f99ad61 100644 --- a/cli.nix +++ b/cli.nix @@ -3,8 +3,8 @@ , diskoFile , ... }@args: let - disko = import ./. {}; - diskFormat = import diskoFile args; + disko = import ./. { inherit (pkgs) lib; }; + diskFormat = import diskoFile; diskoEval = if (mode == "create") then disko.createScript diskFormat pkgs else if (mode == "mount") then -- cgit v1.2.3 From fa17cfe8782b51f39900cb216cb44c6cc6747856 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sun, 6 Nov 2022 00:12:15 -0500 Subject: feat: trim the build to the minimum on a slow finicky target machine, no time to pull gcc --- Makefile | 15 --------------- flake.nix | 32 +++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index d01f5bf..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -PREFIX ?= /usr/local -SHARE ?= $(PREFIX)/share/disko - -all: - -SOURCES = disko cli.nix default.nix types.nix - -install: - mkdir -p $(PREFIX)/bin $(SHARE) - sed \ - -e "s|libexec_dir=\".*\"|libexec_dir=\"$(SHARE)\"|" \ - -e "s|#!/usr/bin/env.*|#!/usr/bin/env bash|" \ - disko > $(PREFIX)/bin/disko - chmod 755 $(PREFIX)/bin/disko - cp -r $(SOURCES) $(SHARE) diff --git a/flake.nix b/flake.nix index adb2add..cd955a2 100644 --- a/flake.nix +++ b/flake.nix @@ -9,12 +9,38 @@ inherit (nixpkgs) lib; }; packages.x86_64-linux.disko = let + inherit (nixpkgs) lib; pkgs = nixpkgs.legacyPackages.x86_64-linux; - in pkgs.stdenv.mkDerivation { + inclFiles = {src, name}: files: lib.cleanSourceWith { + inherit src name; + filter = _path: _type: _type == "regular" + && lib.any (file: builtins.baseNameOf _path == file) files; + }; + in derivation rec{ + system = "x86_64-linux"; name = "disko"; - src = ./.; + builder = "/bin/sh"; + PATH = "${pkgs.coreutils}/bin:${pkgs.gnused}/bin"; + passAsFile = ["buildPhase"]; + buildPhase = '' + mkdir -p $out/bin $out/share/disko + cp -r $src/* $out/share/disko + sed \ + -e "s|libexec_dir=\".*\"|libexec_dir=\"$out/share/disko\"|" \ + -e "s|#!/usr/bin/env.*|#!/usr/bin/env bash|" \ + $src/disko > $out/bin/disko + chmod 755 $out/bin/disko + ''; + args = ["-c" ". $buildPhasePath"]; + src = inclFiles { inherit name; src = ./.; } [ + "disko" + "cli.nix" + "default.nix" + "types.nix" + "options.nix" + ]; + } // { meta.description = "Format disks with nix-config"; - installFlags = [ "PREFIX=$(out)" ]; }; packages.x86_64-linux.default = self.packages.x86_64-linux.disko; checks.x86_64-linux = let -- cgit v1.2.3 From a023d391a08f8c8b1b7c26fcbb8d06edd5ceb203 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sun, 6 Nov 2022 00:30:18 -0500 Subject: feat: reuse the pre-installed channel --- flake.lock | 27 --------------------------- flake.nix | 5 +++-- 2 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 flake.lock diff --git a/flake.lock b/flake.lock deleted file mode 100644 index d99ebe5..0000000 --- a/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1660646295, - "narHash": "sha256-V4G+egGRc3elXPTr7QLJ7r7yrYed0areIKDiIAlMLC8=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "762b003329510ea855b4097a37511eb19c7077f0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix index cd955a2..dd065cf 100644 --- a/flake.nix +++ b/flake.nix @@ -1,7 +1,8 @@ { description = "Description for the project"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # don't lock to give precedence to a USB live-installer's registry + inputs.nixpkgs.url = "nixpkgs"; outputs = { self, nixpkgs, ... }: { nixosModules.disko = import ./module.nix; @@ -9,8 +10,8 @@ inherit (nixpkgs) lib; }; packages.x86_64-linux.disko = let - inherit (nixpkgs) lib; pkgs = nixpkgs.legacyPackages.x86_64-linux; + inherit (pkgs) lib; inclFiles = {src, name}: files: lib.cleanSourceWith { inherit src name; filter = _path: _type: _type == "regular" -- cgit v1.2.3 From 0af2a7c206bd69ecdc01361e12c7cb0ec9820911 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Sun, 6 Nov 2022 01:46:48 -0500 Subject: feat: allow to declare disko-config relative to flake --- cli.nix | 8 ++++++-- disko | 22 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cli.nix b/cli.nix index f99ad61..ed80160 100644 --- a/cli.nix +++ b/cli.nix @@ -1,10 +1,14 @@ { pkgs ? import {} , mode ? "mount" +, fromFlake ? null , diskoFile , ... }@args: let - disko = import ./. { inherit (pkgs) lib; }; - diskFormat = import diskoFile; + disko = import ./. { }; + diskFormat = + if fromFlake != null + then (builtins.getFlake fromFlake) + "/${diskoFile}" + else import diskoFile; diskoEval = if (mode == "create") then disko.createScript diskFormat pkgs else if (mode == "mount") then diff --git a/disko b/disko index f51339e..deb3cbd 100755 --- a/disko +++ b/disko @@ -6,6 +6,9 @@ readonly libexec_dir="${0%/*}" # a file with the disko config declare disko_config +# a flake uri, if present disko config is relative to the flake root +declare from_flake + # mount was chosen as the default mode because it's less destructive mode=mount nix_args=() @@ -18,6 +21,8 @@ Options: * -m, --mode mode set the mode, either create or mount +* -f, --flake uri + fetch the disko config relative to this flake's root * --arg name value pass value to nix-build. can be used to set disk-names for example * --argstr name value @@ -43,6 +48,11 @@ while [[ $# -gt 0 ]]; do mode=$2 shift ;; + -f | --flake) + from_flake="$2" + nix_args+=("--argstr" "fromFlake" "$2") + shift + ;; --argstr | --arg) nix_args+=("$1" "$2" "$3") shift @@ -53,7 +63,7 @@ while [[ $# -gt 0 ]]; do exit 0 ;; *) - if [ -z ${disko_config+x} ] && [ -e "$1" ]; then + if [ -z ${disko_config+x} ]; then disko_config=$1 else showUsage @@ -68,8 +78,16 @@ if ! ([