mirror of
https://github.com/TECHNOFAB11/disko.git
synced 2025-12-12 16:10:03 +01:00
Merge pull request #48 from nix-community/module
This commit is contained in:
commit
45ef21831e
33 changed files with 766 additions and 213 deletions
204
README.md
204
README.md
|
|
@ -1,38 +1,166 @@
|
||||||
disko
|
# disko - declarative disk partitioning
|
||||||
=====
|
|
||||||
|
|
||||||
nix-powered automatic disk partitioning
|
Disko takes the NixOS module system and makes it work for disk partitioning
|
||||||
|
as well.
|
||||||
|
|
||||||
Usage
|
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.
|
||||||
|
|
||||||
Master Boot Record
|
## Features
|
||||||
------------------
|
|
||||||
This is how your iso configuation may look like
|
* 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
|
||||||
|
|
||||||
|
You can use the NixOS module in one of the following ways:
|
||||||
|
|
||||||
|
### Flakes
|
||||||
|
|
||||||
|
If you use nix flakes support:
|
||||||
|
|
||||||
/etc/nixos/configuration.nix
|
|
||||||
``` nix
|
``` nix
|
||||||
{ pkgs, modulesPath, ... }:
|
{
|
||||||
let
|
inputs.disko.url = "github:nix-community/disko";
|
||||||
disko = pkgs.callPackage (builtins.fetchGit {
|
inputs.disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
url = "https://github.com/nix-community/disko";
|
|
||||||
ref = "master";
|
outputs = { self, nixpkgs, disko }: {
|
||||||
}) {};
|
# change `yourhostname` to your actual hostname
|
||||||
cfg = {
|
nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
|
||||||
disk = {
|
# change to your system:
|
||||||
sda = {
|
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:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
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 = [ <disko/modules/disko.nix> ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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";
|
device = "/dev/sda";
|
||||||
type = "device";
|
type = "disk";
|
||||||
content = {
|
content = {
|
||||||
type = "table";
|
type = "table";
|
||||||
format = "msdos";
|
format = "gpt";
|
||||||
partitions = [
|
partitions = [
|
||||||
|
{
|
||||||
|
type = "partition";
|
||||||
|
name = "ESP";
|
||||||
|
start = "1MiB";
|
||||||
|
end = "100MiB";
|
||||||
|
bootable = true;
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "root";
|
name = "root";
|
||||||
type = "partition";
|
type = "partition";
|
||||||
part-type = "primary";
|
start = "100MiB";
|
||||||
start = "1M";
|
|
||||||
end = "100%";
|
end = "100%";
|
||||||
|
part-type = "primary";
|
||||||
bootable = true;
|
bootable = true;
|
||||||
content = {
|
content = {
|
||||||
type = "filesystem";
|
type = "filesystem";
|
||||||
|
|
@ -44,37 +172,11 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
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`
|
this will configure `fileSystems` and other required NixOS options to boot the specified configuration.
|
||||||
command:
|
|
||||||
|
|
||||||
- **tsp-create**: creates & formats the partitions according to `tsp-disk.json`
|
If you are on an installer, you probably want to disable `enableConfig`.
|
||||||
- **tsp-mount**: mounts the partitions to `/mnt`
|
|
||||||
|
|
||||||
GUID Partition Table, LVM and dm-crypt
|
disko will create the scripts `disko-create` and `disko-mount` which can be used to create/mount the configured disk layout.
|
||||||
--------------------------------------
|
|
||||||
See `examples/`
|
|
||||||
|
|
|
||||||
19
cli.nix
Normal file
19
cli.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {}
|
||||||
|
, mode ? "mount"
|
||||||
|
, fromFlake ? null
|
||||||
|
, diskoFile
|
||||||
|
, ... }@args:
|
||||||
|
let
|
||||||
|
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
|
||||||
|
disko.mountScript diskFormat pkgs
|
||||||
|
else
|
||||||
|
builtins.abort "invalid mode"
|
||||||
|
;
|
||||||
|
in diskoEval
|
||||||
21
default.nix
21
default.nix
|
|
@ -4,17 +4,26 @@ let
|
||||||
eval = cfg: lib.evalModules {
|
eval = cfg: lib.evalModules {
|
||||||
modules = lib.singleton {
|
modules = lib.singleton {
|
||||||
# _file = toString input;
|
# _file = toString input;
|
||||||
imports = lib.singleton { topLevel.devices = cfg; };
|
imports = lib.singleton { devices = cfg; };
|
||||||
options = {
|
options = {
|
||||||
topLevel = lib.mkOption {
|
devices = lib.mkOption {
|
||||||
type = types.topLevel;
|
type = types.devices;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
types = types;
|
types = types;
|
||||||
create = cfg: (eval cfg).config.topLevel.create;
|
create = cfg: types.diskoLib.create (eval cfg).config.devices;
|
||||||
mount = cfg: (eval cfg).config.topLevel.mount;
|
createScript = cfg: pkgs: pkgs.writeScript "disko-create" ''
|
||||||
config = cfg: (eval cfg).config.topLevel.config;
|
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 = 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}
|
||||||
|
'';
|
||||||
|
config = cfg: { imports = types.diskoLib.config (eval cfg).config.devices; };
|
||||||
|
packages = cfg: types.diskoLib.packages (eval cfg).config.devices;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
94
disko
Executable file
94
disko
Executable file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
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=()
|
||||||
|
|
||||||
|
showUsage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage: $0 [options] disk-config.nix
|
||||||
|
|
||||||
|
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
|
||||||
|
pass value to nix-build as string
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
echo "aborted: $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
## Main ##
|
||||||
|
|
||||||
|
[[ $# -eq 0 ]] && {
|
||||||
|
showUsage
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-m | --mode)
|
||||||
|
mode=$2
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-f | --flake)
|
||||||
|
from_flake="$2"
|
||||||
|
nix_args+=("--argstr" "fromFlake" "$2")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--argstr | --arg)
|
||||||
|
nix_args+=("$1" "$2" "$3")
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
showUsage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -z ${disko_config+x} ]; then
|
||||||
|
disko_config=$1
|
||||||
|
else
|
||||||
|
showUsage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! ([[ $mode = "create" ]] || [[ $mode = "mount" ]]); then
|
||||||
|
abort "mode must be either create or mount"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e "${disko_config}" ]]; then
|
||||||
|
nix_args+=("--arg" "diskoFile" "$disko_config")
|
||||||
|
elif [[ -n "${from_flake+x}" ]]; then
|
||||||
|
nix_args+=("--argstr" "diskoFile" "$disko_config")
|
||||||
|
else
|
||||||
|
abort "disko config must be an exising file of flake must be set"
|
||||||
|
fi
|
||||||
|
|
||||||
|
script=$(nix-build "${libexec_dir}"/cli.nix \
|
||||||
|
--argstr diskoFile "$disko_config" \
|
||||||
|
--argstr mode "$mode" \
|
||||||
|
"${nix_args[@]}"
|
||||||
|
)
|
||||||
|
exec "$script"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
one = {
|
one = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" ] }: {
|
{ disks ? [ "/dev/vdb" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
vdb = {
|
vdb = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" "/dev/vdd" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
disk0 = {
|
disk0 = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Example to create a bios compatible gpt partition
|
# Example to create a bios compatible gpt partition
|
||||||
{ disks ? [ "/dev/vdb" ] }: {
|
{ disks ? [ "/dev/vdb" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
vdb = {
|
vdb = {
|
||||||
device = builtins.elemAt disks 0;
|
device = builtins.elemAt disks 0;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" ] }: {
|
{ disks ? [ "/dev/vdb" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
vdb = {
|
vdb = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
one = {
|
one = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
vdb = {
|
vdb = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
40
example/simple-efi.nix
Normal file
40
example/simple-efi.nix
Normal file
|
|
@ -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 = "/";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
35
example/with-lib.nix
Normal file
35
example/with-lib.nix
Normal file
|
|
@ -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 = "/";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
vdb = {
|
vdb = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ disks ? [ "/dev/vdb" "/dev/vdc" ] }: {
|
{ disks ? [ "/dev/vdb" "/dev/vdc" ], ... }: {
|
||||||
disk = {
|
disk = {
|
||||||
x = {
|
x = {
|
||||||
type = "disk";
|
type = "disk";
|
||||||
|
|
|
||||||
27
flake.lock
generated
27
flake.lock
generated
|
|
@ -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
|
|
||||||
}
|
|
||||||
39
flake.nix
39
flake.nix
|
|
@ -1,12 +1,49 @@
|
||||||
{
|
{
|
||||||
description = "Description for the project";
|
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, ... }: {
|
outputs = { self, nixpkgs, ... }: {
|
||||||
|
nixosModules.disko = import ./module.nix;
|
||||||
lib = import ./. {
|
lib = import ./. {
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
};
|
};
|
||||||
|
packages.x86_64-linux.disko = let
|
||||||
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
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";
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
packages.x86_64-linux.default = self.packages.x86_64-linux.disko;
|
||||||
checks.x86_64-linux = let
|
checks.x86_64-linux = let
|
||||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
in
|
in
|
||||||
|
|
|
||||||
43
module.nix
Normal file
43
module.nix
Normal file
|
|
@ -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)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/boot-raid1.nix;
|
disko-config = ../example/boot-raid1.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("test -b /dev/md/boot");
|
machine.succeed("test -b /dev/md/boot");
|
||||||
machine.succeed("mountpoint /boot");
|
machine.succeed("mountpoint /boot");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/btrfs-subvolumes.nix;
|
disko-config = ../example/btrfs-subvolumes.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("test -e /test");
|
machine.succeed("test -e /test");
|
||||||
machine.succeed("btrfs subvolume list / | grep -qs 'path test$'");
|
machine.succeed("btrfs subvolume list / | grep -qs 'path test$'");
|
||||||
|
|
|
||||||
28
tests/cli.nix
Normal file
28
tests/cli.nix
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{ pkgs ? (import <nixpkgs> { })
|
||||||
|
, 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" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/complex.nix;
|
disko-config = ../example/complex.nix;
|
||||||
extraConfig = {
|
extraConfig = {
|
||||||
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/gpt-bios-compat.nix;
|
disko-config = ../example/gpt-bios-compat.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("mountpoint /");
|
machine.succeed("mountpoint /");
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
, grub-devices ? [ "nodev" ]
|
, grub-devices ? [ "nodev" ]
|
||||||
, efi ? true
|
, efi ? true
|
||||||
, enableOCR ? false
|
, enableOCR ? false
|
||||||
|
, testMode ? "direct" # can be one of direct module cli
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
|
|
@ -21,13 +22,21 @@
|
||||||
inherit (pkgs) system;
|
inherit (pkgs) system;
|
||||||
};
|
};
|
||||||
disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ];
|
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-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (import disko-config { disks = builtins.tail disks; inherit lib; }));
|
||||||
tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (disko-config { disks = builtins.tail disks; }));
|
tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (import disko-config { disks = builtins.tail disks; inherit lib; }));
|
||||||
tsp-config = (pkgs.callPackage ../. { }).config (disko-config { inherit disks; });
|
tsp-config = (pkgs.callPackage ../. { }).config (import disko-config { inherit disks; inherit lib; });
|
||||||
num-disks = builtins.length (lib.attrNames (disko-config {}).disk);
|
num-disks = builtins.length (lib.attrNames (import disko-config { inherit lib; }).disk);
|
||||||
installed-system = { modulesPath, ... }: {
|
installed-system = { modulesPath, ... }: {
|
||||||
imports = [
|
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 + "/testing/test-instrumentation.nix")
|
||||||
(modulesPath + "/profiles/qemu-guest.nix")
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
(modulesPath + "/profiles/minimal.nix")
|
(modulesPath + "/profiles/minimal.nix")
|
||||||
|
|
@ -63,6 +72,21 @@
|
||||||
inherit enableOCR;
|
inherit enableOCR;
|
||||||
nodes.machine = { config, pkgs, modulesPath, ... }: {
|
nodes.machine = { config, pkgs, modulesPath, ... }: {
|
||||||
imports = [
|
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/base.nix")
|
||||||
(modulesPath + "/profiles/minimal.nix")
|
(modulesPath + "/profiles/minimal.nix")
|
||||||
extraConfig
|
extraConfig
|
||||||
|
|
@ -97,9 +121,25 @@
|
||||||
|
|
||||||
machine.start()
|
machine.start()
|
||||||
machine.succeed("echo -n 'secret' > /tmp/secret.key")
|
machine.succeed("echo -n 'secret' > /tmp/secret.key")
|
||||||
|
${lib.optionalString (testMode == "direct") ''
|
||||||
machine.succeed("${tsp-create}")
|
machine.succeed("${tsp-create}")
|
||||||
machine.succeed("${tsp-mount}")
|
machine.succeed("${tsp-mount}")
|
||||||
machine.succeed("${tsp-mount}") # verify that the command is idempotent
|
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
|
# mount nix-store in /mnt
|
||||||
machine.succeed("mkdir -p /mnt/nix/store")
|
machine.succeed("mkdir -p /mnt/nix/store")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/luks-lvm.nix;
|
disko-config = ../example/luks-lvm.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("cryptsetup isLuks /dev/vda2");
|
machine.succeed("cryptsetup isLuks /dev/vda2");
|
||||||
machine.succeed("mountpoint /home");
|
machine.succeed("mountpoint /home");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/lvm-raid.nix;
|
disko-config = ../example/lvm-raid.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("mountpoint /home");
|
machine.succeed("mountpoint /home");
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/mdadm.nix;
|
disko-config = ../example/mdadm.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("test -b /dev/md/raid1");
|
machine.succeed("test -b /dev/md/raid1");
|
||||||
machine.succeed("mountpoint /");
|
machine.succeed("mountpoint /");
|
||||||
|
|
|
||||||
28
tests/module.nix
Normal file
28
tests/module.nix
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{ pkgs ? (import <nixpkgs> { })
|
||||||
|
, 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" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
9
tests/simple-efi.nix
Normal file
9
tests/simple-efi.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{ pkgs ? (import <nixpkgs> { })
|
||||||
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
|
}:
|
||||||
|
makeDiskoTest {
|
||||||
|
disko-config = ../example/simple-efi.nix;
|
||||||
|
extraTestScript = ''
|
||||||
|
machine.succeed("mountpoint /");
|
||||||
|
'';
|
||||||
|
}
|
||||||
11
tests/with-lib.nix
Normal file
11
tests/with-lib.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{ pkgs ? (import <nixpkgs> { })
|
||||||
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
|
}:
|
||||||
|
makeDiskoTest {
|
||||||
|
disko-config = ../example/with-lib.nix;
|
||||||
|
extraTestScript = ''
|
||||||
|
machine.succeed("mountpoint /");
|
||||||
|
'';
|
||||||
|
efi = false;
|
||||||
|
grub-devices = [ "/dev/vdb" ];
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/zfs-over-legacy.nix;
|
disko-config = ../example/zfs-over-legacy.nix;
|
||||||
extraTestScript = ''
|
extraTestScript = ''
|
||||||
machine.succeed("test -e /zfs_fs");
|
machine.succeed("test -e /zfs_fs");
|
||||||
machine.succeed("mountpoint /zfs_fs");
|
machine.succeed("mountpoint /zfs_fs");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
, makeDiskoTest ? (pkgs.callPackage ./lib.nix { }).makeDiskoTest
|
||||||
}:
|
}:
|
||||||
makeDiskoTest {
|
makeDiskoTest {
|
||||||
disko-config = import ../example/zfs.nix;
|
disko-config = ../example/zfs.nix;
|
||||||
extraConfig = {
|
extraConfig = {
|
||||||
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||||
};
|
};
|
||||||
|
|
|
||||||
209
types.nix
209
types.nix
|
|
@ -81,15 +81,15 @@ rec {
|
||||||
};
|
};
|
||||||
in valueType;
|
in valueType;
|
||||||
|
|
||||||
/* Given a attrset of dependencies and a devices attrset
|
/* Given a attrset of deviceDependencies and a devices attrset
|
||||||
returns a sorted list by dependencies. aborts if a loop is found
|
returns a sorted list by deviceDependencies. aborts if a loop is found
|
||||||
|
|
||||||
sortDevicesByDependencies :: AttrSet -> AttrSet -> [ [ str str ] ]
|
sortDevicesByDependencies :: AttrSet -> AttrSet -> [ [ str str ] ]
|
||||||
*/
|
*/
|
||||||
sortDevicesByDependencies = dependencies: devices:
|
sortDevicesByDependencies = deviceDependencies: devices:
|
||||||
let
|
let
|
||||||
dependsOn = a: b:
|
dependsOn = a: b:
|
||||||
elem a (attrByPath b [] dependencies);
|
elem a (attrByPath b [] deviceDependencies);
|
||||||
maybeSortedDevices = toposort dependsOn (diskoLib.deviceList devices);
|
maybeSortedDevices = toposort dependsOn (diskoLib.deviceList devices);
|
||||||
in
|
in
|
||||||
if (hasAttr "cycle" maybeSortedDevices) then
|
if (hasAttr "cycle" maybeSortedDevices) then
|
||||||
|
|
@ -119,6 +119,49 @@ rec {
|
||||||
=> "hello world"
|
=> "hello world"
|
||||||
*/
|
*/
|
||||||
maybeStr = x: optionalString (!isNull x) x;
|
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: 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 {
|
optionTypes = rec {
|
||||||
|
|
@ -152,11 +195,9 @@ rec {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* topLevel type of the disko config, takes attrsets of disks mdadms zpools and lvm vgs.
|
/* 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 = {
|
options = {
|
||||||
devices = {
|
|
||||||
disk = mkOption {
|
disk = mkOption {
|
||||||
type = types.attrsOf disk;
|
type = types.attrsOf disk;
|
||||||
default = {};
|
default = {};
|
||||||
|
|
@ -174,57 +215,7 @@ rec {
|
||||||
default = {};
|
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.dependencies config.devices;
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
create = mkOption {
|
|
||||||
readOnly = true;
|
|
||||||
type = types.str;
|
|
||||||
default = ''
|
|
||||||
set -efux
|
|
||||||
${concatStrings (map (dev: attrByPath (dev ++ [ "_create" ]) "" config.devices) config.meta.sortedDeviceList)}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
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)}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
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
|
|
||||||
])));};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
btrfs = types.submodule ({ config, ... }: {
|
btrfs = types.submodule ({ config, ... }: {
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -290,6 +281,12 @@ rec {
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
_pkgs= mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -358,6 +355,22 @@ rec {
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
# type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs:
|
||||||
|
[ 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 []
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -411,6 +424,13 @@ rec {
|
||||||
default = dev:
|
default = dev:
|
||||||
map (partition: partition._config dev) config.partitions;
|
map (partition: partition._config dev) config.partitions;
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs:
|
||||||
|
[ pkgs.parted pkgs.systemdMinimal ] ++ flatten (map (partition: partition._pkgs pkgs) config.partitions);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -497,6 +517,12 @@ rec {
|
||||||
default = dev:
|
default = dev:
|
||||||
optional (!isNull config.content) (config.content._config (diskoLib.deviceNumbering dev config.index));
|
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);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -514,7 +540,7 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.functionTo diskoLib.jsonType;
|
type = types.functionTo diskoLib.jsonType;
|
||||||
default = dev: {
|
default = dev: {
|
||||||
dependencies.lvm_vg.${config.vg} = [ dev ];
|
deviceDependencies.lvm_vg.${config.vg} = [ dev ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
_create = mkOption {
|
_create = mkOption {
|
||||||
|
|
@ -538,6 +564,12 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = dev: [];
|
default = dev: [];
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [ pkgs.lvm2 ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -591,6 +623,12 @@ rec {
|
||||||
default =
|
default =
|
||||||
map (lv: lv._config config.name) (attrValues config.lvs);
|
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 +694,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);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -673,7 +717,7 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.functionTo diskoLib.jsonType;
|
type = types.functionTo diskoLib.jsonType;
|
||||||
default = dev: {
|
default = dev: {
|
||||||
dependencies.zpool.${config.pool} = [ dev ];
|
deviceDependencies.zpool.${config.pool} = [ dev ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
_create = mkOption {
|
_create = mkOption {
|
||||||
|
|
@ -696,6 +740,12 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = dev: [];
|
default = dev: [];
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [ pkgs.zfs ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -779,8 +829,7 @@ rec {
|
||||||
_config = mkOption {
|
_config = mkOption {
|
||||||
internal = true;
|
internal = true;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default =
|
default = [
|
||||||
[
|
|
||||||
(map (dataset: dataset._config config.name) (attrValues config.datasets))
|
(map (dataset: dataset._config config.name) (attrValues config.datasets))
|
||||||
(optional (!isNull config.mountpoint) {
|
(optional (!isNull config.mountpoint) {
|
||||||
fileSystems.${config.mountpoint} = {
|
fileSystems.${config.mountpoint} = {
|
||||||
|
|
@ -791,6 +840,12 @@ rec {
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [ pkgs.util-linux ] ++ flatten (map (dataset: dataset._pkgs pkgs) (attrValues config.datasets));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -880,6 +935,12 @@ rec {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [ pkgs.util-linux ] ++ lib.optionals (!isNull config.content) (config.content._pkgs pkgs);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -939,6 +1000,12 @@ rec {
|
||||||
default =
|
default =
|
||||||
optional (!isNull config.content) (config.content._config "/dev/md/${config.name}");
|
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));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -957,7 +1024,7 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.functionTo diskoLib.jsonType;
|
type = types.functionTo diskoLib.jsonType;
|
||||||
default = dev: {
|
default = dev: {
|
||||||
dependencies.mdadm.${config.name} = [ dev ];
|
deviceDependencies.mdadm.${config.name} = [ dev ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
_create = mkOption {
|
_create = mkOption {
|
||||||
|
|
@ -981,6 +1048,12 @@ rec {
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
default = dev: [];
|
default = dev: [];
|
||||||
};
|
};
|
||||||
|
_pkgs = mkOption {
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = types.functionTo (types.listOf types.package);
|
||||||
|
default = pkgs: [ pkgs.mdadm ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1045,6 +1118,12 @@ rec {
|
||||||
{ boot.initrd.luks.devices.${config.name}.device = dev; }
|
{ boot.initrd.luks.devices.${config.name}.device = dev; }
|
||||||
] ++ (optional (!isNull config.content) (config.content._config "/dev/mapper/${config.name}"));
|
] ++ (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 +1166,12 @@ rec {
|
||||||
default =
|
default =
|
||||||
optional (!isNull config.content) (config.content._config config.device);
|
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);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue