deleted diskco
This commit is contained in:
parent
aecbeb4bd3
commit
8bf0427e52
6
pkgs/disko/.github/dependabot.yml
vendored
6
pkgs/disko/.github/dependabot.yml
vendored
@ -1,6 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
22
pkgs/disko/.github/workflows/publish.yml
vendored
22
pkgs/disko/.github/workflows/publish.yml
vendored
@ -1,22 +0,0 @@
|
||||
name: "Publish a flake to flakestry"
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v?[0-9]+.[0-9]+.[0-9]+"
|
||||
- "v?[0-9]+.[0-9]+"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "The existing tag to publish"
|
||||
type: "string"
|
||||
required: true
|
||||
jobs:
|
||||
publish-flake:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: "write"
|
||||
contents: "read"
|
||||
steps:
|
||||
- uses: flakestry/flakestry-publish@main
|
||||
with:
|
||||
version: "${{ inputs.tag || github.ref_name }}"
|
||||
@ -1,21 +0,0 @@
|
||||
name: update-flake-lock
|
||||
on:
|
||||
workflow_dispatch: # allows manual triggering
|
||||
schedule:
|
||||
- cron: '0 0 * * 1,4' # Run twice a week
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
jobs:
|
||||
lockfile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v30
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@v24
|
||||
with:
|
||||
pr-labels: |
|
||||
merge-queue
|
||||
4
pkgs/disko/.gitignore
vendored
4
pkgs/disko/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
result
|
||||
|
||||
# Created by the NixOS interactive test driver
|
||||
.nixos-test-history
|
||||
@ -1,12 +0,0 @@
|
||||
queue_rules:
|
||||
- name: default
|
||||
merge_conditions:
|
||||
- check-success=buildbot/nix-build
|
||||
merge_method: rebase
|
||||
pull_request_rules:
|
||||
- name: merge using the merge queue
|
||||
conditions:
|
||||
- base=master
|
||||
- label=merge-queue
|
||||
actions:
|
||||
queue: {}
|
||||
@ -1,39 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
We welcome contributions of all kinds, be it in terms of bug fixes,
|
||||
reproductions, features or documentation.
|
||||
|
||||
In general, PRs are more likely to be merged quickly if they contain tests which
|
||||
prove that a feature is working as intended or that a bug was indeed present and
|
||||
has now been fixed. Creating a draft PR that reproduces a bug is also a great
|
||||
way to help us fix issues quickly. Check out
|
||||
[this PR](https://github.com/nix-community/disko/pull/330) as an example.
|
||||
|
||||
For more information on how to run and debug tests, check out
|
||||
[Running and debugging tests](./docs/testing.md).
|
||||
|
||||
## How to find issues to work on
|
||||
|
||||
If you're looking for a low-hanging fruit, check out
|
||||
[this list of `good first issue`s](https://github.com/nix-community/disko/labels/good%20first%20issue).
|
||||
These are issues that we have confirmed to be real and which have a strategy for
|
||||
a fix already lined out in the comments. All you need to do is implement.
|
||||
|
||||
If you're looking for something more challenging, check out
|
||||
[this list of issues tagged `contributions welcome`](https://github.com/nix-community/disko/labels/contributions%20welcome).
|
||||
These are issues that we have confirmed to be real and we know we want to be
|
||||
fixed.
|
||||
|
||||
For the real though nuts, we also have
|
||||
[the `help wanted` label](https://github.com/nix-community/disko/labels/help%20wanted)
|
||||
for issues that we feel like we need external help with. If you want a real
|
||||
challenge, take a look there!
|
||||
|
||||
If you're looking for bugs that still need to be reproduced, have a look at
|
||||
[this list of non-`confirmed` bugs](https://github.com/nix-community/disko/issues?q=is%3Aissue+is%3Aopen+label%3Abug+-label%3Aconfirmed+).
|
||||
These are things that look like bugs but that we haven't reproduced yet.
|
||||
|
||||
If you're looking to contribute to the documentation, check out
|
||||
[the `documentation` tag](https://github.com/nix-community/disko/issues?q=is%3Aissue+is%3Aopen+label%3Adocumentation)
|
||||
or just read through [our docs](./docs/INDEX.md) and see if you can find any
|
||||
issues.
|
||||
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, 2019, 2022–2024 Nix community projects
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -1,142 +0,0 @@
|
||||
# disko - Declarative disk partitioning
|
||||
|
||||
<img title="" src="./docs/logo.png" alt="Project logo" width="274">
|
||||
|
||||
[Documentation Index](./docs/INDEX.md)
|
||||
|
||||
NixOS is a Linux distribution where everything is described as code, with one
|
||||
exception: during installation, the disk partitioning and formatting are manual
|
||||
steps. **disko** aims to correct this sad 🤡 omission.
|
||||
|
||||
This is especially useful for unattended installations, re-installation after a
|
||||
system crash or for setting up more than one identical server.
|
||||
|
||||
## Overview
|
||||
|
||||
**disko** can either be used after booting from a NixOS installer, or in
|
||||
conjunction with [nixos-anywhere](https://github.com/numtide/nixos-anywhere) if
|
||||
you're installing remotely.
|
||||
|
||||
Before using **disko**, the specifications of the disks, partitions, type of
|
||||
formatting and the mount points must be defined in a Nix configuration. You can
|
||||
find [examples](./example) of typical configurations in the Nix community
|
||||
repository, and use one of these as the basis of your own configuration.
|
||||
|
||||
You can keep your configuration and re-use it for other installations, or for a
|
||||
system rebuild.
|
||||
|
||||
**disko** is flexible, in that it supports most of the common formatting and
|
||||
partitioning options, including:
|
||||
|
||||
- Disk layouts: GPT, MBR, and mixed.
|
||||
- Partition tools: LVM, mdadm, LUKS, and more.
|
||||
- Filesystems: ext4, btrfs, ZFS, bcachefs, tmpfs, and others.
|
||||
|
||||
It can work with these in various configurations and orders, and supports
|
||||
recursive layouts.
|
||||
|
||||
## How to use disko
|
||||
|
||||
Disko doesn't require installation: it can be run directly from nix-community
|
||||
repository. The [Quickstart Guide](./docs/quickstart.md) documents how to run
|
||||
Disko in its simplest form when installing NixOS. Alternatively, you can also
|
||||
use the new [disko-install](./docs/disko-install.md) tool, which combines
|
||||
`disko` and `nixos-install` into one step.
|
||||
|
||||
For information on other use cases, including upgrading from an older version of
|
||||
**disko**, using **disko** without NixOS and downloading the module, see the
|
||||
[How To Guide](./docs/HowTo.md)
|
||||
|
||||
For more detailed options, such as command line switches, see the
|
||||
[Reference Guide](./docs/reference.md)
|
||||
|
||||
To access sample configurations for commonly-used disk layouts, refer to the
|
||||
[examples](./example) provided.
|
||||
|
||||
Disko can be also used to create [disk images](./docs/disko-images.md).
|
||||
|
||||
## Sample Configuration and CLI command
|
||||
|
||||
A simple disko configuration may look like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
my-disk = {
|
||||
device = "/dev/sda";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
If you'd saved this configuration in /tmp/disk-config.nix, and wanted to create
|
||||
a disk named /dev/sda, you would run the following command to partition, format
|
||||
and mount the disk.
|
||||
|
||||
```console
|
||||
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount /tmp/disk-config.nix
|
||||
```
|
||||
|
||||
## Related Tools
|
||||
|
||||
This tool is used by
|
||||
[nixos-anywhere](https://github.com/numtide/nixos-anywhere), which carries out a
|
||||
fully-automated remote install of NixOS.
|
||||
|
||||
We also acknowledge https://github.com/NixOS/nixpart, the conceptual ancestor of
|
||||
this project.
|
||||
|
||||
## Licensing and Contribution details
|
||||
|
||||
This software is provided free under the
|
||||
[MIT Licence](https://opensource.org/licenses/MIT).
|
||||
|
||||
If you want to contribute, check out [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Get in touch
|
||||
|
||||
We have a public matrix channel at
|
||||
[disko](https://matrix.to/#/#disko:nixos.org).
|
||||
|
||||
---
|
||||
|
||||
This project is supported by [Numtide](https://numtide.com/).
|
||||

|
||||
|
||||
We are a team of independent freelancers that love open source. We help our
|
||||
customers make their project lifecycles more efficient by:
|
||||
|
||||
- Providing and supporting useful tools such as this one
|
||||
- Building and deploying infrastructure, and offering dedicated DevOps support
|
||||
- Building their in-house Nix skills, and integrating Nix with their workflows
|
||||
- Developing additional features and tools
|
||||
- Carrying out custom research and development.
|
||||
|
||||
[Contact us](https://numtide.com/contact) if you have a project in mind, or if
|
||||
you need help with any of our supported tools, including this one. We'd love to
|
||||
hear from you.
|
||||
@ -1,116 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, lib ? pkgs.lib
|
||||
, mode ? "mount"
|
||||
, flake ? null
|
||||
, flakeAttr ? null
|
||||
, diskoFile ? null
|
||||
, rootMountPoint ? "/mnt"
|
||||
, noDeps ? false
|
||||
, ...
|
||||
}@args:
|
||||
let
|
||||
disko = import ./. {
|
||||
inherit rootMountPoint;
|
||||
inherit lib;
|
||||
};
|
||||
|
||||
hasDiskoFile = diskoFile != null;
|
||||
|
||||
diskoAttr =
|
||||
(if noDeps then
|
||||
(if hasDiskoFile then
|
||||
{
|
||||
destroy = "_cliDestroyNoDeps";
|
||||
format = "_cliFormatNoDeps";
|
||||
mount = "_cliMountNoDeps";
|
||||
unmount = "_cliUnmountNoDeps";
|
||||
|
||||
"format,mount" = "_cliFormatMountNoDeps";
|
||||
"destroy,format,mount" = "_cliDestroyFormatMountNoDeps";
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy = "destroyNoDeps";
|
||||
format = "formatNoDeps";
|
||||
mount = "mountNoDeps";
|
||||
unmount = "unmountNoDeps";
|
||||
|
||||
"format,mount" = "formatMountNoDeps";
|
||||
"destroy,format,mount" = "destroyFormatMountNoDeps";
|
||||
}) // {
|
||||
# legacy aliases
|
||||
disko = "diskoScriptNoDeps";
|
||||
create = "createScriptNoDeps";
|
||||
zap_create_mount = "diskoScriptNoDeps";
|
||||
}
|
||||
else
|
||||
(if hasDiskoFile then
|
||||
{
|
||||
destroy = "_cliDestroy";
|
||||
format = "_cliFormat";
|
||||
mount = "_cliMount";
|
||||
unmount = "_cliUnmount";
|
||||
|
||||
"format,mount" = "_cliFormatMount";
|
||||
"destroy,format,mount" = "_cliDestroyFormatMount";
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy = "destroy";
|
||||
format = "format";
|
||||
mount = "mount";
|
||||
unmount = "unmount";
|
||||
|
||||
"format,mount" = "formatMount";
|
||||
"destroy,format,mount" = "destroyFormatMount";
|
||||
}) // {
|
||||
# legacy aliases
|
||||
disko = "diskoScript";
|
||||
create = "createScript";
|
||||
zap_create_mount = "diskoScript";
|
||||
}
|
||||
).${mode};
|
||||
|
||||
hasDiskoConfigFlake =
|
||||
hasDiskoFile || lib.hasAttrByPath [ "diskoConfigurations" flakeAttr ] (builtins.getFlake flake);
|
||||
|
||||
hasDiskoModuleFlake =
|
||||
lib.hasAttrByPath [ "nixosConfigurations" flakeAttr "config" "disko" "devices" ] (builtins.getFlake flake);
|
||||
|
||||
|
||||
diskFormat =
|
||||
let
|
||||
diskoConfig =
|
||||
if hasDiskoFile then
|
||||
import diskoFile
|
||||
else
|
||||
(builtins.getFlake flake).diskoConfigurations.${flakeAttr};
|
||||
in
|
||||
if builtins.isFunction diskoConfig then
|
||||
diskoConfig ({ inherit lib; } // args)
|
||||
else
|
||||
diskoConfig;
|
||||
|
||||
diskoEval =
|
||||
disko.${diskoAttr} diskFormat pkgs;
|
||||
|
||||
diskoScript =
|
||||
if hasDiskoConfigFlake then
|
||||
diskoEval
|
||||
else if hasDiskoModuleFlake then
|
||||
(builtins.getFlake flake).nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr} or (
|
||||
pkgs.writeShellScriptBin "disko-compat-error" ''
|
||||
echo 'Error: Attribute `nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr}` >&2
|
||||
echo ' not found in flake `${flake}`!' >&2
|
||||
echo ' This is probably caused by the locked version of disko in the flake' >&2
|
||||
echo ' being different from the version of disko you executed.' >&2
|
||||
echo 'EITHER set the `disko` input of your flake to `github:nix-community/disko/latest`,' >&2
|
||||
echo ' run `nix flake update disko` in the flake directory and then try again,' >&2
|
||||
echo 'OR run `nix run github:nix-community/disko/v1.9.0 -- --help` and use one of its modes.' >&2
|
||||
exit 1;''
|
||||
)
|
||||
else
|
||||
(builtins.abort "couldn't find `diskoConfigurations.${flakeAttr}` or `nixosConfigurations.${flakeAttr}.config.disko.devices`");
|
||||
|
||||
in
|
||||
diskoScript
|
||||
@ -1,65 +0,0 @@
|
||||
{ lib ? import <nixpkgs/lib>
|
||||
, rootMountPoint ? "/mnt"
|
||||
, checked ? false
|
||||
, diskoLib ? import ./lib { inherit lib rootMountPoint; }
|
||||
}:
|
||||
let
|
||||
eval = cfg: lib.evalModules {
|
||||
modules = lib.singleton {
|
||||
# _file = toString input;
|
||||
imports = lib.singleton { disko.devices = cfg.disko.devices; };
|
||||
options = {
|
||||
disko.devices = lib.mkOption {
|
||||
type = diskoLib.toplevel;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
# We might instead reuse some of the deprecated output names to refer to the values the _cli* outputs currently do,
|
||||
# but this warning allows us to get feedback from users early in case they have a use case we haven't considered.
|
||||
warnDeprecated = name: lib.warn "the ${name} output is deprecated and will be removed, please open an issue if you're using it!";
|
||||
in
|
||||
{
|
||||
lib = warnDeprecated ".lib.lib" diskoLib;
|
||||
|
||||
_cliDestroy = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy;
|
||||
_cliDestroyNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps;
|
||||
|
||||
_cliFormat = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).format;
|
||||
_cliFormatNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps;
|
||||
|
||||
_cliMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mount;
|
||||
_cliMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps;
|
||||
|
||||
_cliUnmount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmount;
|
||||
_cliUnmountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps;
|
||||
|
||||
_cliFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount;
|
||||
_cliFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps;
|
||||
|
||||
_cliDestroyFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount;
|
||||
_cliDestroyFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps;
|
||||
|
||||
# legacy aliases
|
||||
create = cfg: warnDeprecated "create" (eval cfg).config.disko.devices._create;
|
||||
createScript = cfg: pkgs: warnDeprecated "createScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
|
||||
createScriptNoDeps = cfg: pkgs: warnDeprecated "createScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
|
||||
|
||||
format = cfg: warnDeprecated "format" (eval cfg).config.disko.devices._create;
|
||||
formatScript = cfg: pkgs: warnDeprecated "formatScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
|
||||
formatScriptNoDeps = cfg: pkgs: warnDeprecated "formatScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
|
||||
|
||||
mount = cfg: warnDeprecated "mount" (eval cfg).config.disko.devices._mount;
|
||||
mountScript = cfg: pkgs: warnDeprecated "mountScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript;
|
||||
mountScriptNoDeps = cfg: pkgs: warnDeprecated "mountScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps;
|
||||
|
||||
disko = cfg: warnDeprecated "disko" (eval cfg).config.disko.devices._disko;
|
||||
diskoScript = cfg: pkgs: warnDeprecated "diskoScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript;
|
||||
diskoScriptNoDeps = cfg: pkgs: warnDeprecated "diskoScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
|
||||
|
||||
# we keep this old output for backwards compatibility
|
||||
diskoNoDeps = cfg: pkgs: warnDeprecated "diskoNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
|
||||
|
||||
config = cfg: (eval cfg).config.disko.devices._config;
|
||||
packages = cfg: (eval cfg).config.disko.devices._packages;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -efux -o pipefail
|
||||
# dependencies: bash jq util-linux lvm2 mdadm zfs gnugrep sed
|
||||
disk=$(realpath "$1")
|
||||
|
||||
lsblk -a -f >&2
|
||||
lsblk --output-all --json | jq -r --arg disk_to_clear "$disk" -f "$(dirname "$0")/disk-deactivate.jq" | bash -x
|
||||
lsblk -a -f >&2
|
||||
@ -1,86 +0,0 @@
|
||||
# since lsblk lacks zfs support, we have to do it this way
|
||||
def remove:
|
||||
if .fstype == "zfs_member" then
|
||||
"if type zpool >/dev/null; then zpool destroy -f \(.label); zpool labelclear -f \(.label); fi"
|
||||
elif .fstype == "LVM2_member" then
|
||||
[
|
||||
"vg=$(pvs \(.path) --noheadings --options vg_name | grep -o '[a-zA-Z0-9-]*')",
|
||||
"vgchange -a n \"$vg\"",
|
||||
"vgremove -f \"$vg\""
|
||||
]
|
||||
elif .fstype == "swap" then
|
||||
"swapoff \(.path)"
|
||||
elif .fstype == null then
|
||||
# maybe its zfs
|
||||
[
|
||||
# the next line has some horrible escaping
|
||||
"zpool=$(if type zdb >/dev/null; then zdb -l \(.path) | sed -nr $'s/ +name: \\'(.*)\\'/\\\\1/p'; fi)",
|
||||
"if [[ -n \"${zpool}\" ]]; then zpool destroy -f \"$zpool\"; zpool labelclear -f \"$zpool\"; fi",
|
||||
"unset zpool"
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
;
|
||||
|
||||
def deactivate:
|
||||
if .type == "disk" or .type == "loop" then
|
||||
[
|
||||
# If this disk is a member of raid, stop that raid
|
||||
"md_dev=$(lsblk \(.path) -l -p -o type,name | awk 'match($1,\"raid.*\") {print $2}')",
|
||||
"if [[ -n \"${md_dev}\" ]]; then umount \"$md_dev\"; mdadm --stop \"$md_dev\"; fi",
|
||||
# Remove all file-systems and other magic strings
|
||||
"wipefs --all -f \(.path)",
|
||||
# Remove the MBR bootstrap code
|
||||
"dd if=/dev/zero of=\(.path) bs=440 count=1"
|
||||
]
|
||||
elif .type == "part" then
|
||||
[
|
||||
"wipefs --all -f \(.path)"
|
||||
]
|
||||
elif .type == "crypt" then
|
||||
[
|
||||
"cryptsetup luksClose \(.path)",
|
||||
"wipefs --all -f \(.path)"
|
||||
]
|
||||
elif .type == "lvm" then
|
||||
(.name | split("-")[0]) as $vgname |
|
||||
(.name | split("-")[1]) as $lvname |
|
||||
[
|
||||
"lvremove -fy \($vgname)/\($lvname)"
|
||||
]
|
||||
elif (.type | contains("raid")) then
|
||||
[
|
||||
"mdadm --stop \(.name)"
|
||||
]
|
||||
else
|
||||
["echo Warning: unknown type '\(.type)'. Consider handling this in https://github.com/nix-community/disko/blob/master/disk-deactivate/disk-deactivate.jq"]
|
||||
end
|
||||
;
|
||||
|
||||
def walk:
|
||||
[
|
||||
(.mountpoints[] | select(. != null) | "umount -R \(.)"),
|
||||
((.children // []) | map(walk)),
|
||||
remove,
|
||||
deactivate
|
||||
]
|
||||
;
|
||||
|
||||
def init:
|
||||
"/dev/\(.name)" as $disk |
|
||||
"/dev/disk/by-id/\(."id-link")" as $disk_by_id |
|
||||
"/dev/disk/by-id/\(.tran)-\(.id)" as $disk_by_id2 |
|
||||
"/dev/disk/by-id/\(.tran)-\(.wwn)" as $disk_by_wwn |
|
||||
if $disk == $disk_to_clear or $disk_by_id == $disk_to_clear or $disk_by_id2 == $disk_to_clear or $disk_by_wwn == $disk_to_clear then
|
||||
[
|
||||
"set -fu",
|
||||
walk
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
;
|
||||
|
||||
.blockdevices | map(init) | flatten | join("\n")
|
||||
|
||||
193
pkgs/disko/disko
193
pkgs/disko/disko
@ -1,193 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
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=()
|
||||
skip_destroy_safety_check=false
|
||||
|
||||
# DISKO_VERSION is set by the wrapper in package.nix
|
||||
DISKO_VERSION="${DISKO_VERSION:="unknown! This is a bug, please report it!"}"
|
||||
onlyPrintVersion=false
|
||||
|
||||
showUsage() {
|
||||
cat <<USAGE
|
||||
Usage: $0 [options] disk-config.nix
|
||||
or $0 [options] --flake github:somebody/somewhere#disk-config
|
||||
|
||||
With flakes, disk-config is discovered first under the .diskoConfigurations top level attribute
|
||||
or else from the disko module of a NixOS configuration of that name under .nixosConfigurations.
|
||||
|
||||
Options:
|
||||
|
||||
* -m, --mode mode
|
||||
set the mode, either distroy, format, mount, unmount, format,mount or destroy,format,mount
|
||||
destroy: unmount filesystems and destroy partition tables of the selected disks
|
||||
format: create partition tables, zpools, lvms, raids and filesystems if they don't exist yet
|
||||
mount: mount the partitions at the specified root-mountpoint
|
||||
format,mount: run format and mount in sequence
|
||||
destroy,format,mount: run all three modes in sequence. Previously known as --mode disko
|
||||
* -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
|
||||
* --root-mountpoint /some/other/mnt
|
||||
where to mount the device tree (default: /mnt)
|
||||
* --dry-run
|
||||
just show the path to the script instead of running it
|
||||
* --no-deps
|
||||
avoid adding another dependency closure to an in-memory installer
|
||||
requires all necessary dependencies to be available in the environment
|
||||
* --yes-wipe-all-disks
|
||||
skip the safety check for destroying partitions, useful for automation
|
||||
* --debug
|
||||
run with set -x
|
||||
* --help
|
||||
show this help
|
||||
USAGE
|
||||
}
|
||||
|
||||
abort() {
|
||||
echo "aborted: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
## Main ##
|
||||
|
||||
[[ $# -eq 0 ]] && {
|
||||
showUsage
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--debug)
|
||||
set -x
|
||||
;;
|
||||
-m | --mode)
|
||||
mode=$2
|
||||
shift
|
||||
;;
|
||||
-f | --flake)
|
||||
flake=$2
|
||||
shift
|
||||
;;
|
||||
--argstr | --arg)
|
||||
nix_args+=("$1" "$2" "$3")
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
showUsage
|
||||
exit 0
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run=y
|
||||
;;
|
||||
--root-mountpoint)
|
||||
nix_args+=(--argstr rootMountPoint "$2")
|
||||
shift
|
||||
;;
|
||||
--no-deps)
|
||||
nix_args+=(--arg noDeps true)
|
||||
;;
|
||||
--yes-wipe-all-disks)
|
||||
skip_destroy_safety_check=true
|
||||
;;
|
||||
--show-trace)
|
||||
nix_args+=("$1")
|
||||
;;
|
||||
--version)
|
||||
onlyPrintVersion=true
|
||||
;;
|
||||
*)
|
||||
if [ -z ${disko_config+x} ]; then
|
||||
disko_config=$1
|
||||
else
|
||||
showUsage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ "$onlyPrintVersion" = true ]]; then
|
||||
echo "$DISKO_VERSION"
|
||||
exit 0
|
||||
fi
|
||||
# Always print version information to help with debugging
|
||||
echo "disko version $DISKO_VERSION"
|
||||
|
||||
nixBuild() {
|
||||
if command -v nom-build > /dev/null; then
|
||||
nom-build "$@"
|
||||
else
|
||||
nix-build "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
if ! {
|
||||
# Base modes
|
||||
[[ $mode = "destroy" ]] || [[ $mode = "format" ]] || [[ $mode = "mount" ]] || [[ $mode = "unmount" ]] ||
|
||||
# Combined modes
|
||||
[[ $mode = "format,mount" ]] ||
|
||||
[[ $mode = "destroy,format,mount" ]] || # Replaces --mode disko
|
||||
# Legacy modes, will be removed in next major version
|
||||
[[ $mode = "disko" ]] || [[ $mode = "create" ]] || [[ $mode = "zap_create_mount" ]] ;
|
||||
}; then
|
||||
abort 'mode must be one of "destroy", "format", "mount", "destroy,format,mount" or "format,mount"'
|
||||
fi
|
||||
|
||||
if [[ -n "${flake+x}" ]]; then
|
||||
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
|
||||
flake="${BASH_REMATCH[1]}"
|
||||
flakeAttr="${BASH_REMATCH[2]}"
|
||||
fi
|
||||
if [[ -z "${flakeAttr-}" ]]; then
|
||||
echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri."
|
||||
echo "For example, to use the output diskoConfigurations.foo from the flake.nix, append \"#foo\" to the flake-uri."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e "$flake" ]]; then
|
||||
flake="$(realpath "$flake")"
|
||||
fi
|
||||
nix_args+=("--arg" "flake" "\"$flake\"")
|
||||
nix_args+=("--argstr" "flakeAttr" "$flakeAttr")
|
||||
nix_args+=(--extra-experimental-features flakes)
|
||||
elif [[ -n "${disko_config+x}" ]] && [[ -e "$disko_config" ]]; then
|
||||
nix_args+=("--arg" "diskoFile" "$(realpath "$disko_config")")
|
||||
else
|
||||
abort "disko config must be an existing file or flake must be set"
|
||||
fi
|
||||
|
||||
# The "--impure" is still pure, as the path is within the nix store.
|
||||
script=$(nixBuild "${libexec_dir}"/cli.nix \
|
||||
--no-out-link \
|
||||
--impure \
|
||||
--argstr mode "$mode" \
|
||||
"${nix_args[@]}"
|
||||
)
|
||||
|
||||
command=("$(echo "$script"/bin/*)")
|
||||
if [[ $mode = "destroy,format,mount" && $skip_destroy_safety_check = true ]]; then
|
||||
command+=("--yes-wipe-all-disks")
|
||||
fi
|
||||
|
||||
# Legacy modes don't support --yes-wipe-all-disks and are not in `$script/bin`
|
||||
if [[ $mode = "disko" ]] || [[ $mode = "create" ]] || [[ $mode = "zap_create_mount" ]] ; then
|
||||
command=("$script")
|
||||
fi
|
||||
|
||||
if [[ -n "${dry_run+x}" ]]; then
|
||||
echo "${command[@]}"
|
||||
else
|
||||
exec "${command[@]}"
|
||||
fi
|
||||
@ -1,273 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
showUsage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
--mode MODE Specify the mode of operation. Valid modes are: format, mount.
|
||||
Format will format the disk before installing.
|
||||
Mount will mount the disk before installing.
|
||||
Mount is useful for updating an existing system without losing data.
|
||||
-f, --flake FLAKE_URI#ATTR Use the specified flake to install the NixOS configuration.
|
||||
--disk NAME DEVICE Map the specified disk name to the specified device path.
|
||||
--dry-run Print the commands that would be run, but do not run them.
|
||||
--show-trace Show the stack trace on error.
|
||||
-h, --help Show this help message.
|
||||
--extra-files SOURCE DEST Copy the specified file or directory from the host into the NixOS configuration.
|
||||
--option NAME VALUE Pass the specified option to Nix.
|
||||
--write-efi-boot-entries Write EFI boot entries to the NVRAM of the system for the installed system.
|
||||
Specify this option if you plan to boot from this disk on the current machine,
|
||||
but not if you plan to move the disk to another machine.
|
||||
--system-config JSON Merges the specified JSON object into the NixOS configuration.
|
||||
--mount-point PATH Specify the mount point for the NixOS installation.
|
||||
Default: /mnt/disko-install-root
|
||||
EOF
|
||||
}
|
||||
|
||||
serialiaseArrayToNix() {
|
||||
local -n array=$1
|
||||
nixExpr="{ "
|
||||
# Iterate over the associative array to populate the Nix attrset string
|
||||
for key in "${!array[@]}"; do
|
||||
value=${array[$key]}
|
||||
nixExpr+="\"${key//\"/\\\"}\" = \"${value//\"/\\\"}\"; "
|
||||
done
|
||||
nixExpr+="}"
|
||||
|
||||
echo "$nixExpr"
|
||||
}
|
||||
|
||||
readonly libexec_dir="${0%/*}"
|
||||
|
||||
nix_args=(
|
||||
--extra-experimental-features 'nix-command flakes'
|
||||
"--option" "no-write-lock-file" "true"
|
||||
)
|
||||
dry_run=
|
||||
extraSystemConfig="{}"
|
||||
diskoAttr=diskoScript
|
||||
writeEfiBootEntries=false
|
||||
mountPoint=/mnt/disko-install-root
|
||||
declare -A diskMappings
|
||||
declare -A extraFiles
|
||||
|
||||
|
||||
parseArgs() {
|
||||
[[ $# -eq 0 ]] && {
|
||||
showUsage
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-d | --debug)
|
||||
set -x
|
||||
;;
|
||||
-f | --flake)
|
||||
flake=$2
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
showUsage
|
||||
exit 0
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run=y
|
||||
;;
|
||||
--show-trace)
|
||||
nix_args+=("$1")
|
||||
;;
|
||||
--write-efi-boot-entries)
|
||||
writeEfiBootEntries=true
|
||||
;;
|
||||
--mode)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Option $1 requires an argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
case $2 in
|
||||
format)
|
||||
diskoAttr=diskoScript
|
||||
;;
|
||||
mount)
|
||||
diskoAttr=mountScript
|
||||
;;
|
||||
*)
|
||||
echo "Invalid mode: $2" >&2
|
||||
echo "Valid modes are: format, mount" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
;;
|
||||
--system-config)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Option $1 requires one JSON argument." >&2
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck disable=SC2034
|
||||
extraSystemConfig="$2"
|
||||
shift
|
||||
;;
|
||||
--extra-files)
|
||||
if [[ $# -lt 3 ]]; then
|
||||
echo "Option $1 requires two arguments: source, destination" >&2
|
||||
exit 1
|
||||
fi
|
||||
extraFiles[$2]=$3
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--option)
|
||||
if [[ $# -lt 3 ]]; then
|
||||
echo "Option $1 requires two arguments: key, value" >&2
|
||||
exit 1
|
||||
fi
|
||||
nix_args+=(--option "$2" "$3")
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--disk)
|
||||
if [[ $# -lt 3 ]]; then
|
||||
echo "Option $1 requires two arguments: disk_name, device_path" >&2
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck disable=SC2034
|
||||
diskMappings[$2]=$3
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--mount-point)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Option $1 requires an argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
mountPoint=$2
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
showUsage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
cleanupMountPoint() {
|
||||
if mountpoint -q "${mountPoint}"; then
|
||||
umount -R "${mountPoint}"
|
||||
fi
|
||||
rmdir "${mountPoint}"
|
||||
}
|
||||
|
||||
nixBuild() {
|
||||
if command -v nom-build > /dev/null; then
|
||||
nom-build "$@"
|
||||
else
|
||||
nix-build "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
maybeRun () {
|
||||
if [[ -z ${dry_run-} ]]; then
|
||||
"$@"
|
||||
else
|
||||
echo "Would run: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
parseArgs "$@"
|
||||
|
||||
if [[ -z ${flake-} ]]; then
|
||||
echo "Please specify the flake-uri with --flake to use for installation." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if we are root
|
||||
if [[ "$EUID" -ne 0 ]] && [[ -z ${dry_run-} ]]; then
|
||||
echo "This script must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
|
||||
flake="${BASH_REMATCH[1]}"
|
||||
flakeAttr="${BASH_REMATCH[2]}"
|
||||
fi
|
||||
|
||||
if [[ -e "$flake" ]]; then
|
||||
flake=$(realpath "$flake")
|
||||
fi
|
||||
|
||||
if [[ -z ${flakeAttr-} ]]; then
|
||||
echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri." >&2
|
||||
echo 'For example, to use the output nixosConfigurations.foo from the flake.nix, append "#foo" to the flake-uri.' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
maybeRun mkdir -p "${mountPoint}"
|
||||
maybeRun chmod 755 "${mountPoint}" # bcachefs wants 755
|
||||
# shellcheck disable=SC2064
|
||||
if [[ -z ${dry_run-} ]]; then
|
||||
trap cleanupMountPoint EXIT
|
||||
fi
|
||||
|
||||
outputs=$(nixBuild "${libexec_dir}"/install-cli.nix \
|
||||
"${nix_args[@]}" \
|
||||
--no-out-link \
|
||||
--impure \
|
||||
--argstr flake "$flake" \
|
||||
--argstr flakeAttr "$flakeAttr" \
|
||||
--argstr rootMountPoint "$mountPoint" \
|
||||
--arg writeEfiBootEntries "$writeEfiBootEntries" \
|
||||
--arg diskMappings "$(serialiaseArrayToNix diskMappings)" \
|
||||
--argstr extraSystemConfig "$extraSystemConfig" \
|
||||
-A installToplevel \
|
||||
-A closureInfo \
|
||||
-A "$diskoAttr")
|
||||
|
||||
IFS=$'\n' mapfile -t artifacts <<<"$outputs"
|
||||
nixos_system=${artifacts[0]}
|
||||
closure_info=${artifacts[1]}
|
||||
disko_script=${artifacts[2]}
|
||||
|
||||
if [[ -n ${dry_run-} ]]; then
|
||||
echo "Would run: $disko_script"
|
||||
echo "Would run: nixos-install --system '$nixos_system' --root '$mountPoint'"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# We don't want swap as can break your running system in weird ways if you eject the disk
|
||||
# Hopefully disko-install has enough RAM to run without swap, otherwise we can make this configurable in future.
|
||||
DISKO_SKIP_SWAP=1 "$disko_script"
|
||||
|
||||
for source in "${!extraFiles[@]}"; do
|
||||
destination=${extraFiles[$source]}
|
||||
mkdir -p "$mountPoint/$(dirname "$destination")"
|
||||
cp -ar "$source" "$mountPoint/$destination"
|
||||
done
|
||||
|
||||
# nix copy uses up a lot of memory and we work around issues with incorrect checksums in our store
|
||||
# that can be caused by using closureInfo in combination with multiple builders and non-deterministic builds.
|
||||
# Therefore if we have a blank store, we copy the store paths and registration from the closureInfo.
|
||||
if [[ ! -f "${mountPoint}/nix/var/nix/db/db.sqlite" ]]; then
|
||||
echo "Copying store paths" >&2
|
||||
mkdir -p "${mountPoint}/nix/store"
|
||||
xargs cp --recursive --target "${mountPoint}/nix/store" < "${closure_info}/store-paths"
|
||||
echo "Loading nix database" >&2
|
||||
NIX_STATE_DIR=${mountPoint}/nix/var/nix nix-store --load-db < "${closure_info}/registration"
|
||||
fi
|
||||
|
||||
nixos-install --no-channel-copy --no-root-password --system "$nixos_system" --root "$mountPoint"
|
||||
}
|
||||
|
||||
if main "$@"; then
|
||||
echo "disko-install succeeded"
|
||||
exit 0
|
||||
else
|
||||
echo "disko-install failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
@ -1,43 +0,0 @@
|
||||
{ lib, nixosOptionsDoc, runCommand, fetchurl, pandoc }:
|
||||
|
||||
let
|
||||
diskoLib = import ./lib {
|
||||
inherit lib;
|
||||
rootMountPoint = "/mnt";
|
||||
};
|
||||
eval = lib.evalModules {
|
||||
modules = [
|
||||
{
|
||||
options.disko = {
|
||||
devices = lib.mkOption {
|
||||
type = diskoLib.toplevel;
|
||||
default = { };
|
||||
description = "The devices to set up";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
options = nixosOptionsDoc {
|
||||
options = eval.options;
|
||||
};
|
||||
md = (runCommand "disko-options.md" { } ''
|
||||
cat >$out <<EOF
|
||||
# Disko options
|
||||
|
||||
EOF
|
||||
cat ${options.optionsCommonMark} >>$out
|
||||
'').overrideAttrs (_o: {
|
||||
# Work around https://github.com/hercules-ci/hercules-ci-agent/issues/168
|
||||
allowSubstitutes = true;
|
||||
});
|
||||
css = fetchurl {
|
||||
url = "https://gist.githubusercontent.com/killercup/5917178/raw/40840de5352083adb2693dc742e9f75dbb18650f/pandoc.css";
|
||||
sha256 = "sha256-SzSvxBIrylxBF6B/mOImLlZ+GvCfpWNLzGFViLyOeTk=";
|
||||
};
|
||||
in
|
||||
runCommand "disko.html" { nativeBuildInputs = [ pandoc ]; } ''
|
||||
mkdir $out
|
||||
cp ${css} $out/pandoc.css
|
||||
pandoc --css="pandoc.css" ${md} --to=html5 -s -f markdown+smart --metadata pagetitle="Disko options" -o $out/index.html
|
||||
''
|
||||
@ -1,178 +0,0 @@
|
||||
# How-to Guide: Disko
|
||||
|
||||
## How to use Disko without NixOS
|
||||
|
||||
TODO: Still to be documented
|
||||
|
||||
## Upgrading From Older disko versions
|
||||
|
||||
TODO: Include documentation here.
|
||||
|
||||
For now, see the
|
||||
[upgrade guide](https://github.com/JillThornhill/disko/blob/master/docs/upgrade-guide.md)
|
||||
|
||||
## Installing NixOS module
|
||||
|
||||
You can use the NixOS module in one of the following ways:
|
||||
|
||||
<details>
|
||||
<summary>Flakes (Current recommendation)</summary>
|
||||
|
||||
If you use nix flakes support:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs.disko.url = "github:nix-community/disko/latest";
|
||||
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
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>niv</summary>
|
||||
|
||||
First add it to [niv](https://github.com/nmattia/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}/module.nix" ];
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>npins</summary>
|
||||
|
||||
First add it to [npins](https://github.com/andir/npins):
|
||||
|
||||
```console
|
||||
npins add github nix-community disko
|
||||
```
|
||||
|
||||
Then add the following to your configuration.nix in the `imports` list:
|
||||
|
||||
```nix
|
||||
let
|
||||
sources = import ./npins;
|
||||
disko = import sources.disko {};
|
||||
in
|
||||
{
|
||||
imports = [ "${disko}/module.nix" ];
|
||||
…
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>nix-channel</summary>
|
||||
|
||||
As root run:
|
||||
|
||||
```console
|
||||
nix-channel --add https://github.com/nix-community/disko/archive/master.tar.gz disko
|
||||
nix-channel --update
|
||||
```
|
||||
|
||||
Then add the following to your configuration.nix in the `imports` list:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = [ <disko/module.nix> ];
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>fetchTarball</summary>
|
||||
|
||||
Add the following to your configuration.nix:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = [ "${builtins.fetchTarball "https://github.com/nix-community/disko/archive/master.tar.gz"}/module.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"
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Using the NixOS module
|
||||
|
||||
```nix
|
||||
{
|
||||
# checkout the example folder for how to configure different disko layouts
|
||||
disko.devices = {
|
||||
disk = {
|
||||
vdb = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
this will configure `fileSystems` and other required NixOS options to boot the
|
||||
specified configuration.
|
||||
|
||||
If you are on an installer, you probably want to disable `enableConfig`.
|
||||
|
||||
disko will create the scripts `disko-create` and `disko-mount` which can be used
|
||||
to create/mount the configured disk layout.
|
||||
@ -1,22 +0,0 @@
|
||||
# disko - Declarative disk partitioning
|
||||
|
||||
<img title="" src="./logo.png" alt="" width="220">
|
||||
|
||||
## Table of Contents
|
||||
|
||||
### For users
|
||||
|
||||
- [README](../README.md)
|
||||
- [Quickstart](./quickstart.md)
|
||||
- [System Requirements](./requirements.md)
|
||||
- [How to Guide](./HowTo.md)
|
||||
- [Disko-Install](./disko-install.md)
|
||||
- [Disko-Images](./disko-images.md)
|
||||
- [Support Matrix](./supportmatrix.md)
|
||||
- [Reference](./reference.md)
|
||||
- [Upgrade Guide](./upgrade-guide.md)
|
||||
- [Migrating to the new GPT layout](./table-to-gpt.md)
|
||||
|
||||
### For contributors
|
||||
|
||||
- [Running and debugging tests](./testing.md)
|
||||
@ -1,122 +0,0 @@
|
||||
# Generating Disk Images with Secrets Included using Disko
|
||||
|
||||
Using Disko on NixOS allows you to efficiently create `.raw` VM images from a
|
||||
system configuration. The generated image can be used as a VM or directly
|
||||
written to a physical drive to create a bootable disk. Follow the steps below to
|
||||
generate disk images:
|
||||
|
||||
## Generating the `.raw` VM Image
|
||||
|
||||
1. **Create a NixOS configuration that includes the disko and the disk
|
||||
configuration of your choice**
|
||||
|
||||
In the this example we create a flake containing a nixos configuration for
|
||||
`myhost`.
|
||||
|
||||
```nix
|
||||
# save this as flake.nix
|
||||
{
|
||||
description = "A disko images example";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
disko.url = "github:nix-community/disko/latest";
|
||||
disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, disko, nixpkgs }: {
|
||||
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
# You can get this file from here: https://github.com/nix-community/disko/blob/master/example/simple-efi.nix
|
||||
./simple-efi.nix
|
||||
disko.nixosModules.disko
|
||||
({ config, ... }: {
|
||||
# shut up state version warning
|
||||
system.stateVersion = config.system.nixos.version;
|
||||
# Adjust this to your liking.
|
||||
# WARNING: if you set a too low value the image might be not big enough to contain the nixos installation
|
||||
disko.devices.disk.main.imageSize = "10G";
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
2. **Build the disko image script:** Replace `myhost` in the command below with
|
||||
your specific system configuration name:
|
||||
|
||||
```console
|
||||
nix build .#nixosConfigurations.myhost.config.system.build.diskoImagesScript
|
||||
```
|
||||
|
||||
3. **Execute the disko image script:** Execute the generated disko image script.
|
||||
Running `./result --help` will output the available options:
|
||||
|
||||
```console
|
||||
./result --help
|
||||
Usage: $script [options]
|
||||
|
||||
Options:
|
||||
* --pre-format-files <src> <dst>
|
||||
copies the src to the dst on the VM, before disko is run
|
||||
This is useful to provide secrets like LUKS keys, or other files you need for formatting
|
||||
* --post-format-files <src> <dst>
|
||||
copies the src to the dst on the finished image
|
||||
These end up in the images later and is useful if you want to add some extra stateful files
|
||||
They will have the same permissions but will be owned by root:root
|
||||
* --build-memory <amt>
|
||||
specify the amount of memory in MiB that gets allocated to the build VM
|
||||
This can be useful if you want to build images with a more involed NixOS config
|
||||
The default is 1024 MiB
|
||||
```
|
||||
|
||||
An example run may look like this:
|
||||
|
||||
```
|
||||
sudo ./result --build-memory 2048
|
||||
```
|
||||
|
||||
The script will generate the actual image outside of the nix store in the
|
||||
current working directory. The create image names depend on the names used in
|
||||
`disko.devices.disk` attrset in the NixOS configuration. In our code example
|
||||
it will produce the following image:
|
||||
|
||||
```
|
||||
$ ls -la main.raw
|
||||
.rw-r--r-- root root 10 GB 2 minutes ago main.raw
|
||||
```
|
||||
|
||||
## Additional Configuration
|
||||
|
||||
- For custom image name output, define the image name in your Disko configuration:
|
||||
|
||||
```console
|
||||
disko.devices.disk.<drive>.imageName = "nixos-x86_64-linux-generic-btrfs"; # Set your preferred name
|
||||
```
|
||||
|
||||
The image scirpt will produce `nixos-x86_64-linux-generic-btrfs.raw` instead of `<drive>.raw`.
|
||||
|
||||
- For virtual drive use, define the image size in your Disko configuration:
|
||||
|
||||
```console
|
||||
disko.devices.disk.<drive>.imageSize = "32G"; # Set your preferred size
|
||||
```
|
||||
|
||||
## Understanding the Image Generation Process
|
||||
|
||||
1. Files specified in `--pre-format-files` and `--post-format-files` are
|
||||
temporarily copied to `/tmp`.
|
||||
2. Files are then moved to their respective locations in the VM both before and
|
||||
after the Disko partitioning script runs.
|
||||
3. The NixOS installer is executed, having access only to `--post-format-files`.
|
||||
4. Upon installer completion, the VM is shutdown, and the `.raw` disk files are
|
||||
moved to the local directory.
|
||||
|
||||
> **Note**: The auto-resizing feature is currently not available in Disko.
|
||||
> Contributions for this feature are welcomed. Adjust the `imageSize`
|
||||
> configuration to prevent issues related to file size and padding.
|
||||
|
||||
By following these instructions and understanding the process, you can smoothly
|
||||
generate disk images with Disko for your NixOS system configurations.
|
||||
@ -1,233 +0,0 @@
|
||||
# disko-install
|
||||
|
||||
**disko-install** enhances the normal `nixos-install` with disko's partitioning
|
||||
feature. It can be started from the NixOS installer but it can also be used to
|
||||
create bootable USB-Sticks from your normal workstation. Furthermore
|
||||
`disko-install` has a mount mode that will only mount but not destroy existing
|
||||
partitions. The mount mode can be used to mount and repair existing NixOS
|
||||
installations. This document provides a comprehensive guide on how to use
|
||||
**disko-install**, including examples for typical usage scenarios.
|
||||
|
||||
## Requirements
|
||||
|
||||
- a Linux system with Nix installed.
|
||||
- a target disk or partition for the NixOS installation.
|
||||
- a Nix flake that defines your desired NixOS configuration.
|
||||
|
||||
## Usage
|
||||
|
||||
### Fresh Installation
|
||||
|
||||
For a fresh installation, where **disko-install** will handle partitioning and
|
||||
setting up the disk, use the following syntax:
|
||||
|
||||
```console
|
||||
sudo nix run 'github:nix-community/disko/latest#disko-install' -- --flake <flake-url>#<flake-attr> --disk <disk-name> <disk-device>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
First run `nixos-generate-config --root /tmp/config --no-filesystems` and edit
|
||||
`configuration.nix` to your liking.
|
||||
|
||||
Then add the following `flake.nix` inside `/tmp/config/etc/nixos`. In this
|
||||
example we assume a system that has been booted with EFI:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
inputs.disko.url = "github:nix-community/disko/latest";
|
||||
inputs.disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
outputs = { self, disko, nixpkgs }: {
|
||||
nixosConfigurations.mymachine = nixpkgs.legacyPackages.x86_64-linux.nixos [
|
||||
./configuration.nix
|
||||
disko.nixosModules.disko
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
# When using disko-install, we will overwrite this value from the commandline
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
MBR = {
|
||||
type = "EF02"; # for grub MBR
|
||||
size = "1M";
|
||||
priority = 1; # Needs to be first partition
|
||||
};
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Identify the device name that you want to install NixOS to:
|
||||
|
||||
```console
|
||||
$ lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
sda 8:0 1 14.9G 0 disk
|
||||
└─sda1 8:1 1 14.9G 0 part
|
||||
zd0 230:0 0 10G 0 disk
|
||||
├─zd0p1 230:1 0 500M 0 part
|
||||
└─zd0p2 230:2 0 9.5G 0 part /mnt
|
||||
nvme0n1 259:0 0 1.8T 0 disk
|
||||
├─nvme0n1p1 259:1 0 1G 0 part /boot
|
||||
├─nvme0n1p2 259:2 0 16M 0 part
|
||||
├─nvme0n1p3 259:3 0 250G 0 part
|
||||
└─nvme0n1p4 259:4 0 1.6T 0 part
|
||||
```
|
||||
|
||||
In our example, we want to install to a USB-stick (/dev/sda):
|
||||
|
||||
```console
|
||||
$ sudo nix run 'github:nix-community/disko/latest#disko-install' -- --flake '/tmp/config/etc/nixos#mymachine' --disk main /dev/sda
|
||||
```
|
||||
|
||||
Afterwards you can test your USB-stick by either selecting during the boot or
|
||||
attaching it to a qemu-vm:
|
||||
|
||||
```
|
||||
$ sudo qemu-kvm -enable-kvm -hda /dev/sda
|
||||
```
|
||||
|
||||
### Persisting boot entries to EFI vars flash
|
||||
|
||||
**disko-install** is designed for NixOS installations on portable storage or
|
||||
disks that may be transferred between computers. As such, it does not modify the
|
||||
host's NVRAM by default. To ensure your NixOS installation boots seamlessly on
|
||||
new hardware or to prioritize it in your current machine's boot order, use the
|
||||
--write-efi-boot-entries option:
|
||||
|
||||
```console
|
||||
$ sudo nix run 'github:nix-community/disko/latest#disko-install' -- --write-efi-boot-entries --flake '/tmp/config/etc/nixos#mymachine' --disk main /dev/sda
|
||||
```
|
||||
|
||||
This command installs NixOS with **disko-install** and sets the newly installed
|
||||
system as the default boot option, without affecting the flexibility to boot
|
||||
from other devices if needed.
|
||||
|
||||
### Using disko-install in an offline installer
|
||||
|
||||
If you want to use **disko-install** from a custom installer without internet,
|
||||
you need to make sure that in addition to the toplevel of your NixOS closure
|
||||
that you plan to install, it also needs to contain **diskoScript** and all the
|
||||
flake inputs for evaluation.
|
||||
|
||||
#### Example configuration to install
|
||||
|
||||
Add this to your flake.nix output:
|
||||
|
||||
```nix
|
||||
{
|
||||
nixosConfigurations.your-machine = inputs.nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
# to pass this flake into your configuration (see the example below)
|
||||
specialArgs = {inherit self;};
|
||||
modules = [
|
||||
{
|
||||
# TODO: add your NixOS configuration here, don't forget your hardware-configuration.nix as well!
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
imports = [ self.inputs.disko.nixosModules.disko ];
|
||||
disko.devices = {
|
||||
disk = {
|
||||
vdb = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Example for a NixOS installer
|
||||
|
||||
```nix
|
||||
# `self` here is referring to the flake `self`, you may need to pass it using `specialArgs` or define your NixOS installer configuration
|
||||
# in the flake.nix itself to get direct access to the `self` flake variable.
|
||||
{ pkgs, self, ... }:
|
||||
let
|
||||
dependencies = [
|
||||
self.nixosConfigurations.your-machine.config.system.build.toplevel
|
||||
self.nixosConfigurations.your-machine.config.system.build.diskoScript
|
||||
self.nixosConfigurations.your-machine.config.system.build.diskoScript.drvPath
|
||||
self.nixosConfigurations.your-machine.pkgs.stdenv.drvPath
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/f2fd33a198a58c4f3d53213f01432e4d88474956/nixos/modules/system/activation/top-level.nix#L342
|
||||
self.nixosConfigurations.your-machine.pkgs.perlPackages.ConfigIniFiles
|
||||
self.nixosConfigurations.your-machine.pkgs.perlPackages.FileSlurp
|
||||
|
||||
(self.nixosConfigurations.your-machine.pkgs.closureInfo { rootPaths = [ ]; }).drvPath
|
||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||
|
||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||
in
|
||||
# Now add `closureInfo` to your NixOS installer
|
||||
{
|
||||
environment.etc."install-closure".source = "${closureInfo}/store-paths";
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellScriptBin "install-nixos-unattended" ''
|
||||
set -eux
|
||||
# Replace "/dev/disk/by-id/some-disk-id" with your actual disk ID
|
||||
exec ${pkgs.disko}/bin/disko-install --flake "${self}#your-machine" --disk vdb "/dev/disk/by-id/some-disk-id"
|
||||
'')
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Also see the
|
||||
[NixOS test of disko-install](https://github.com/nix-community/disko/blob/master/tests/disko-install/default.nix)
|
||||
that also runs without internet.
|
||||
@ -1,26 +0,0 @@
|
||||
# Running Interactive VMs with disko
|
||||
|
||||
disko now exports its own flavor of interactive VMs (similiar to
|
||||
config.system.build.vm). Simply import the disko module and build the vm runner
|
||||
with:
|
||||
|
||||
```
|
||||
nix run -L '.#nixosConfigurations.mymachine.config.system.build.vmWithDisko'
|
||||
```
|
||||
|
||||
You can configure the VM using the `virtualisation.vmVariantWithDisko` NixOS
|
||||
option:
|
||||
|
||||
```nix
|
||||
{
|
||||
virtualisation.vmVariantWithDisko = {
|
||||
virtualisation.fileSystems."/persist".neededForBoot = true;
|
||||
# For running VM on macos: https://www.tweag.io/blog/2023-02-09-nixos-vm-on-macos/
|
||||
# virtualisation.host.pkgs = inputs.nixpkgs.legacyPackages.aarch64-darwin;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
extraConfig that is set in disko.tests.extraConfig is also applied to the
|
||||
interactive VMs. imageSize of the VMs will be determined by the imageSize in the
|
||||
disk type in your disko config. memorySize is set by disko.memSize
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
@ -1,225 +0,0 @@
|
||||
# disko - Declarative disk partitioning
|
||||
|
||||
<img src="./logo.png" title="" alt="Project logo" width="247">
|
||||
|
||||
[Documentation Index](./INDEX.md)
|
||||
|
||||
## Quickstart Guide
|
||||
|
||||
This tutorial describes how to install NixOS on a single disk system using
|
||||
`disko`. You will also need to refer to the NixOS manual, which is available
|
||||
[here.](https://nixos.org/manual/nixos/stable/index.html#ex-config)
|
||||
|
||||
Please note that `disko` will reformat the entire disk and overwrite any
|
||||
existing partitions. Dual booting with other operating systems is not supported.
|
||||
|
||||
### Step 1: Choose a Disk Configuration
|
||||
|
||||
Real-world templates are provided in this
|
||||
[repository](https://github.com/nix-community/disko-templates).
|
||||
|
||||
More disk layouts for all filesystems can be also found in the
|
||||
[example](https://github.com/nix-community/disko/tree/master/example) directory
|
||||
of disko. However these examples are also used for regression tests in disko and
|
||||
may have uncommon options in them to fully exercise all features of disko, that
|
||||
you may need to change or remove.
|
||||
|
||||
Decide which of these layouts best suits your requirements. If you're not sure
|
||||
which layout to pick, use the
|
||||
[single-disk-ext4](https://github.com/nix-community/disko-templates/blob/main/single-disk-ext4/disko-config.nix)
|
||||
configuration. This layout is compatible with both BIOS and EFI systems.
|
||||
|
||||
Refer to the [reference manual](./reference.md) for more information about the
|
||||
sample layouts and how to build your own configuration.
|
||||
|
||||
To copy a template use this command in your nixos configuration directory:
|
||||
|
||||
```
|
||||
nix flake init --template github:nix-community/disko-templates#single-disk-ext4
|
||||
```
|
||||
|
||||
This will write a file called `disko-config.nix` into the current directory.
|
||||
Import this file in your NixOS configuration:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = [ ./disko-config.nix ];
|
||||
}
|
||||
```
|
||||
|
||||
If you want to choose a layout from the disko example directory instead, you'll
|
||||
need to make a note of the URL to the raw file. To do this, open the file in
|
||||
Github. Immediately below the list of contributors, you will see a button
|
||||
labelled 'RAW' near the right hand side. Click this. The URL of the raw file
|
||||
will appear in the search bar of your browser. It will look something like this:
|
||||
|
||||
```
|
||||
https://raw.githubusercontent.com/nix-community/disko/master/example/hybrid.nix
|
||||
```
|
||||
|
||||
### Step 2: Boot the installer
|
||||
|
||||
Download the NixOS ISO image from the NixOS
|
||||
[download page](https://nixos.org/download.html#nixos-iso), and create a
|
||||
bootable USB drive following the instructions
|
||||
in [Section 2.4.1 "Booting from a USB flash drive"](https://nixos.org/manual/nixos/stable/index.html#sec-booting-from-usb) of
|
||||
the NixOS manual. Boot the machine from this USB drive.
|
||||
|
||||
### Step 3: Retrieve the disk name
|
||||
|
||||
Identify the name of your system disk by using the `lsblk` command as follows:
|
||||
|
||||
```console
|
||||
lsblk
|
||||
```
|
||||
|
||||
The output from this command will look something like this:
|
||||
|
||||
```
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
nvme0n1 259:0 0 1,8T 0 disk
|
||||
```
|
||||
|
||||
In this example, an empty NVME SSD with 2TB space is shown with the disk name
|
||||
"nvme0n1". Make a note of the disk name as you will need it later.
|
||||
|
||||
### Step 4: Copy the disk configuration to your machine
|
||||
|
||||
In Step 1, you chose a disk layout configuration from the
|
||||
[examples directory](https://github.com/nix-community/disko/tree/master/example),
|
||||
and made a note of its URL.
|
||||
|
||||
Your configuration needs to be saved on the new machine for example
|
||||
as /tmp/disk-config.nix. You can do this using the `curl` command to download
|
||||
from the url you noted above, using the `-o` option to save the file as
|
||||
disk-config.nix. Your commands would look like this if you had chosen the hybrid
|
||||
layout:
|
||||
|
||||
```console
|
||||
cd /tmp
|
||||
curl https://raw.githubusercontent.com/nix-community/disko/master/example/hybrid.nix -o /tmp/disk-config.nix
|
||||
```
|
||||
|
||||
### Step 5: Adjust the device in the disk configuration
|
||||
|
||||
Inside the disk-config.nix the device needs to point to the correct disk name.
|
||||
|
||||
Open the configuration in your favorite editor i.e.:
|
||||
|
||||
```console
|
||||
nano /tmp/disk-config.nix
|
||||
```
|
||||
|
||||
Replace `<disk-name>` with the name of your disk obtained in Step 1.
|
||||
|
||||
```nix
|
||||
# ...
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "<disk-name>";
|
||||
content = {
|
||||
type = "gpt";
|
||||
# ...
|
||||
```
|
||||
|
||||
### Step 6: Run disko to partition, format and mount your disks
|
||||
|
||||
The following step will partition and format your disk, and mount it to `/mnt`.
|
||||
|
||||
**Please note: This will erase any existing data on your disk.**
|
||||
|
||||
```console
|
||||
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount /tmp/disk-config.nix
|
||||
```
|
||||
|
||||
After the command has run, your file system should have been formatted and
|
||||
mounted. You can verify this by running the following command:
|
||||
|
||||
```console
|
||||
mount | grep /mnt
|
||||
```
|
||||
|
||||
The output should look like this if your disk name is `nvme0n1`.
|
||||
|
||||
```
|
||||
/dev/nvme0n1p1 on /mnt type ext4 (rw,relatime,stripe=2)
|
||||
/dev/nvme0n1p2 on /mnt/boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
|
||||
```
|
||||
|
||||
### Step 7: Complete the NixOS installation.
|
||||
|
||||
Your disks have now been formatted and mounted, and you are ready to complete
|
||||
the NixOS installation as described in the
|
||||
[NixOS manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation) -
|
||||
see the section headed "**Installing**", Steps 3 onwards. However, you will need
|
||||
to include the partitioning and formatting configurations that you copied into
|
||||
`/tmp/disk-config.nix` in your configuration, rather than allowing NixOS to
|
||||
generate information about your file systems. When you are configuring the
|
||||
system as per Step 4 of the manual, you should:
|
||||
|
||||
a) Include the `no-filesystems` switch when using the `nixos-generate-config`
|
||||
command to generate an initial `configuration.nix`. You will be supplying the
|
||||
file system configuration details from `disk-config.nix`. Your CLI command to
|
||||
generate the configuration will be:
|
||||
|
||||
```console
|
||||
nixos-generate-config --no-filesystems --root /mnt
|
||||
```
|
||||
|
||||
This will create the file `configuration.nix` in `/mnt/etc/nixos`.
|
||||
|
||||
b) Move the `disko` configuration to /etc/nixos
|
||||
|
||||
```console
|
||||
mv /tmp/disk-config.nix /mnt/etc/nixos
|
||||
```
|
||||
|
||||
c) You can now edit `configuration.nix` as per your requirements. This is
|
||||
described in Step 4 of the manual. For more information about configuring your
|
||||
system, refer to the NixOS manual.
|
||||
[Chapter 6, Configuration Syntax](https://nixos.org/manual/nixos/stable/index.html#sec-configuration-syntax)
|
||||
describes the NixOS configuration syntax, and
|
||||
[Appendix A, Configuration Options](https://nixos.org/manual/nixos/stable/options.html)
|
||||
gives a list of available options. You can find also find a minimal example of a
|
||||
NixOS configuration in the manual:
|
||||
[Example: NixOS Configuration](https://nixos.org/manual/nixos/stable/index.html#ex-config).
|
||||
|
||||
d) When editing `configuration.nix`, you will need to add the `disko` NixOS
|
||||
module and `disk-config.nix` to the imports section. This section will already
|
||||
include the file `./hardware-configuration.nix`, and you can add the new entries
|
||||
just below this. This section will now include:
|
||||
|
||||
```nix
|
||||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
./hardware-configuration.nix
|
||||
"${builtins.fetchTarball "https://github.com/nix-community/disko/archive/master.tar.gz"}/module.nix"
|
||||
./disk-config.nix
|
||||
];
|
||||
```
|
||||
|
||||
e) If you chose the hybrid-partition scheme, then choose `grub` as a bootloader,
|
||||
otherwise follow the recommendations in Step 4 of the **Installation** section
|
||||
of the NixOS manual. The following configuration for `grub` works for both EFI
|
||||
and BIOS systems. Add this to your configuration.nix, commenting out the
|
||||
existing lines that configure `systemd-boot`. The entries will look like this:
|
||||
|
||||
**Note:** Its not necessary to set `boot.loader.grub.device` here, since Disko
|
||||
will take care of that automatically.
|
||||
|
||||
```nix
|
||||
# ...
|
||||
#boot.loader.systemd-boot.enable = true;
|
||||
#boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.grub.enable = true;
|
||||
boot.loader.grub.efiSupport = true;
|
||||
boot.loader.grub.efiInstallAsRemovable = true;
|
||||
# ...
|
||||
```
|
||||
|
||||
f) Finish the installation and reboot your machine,
|
||||
|
||||
```console
|
||||
nixos-install
|
||||
reboot
|
||||
```
|
||||
@ -1,47 +0,0 @@
|
||||
# Reference Manual: disko
|
||||
|
||||
## Module Options
|
||||
|
||||
We are currently having issues being able to generate proper module option
|
||||
documentation for our recursive disko types. However you can read the available
|
||||
options [here](https://github.com/nix-community/disko/tree/master/lib/types).
|
||||
Combined with the
|
||||
[examples](https://github.com/nix-community/disko/tree/master/example) this
|
||||
hopefully gives you an overview.
|
||||
|
||||
## Command Line Options
|
||||
|
||||
```
|
||||
Usage: ./disko [options] disk-config.nix
|
||||
or ./disko [options] --flake github:somebody/somewhere#disk-config
|
||||
|
||||
With flakes, disk-config is discovered first under the .diskoConfigurations top level attribute
|
||||
or else from the disko module of a NixOS configuration of that name under .nixosConfigurations.
|
||||
|
||||
Options:
|
||||
|
||||
* -m, --mode mode
|
||||
set the mode, either distroy, format, mount, format,mount or destroy,format,mount
|
||||
destroy: unmount filesystems and destroy partition tables of the selected disks
|
||||
format: create partition tables, zpools, lvms, raids and filesystems if they don't exist yet
|
||||
mount: mount the partitions at the specified root-mountpoint
|
||||
format,mount: run format and mount in sequence
|
||||
destroy,format,mount: run all three modes in sequence. Previously known as --mode disko
|
||||
* -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
|
||||
* --root-mountpoint /some/other/mnt
|
||||
where to mount the device tree (default: /mnt)
|
||||
* --dry-run
|
||||
just show the path to the script instead of running it
|
||||
* --no-deps
|
||||
avoid adding another dependency closure to an in-memory installer
|
||||
requires all necessary dependencies to be available in the environment
|
||||
* --debug
|
||||
run with set -x
|
||||
* --yes-wipe-all-disks
|
||||
skip the safety check for destroying partitions, useful for automation
|
||||
```
|
||||
@ -1,9 +0,0 @@
|
||||
# disko - Declarative disk partitioning
|
||||
|
||||
<img title="" src="./logo.jpeg" alt="" width="220">
|
||||
|
||||
[Documentation Index](./INDEX.md)
|
||||
|
||||
## System Requirements
|
||||
|
||||
TODO: Populate this
|
||||
@ -1,9 +0,0 @@
|
||||
# disko - Declarative disk partitioning
|
||||
|
||||
<img title="" src="./logo.jpeg" alt="" width="220">
|
||||
|
||||
[Documentation Index](./INDEX.md)
|
||||
|
||||
## Support Matrix
|
||||
|
||||
TODO: Populate this
|
||||
@ -1,137 +0,0 @@
|
||||
# Migrating to the new GPT layout
|
||||
|
||||
## Situation
|
||||
|
||||
When evaluating your NixOS system closure the following trace appears:
|
||||
|
||||
```
|
||||
trace: warning: The legacy table is outdated and should not be used. We recommend using the gpt type instead.
|
||||
Please note that certain features, such as the test framework, may not function properly with the legacy table type.
|
||||
If you encounter errors similar to:
|
||||
"error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times,"
|
||||
this is likely due to the use of the legacy table type.
|
||||
```
|
||||
|
||||
The solution is to migrate to the new `gpt` layout type.
|
||||
|
||||
## Precondition
|
||||
|
||||
Disko was set up with
|
||||
|
||||
- `type = "table"` and
|
||||
- `format = "gpt"`,
|
||||
|
||||
for example like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
disko.devices.disk.example = {
|
||||
type = "disk";
|
||||
device = "/dev/nvme0n1";
|
||||
content = {
|
||||
type = "table";
|
||||
format = "gpt";
|
||||
partitions = [
|
||||
{
|
||||
name = "ESP";
|
||||
start = "0";
|
||||
end = "512MiB";
|
||||
fs-type = "fat32";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "root";
|
||||
start = "512MiB";
|
||||
end = "100%";
|
||||
content.format = "ext4";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Remediation
|
||||
|
||||
The new GPT layout (`type = "gpt"`) uses partlabels to realize the partiton
|
||||
numbering. For this reason you have to manually set up partition labels, if you
|
||||
want to resolve this issue.
|
||||
|
||||
### Create GPT partition labels
|
||||
|
||||
For each partition involved, create the partition label from these components:
|
||||
|
||||
- The partition number (e.g. /dev/nvme0n**1**, or /dev/sda**1**)
|
||||
- The parent type in your disko config (value of
|
||||
`disko.device.disk.example.type = "disk";`)
|
||||
- The parent name in your disko config (attribute name of
|
||||
`disko.devices.disk.example`, so `example` in this example)
|
||||
- The partition name in your disko config (attribute name of
|
||||
`disko.devices.disk.content.partitions.*.name`)
|
||||
|
||||
```bash
|
||||
# sgdisk -c 1:disk-example-ESP /dev/nvme0n1
|
||||
# sgdisk -c 2:disk-example-zfs /dev/nvme0n1
|
||||
Warning: The kernel is still using the old partition table.
|
||||
The new table will be used at the next reboot or after you
|
||||
run partprobe(8) or kpartx(8)
|
||||
The operation has completed successfully.
|
||||
```
|
||||
|
||||
### Update disko configuration
|
||||
|
||||
Make the following changes to your disko configuration:
|
||||
|
||||
1. Set `disko.devices.disk.example.content.type = "gpt"`
|
||||
1. Remove `disko.devices.disk.example.content.format`
|
||||
1. Convert `disko.devices.disk.example.content.partitions` to an attribute set and
|
||||
promote the `name` field to the key for its partition
|
||||
1. Add a `priority` field to each partition, to reflect the intended partition
|
||||
number
|
||||
|
||||
Then rebuild your system and reboot.
|
||||
|
||||
### Recovering from mistake
|
||||
|
||||
If you made a mistake here, your system will be waiting for devices to appear,
|
||||
and then run into timeouts. You can easily recover from this, since rebooting
|
||||
into an old generation will still use the legacy way of numbering of partitions.
|
||||
|
||||
## Result
|
||||
|
||||
The fixed disko configuration would look like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
disko.devices.disk.example = {
|
||||
type = "disk";
|
||||
device = "/dev/nvme0n1";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "512MiB";
|
||||
type = "EF00";
|
||||
priority = 1;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
priority = 2;
|
||||
content.format = "ext4";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -1,160 +0,0 @@
|
||||
# Running and debugging tests
|
||||
|
||||
Disko makes extensive use of VM tests. All examples you can find in
|
||||
[the example directory](../example) have a respective test suite that verifies
|
||||
the example is working in [the tests directory](../tests/). They utilize the
|
||||
[NixOS test functionality](https://nixos.org/manual/nixos/stable/#sec-nixos-tests).
|
||||
|
||||
We use a wrapper around this called `makeDiskoTest`. There is currently (as of
|
||||
2024-10-16) no documentation for all its arguments, but you can have a look at
|
||||
[its current code](https://github.com/nix-community/disko/blob/master/lib/tests.nix#L44C5-L58C10),
|
||||
that should already be helpful.
|
||||
|
||||
However, you don't need to know about all of the inner workings to interact with
|
||||
the tests effectively. For some of the most common operations, see the sections
|
||||
below.
|
||||
|
||||
## Run just one of the tests
|
||||
|
||||
```sh
|
||||
nix build --no-link .#checks.x86_64-linux.simple-efi
|
||||
```
|
||||
|
||||
This will run the test in [`tests/simple-efi.nix`](../tests/simple-efi.nix),
|
||||
which builds a VM with all disks specified in the
|
||||
[`example/simple-efi.nix`](../example/simple-efi.nix) config connected as
|
||||
virtual devices, run disko to format them, reboot, verify the VM boots properly,
|
||||
and then run the code specified in `extraTestScript` to validate that the
|
||||
partitions have been created and were mounted as expected.
|
||||
|
||||
### How `extraTestScript` works
|
||||
|
||||
This is written in Python. The most common lines you'll see look something like
|
||||
this:
|
||||
|
||||
```python
|
||||
machine.succeed("test -b /dev/md/raid1");
|
||||
machine.succeed("mountpoint /");
|
||||
```
|
||||
|
||||
The `machine` in these is a machine object, which defines
|
||||
[a multitude of functions to interact with and test](https://nixos.org/manual/nixos/stable/#ssec-machine-objects),
|
||||
assumptions about the state of the VM after formatting and rebooting.
|
||||
|
||||
Disko currently (as of 2024-10-16) doesn't have any tests that utilize multiple
|
||||
VMs at once, so the only machine available in these scripts is always just the
|
||||
default `machine`.
|
||||
|
||||
## Debugging tests
|
||||
|
||||
If you make changes to disko, you might break a test, or you may want to modify
|
||||
a test to prevent regressions. In these cases, running the full test with
|
||||
`nix build` every time is time-consuming and tedious.
|
||||
|
||||
Instead, you can build and then run the VM for a test in interactive mode. This
|
||||
will create the VM and all virtual disks as required by the test's config, but
|
||||
allow you to interact with the machine on a terminal afterwards.
|
||||
|
||||
First, build the interactive test driver and run it:
|
||||
|
||||
```
|
||||
nix build .#checks.x86_64-linux.simple-efi.driverInteractive
|
||||
result/bin/nixos-test-driver --keep-vm-state
|
||||
```
|
||||
|
||||
This will open an IPython prompt in which you can use th same objects and
|
||||
functions as in `extraTestScript`. In there, you can run
|
||||
|
||||
```
|
||||
machine.shell_interact()
|
||||
```
|
||||
|
||||
to start the VM and attach the terminal to it. This will also open a QEMU
|
||||
window, in which you can log in as `root` with no password, but that makes it
|
||||
more difficult to paste input and output. Instead, wait for the systemd messages
|
||||
to settle down, and then **simply start typing**. This should make a `$` prompt
|
||||
appear, indicating that the machine is ready to take commands. The NixOS manual
|
||||
calls out a few special messages to look for, but these are buried underneath
|
||||
the systemd logs.
|
||||
|
||||
Once you are in this terminal, you're running commands on the VM. The only thing
|
||||
that doesn't work here is the `exit` command. Instead, you need to press Ctrl+D
|
||||
and wait for a second to return to the IPython prompt.
|
||||
|
||||
In summary, a full session looks something like this:
|
||||
|
||||
```
|
||||
# nix build .#checks.x86_64-linux.simple-efi.driverInteractive
|
||||
# result/bin/nixos-test-driver --keep-vm-state
|
||||
start all VLans
|
||||
start vlan
|
||||
running vlan (pid 146244; ctl /tmp/vde1.ctl)
|
||||
(finished: start all VLans, in 0.00 seconds)
|
||||
additionally exposed symbols:
|
||||
machine,
|
||||
vlan1,
|
||||
start_all, test_script, machines, vlans, driver, log, os, create_machine, subtest, run_tests, join_all, retry, serial_stdout_off, serial_stdout_on, polling_condition, Machine
|
||||
>>> machine.shell_interact()
|
||||
machine: waiting for the VM to finish booting
|
||||
machine: starting vm
|
||||
machine: QEMU running (pid 146286)
|
||||
machine # [ 0.000000] Linux version 6.6.48 (nixbld@localhost) (gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42) #1-NixOS SMP PREEMPT_DYNAMIC Thu Aug 29 15:33:59 UTC 2024
|
||||
machine # [ 0.000000] Command line: console=ttyS0 panic=1 boot.panic_on_fail clocksource=acpi_pm loglevel=7 net.ifnames=0 init=/nix/store/0a52bbvxr5p7xijbbk17qqlk8xm4790y-nixos-system-machine-test/init regInfo=/nix/store/3sh5nl75bnj1jg87p5gcrdzs0lk154ma-closure-info/registration console=ttyS0
|
||||
machine # [ 0.000000] BIOS-provided physical RAM map:
|
||||
...
|
||||
... more systemd messages
|
||||
...
|
||||
machine # [ 6.135577] dhcpcd[679]: DUID 00:01:00:01:2e:a2:74:e6:52:54:00:12:34:56
|
||||
machine # [ 6.142785] systemd[1]: Finished Kernel Auditing.
|
||||
machine: Guest shell says: b'Spawning backdoor root shell...\n'
|
||||
machine: connected to guest root shell
|
||||
machine: (connecting took 6.61 seconds)
|
||||
(finished: waiting for the VM to finish booting, in 6.99 seconds)
|
||||
machine: Terminal is ready (there is no initial prompt):
|
||||
machine # [ 6.265451] 8021q: 802.1Q VLAN Support v1.8
|
||||
machine # [ 6.186797] nsncd[669]: Oct 16 13:11:55.010 INFO started, config: Config { ignored_request_types: {}, worker_count: 8, handoff_timeout: 3s }, path: "/var/run/nscd/socket"
|
||||
...
|
||||
... more systemd messages
|
||||
...
|
||||
machine # [ 12.376900] systemd[1]: Reached target Host and Network Name Lookups.
|
||||
machine # [ 12.379265] systemd[1]: Reached target User and Group Name Lookups.
|
||||
$ lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
fd0 2:0 1 4K 0 disk
|
||||
sr0 11:0 1 1024M 0 rom
|
||||
vda 253:0 0 1G 0 disk /
|
||||
vdb 253:16 0 4G 0 disk
|
||||
├─vdb1 253:17 0 500M 0 part
|
||||
└─vdb2 253:18 0 3.5G 0 part
|
||||
```
|
||||
|
||||
You can find some additional details in
|
||||
[the NixOS manual's section on interactive testing](https://nixos.org/manual/nixos/stable/#sec-running-nixos-tests-interactively).
|
||||
|
||||
## Running all tests at once
|
||||
|
||||
If you have a bit of experience, you might be inclined to run `nix flake check`
|
||||
to run all tests at once. However, we instead recommend using
|
||||
[nix-fast-build](https://github.com/Mic92/nix-fast-build). The reason for this
|
||||
is that each individual test takes a while to run, but only uses <=4GiB of RAM
|
||||
and a limited amount of CPU resources. This means they can easily be evaluated
|
||||
and run in parallel to save time, but `nix` doesn't to that, so a full test run
|
||||
takes >40 minutes on a mid-range system. With `nix-fast-build` you can scale up
|
||||
the number of workers depending on your system's capabilities. It also utilizes
|
||||
[`nix-output-monitor`](https://github.com/maralorn/nix-output-monitor) to give
|
||||
you a progress indicator during the build process as well. For example, on a
|
||||
machine with 16GB of RAM, this gives you a 2x speed up without clogging your
|
||||
system:
|
||||
|
||||
```sh
|
||||
nix shell nixpkgs#nix-fast-build
|
||||
nix-fast-build --no-link -j 2 --eval-workers 2 --flake .#checks
|
||||
```
|
||||
|
||||
You can try higher numbers if you want to. Be careful with scaling up
|
||||
`--eval-workers`, each of these will use 100% of a CPU core and they don't leave
|
||||
any time for hyperthreading, so 4 workers will max out a a CPU with 4 cores and
|
||||
8 threads, potentially rendering your system unresponsive! `-j` is less
|
||||
dangerous to scale up, but you probably don't want to go higher than
|
||||
`(<ram in your system> - 4GB)/4GB` to prevent excessive swap usage, which will
|
||||
would slow down the test VMs to a crawl.
|
||||
@ -1,173 +0,0 @@
|
||||
# 2023-07-09 121df48
|
||||
|
||||
Changes:
|
||||
|
||||
- BTRFS subvolumes are mounted if and only their `mountpoint` is set.
|
||||
|
||||
Especially, if you have specific mount options for a subvolume (through
|
||||
`mountOptions`), make sure to set `mountpoint` otherwise the subvolume will not
|
||||
be mounted.
|
||||
|
||||
This change allows more flexibility when using BTRFS, giving access to its
|
||||
volume management functionality.
|
||||
|
||||
It allows layouts as the following:
|
||||
|
||||
```nix
|
||||
content = {
|
||||
type = "btrfs";
|
||||
# BTRFS partition is not mounted as it doesn't set a mountpoint explicitly
|
||||
subvolumes = {
|
||||
# This subvolume will not be mounted
|
||||
"SYSTEM" = { };
|
||||
# mounted as "/"
|
||||
"SYSTEM/rootfs" = {
|
||||
mountpoint = "/";
|
||||
};
|
||||
# mounted as "/nix"
|
||||
"SYSTEM/nix" = {
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
mountpoint = "/nix";
|
||||
};
|
||||
# This subvolume will not be mounted
|
||||
"DATA" = { };
|
||||
# mounted as "/home"
|
||||
"DATA/home" = {
|
||||
mountOptions = [ "compress=zstd" ];
|
||||
mountpoint = "/home";
|
||||
};
|
||||
# mounted as "/var/www"
|
||||
"DATA/www" = {
|
||||
mountpoint = "/var/www";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
corresponding to the following BTRFS layout:
|
||||
|
||||
```
|
||||
BTRFS partition # not mounted
|
||||
|
|
||||
|-SYSTEM # not mounted
|
||||
| |-rootfs # mounted as "/"
|
||||
| |-nix # mounted as "/nix"
|
||||
|
|
||||
|-DATA # not mounted
|
||||
|-home # mounted as "/home"
|
||||
|-www # mounted as "/var/www"
|
||||
```
|
||||
|
||||
# 2023-04-07 7d70009
|
||||
|
||||
Changes:
|
||||
|
||||
- ZFS datasets have been split into two types: `zfs_fs` and `zfs_volume`.
|
||||
- The `zfs_type` attribute has been removed.
|
||||
- The size attribute is now only available for `zfs_volume`.
|
||||
|
||||
Updated example/zfs.nix file:
|
||||
|
||||
```nix
|
||||
{
|
||||
datasets = {
|
||||
zfs_fs = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_fs";
|
||||
options."com.sun:auto-snapshot" = "true";
|
||||
};
|
||||
zfs_unmounted_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "none";
|
||||
};
|
||||
zfs_legacy_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "legacy";
|
||||
mountpoint = "/zfs_legacy_fs";
|
||||
};
|
||||
zfs_testvolume = {
|
||||
type = "zfs_volume";
|
||||
size = "10M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
Note: The `zfs_type` attribute has been replaced with a type attribute for each
|
||||
dataset, and the `size` attribute is only available for `zfs_volume`. These
|
||||
changes have been reflected in the `example/zfs.nix` file.
|
||||
|
||||
# 2023-04-07 654ecb3
|
||||
|
||||
The `lvm_lv` type is always part of an `lvm_vg` and it is no longer necessary to
|
||||
specify the type.
|
||||
|
||||
This means that if you were using the `lvm_lv` type in your code, you should
|
||||
remove it. For example, if you were defining an `lvm_lv` type like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
type = "lvm_lv";
|
||||
size = "10G";
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
You should now define it like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
size = "10G";
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `type` field is no longer necessary and should be removed from
|
||||
your code.
|
||||
|
||||
# 2023-04-07 d6f062e
|
||||
|
||||
Partition types are now always part of a table and cannot be specified
|
||||
individually anymore. This change makes the library more consistent and easier
|
||||
to use.
|
||||
|
||||
Example of how to change code:
|
||||
|
||||
Before:
|
||||
|
||||
```nix
|
||||
{
|
||||
type = "partition";
|
||||
name = "ESP";
|
||||
start = "1MiB";
|
||||
end = "100MiB";
|
||||
part-type = "primary";
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```nix
|
||||
{
|
||||
name = "ESP";
|
||||
start = "1MiB";
|
||||
end = "100MiB";
|
||||
part-type = "primary";
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `type` field is no longer necessary and should be removed from
|
||||
your code.
|
||||
|
||||
# 2023-03-22 2624af6
|
||||
|
||||
disk config now needs to be inside a disko.devices attrset always
|
||||
|
||||
# 2023-03-22 0577409
|
||||
|
||||
the extraArgs option in the luks type was renamed to extraFormatArgs
|
||||
|
||||
# 2023-02-14 6d630b8
|
||||
|
||||
btrfs, `btrfs_subvol` filesystem and `lvm_lv` extraArgs are now lists
|
||||
@ -1,34 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/disk/by-path/pci-0000:02:00.0-nvme-1";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
end = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
name = "root";
|
||||
end = "-0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "bcachefs";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
one = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
BOOT = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "boot";
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
two = {
|
||||
type = "disk";
|
||||
device = "/dev/sdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "boot";
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
boot = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
metadata = "1.0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
raid1 = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions.primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-diskseq/1";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
priority = 1;
|
||||
name = "ESP";
|
||||
start = "1M";
|
||||
end = "128M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "btrfs";
|
||||
extraArgs = [ "-f" ]; # Override existing partition
|
||||
mountpoint = "/";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-diskseq/1";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
priority = 1;
|
||||
name = "ESP";
|
||||
start = "1M";
|
||||
end = "128M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "btrfs";
|
||||
extraArgs = [ "-f" ]; # Override existing partition
|
||||
# Subvolumes must set a mountpoint in order to be mounted,
|
||||
# unless their parent is mounted
|
||||
subvolumes = {
|
||||
# Subvolume name is different from mountpoint
|
||||
"/rootfs" = {
|
||||
mountpoint = "/";
|
||||
};
|
||||
# Subvolume name is the same as the mountpoint
|
||||
"/home" = {
|
||||
mountOptions = [ "compress=zstd" ];
|
||||
mountpoint = "/home";
|
||||
};
|
||||
# Sub(sub)volume doesn't need a mountpoint as its parent is mounted
|
||||
"/home/user" = { };
|
||||
# Parent is not mounted so the mountpoint must be set
|
||||
"/nix" = {
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
mountpoint = "/nix";
|
||||
};
|
||||
# This subvolume will be created but not mounted
|
||||
"/test" = { };
|
||||
# Subvolume for the swapfile
|
||||
"/swap" = {
|
||||
mountpoint = "/.swapvol";
|
||||
swap = {
|
||||
swapfile.size = "20M";
|
||||
swapfile2.size = "20M";
|
||||
swapfile2.path = "rel-path";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mountpoint = "/partition-root";
|
||||
swap = {
|
||||
swapfile = {
|
||||
size = "20M";
|
||||
};
|
||||
swapfile1 = {
|
||||
size = "20M";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,192 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk0 = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00001";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
start = "1M";
|
||||
end = "128M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk1 = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00002";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
start = "1M";
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted1";
|
||||
settings.keyFile = "/tmp/secret.key";
|
||||
additionalKeyFiles = [ "/tmp/additionalSecret.key" ];
|
||||
extraFormatArgs = [
|
||||
"--iter-time 1" # insecure but fast for tests
|
||||
];
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk2 = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00003";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
start = "1M";
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted2";
|
||||
settings = {
|
||||
keyFile = "/tmp/secret.key";
|
||||
keyFileSize = 8;
|
||||
keyFileOffset = 2;
|
||||
};
|
||||
extraFormatArgs = [
|
||||
"--iter-time 1" # insecure but fast for tests
|
||||
];
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
raid1 = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
bla = {
|
||||
start = "1M";
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/ext4_mdadm_lvm";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "10M";
|
||||
lvm_type = "mirror";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/ext4_on_lvm";
|
||||
mountOptions = [
|
||||
"defaults"
|
||||
];
|
||||
postMountHook = ''
|
||||
touch /mnt/ext4_on_lvm/file-from-postMountHook
|
||||
'';
|
||||
};
|
||||
};
|
||||
raid1 = {
|
||||
size = "30M";
|
||||
lvm_type = "raid0";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
raid2 = {
|
||||
size = "30M";
|
||||
lvm_type = "raid0";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
zfs1 = {
|
||||
size = "128M";
|
||||
lvm_type = "raid0";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
zfs2 = {
|
||||
size = "128M";
|
||||
lvm_type = "raid0";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
zpool = {
|
||||
zroot = {
|
||||
type = "zpool";
|
||||
mode = "mirror";
|
||||
rootFsOptions = {
|
||||
compression = "zstd";
|
||||
"com.sun:auto-snapshot" = "false";
|
||||
};
|
||||
mountpoint = "/";
|
||||
|
||||
datasets = {
|
||||
zfs_fs = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_fs";
|
||||
options."com.sun:auto-snapshot" = "true";
|
||||
};
|
||||
zfs_unmounted_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "none";
|
||||
};
|
||||
zfs_legacy_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "legacy";
|
||||
mountpoint = "/zfs_legacy_fs";
|
||||
};
|
||||
zfs_testvolume = {
|
||||
type = "zfs_volume";
|
||||
size = "10M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/ext4onzfs";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/disk/by-path/pci-0000:02:00.0-nvme-1";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
end = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
name = "root";
|
||||
end = "-0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "f2fs";
|
||||
mountpoint = "/";
|
||||
extraArgs = [
|
||||
"-O"
|
||||
"extra_attr,inode_checksum,sb_checksum,compression"
|
||||
];
|
||||
mountOptions = [
|
||||
"compress_algorithm=zstd:6,compress_chksum,atgc,gc_merge,lazytime,nodiscard"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
# Example to create a bios compatible gpt partition
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/vdb";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
vdb = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
"name with spaces" = {
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/name with spaces";
|
||||
};
|
||||
};
|
||||
"name^with\\some@special#chars" = {
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/name^with\\some@special#chars";
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
# Example to create a GPT partition but doesn't format it
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/vdb";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
empty = {
|
||||
size = "1G";
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/sdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
efiGptPartitionFirst = false;
|
||||
partitions = {
|
||||
TOW-BOOT-FI = {
|
||||
priority = 1;
|
||||
type = "EF00";
|
||||
size = "32M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = null;
|
||||
};
|
||||
hybrid = {
|
||||
mbrPartitionType = "0x0c";
|
||||
mbrBootableFlag = false;
|
||||
};
|
||||
};
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "512M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk.main = {
|
||||
device = "/dev/disk/by-id/ata-Samsung_SSD_860_EVO_500GB_S3Z1NB0K303456L";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
ESP = {
|
||||
name = "ESP";
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
nix = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/nix";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
nodev."/" = {
|
||||
fsType = "tmpfs";
|
||||
mountOptions = [
|
||||
"size=2G"
|
||||
"defaults"
|
||||
"mode=755"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-Samsung_SSD_850_EVO_250GB_S21PNXAGB12345";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
ESP = {
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
vdb = {
|
||||
device = "/dev/sda";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "table";
|
||||
format = "gpt";
|
||||
partitions = [
|
||||
{
|
||||
name = "ESP";
|
||||
start = "1MiB";
|
||||
end = "100MiB";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "name with spaces";
|
||||
start = "100MiB";
|
||||
end = "200MiB";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/name_with_spaces";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "root";
|
||||
start = "200MiB";
|
||||
end = "100%";
|
||||
part-type = "primary";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/sda";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "table";
|
||||
format = "gpt";
|
||||
partitions = [
|
||||
{
|
||||
name = "ESP";
|
||||
start = "1M";
|
||||
end = "500M";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "root";
|
||||
start = "500M";
|
||||
end = "100%";
|
||||
part-type = "primary";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
name = "this-is-some-super-long-name-to-test-what-happens-when-the-name-is-too-long";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
# Devices will be mounted and formatted in alphabetical order, and btrfs can only mount raids
|
||||
# when all devices are present. So we define an "empty" luks device on the first disk,
|
||||
# and the actual btrfs raid on the second disk, and the name of these entries matters!
|
||||
disk1 = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
crypt_p1 = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "p1"; # device-mapper name when decrypted
|
||||
# Remove settings.keyFile if you want to use interactive password entry
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
keyFile = "/tmp/secret.key";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk2 = {
|
||||
type = "disk";
|
||||
device = "/dev/sdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
crypt_p2 = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "p2";
|
||||
# Remove settings.keyFile if you want to use interactive password entry
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
keyFile = "/tmp/secret.key"; # Same key for both devices
|
||||
};
|
||||
content = {
|
||||
type = "btrfs";
|
||||
extraArgs = [
|
||||
"-d raid1"
|
||||
"/dev/mapper/p1" # Use decrypted mapped device, same name as defined in disk1
|
||||
];
|
||||
subvolumes = {
|
||||
"/root" = {
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"rw"
|
||||
"relatime"
|
||||
"ssd"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "512M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
# disable settings.keyFile if you want to use interactive password entry
|
||||
#passwordFile = "/tmp/secret.key"; # Interactive
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
keyFile = "/tmp/secret.key";
|
||||
};
|
||||
additionalKeyFiles = [ "/tmp/additionalSecret.key" ];
|
||||
content = {
|
||||
type = "btrfs";
|
||||
extraArgs = [ "-f" ];
|
||||
subvolumes = {
|
||||
"/root" = {
|
||||
mountpoint = "/";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
"/home" = {
|
||||
mountpoint = "/home";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
"/nix" = {
|
||||
mountpoint = "/nix";
|
||||
mountOptions = [ "compress=zstd" "noatime" ];
|
||||
};
|
||||
"/swap" = {
|
||||
mountpoint = "/.swapvol";
|
||||
swap.swapfile.size = "20M";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
settings.allowDiscards = true;
|
||||
passwordFile = "/tmp/secret.key";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
extraOpenArgs = [ ];
|
||||
settings = {
|
||||
# if you want to use the key for interactive login be sure there is no trailing newline
|
||||
# for example use `echo -n "password" > /tmp/secret.key`
|
||||
keyFile = "/tmp/secret.key";
|
||||
allowDiscards = true;
|
||||
};
|
||||
additionalKeyFiles = [ "/tmp/additionalSecret.key" ];
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
};
|
||||
home = {
|
||||
size = "10M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/home";
|
||||
};
|
||||
};
|
||||
raw = {
|
||||
size = "10M";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
disko.devices.disk = lib.genAttrs [ "a" "b" ] (name: {
|
||||
type = "disk";
|
||||
device = "/dev/sd${name}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "boot";
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
disko.devices.mdadm = {
|
||||
boot = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
metadata = "1.0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
raid1 = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
settings.keyFile = "/tmp/secret.key";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
one = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "boot";
|
||||
};
|
||||
};
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
two = {
|
||||
type = "disk";
|
||||
device = "/dev/sdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "boot";
|
||||
};
|
||||
};
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
boot = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
metadata = "1.0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
};
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100M";
|
||||
lvm_type = "mirror";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
};
|
||||
home = {
|
||||
size = "10M";
|
||||
lvm_type = "raid0";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/home";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
one = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-VMware_Virtual_SATA_CDRW_Drive_00000000000000000001";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
aaa = {
|
||||
size = "1M";
|
||||
};
|
||||
zzz = {
|
||||
size = "1M";
|
||||
};
|
||||
root = {
|
||||
size = "100M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
};
|
||||
home = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/home";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "mainpool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
lvm_vg = {
|
||||
mainpool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
thinpool = {
|
||||
size = "100M";
|
||||
lvm_type = "thin-pool";
|
||||
};
|
||||
root = {
|
||||
size = "10M";
|
||||
lvm_type = "thinlv";
|
||||
pool = "thinpool";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
};
|
||||
home = {
|
||||
size = "10M";
|
||||
lvm_type = "thinlv";
|
||||
pool = "thinpool";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/home";
|
||||
};
|
||||
};
|
||||
raw = {
|
||||
size = "10M";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk1 = {
|
||||
type = "disk";
|
||||
device = "/dev/my-disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk2 = {
|
||||
type = "disk";
|
||||
device = "/dev/my-disk2";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
raid0 = {
|
||||
type = "mdadm";
|
||||
level = 0;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk1 = {
|
||||
type = "disk";
|
||||
device = "/dev/my-disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk2 = {
|
||||
type = "disk";
|
||||
device = "/dev/my-disk2";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
};
|
||||
mdadm = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "mdraid";
|
||||
name = "raid1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
mdadm = {
|
||||
raid1 = {
|
||||
type = "mdadm";
|
||||
level = 1;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk0 = {
|
||||
device = "/dev/vda";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
nix = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/a";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk1 = {
|
||||
device = "/dev/vdb";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/b";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk0 = {
|
||||
device = "/dev/disk/by-id/ata-disk0";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
nix = {
|
||||
end = "-10M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
x = {
|
||||
type = "disk";
|
||||
device = "/dev/sdx";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "64M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
y = {
|
||||
type = "disk";
|
||||
device = "/dev/sdy";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "storage";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
z = {
|
||||
type = "disk";
|
||||
device = "/dev/sdz";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "storage";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
a = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "storage2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
zpool = {
|
||||
storage = {
|
||||
type = "zpool";
|
||||
mode = "mirror";
|
||||
mountpoint = "/storage";
|
||||
|
||||
datasets = {
|
||||
dataset = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/storage/dataset";
|
||||
};
|
||||
};
|
||||
};
|
||||
storage2 = {
|
||||
type = "zpool";
|
||||
mountpoint = "/storage2";
|
||||
rootFsOptions = {
|
||||
canmount = "off";
|
||||
};
|
||||
|
||||
datasets = {
|
||||
dataset = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/storage2/dataset";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
{ pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
# We just import from the repository for testing here:
|
||||
disko = import ../../. {
|
||||
inherit lib;
|
||||
};
|
||||
# In your own system use something like this:
|
||||
#import (builtins.fetchGit {
|
||||
# url = "https://github.com/nix-community/disko";
|
||||
# ref = "master";
|
||||
#}) {
|
||||
# inherit lib;
|
||||
#};
|
||||
cfg.disko.devices = {
|
||||
disk = {
|
||||
sda = {
|
||||
device = "/dev/sda";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "table";
|
||||
format = "msdos";
|
||||
partitions = [
|
||||
{
|
||||
name = "root";
|
||||
part-type = "primary";
|
||||
start = "1M";
|
||||
end = "100%";
|
||||
bootable = true;
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(disko.config cfg)
|
||||
];
|
||||
boot.loader.grub.devices = [ "/dev/sda" ];
|
||||
system.stateVersion = "22.05";
|
||||
environment.systemPackages = with pkgs; [
|
||||
(pkgs.writeScriptBin "tsp-create" (disko.create cfg))
|
||||
(pkgs.writeScriptBin "tsp-mount" (disko.mount cfg))
|
||||
];
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/vdb";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
end = "-1G";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
encryptedSwap = {
|
||||
size = "10M";
|
||||
content = {
|
||||
type = "swap";
|
||||
randomEncryption = true;
|
||||
priority = 100; # prefer to encrypt as long as we have space for it
|
||||
};
|
||||
};
|
||||
plainSwap = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "swap";
|
||||
discardPolicy = "both";
|
||||
resumeDevice = true; # resume from hiberation from this device
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/vdb";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
nodev = {
|
||||
"/tmp" = {
|
||||
fsType = "tmpfs";
|
||||
mountOptions = [
|
||||
"size=200M"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
# Example to create a bios compatible gpt partition
|
||||
{ disks ? [ "/dev/vdb" ], lib, ... }: {
|
||||
disko.devices = {
|
||||
disk = lib.genAttrs disks (device: {
|
||||
name = lib.replaceStrings [ "/" ] [ "_" ] device;
|
||||
device = device;
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02";
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
main = {
|
||||
device = "/dev/disk/by-id/some-disk-id";
|
||||
type = "disk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
type = "EF00";
|
||||
size = "500M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
root = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/";
|
||||
mountOptions = [ "defaults" "pquota" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
# systemd will mount an ext4 filesystem at / and zfs will mount the dataset underneath it
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
disk1 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "500M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
primary = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk2 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdc";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
zpool = {
|
||||
zroot = {
|
||||
type = "zpool";
|
||||
datasets = {
|
||||
"root" = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "none";
|
||||
};
|
||||
"root/zfs_fs" = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_fs";
|
||||
options."com.sun:auto-snapshot" = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,305 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
data1 = {
|
||||
type = "disk";
|
||||
device = "/dev/vda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "64M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
data2 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdb";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
data3 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdc";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
spare = {
|
||||
type = "disk";
|
||||
device = "/dev/vdd";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
log1 = {
|
||||
type = "disk";
|
||||
device = "/dev/vde";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
log2 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdf";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
log3 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdg";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
dedup1 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdh";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
dedup2 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdi";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
dedup3 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdj";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
special1 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdk";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
special2 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdl";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
special3 = {
|
||||
type = "disk";
|
||||
device = "/dev/vdm";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
cache = {
|
||||
type = "disk";
|
||||
device = "/dev/vdn";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
zpool = {
|
||||
zroot = {
|
||||
type = "zpool";
|
||||
mode = {
|
||||
topology = {
|
||||
type = "topology";
|
||||
vdev = [
|
||||
{
|
||||
# This syntax expects a disk called 'data3' with a gpt partition called 'zfs'.
|
||||
members = [ "data1" ];
|
||||
# It's also possible to use the full path of the device or partition
|
||||
# members = [ "/dev/disk/by-id/wwn-0x5000c500af8b2a14" ];
|
||||
}
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "data2" "data3" ];
|
||||
}
|
||||
];
|
||||
spare = [ "spare" ];
|
||||
log = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "log1" "log2" ];
|
||||
}
|
||||
{
|
||||
members = [ "log3" ];
|
||||
}
|
||||
];
|
||||
dedup = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "dedup1" "dedup2" ];
|
||||
}
|
||||
{
|
||||
members = [ "dedup3" ];
|
||||
}
|
||||
];
|
||||
special = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "special1" "special2" ];
|
||||
}
|
||||
{
|
||||
members = [ "special3" ];
|
||||
}
|
||||
];
|
||||
cache = [ "cache" ];
|
||||
};
|
||||
};
|
||||
|
||||
rootFsOptions = {
|
||||
compression = "zstd";
|
||||
"com.sun:auto-snapshot" = "false";
|
||||
};
|
||||
mountpoint = "/";
|
||||
datasets = {
|
||||
# See examples/zfs.nix for more comprehensive usage.
|
||||
zfs_fs = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_fs";
|
||||
options."com.sun:auto-snapshot" = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
x = {
|
||||
type = "disk";
|
||||
device = "/dev/sdx";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "64M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
y = {
|
||||
type = "disk";
|
||||
device = "/dev/sdy";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
zfs = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "zfs";
|
||||
pool = "zroot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
zpool = {
|
||||
zroot = {
|
||||
type = "zpool";
|
||||
mode = "mirror";
|
||||
# Workaround: cannot import 'zroot': I/O error in disko tests
|
||||
options.cachefile = "none";
|
||||
rootFsOptions = {
|
||||
compression = "zstd";
|
||||
"com.sun:auto-snapshot" = "false";
|
||||
};
|
||||
mountpoint = "/";
|
||||
postCreateHook = "zfs list -t snapshot -H -o name | grep -E '^zroot@blank$' || zfs snapshot zroot@blank";
|
||||
|
||||
datasets = {
|
||||
zfs_fs = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_fs";
|
||||
options."com.sun:auto-snapshot" = "true";
|
||||
};
|
||||
zfs_unmounted_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "none";
|
||||
};
|
||||
zfs_legacy_fs = {
|
||||
type = "zfs_fs";
|
||||
options.mountpoint = "legacy";
|
||||
mountpoint = "/zfs_legacy_fs";
|
||||
};
|
||||
zfs_volume = {
|
||||
type = "zfs_volume";
|
||||
size = "10M";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/ext4onzfs";
|
||||
};
|
||||
};
|
||||
zfs_encryptedvolume = {
|
||||
type = "zfs_volume";
|
||||
size = "10M";
|
||||
options = {
|
||||
encryption = "aes-256-gcm";
|
||||
keyformat = "passphrase";
|
||||
keylocation = "file:///tmp/secret.key";
|
||||
};
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/ext4onzfsencrypted";
|
||||
};
|
||||
};
|
||||
encrypted = {
|
||||
type = "zfs_fs";
|
||||
options = {
|
||||
mountpoint = "none";
|
||||
encryption = "aes-256-gcm";
|
||||
keyformat = "passphrase";
|
||||
keylocation = "file:///tmp/secret.key";
|
||||
};
|
||||
# use this to read the key during boot
|
||||
# postCreateHook = ''
|
||||
# zfs set keylocation="prompt" "zroot/$name";
|
||||
# '';
|
||||
};
|
||||
"encrypted/test" = {
|
||||
type = "zfs_fs";
|
||||
mountpoint = "/zfs_crypted";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1734435836,
|
||||
"narHash": "sha256-kMBQ5PRiFLagltK0sH+08aiNt3zGERC2297iB6vrvlU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4989a246d7a390a859852baddb1013f825435cee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@ -1,155 +0,0 @@
|
||||
{
|
||||
description = "Disko - declarative disk partitioning";
|
||||
|
||||
# FIXME: in future we don't want lock here to give precedence to a USB live-installer's registry,
|
||||
# but garnix currently does not allow this.
|
||||
#inputs.nixpkgs.url = "nixpkgs";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
|
||||
outputs = { self, nixpkgs, ... }:
|
||||
let
|
||||
lib = nixpkgs.lib;
|
||||
supportedSystems = [
|
||||
"x86_64-linux"
|
||||
"i686-linux"
|
||||
"aarch64-linux"
|
||||
"riscv64-linux"
|
||||
];
|
||||
forAllSystems = lib.genAttrs supportedSystems;
|
||||
|
||||
versionInfo = import ./version.nix;
|
||||
version = versionInfo.version + (lib.optionalString (!versionInfo.released) "-dirty");
|
||||
|
||||
diskoLib = import ./lib {
|
||||
inherit (nixpkgs) lib;
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosModules.default = self.nixosModules.disko; # convention
|
||||
nixosModules.disko.imports = [ ./module.nix ];
|
||||
lib = diskoLib;
|
||||
packages = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
disko = pkgs.callPackage ./package.nix { diskoVersion = version; };
|
||||
# alias to make `nix run` more convenient
|
||||
disko-install = self.packages.${system}.disko.overrideAttrs (_old: {
|
||||
name = "disko-install";
|
||||
});
|
||||
default = self.packages.${system}.disko;
|
||||
|
||||
create-release = pkgs.callPackage ./scripts/create-release.nix { };
|
||||
} // pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64) {
|
||||
disko-doc = pkgs.callPackage ./doc.nix { };
|
||||
});
|
||||
# TODO: disable bios-related tests on aarch64...
|
||||
# Run checks: nix flake check -L
|
||||
checks = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
# FIXME: aarch64-linux seems to hang on boot
|
||||
nixosTests = lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (import ./tests {
|
||||
inherit pkgs;
|
||||
makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix");
|
||||
eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix");
|
||||
});
|
||||
|
||||
disko-install = pkgs.callPackage ./tests/disko-install {
|
||||
inherit self;
|
||||
diskoVersion = version;
|
||||
};
|
||||
|
||||
shellcheck = pkgs.runCommand "shellcheck" { nativeBuildInputs = [ pkgs.shellcheck ]; } ''
|
||||
cd ${./.}
|
||||
shellcheck disk-deactivate/disk-deactivate disko
|
||||
touch $out
|
||||
'';
|
||||
|
||||
jsonTypes = pkgs.writeTextFile { name = "jsonTypes"; text = (builtins.toJSON diskoLib.jsonTypes); };
|
||||
in
|
||||
# FIXME: aarch64-linux seems to hang on boot
|
||||
lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (nixosTests // { inherit disko-install; }) //
|
||||
pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) {
|
||||
inherit shellcheck jsonTypes;
|
||||
inherit (self.packages.${system}) disko-doc;
|
||||
});
|
||||
|
||||
nixosConfigurations.testmachine = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
./tests/disko-install/configuration.nix
|
||||
./example/hybrid.nix
|
||||
./module.nix
|
||||
];
|
||||
};
|
||||
formatter = forAllSystems (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
pkgs.writeShellApplication {
|
||||
name = "format";
|
||||
runtimeInputs = with pkgs; [
|
||||
nixpkgs-fmt
|
||||
deno
|
||||
deadnix
|
||||
];
|
||||
text = ''
|
||||
showUsage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS] FILES...
|
||||
-c, --check Only check formatting, do not modify files.
|
||||
-h, --help Show this help message.
|
||||
EOF
|
||||
}
|
||||
|
||||
check=
|
||||
files=()
|
||||
|
||||
parseArgs() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
showUsage
|
||||
exit 0
|
||||
;;
|
||||
-c | --check)
|
||||
check=1
|
||||
;;
|
||||
*)
|
||||
files+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ ''${#files[@]} -eq 0 ]]; then
|
||||
files=(.)
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
parseArgs "$@"
|
||||
|
||||
if [[ -z "$check" ]]; then
|
||||
set -o xtrace
|
||||
|
||||
nixpkgs-fmt -- "''${files[@]}"
|
||||
deno fmt -- "''${files[@]}"
|
||||
deadnix --edit -- "''${files[@]}"
|
||||
else
|
||||
set -o xtrace
|
||||
|
||||
nixpkgs-fmt --check -- "''${files[@]}"
|
||||
deno fmt --check -- "''${files[@]}"
|
||||
deadnix -- "''${files[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
'';
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
{ flake
|
||||
, flakeAttr
|
||||
, diskMappings
|
||||
, extraSystemConfig ? "{}"
|
||||
, writeEfiBootEntries ? false
|
||||
, rootMountPoint ? "/mnt"
|
||||
,
|
||||
}:
|
||||
let
|
||||
originalSystem = (builtins.getFlake "${flake}").nixosConfigurations."${flakeAttr}";
|
||||
lib = originalSystem.pkgs.lib;
|
||||
|
||||
deviceName =
|
||||
name:
|
||||
if diskMappings ? ${name} then
|
||||
diskMappings.${name}
|
||||
else
|
||||
throw "No device passed for disk '${name}'. Pass `--disk ${name} /dev/name` via commandline";
|
||||
|
||||
modifiedDisks = builtins.mapAttrs
|
||||
(
|
||||
name: value:
|
||||
let
|
||||
dev = deviceName name;
|
||||
in
|
||||
value
|
||||
// {
|
||||
device = dev;
|
||||
content = value.content // {
|
||||
device = dev;
|
||||
};
|
||||
}
|
||||
)
|
||||
originalSystem.config.disko.devices.disk;
|
||||
|
||||
# filter all nixos module internal attributes
|
||||
cleanedDisks = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) modifiedDisks;
|
||||
|
||||
diskoSystem = originalSystem.extendModules {
|
||||
modules = [
|
||||
{
|
||||
disko.rootMountPoint = rootMountPoint;
|
||||
disko.devices.disk = lib.mkVMOverride cleanedDisks;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
installSystem = originalSystem.extendModules {
|
||||
modules = [
|
||||
(
|
||||
{ lib, ... }:
|
||||
{
|
||||
boot.loader.efi.canTouchEfiVariables = lib.mkVMOverride writeEfiBootEntries;
|
||||
boot.loader.grub.devices = lib.mkVMOverride diskoSystem.config.boot.loader.grub.devices;
|
||||
imports = [
|
||||
({ _file = "disko-install --system-config"; } // (builtins.fromJSON extraSystemConfig))
|
||||
];
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
installToplevel = installSystem.config.system.build.toplevel;
|
||||
closureInfo = installSystem.pkgs.closureInfo {
|
||||
rootPaths = [ installSystem.config.system.build.toplevel ];
|
||||
};
|
||||
inherit (diskoSystem.config.system.build) formatScript mountScript diskoScript;
|
||||
}
|
||||
@ -1,841 +0,0 @@
|
||||
{ lib ? import <nixpkgs/lib>
|
||||
, rootMountPoint ? "/mnt"
|
||||
, makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>
|
||||
, eval-config ? import <nixpkgs/nixos/lib/eval-config.nix>
|
||||
}:
|
||||
let
|
||||
outputs = import ../default.nix { inherit lib diskoLib; };
|
||||
diskoLib = {
|
||||
testLib = import ./tests.nix { inherit lib makeTest eval-config; };
|
||||
# like lib.types.oneOf but instead of a list takes an attrset
|
||||
# uses the field "type" to find the correct type in the attrset
|
||||
subType = { types, extraArgs ? { parent = { type = "rootNode"; name = "root"; }; } }: lib.mkOptionType {
|
||||
name = "subType";
|
||||
description = "one of ${lib.concatStringsSep "," (lib.attrNames types)}";
|
||||
check = x: if x ? type then types.${x.type}.check x else throw "No type option set in:\n${lib.generators.toPretty {} x}";
|
||||
merge = loc: lib.foldl'
|
||||
(_res: def: types.${def.value.type}.merge loc [
|
||||
# we add a dummy root parent node to render documentation
|
||||
(lib.recursiveUpdate { value._module.args = extraArgs; } def)
|
||||
])
|
||||
{ };
|
||||
nestedTypes = types;
|
||||
};
|
||||
|
||||
# option for valid contents of partitions (basically like devices, but without tables)
|
||||
_partitionTypes = { inherit (diskoLib.types) btrfs filesystem zfs mdraid luks lvm_pv swap; };
|
||||
partitionType = extraArgs: lib.mkOption {
|
||||
type = lib.types.nullOr (diskoLib.subType {
|
||||
types = diskoLib._partitionTypes;
|
||||
inherit extraArgs;
|
||||
});
|
||||
default = null;
|
||||
description = "The type of partition";
|
||||
};
|
||||
|
||||
# option for valid contents of devices
|
||||
_deviceTypes = { inherit (diskoLib.types) table gpt btrfs filesystem zfs mdraid luks lvm_pv swap; };
|
||||
deviceType = extraArgs: lib.mkOption {
|
||||
type = lib.types.nullOr (diskoLib.subType {
|
||||
types = diskoLib._deviceTypes;
|
||||
inherit extraArgs;
|
||||
});
|
||||
default = null;
|
||||
description = "The type of device";
|
||||
};
|
||||
|
||||
/* deepMergeMap takes a function and a list of attrsets and deep merges them
|
||||
|
||||
deepMergeMap :: (AttrSet -> AttrSet ) -> [ AttrSet ] -> Attrset
|
||||
|
||||
Example:
|
||||
deepMergeMap (x: x.t = "test") [ { x = { y = 1; z = 3; }; } { x = { bla = 234; }; } ]
|
||||
=> { x = { y = 1; z = 3; bla = 234; t = "test"; }; }
|
||||
*/
|
||||
deepMergeMap = f: lib.foldr (attr: acc: (lib.recursiveUpdate acc (f attr))) { };
|
||||
|
||||
/* get a device and an index to get the matching device name
|
||||
|
||||
deviceNumbering :: str -> int -> str
|
||||
|
||||
Example:
|
||||
deviceNumbering "/dev/sda" 3
|
||||
=> "/dev/sda3"
|
||||
|
||||
deviceNumbering "/dev/disk/by-id/xxx" 2
|
||||
=> "/dev/disk/by-id/xxx-part2"
|
||||
*/
|
||||
deviceNumbering = dev: index:
|
||||
let inherit (lib) match; in
|
||||
if match "/dev/([vs]|(xv)d).+" dev != null then
|
||||
dev + toString index # /dev/{s,v,xv}da style
|
||||
else if match "/dev/(disk|zvol)/.+" dev != null then
|
||||
"${dev}-part${toString index}" # /dev/disk/by-id/xxx style, also used by zfs's zvolumes
|
||||
else if match "/dev/((nvme|mmcblk).+|md/.*[[:digit:]])" dev != null then
|
||||
"${dev}p${toString index}" # /dev/nvme0n1p1 style
|
||||
else if match "/dev/md/.+" dev != null then
|
||||
"${dev}${toString index}" # /dev/md/raid1 style
|
||||
else if match "/dev/mapper/.+" dev != null then
|
||||
"${dev}${toString index}" # /dev/mapper/vg-lv1 style
|
||||
else if match "/dev/loop[[:digit:]]+" dev != null
|
||||
then "${dev}p${toString index}" # /dev/mapper/vg-lv1 style
|
||||
else
|
||||
abort ''
|
||||
${dev} seems not to be a supported disk format. Please add this to disko in https://github.com/nix-community/disko/blob/master/lib/default.nix
|
||||
'';
|
||||
|
||||
/* Escape a string as required to be used in udev symlinks
|
||||
|
||||
The allowed characters are "0-9A-Za-z#+-.:=@_/", valid UTF-8 character sequences, and "\x00" hex encoding.
|
||||
Everything else is escaped as "\xXX" where XX is the hex value of the character.
|
||||
|
||||
The source of truth for the list of allowed characters is the udev documentation:
|
||||
https://www.freedesktop.org/software/systemd/man/latest/udev.html#SYMLINK1
|
||||
|
||||
This function is implemented as a best effort. It is not guaranteed to be 100% in line
|
||||
with the udev implementation, and we hope that you're not crazy enough to try to break it.
|
||||
|
||||
hexEscapeUdevSymlink :: str -> str
|
||||
|
||||
Example:
|
||||
hexEscapeUdevSymlink "Boot data partition"
|
||||
=> "Boot\x20data\x20partition"
|
||||
|
||||
hexEscapeUdevSymlink "Even(crazier)par&titi^onName"
|
||||
=> "Even\x28crazier\x29par\x26titi\x5EonName"
|
||||
|
||||
hexEscapeUdevSymlink "all0these@char#acters+_are-allow.ed"
|
||||
=> "all0these@char#acters+_are-allow.ed"
|
||||
*/
|
||||
hexEscapeUdevSymlink =
|
||||
let
|
||||
allowedChars = "[0-9A-Za-z#+-.:=@_/]";
|
||||
charToHex = c: lib.toHexString (lib.strings.charToInt c);
|
||||
in
|
||||
lib.stringAsChars
|
||||
(c: if lib.match allowedChars c != null || c == "" then c else "\\x" + charToHex c);
|
||||
|
||||
/* get the index an item in a list
|
||||
|
||||
indexOf :: (a -> bool) -> [a] -> int -> int
|
||||
|
||||
Example:
|
||||
indexOf (x: x == 2) [ 1 2 3 ] 0
|
||||
=> 2
|
||||
|
||||
indexOf (x: x == "x") [ 1 2 3 ] 0
|
||||
=> 0
|
||||
*/
|
||||
indexOf = f: list: fallback:
|
||||
let
|
||||
iter = index: list:
|
||||
if list == [ ] then
|
||||
fallback
|
||||
else if f (lib.head list) then
|
||||
index
|
||||
else
|
||||
iter (index + 1) (lib.tail list);
|
||||
in
|
||||
iter 1 list;
|
||||
|
||||
|
||||
/* indent takes a multiline string and indents it by 2 spaces starting on the second line
|
||||
|
||||
indent :: str -> str
|
||||
|
||||
Example:
|
||||
indent "test\nbla"
|
||||
=> "test\n bla"
|
||||
*/
|
||||
indent = lib.replaceStrings [ "\n" ] [ "\n " ];
|
||||
|
||||
/* A nix option type representing a json datastructure, vendored from nixpkgs to avoid dependency on pkgs */
|
||||
jsonType =
|
||||
let
|
||||
valueType = lib.types.nullOr
|
||||
(lib.types.oneOf [
|
||||
lib.types.bool
|
||||
lib.types.int
|
||||
lib.types.float
|
||||
lib.types.str
|
||||
lib.types.path
|
||||
(lib.types.attrsOf valueType)
|
||||
(lib.types.listOf valueType)
|
||||
]) // {
|
||||
description = "JSON value";
|
||||
};
|
||||
in
|
||||
valueType;
|
||||
|
||||
/* 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 = deviceDependencies: devices:
|
||||
let
|
||||
dependsOn = a: b:
|
||||
lib.elem a (lib.attrByPath b [ ] deviceDependencies);
|
||||
maybeSortedDevices = lib.toposort dependsOn (diskoLib.deviceList devices);
|
||||
in
|
||||
if (lib.hasAttr "cycle" maybeSortedDevices) then
|
||||
abort "detected a cycle in your disk setup: ${maybeSortedDevices.cycle}"
|
||||
else
|
||||
maybeSortedDevices.result;
|
||||
|
||||
/* Takes a devices attrSet and returns it as a list
|
||||
|
||||
deviceList :: AttrSet -> [ [ str str ] ]
|
||||
|
||||
Example:
|
||||
deviceList { zfs.pool1 = {}; zfs.pool2 = {}; mdadm.raid1 = {}; }
|
||||
=> [ [ "zfs" "pool1" ] [ "zfs" "pool2" ] [ "mdadm" "raid1" ] ]
|
||||
*/
|
||||
deviceList = devices:
|
||||
lib.concatLists (lib.mapAttrsToList (n: v: (map (x: [ n x ]) (lib.attrNames v))) devices);
|
||||
|
||||
/* Takes either a string or null and returns the string or an empty string
|
||||
|
||||
maybeStr :: Either (str null) -> str
|
||||
|
||||
Example:
|
||||
maybeStr null
|
||||
=> ""
|
||||
maybeSTr "hello world"
|
||||
=> "hello world"
|
||||
*/
|
||||
maybeStr = x: lib.optionalString (x != null) x;
|
||||
|
||||
/* Takes a Submodules config and options argument and returns a serializable
|
||||
subset of config variables as a shell script snippet.
|
||||
*/
|
||||
defineHookVariables = { options }:
|
||||
let
|
||||
sanitizeName = lib.replaceStrings [ "-" ] [ "_" ];
|
||||
isAttrsOfSubmodule = o: o.type.name == "attrsOf" && o.type.nestedTypes.elemType.name == "submodule";
|
||||
isSerializable = n: o: !(
|
||||
lib.hasPrefix "_" n
|
||||
|| lib.hasSuffix "Hook" n
|
||||
|| isAttrsOfSubmodule o
|
||||
# TODO don't hardcode diskoLib.subType options.
|
||||
|| n == "content" || n == "partitions" || n == "datasets" || n == "swap"
|
||||
|| n == "mode"
|
||||
);
|
||||
in
|
||||
lib.toShellVars
|
||||
(lib.mapAttrs'
|
||||
(n: o: lib.nameValuePair (sanitizeName n) o.value)
|
||||
(lib.filterAttrs isSerializable options));
|
||||
|
||||
mkHook = description: lib.mkOption {
|
||||
inherit description;
|
||||
type = lib.types.lines;
|
||||
default = "";
|
||||
};
|
||||
|
||||
mkSubType = module: lib.types.submodule [
|
||||
module
|
||||
|
||||
{
|
||||
options = {
|
||||
preCreateHook = diskoLib.mkHook "shell commands to run before create";
|
||||
postCreateHook = diskoLib.mkHook "shell commands to run after create";
|
||||
preMountHook = diskoLib.mkHook "shell commands to run before mount";
|
||||
postMountHook = diskoLib.mkHook "shell commands to run after mount";
|
||||
preUnmountHook = diskoLib.mkHook "shell commands to run before unmount";
|
||||
postUnmountHook = diskoLib.mkHook "shell commands to run after unmount";
|
||||
};
|
||||
config._module.args = {
|
||||
inherit diskoLib rootMountPoint;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
mkCreateOption = { config, options, default }@attrs:
|
||||
lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.str;
|
||||
default = ''
|
||||
( # ${config.type} ${lib.concatMapStringsSep " " (n: toString (config.${n} or "")) ["name" "device" "format" "mountpoint"]} #
|
||||
${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })}
|
||||
${diskoLib.indent config.preCreateHook}
|
||||
${diskoLib.indent attrs.default}
|
||||
${diskoLib.indent config.postCreateHook}
|
||||
)
|
||||
'';
|
||||
description = "Creation script";
|
||||
};
|
||||
|
||||
mkMountOption = { config, options, default }@attrs:
|
||||
lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default = lib.mapAttrsRecursive
|
||||
(_name: value:
|
||||
if builtins.isString value then ''
|
||||
(
|
||||
${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })}
|
||||
${diskoLib.indent config.preMountHook}
|
||||
${diskoLib.indent value}
|
||||
${diskoLib.indent config.postMountHook}
|
||||
)
|
||||
'' else value)
|
||||
attrs.default;
|
||||
description = "Mount script";
|
||||
};
|
||||
|
||||
mkUnmountOption = { config, options, default }@attrs:
|
||||
lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default = lib.mapAttrsRecursive
|
||||
(_name: value:
|
||||
if builtins.isString value then ''
|
||||
(
|
||||
${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })}
|
||||
${diskoLib.indent config.preUnmountHook}
|
||||
${diskoLib.indent value}
|
||||
${diskoLib.indent config.postUnmountHook}
|
||||
)
|
||||
'' else value)
|
||||
attrs.default;
|
||||
description = "Unmount script";
|
||||
};
|
||||
|
||||
/* Writer for optionally checking bash scripts before writing them to the store
|
||||
|
||||
writeCheckedBash :: AttrSet -> str -> str -> derivation
|
||||
*/
|
||||
writeCheckedBash = { pkgs, checked ? false, noDeps ? false }: pkgs.writers.makeScriptWriter {
|
||||
interpreter = if noDeps then "/usr/bin/env bash" else "${pkgs.bash}/bin/bash";
|
||||
check = lib.optionalString (checked && !pkgs.stdenv.hostPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) (pkgs.writeScript "check" ''
|
||||
set -efu
|
||||
# SC2054: our toShellVars function doesn't quote list elements with commas
|
||||
# SC2034: We don't use all variables exported by hooks.
|
||||
${pkgs.shellcheck}/bin/shellcheck -e SC2034,SC2054 "$1"
|
||||
'');
|
||||
};
|
||||
|
||||
|
||||
/* Takes a disko device specification, returns an attrset with metadata
|
||||
|
||||
meta :: lib.types.devices -> AttrSet
|
||||
*/
|
||||
meta = toplevel: toplevel._meta;
|
||||
|
||||
/* Takes a disko device specification and returns a string which formats the disks
|
||||
|
||||
create :: lib.types.devices -> str
|
||||
*/
|
||||
create = toplevel: toplevel._create;
|
||||
/* Takes a disko device specification and returns a string which mounts the disks
|
||||
|
||||
mount :: lib.types.devices -> str
|
||||
*/
|
||||
mount = toplevel: toplevel._mount;
|
||||
|
||||
/* takes a disko device specification and returns a string which unmounts, destroys all disks and then runs create and mount
|
||||
|
||||
zapCreateMount :: lib.types.devices -> str
|
||||
*/
|
||||
zapCreateMount = toplevel:
|
||||
''
|
||||
set -efux
|
||||
${toplevel._disko}
|
||||
'';
|
||||
/* Takes a disko device specification and returns a nixos configuration
|
||||
|
||||
config :: lib.types.devices -> nixosConfig
|
||||
*/
|
||||
config = toplevel: toplevel._config;
|
||||
|
||||
/* Takes a disko device specification and returns a function to get the needed packages to format/mount the disks
|
||||
|
||||
packages :: lib.types.devices -> pkgs -> [ derivation ]
|
||||
*/
|
||||
packages = toplevel: toplevel._packages;
|
||||
|
||||
/* Checks whether nixpkgs is recent enough for vmTools to support the customQemu argument.
|
||||
|
||||
Returns false, which is technically incorrect, for a few commits on 2024-07-08, but we can't be more accurate.
|
||||
Make sure to pass lib, not pkgs.lib! See https://github.com/nix-community/disko/issues/904
|
||||
|
||||
vmToolsSupportsCustomQemu :: final_lib -> bool
|
||||
*/
|
||||
vmToolsSupportsCustomQemu = final_lib: lib.versionAtLeast final_lib.version "24.11.20240709";
|
||||
|
||||
optionTypes = rec {
|
||||
filename = lib.mkOptionType {
|
||||
name = "filename";
|
||||
check = lib.isString;
|
||||
merge = lib.mergeOneOption;
|
||||
description = "A filename";
|
||||
};
|
||||
|
||||
absolute-pathname = lib.mkOptionType {
|
||||
name = "absolute pathname";
|
||||
check = x: lib.isString x && lib.substring 0 1 x == "/" && pathname.check x;
|
||||
merge = lib.mergeOneOption;
|
||||
description = "An absolute path";
|
||||
};
|
||||
|
||||
pathname = lib.mkOptionType {
|
||||
name = "pathname";
|
||||
check = x:
|
||||
with lib; let
|
||||
# The filter is used to normalize paths, i.e. to remove duplicated and
|
||||
# trailing slashes. It also removes leading slashes, thus we have to
|
||||
# check for "/" explicitly below.
|
||||
xs = filter (s: stringLength s > 0) (splitString "/" x);
|
||||
in
|
||||
isString x && (x == "/" || (length xs > 0 && all filename.check xs));
|
||||
merge = lib.mergeOneOption;
|
||||
description = "A path name";
|
||||
};
|
||||
};
|
||||
|
||||
/* topLevel type of the disko config, takes attrsets of disks, mdadms, zpools, nodevs, and lvm vgs.
|
||||
*/
|
||||
toplevel = lib.types.submodule (cfg:
|
||||
let
|
||||
devices = { inherit (cfg.config) disk mdadm zpool lvm_vg nodev; };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
disk = lib.mkOption {
|
||||
type = lib.types.attrsOf diskoLib.types.disk;
|
||||
default = { };
|
||||
description = "Block device";
|
||||
};
|
||||
mdadm = lib.mkOption {
|
||||
type = lib.types.attrsOf diskoLib.types.mdadm;
|
||||
default = { };
|
||||
description = "mdadm device";
|
||||
};
|
||||
zpool = lib.mkOption {
|
||||
type = lib.types.attrsOf diskoLib.types.zpool;
|
||||
default = { };
|
||||
description = "ZFS pool device";
|
||||
};
|
||||
lvm_vg = lib.mkOption {
|
||||
type = lib.types.attrsOf diskoLib.types.lvm_vg;
|
||||
default = { };
|
||||
description = "LVM VG device";
|
||||
};
|
||||
nodev = lib.mkOption {
|
||||
type = lib.types.attrsOf diskoLib.types.nodev;
|
||||
default = { };
|
||||
description = "A non-block device";
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
meta informationen generated by disko
|
||||
currently used for building a dependency list so we know in which order to create the devices
|
||||
'';
|
||||
default = diskoLib.deepMergeMap (dev: dev._meta) (lib.flatten (map lib.attrValues (lib.attrValues devices)));
|
||||
};
|
||||
_packages = lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
packages required by the disko configuration
|
||||
coreutils is always included
|
||||
'';
|
||||
default = pkgs: with lib; unique ((flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))) ++ [ pkgs.coreutils-full ]);
|
||||
};
|
||||
_scripts = lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
The scripts generated by disko
|
||||
'';
|
||||
default = { pkgs, checked ? false }:
|
||||
let
|
||||
throwIfNoDisksDetected = _: v: if devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v;
|
||||
destroyDependencies = with pkgs; [
|
||||
util-linux
|
||||
e2fsprogs
|
||||
mdadm
|
||||
zfs
|
||||
lvm2
|
||||
bash
|
||||
jq
|
||||
gnused
|
||||
gawk
|
||||
coreutils-full
|
||||
];
|
||||
in
|
||||
lib.mapAttrs throwIfNoDisksDetected {
|
||||
destroy = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy" ''
|
||||
export PATH=${lib.makeBinPath destroyDependencies}:$PATH
|
||||
${cfg.config._destroy}
|
||||
'';
|
||||
format = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-format" ''
|
||||
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
|
||||
${cfg.config._create}
|
||||
'';
|
||||
mount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-mount" ''
|
||||
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
unmount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-unmount" ''
|
||||
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
|
||||
${cfg.config._unmount}
|
||||
'';
|
||||
formatMount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-format-mount" ''
|
||||
export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ])}:$PATH
|
||||
${cfg.config._formatMount}
|
||||
'';
|
||||
destroyFormatMount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy-format-mount" ''
|
||||
export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies)}:$PATH
|
||||
${cfg.config._destroyFormatMount}
|
||||
'';
|
||||
|
||||
# These are useful to skip copying executables uploading a script to an in-memory installer
|
||||
destroyNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy" ''
|
||||
${cfg.config._destroy}
|
||||
'';
|
||||
formatNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format" ''
|
||||
${cfg.config._create}
|
||||
'';
|
||||
mountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-mount" ''
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
unmountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-unmount" ''
|
||||
${cfg.config._unmount}
|
||||
'';
|
||||
formatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format-mount" ''
|
||||
${cfg.config._formatMount}
|
||||
'';
|
||||
destroyFormatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy-format-mount" ''
|
||||
${cfg.config._destroyFormatMount}
|
||||
'';
|
||||
|
||||
|
||||
# Legacy scripts, to be removed in version 2.0.0
|
||||
# They are generally less useful, because the scripts are directly written to their $out path instead of
|
||||
# into the $out/bin directory, which makes them incompatible with `nix run`
|
||||
# (see https://github.com/nix-community/disko/pull/78), `lib.buildEnv` and thus `environment.systemPackages`,
|
||||
# `user.users.<name>.packages` and `home.packages`, see https://github.com/nix-community/disko/issues/454
|
||||
destroyScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-destroy" ''
|
||||
export PATH=${lib.makeBinPath destroyDependencies}:$PATH
|
||||
${cfg.config._legacyDestroy}
|
||||
'';
|
||||
|
||||
formatScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-format" ''
|
||||
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
|
||||
${cfg.config._create}
|
||||
'';
|
||||
|
||||
mountScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" ''
|
||||
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
|
||||
diskoScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" ''
|
||||
export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies)}:$PATH
|
||||
${cfg.config._disko}
|
||||
'';
|
||||
|
||||
# These are useful to skip copying executables uploading a script to an in-memory installer
|
||||
destroyScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-destroy" ''
|
||||
${cfg.config._legacyDestroy}
|
||||
'';
|
||||
|
||||
formatScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-format" ''
|
||||
${cfg.config._create}
|
||||
'';
|
||||
|
||||
mountScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" ''
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
|
||||
diskoScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" ''
|
||||
${cfg.config._disko}
|
||||
'';
|
||||
};
|
||||
};
|
||||
_legacyDestroy = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to unmount (& destroy) all devices defined by disko.devices
|
||||
Does not ask for confirmation! Depracated in favor of _destroy
|
||||
'';
|
||||
default = ''
|
||||
umount -Rv "${rootMountPoint}" || :
|
||||
|
||||
# shellcheck disable=SC2043
|
||||
for dev in ${toString (lib.catAttrs "device" (lib.attrValues devices.disk))}; do
|
||||
$BASH ${../disk-deactivate}/disk-deactivate "$dev"
|
||||
done
|
||||
'';
|
||||
};
|
||||
_destroy = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to unmount (& destroy) all devices defined by disko.devices
|
||||
'';
|
||||
default =
|
||||
let
|
||||
selectedDisks = lib.escapeShellArgs (lib.catAttrs "device" (lib.attrValues devices.disk));
|
||||
in
|
||||
''
|
||||
if [ "$1" != "--yes-wipe-all-disks" ]; then
|
||||
echo "WARNING: This will destroy all data on the disks defined in disko.devices, which are:"
|
||||
echo
|
||||
# shellcheck disable=SC2043,2041
|
||||
for dev in ${selectedDisks}; do
|
||||
echo " - $dev"
|
||||
done
|
||||
echo
|
||||
echo " (If you want to skip this dialogue, pass --yes-wipe-all-disks)"
|
||||
echo
|
||||
echo "Are you sure you want to wipe the devices listed above?"
|
||||
read -rp "Type 'yes' to continue, anything else to abort: " confirmation
|
||||
|
||||
if [ "$confirmation" != "yes" ]; then
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
umount -Rv "${rootMountPoint}" || :
|
||||
|
||||
# shellcheck disable=SC2043
|
||||
for dev in ${selectedDisks}; do
|
||||
$BASH ${../disk-deactivate}/disk-deactivate "$dev"
|
||||
done
|
||||
'';
|
||||
};
|
||||
_create = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to create all devices defined by disko.devices
|
||||
'';
|
||||
default =
|
||||
with lib; let
|
||||
sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices;
|
||||
in
|
||||
''
|
||||
set -efux
|
||||
|
||||
disko_devices_dir=$(mktemp -d)
|
||||
trap 'rm -rf "$disko_devices_dir"' EXIT
|
||||
mkdir -p "$disko_devices_dir"
|
||||
|
||||
${concatMapStrings (dev: (attrByPath (dev ++ [ "_create" ]) {} devices)) sortedDeviceList}
|
||||
'';
|
||||
};
|
||||
_mount = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to mount all devices defined by disko.devices
|
||||
'';
|
||||
default =
|
||||
with lib; let
|
||||
fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or { }) (flatten (map attrValues (attrValues devices)));
|
||||
sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices;
|
||||
in
|
||||
''
|
||||
set -efux
|
||||
# first create the necessary devices
|
||||
${concatMapStrings (dev: (attrByPath (dev ++ [ "_mount" ]) {} devices).dev or "") sortedDeviceList}
|
||||
|
||||
# and then mount the filesystems in alphabetical order
|
||||
${concatStrings (attrValues fsMounts)}
|
||||
'';
|
||||
};
|
||||
_unmount = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to unmount all devices defined by disko.devices
|
||||
'';
|
||||
default =
|
||||
with lib; let
|
||||
fsMounts = diskoLib.deepMergeMap (dev: dev._unmount.fs or { }) (flatten (map attrValues (attrValues devices)));
|
||||
sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices;
|
||||
in
|
||||
''
|
||||
set -efux
|
||||
# first unmount the filesystems in reverse alphabetical order
|
||||
${concatStrings (lib.reverseList (attrValues fsMounts))}
|
||||
|
||||
# Than close the devices
|
||||
${concatMapStrings (dev: (attrByPath (dev ++ [ "_unmount" ]) {} devices).dev or "") (lib.reverseList sortedDeviceList)}
|
||||
'';
|
||||
};
|
||||
_disko = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to umount, create and mount all devices defined by disko.devices
|
||||
Deprecated in favor of _destroyFormatMount
|
||||
'';
|
||||
default = ''
|
||||
${cfg.config._legacyDestroy}
|
||||
${cfg.config._create}
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
};
|
||||
_destroyFormatMount = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to unmount, create and mount all devices defined by disko.devices
|
||||
'';
|
||||
default = ''
|
||||
${cfg.config._destroy}
|
||||
${cfg.config._create}
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
};
|
||||
_formatMount = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The script to create and mount all devices defined by disko.devices, without wiping the disks first
|
||||
'';
|
||||
default = ''
|
||||
${cfg.config._create}
|
||||
${cfg.config._mount}
|
||||
'';
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
The NixOS config generated by disko
|
||||
'';
|
||||
default =
|
||||
with lib; let
|
||||
configKeys = flatten (map attrNames (flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices))))));
|
||||
collectedConfigs = flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices))));
|
||||
in
|
||||
genAttrs configKeys (key: mkMerge (catAttrs key collectedConfigs));
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
# import all the types from the types directory
|
||||
types = lib.listToAttrs (
|
||||
map
|
||||
(file: lib.nameValuePair
|
||||
(lib.removeSuffix ".nix" file)
|
||||
(diskoLib.mkSubType (./types + "/${file}"))
|
||||
)
|
||||
(lib.attrNames (builtins.readDir ./types))
|
||||
);
|
||||
|
||||
|
||||
# render types into an json serializable format
|
||||
serializeType = type:
|
||||
let
|
||||
options = lib.filter (x: !lib.hasPrefix "_" x) (lib.attrNames type.options);
|
||||
in
|
||||
lib.listToAttrs (
|
||||
map
|
||||
(option: lib.nameValuePair
|
||||
option
|
||||
type.options.${option}
|
||||
)
|
||||
options
|
||||
);
|
||||
|
||||
typesSerializerLib = {
|
||||
rootMountPoint = "";
|
||||
options = null;
|
||||
config = {
|
||||
_module = {
|
||||
args.name = "<self.name>";
|
||||
args._parent.name = "<parent.name>";
|
||||
args._parent.type = "<parent.type>";
|
||||
};
|
||||
name = "<config.name>";
|
||||
};
|
||||
parent = { };
|
||||
device = "/dev/<device>";
|
||||
# Spoof part of nixpkgs/lib to analyze the types
|
||||
lib = lib // {
|
||||
mkOption = option: {
|
||||
inherit (option) type;
|
||||
description = option.description or null;
|
||||
default = option.defaultText or option.default or null;
|
||||
};
|
||||
types = {
|
||||
attrsOf = subType: {
|
||||
type = "attrsOf";
|
||||
inherit subType;
|
||||
};
|
||||
listOf = subType: {
|
||||
type = "listOf";
|
||||
inherit subType;
|
||||
};
|
||||
nullOr = subType: {
|
||||
type = "nullOr";
|
||||
inherit subType;
|
||||
};
|
||||
oneOf = types: {
|
||||
type = "oneOf";
|
||||
inherit types;
|
||||
};
|
||||
either = t1: t2: {
|
||||
type = "oneOf";
|
||||
types = [ t1 t2 ];
|
||||
};
|
||||
enum = choices: {
|
||||
type = "enum";
|
||||
inherit choices;
|
||||
};
|
||||
anything = "anything";
|
||||
nonEmptyStr = "str";
|
||||
strMatching = _: "str";
|
||||
str = "str";
|
||||
bool = "bool";
|
||||
int = "int";
|
||||
submodule = x: x {
|
||||
inherit (diskoLib.typesSerializerLib) lib config options;
|
||||
name = "<self.name>";
|
||||
};
|
||||
};
|
||||
};
|
||||
diskoLib = {
|
||||
optionTypes.absolute-pathname = "absolute-pathname";
|
||||
# Spoof these types to avoid infinite recursion
|
||||
deviceType = _: "<deviceType>";
|
||||
partitionType = _: "<partitionType>";
|
||||
subType = { types, ... }: {
|
||||
type = "oneOf";
|
||||
types = lib.attrNames types;
|
||||
};
|
||||
mkCreateOption = option: "_create";
|
||||
};
|
||||
};
|
||||
|
||||
jsonTypes = lib.listToAttrs
|
||||
(
|
||||
map
|
||||
(file: lib.nameValuePair
|
||||
(lib.removeSuffix ".nix" file)
|
||||
(diskoLib.serializeType (import (./types + "/${file}") diskoLib.typesSerializerLib))
|
||||
)
|
||||
(lib.filter (name: lib.hasSuffix ".nix" name) (lib.attrNames (builtins.readDir ./types)))
|
||||
) // {
|
||||
partitionType = {
|
||||
type = "oneOf";
|
||||
types = lib.attrNames diskoLib._partitionTypes;
|
||||
};
|
||||
deviceType = {
|
||||
type = "oneOf";
|
||||
types = lib.attrNames diskoLib._deviceTypes;
|
||||
};
|
||||
};
|
||||
|
||||
} // outputs;
|
||||
in
|
||||
diskoLib
|
||||
@ -1,81 +0,0 @@
|
||||
{ diskoLib, modulesPath, config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
vm_disko = (diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices).disko;
|
||||
cfg_ = (lib.evalModules {
|
||||
modules = lib.singleton {
|
||||
# _file = toString input;
|
||||
imports = lib.singleton { disko.devices = vm_disko.devices; };
|
||||
options = {
|
||||
disko.devices = lib.mkOption {
|
||||
type = diskoLib.toplevel;
|
||||
};
|
||||
disko.testMode = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}).config;
|
||||
disks = lib.attrValues cfg_.disko.devices.disk;
|
||||
rootDisk = {
|
||||
name = "root";
|
||||
file = ''"$tmp"/${lib.escapeShellArg (builtins.head disks).name}.qcow2'';
|
||||
driveExtraOpts.cache = "writeback";
|
||||
driveExtraOpts.werror = "report";
|
||||
deviceExtraOpts.bootindex = "1";
|
||||
deviceExtraOpts.serial = "root";
|
||||
};
|
||||
otherDisks = map
|
||||
(disk: {
|
||||
name = disk.name;
|
||||
file = ''"$tmp"/${lib.escapeShellArg disk.name}.qcow2'';
|
||||
driveExtraOpts.werror = "report";
|
||||
})
|
||||
(builtins.tail disks);
|
||||
|
||||
diskoBasedConfiguration = {
|
||||
# generated from disko config
|
||||
virtualisation.fileSystems = cfg_.disko.devices._config.fileSystems;
|
||||
boot = cfg_.disko.devices._config.boot or { };
|
||||
swapDevices = cfg_.disko.devices._config.swapDevices or [ ];
|
||||
};
|
||||
|
||||
hostPkgs = config.virtualisation.host.pkgs;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/virtualisation/qemu-vm.nix")
|
||||
diskoBasedConfiguration
|
||||
];
|
||||
|
||||
disko.testMode = true;
|
||||
|
||||
disko.imageBuilder.copyNixStore = false;
|
||||
disko.imageBuilder.extraConfig = {
|
||||
disko.devices = cfg_.disko.devices;
|
||||
};
|
||||
disko.imageBuilder.imageFormat = "qcow2";
|
||||
|
||||
virtualisation.useEFIBoot = config.disko.tests.efi;
|
||||
virtualisation.memorySize = lib.mkDefault config.disko.memSize;
|
||||
virtualisation.useDefaultFilesystems = false;
|
||||
virtualisation.diskImage = null;
|
||||
virtualisation.qemu.drives = [ rootDisk ] ++ otherDisks;
|
||||
boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms
|
||||
boot.zfs.forceImportAll = true;
|
||||
boot.zfs.forceImportRoot = lib.mkForce true;
|
||||
|
||||
system.build.vmWithDisko = hostPkgs.writers.writeDashBin "disko-vm" ''
|
||||
set -efux
|
||||
export tmp=$(${hostPkgs.coreutils}/bin/mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
${lib.concatMapStringsSep "\n" (disk: ''
|
||||
${hostPkgs.qemu}/bin/qemu-img create -f qcow2 \
|
||||
-b ${config.system.build.diskoImages}/${lib.escapeShellArg disk.name}.qcow2 \
|
||||
-F qcow2 "$tmp"/${lib.escapeShellArg disk.name}.qcow2
|
||||
'') disks}
|
||||
set +f
|
||||
${config.system.build.vm}/bin/run-*-vm
|
||||
'';
|
||||
}
|
||||
@ -1,228 +0,0 @@
|
||||
{ config
|
||||
, diskoLib
|
||||
, lib
|
||||
, extendModules
|
||||
, options
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
diskoCfg = config.disko;
|
||||
cfg = diskoCfg.imageBuilder;
|
||||
inherit (cfg) pkgs imageFormat;
|
||||
checked = diskoCfg.checkScripts;
|
||||
|
||||
configSupportsZfs = config.boot.supportedFilesystems.zfs or false;
|
||||
vmTools = pkgs.vmTools.override
|
||||
{
|
||||
rootModules = [
|
||||
"9p" "9pnet_virtio" # we can drop those in future if we stop supporting 24.11
|
||||
|
||||
"virtiofs"
|
||||
"virtio_pci"
|
||||
"virtio_blk"
|
||||
"virtio_balloon"
|
||||
"virtio_rng"
|
||||
]
|
||||
++ (lib.optional configSupportsZfs "zfs")
|
||||
++ cfg.extraRootModules;
|
||||
kernel = pkgs.aggregateModules
|
||||
(with cfg.kernelPackages; [ kernel ]
|
||||
++ lib.optional (lib.elem "zfs" cfg.extraRootModules || configSupportsZfs) zfs);
|
||||
}
|
||||
// lib.optionalAttrs (diskoLib.vmToolsSupportsCustomQemu lib)
|
||||
{
|
||||
customQemu = cfg.qemu;
|
||||
};
|
||||
cleanedConfig = diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices;
|
||||
systemToInstall = extendModules {
|
||||
modules = [
|
||||
cfg.extraConfig
|
||||
{
|
||||
disko.testMode = true;
|
||||
disko.devices = lib.mkForce cleanedConfig.disko.devices;
|
||||
boot.loader.grub.devices = lib.mkForce cleanedConfig.boot.loader.grub.devices;
|
||||
}
|
||||
];
|
||||
};
|
||||
dependencies = with pkgs; [
|
||||
bash
|
||||
coreutils
|
||||
gnused
|
||||
parted # for partprobe
|
||||
systemdMinimal
|
||||
nix
|
||||
util-linux
|
||||
findutils
|
||||
kmod
|
||||
] ++ cfg.extraDependencies;
|
||||
preVM = ''
|
||||
# shellcheck disable=SC2154
|
||||
mkdir -p "$out"
|
||||
${lib.concatMapStringsSep "\n" (disk:
|
||||
# shellcheck disable=SC2154
|
||||
"${pkgs.qemu}/bin/qemu-img create -f ${imageFormat} \"$out/${disk.imageName}.${imageFormat}\" ${disk.imageSize}"
|
||||
) (lib.attrValues diskoCfg.devices.disk)}
|
||||
# This makes disko work, when canTouchEfiVariables is set to true.
|
||||
# Technically these boot entries will no be persisted this way, but
|
||||
# in most cases this is OK, because we can rely on the standard location for UEFI executables.
|
||||
install -m600 ${pkgs.OVMF.variables} efivars.fd
|
||||
'';
|
||||
|
||||
closureInfo = pkgs.closureInfo {
|
||||
rootPaths = [ systemToInstall.config.system.build.toplevel ];
|
||||
};
|
||||
partitioner = ''
|
||||
set -efux
|
||||
# running udev, stolen from stage-1.sh
|
||||
echo "running udev..."
|
||||
ln -sfn /proc/self/fd /dev/fd
|
||||
ln -sfn /proc/self/fd/0 /dev/stdin
|
||||
ln -sfn /proc/self/fd/1 /dev/stdout
|
||||
ln -sfn /proc/self/fd/2 /dev/stderr
|
||||
mkdir -p /etc/udev
|
||||
mount -t efivarfs none /sys/firmware/efi/efivars
|
||||
ln -sfn ${systemToInstall.config.system.build.etc}/etc/udev/rules.d /etc/udev/rules.d
|
||||
mkdir -p /dev/.mdadm
|
||||
${pkgs.systemdMinimal}/lib/systemd/systemd-udevd --daemon
|
||||
partprobe
|
||||
udevadm trigger --action=add
|
||||
udevadm settle
|
||||
|
||||
${lib.optionalString diskoCfg.testMode ''
|
||||
export IN_DISKO_TEST=1
|
||||
''}
|
||||
${lib.getExe systemToInstall.config.system.build.destroyFormatMount} --yes-wipe-all-disks
|
||||
'';
|
||||
|
||||
installer = lib.optionalString cfg.copyNixStore ''
|
||||
# populate nix db, so nixos-install doesn't complain
|
||||
export NIX_STATE_DIR=${systemToInstall.config.disko.rootMountPoint}/nix/var/nix
|
||||
nix-store --load-db < "${closureInfo}/registration"
|
||||
|
||||
# We copy files with cp because `nix copy` seems to have a large memory leak
|
||||
mkdir -p ${systemToInstall.config.disko.rootMountPoint}/nix/store
|
||||
time xargs cp --recursive --target ${systemToInstall.config.disko.rootMountPoint}/nix/store < ${closureInfo}/store-paths
|
||||
|
||||
${systemToInstall.config.system.build.nixos-install}/bin/nixos-install --root ${systemToInstall.config.disko.rootMountPoint} --system ${systemToInstall.config.system.build.toplevel} --keep-going --no-channel-copy -v --no-root-password --option binary-caches ""
|
||||
umount -Rv ${systemToInstall.config.disko.rootMountPoint}
|
||||
'';
|
||||
|
||||
QEMU_OPTS = lib.concatStringsSep " " ([
|
||||
"-drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}"
|
||||
"-drive if=pflash,format=raw,unit=1,file=efivars.fd"
|
||||
] ++ builtins.map
|
||||
(disk:
|
||||
"-drive file=\"$out\"/${disk.imageName}.${imageFormat},if=virtio,cache=unsafe,werror=report,format=${imageFormat}"
|
||||
)
|
||||
(lib.attrValues diskoCfg.devices.disk));
|
||||
in
|
||||
{
|
||||
system.build.diskoImages = vmTools.runInLinuxVM (pkgs.runCommand cfg.name
|
||||
{
|
||||
buildInputs = dependencies;
|
||||
inherit preVM QEMU_OPTS;
|
||||
postVm = cfg.extraPostVM;
|
||||
inherit (diskoCfg) memSize;
|
||||
}
|
||||
(partitioner + installer));
|
||||
|
||||
system.build.diskoImagesScript = diskoLib.writeCheckedBash { inherit checked pkgs; } cfg.name ''
|
||||
set -efu
|
||||
export PATH=${lib.makeBinPath dependencies}
|
||||
showUsage() {
|
||||
cat <<\USAGE
|
||||
Usage: $script [options]
|
||||
|
||||
Options:
|
||||
* --pre-format-files <src> <dst>
|
||||
copies the src to the dst on the VM, before disko is run
|
||||
This is useful to provide secrets like LUKS keys, or other files you need for formatting
|
||||
* --post-format-files <src> <dst>
|
||||
copies the src to the dst on the finished image
|
||||
These end up in the images later and is useful if you want to add some extra stateful files
|
||||
They will have the same permissions but will be owned by root:root
|
||||
* --build-memory <amt>
|
||||
specify the amount of memory in MiB that gets allocated to the build VM
|
||||
This can be useful if you want to build images with a more involed NixOS config
|
||||
The default is disko.memSize which defaults to ${builtins.toString options.disko.memSize.default} MiB
|
||||
USAGE
|
||||
}
|
||||
|
||||
export out=$PWD
|
||||
TMPDIR=$(mktemp -d); export TMPDIR
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
cd "$TMPDIR"
|
||||
|
||||
mkdir copy_before_disko copy_after_disko
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--pre-format-files)
|
||||
src=$2
|
||||
dst=$3
|
||||
cp --reflink=auto -r "$src" copy_before_disko/"$(echo "$dst" | base64)"
|
||||
shift 2
|
||||
;;
|
||||
--post-format-files)
|
||||
src=$2
|
||||
dst=$3
|
||||
cp --reflink=auto -r "$src" copy_after_disko/"$(echo "$dst" | base64)"
|
||||
shift 2
|
||||
;;
|
||||
--build-memory)
|
||||
regex="^[0-9]+$"
|
||||
if ! [[ $2 =~ $regex ]]; then
|
||||
echo "'$2' is not a number"
|
||||
exit 1
|
||||
fi
|
||||
build_memory=$2
|
||||
shift 1
|
||||
;;
|
||||
*)
|
||||
showUsage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
export preVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" ''
|
||||
set -efu
|
||||
mv copy_before_disko copy_after_disko xchg/
|
||||
origBuilder=${pkgs.writeScript "disko-builder" ''
|
||||
set -eu
|
||||
export PATH=${lib.makeBinPath dependencies}
|
||||
for src in /tmp/xchg/copy_before_disko/*; do
|
||||
[ -e "$src" ] || continue
|
||||
dst=$(basename "$src" | base64 -d)
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
cp -r "$src" "$dst"
|
||||
done
|
||||
set -f
|
||||
${partitioner}
|
||||
set +f
|
||||
for src in /tmp/xchg/copy_after_disko/*; do
|
||||
[ -e "$src" ] || continue
|
||||
dst=/mnt/$(basename "$src" | base64 -d)
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
cp -r "$src" "$dst"
|
||||
done
|
||||
${installer}
|
||||
''}
|
||||
echo "export origBuilder=$origBuilder" >> xchg/saved-env
|
||||
${preVM}
|
||||
''}
|
||||
export postVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "postVM.sh" cfg.extraPostVM}
|
||||
|
||||
build_memory=''${build_memory:-${builtins.toString diskoCfg.memSize}}
|
||||
# shellcheck disable=SC2016
|
||||
QEMU_OPTS=${lib.escapeShellArg QEMU_OPTS}
|
||||
# replace quoted $out with the actual path
|
||||
QEUM_OPTS=''${QEMU_OPTS//\$out/$out}
|
||||
QEMU_OPTS+=" -m $build_memory"
|
||||
export QEMU_OPTS
|
||||
|
||||
${pkgs.bash}/bin/sh -e ${vmTools.vmRunCommand vmTools.qemuCommandLinux}
|
||||
cd /
|
||||
'';
|
||||
}
|
||||
@ -1,337 +0,0 @@
|
||||
{ lib
|
||||
, makeTest
|
||||
, eval-config
|
||||
, ...
|
||||
}:
|
||||
|
||||
let
|
||||
testLib = {
|
||||
# this takes a nixos config and changes the disk devices so we can run them inside the qemu test runner
|
||||
# basically changes all the disk.*.devices to something like /dev/vda or /dev/vdb etc.
|
||||
prepareDiskoConfig = cfg: devices:
|
||||
let
|
||||
cleanedTopLevel = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) cfg;
|
||||
|
||||
preparedDisks = lib.foldlAttrs
|
||||
(acc: n: v: {
|
||||
devices = lib.tail acc.devices;
|
||||
grub-devices = acc.grub-devices ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (lib.attrValues (v.content.partitions or { }))) (lib.head acc.devices));
|
||||
disks = acc.disks // {
|
||||
"${n}" = v // {
|
||||
device = lib.head acc.devices;
|
||||
content = v.content // { device = lib.head acc.devices; };
|
||||
};
|
||||
};
|
||||
})
|
||||
{
|
||||
inherit devices;
|
||||
grub-devices = [ ];
|
||||
disks = { };
|
||||
}
|
||||
cleanedTopLevel.disko.devices.disk;
|
||||
in
|
||||
cleanedTopLevel // {
|
||||
boot.loader.grub.devices = if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ];
|
||||
disko.devices = cleanedTopLevel.disko.devices // {
|
||||
disk = preparedDisks.disks;
|
||||
};
|
||||
};
|
||||
|
||||
# list of devices generated inside qemu
|
||||
devices = [
|
||||
"/dev/vda"
|
||||
"/dev/vdb"
|
||||
"/dev/vdc"
|
||||
"/dev/vdd"
|
||||
"/dev/vde"
|
||||
"/dev/vdf"
|
||||
"/dev/vdg"
|
||||
"/dev/vdh"
|
||||
"/dev/vdi"
|
||||
"/dev/vdj"
|
||||
"/dev/vdk"
|
||||
"/dev/vdl"
|
||||
"/dev/vdm"
|
||||
"/dev/vdn"
|
||||
"/dev/vdo"
|
||||
];
|
||||
|
||||
# This is the test generator for a disko test
|
||||
makeDiskoTest =
|
||||
{ name
|
||||
, disko-config
|
||||
, extendModules ? null
|
||||
, pkgs ? import <nixpkgs> { }
|
||||
, extraTestScript ? ""
|
||||
, bootCommands ? ""
|
||||
, extraInstallerConfig ? { }
|
||||
, extraSystemConfig ? { }
|
||||
, efi ? !pkgs.stdenv.hostPlatform.isRiscV64
|
||||
, postDisko ? ""
|
||||
, testMode ? "module" # can be one of direct module cli
|
||||
, testBoot ? true # if we actually want to test booting or just create/mount
|
||||
, enableOCR ? false
|
||||
}:
|
||||
let
|
||||
makeTest' = args:
|
||||
makeTest args {
|
||||
inherit pkgs;
|
||||
inherit (pkgs) system;
|
||||
};
|
||||
# for installation we skip /dev/vda because it is the test runner disk
|
||||
|
||||
importedDiskoConfig =
|
||||
if builtins.isPath disko-config then
|
||||
import disko-config
|
||||
else
|
||||
disko-config;
|
||||
|
||||
diskoConfigWithArgs =
|
||||
if builtins.isFunction importedDiskoConfig then
|
||||
importedDiskoConfig { inherit lib; }
|
||||
else
|
||||
importedDiskoConfig;
|
||||
testConfigInstall = testLib.prepareDiskoConfig diskoConfigWithArgs (lib.tail testLib.devices);
|
||||
# we need to shift the disks by one because the first disk is the /dev/vda of the test runner
|
||||
# so /dev/vdb becomes /dev/vda etc.
|
||||
testConfigBooted = testLib.prepareDiskoConfig diskoConfigWithArgs testLib.devices;
|
||||
|
||||
tsp-generator = pkgs.callPackage ../. { checked = true; };
|
||||
tsp-format = (tsp-generator._cliFormat testConfigInstall) pkgs;
|
||||
tsp-mount = (tsp-generator._cliMount testConfigInstall) pkgs;
|
||||
tsp-unmount = (tsp-generator._cliUnmount testConfigInstall) pkgs;
|
||||
tsp-disko = (tsp-generator._cliDestroyFormatMount testConfigInstall) pkgs;
|
||||
tsp-config = tsp-generator.config testConfigBooted;
|
||||
num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk);
|
||||
|
||||
installed-system = { config, ... }: {
|
||||
imports = [
|
||||
(lib.optionalAttrs (testMode == "direct") tsp-config)
|
||||
(lib.optionalAttrs (testMode == "module") {
|
||||
disko.enableConfig = true;
|
||||
imports = [
|
||||
../module.nix
|
||||
testConfigBooted
|
||||
];
|
||||
})
|
||||
];
|
||||
|
||||
# config for tests to make them run faster or work at all
|
||||
documentation.enable = false;
|
||||
hardware.enableAllFirmware = lib.mkForce false;
|
||||
# FIXME: we don't have an systemd in stage-1 equialvent for this
|
||||
boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
|
||||
echo -n 'secretsecret' > /tmp/secret.key
|
||||
'';
|
||||
boot.consoleLogLevel = lib.mkForce 100;
|
||||
boot.loader.systemd-boot.enable = lib.mkDefault efi;
|
||||
};
|
||||
|
||||
installed-system-eval = eval-config {
|
||||
modules = [ installed-system ];
|
||||
inherit (pkgs) system;
|
||||
};
|
||||
|
||||
installedTopLevel = ((if extendModules != null then extendModules else installed-system-eval.extendModules) {
|
||||
modules = [
|
||||
({ config, ... }: {
|
||||
imports = [
|
||||
extraSystemConfig
|
||||
({ modulesPath, ... }: {
|
||||
imports = [
|
||||
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
disko.devices = lib.mkForce testConfigBooted.disko.devices;
|
||||
})
|
||||
];
|
||||
|
||||
# since we boot on a different machine, the efi payload needs to be portable
|
||||
boot.loader.grub.efiInstallAsRemovable = efi;
|
||||
boot.loader.grub.efiSupport = efi;
|
||||
boot.loader.systemd-boot.graceful = true;
|
||||
|
||||
# we always want the bind-mounted nix store. otherwise tests take forever
|
||||
fileSystems."/nix/store" = lib.mkForce {
|
||||
device = "nix-store";
|
||||
fsType = "9p";
|
||||
neededForBoot = true;
|
||||
options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
|
||||
};
|
||||
boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms
|
||||
|
||||
# grub will install to these devices, we need to force those or we are offset by 1
|
||||
# we use mkOveride 70, so that users can override this with mkForce in case they are testing grub mirrored boots
|
||||
boot.loader.grub.devices = lib.mkOverride 70 testConfigInstall.boot.loader.grub.devices;
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = builtins.length config.boot.loader.grub.mirroredBoots > 1 -> config.boot.loader.grub.devices == [ ];
|
||||
message = ''
|
||||
When using `--vm-test` in combination with `mirroredBoots`,
|
||||
it is necessary to configure `boot.loader.grub.devices` as an empty list by setting `boot.loader.grub.devices = lib.mkForce [];`.
|
||||
This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test.
|
||||
'';
|
||||
}
|
||||
];
|
||||
})
|
||||
];
|
||||
}).config.system.build.toplevel;
|
||||
|
||||
in
|
||||
makeTest' {
|
||||
name = "disko-${name}";
|
||||
meta.timeout = 600; # 10 minutes
|
||||
inherit enableOCR;
|
||||
|
||||
nodes.machine = { pkgs, ... }: {
|
||||
imports = [
|
||||
(lib.optionalAttrs (testMode == "module") {
|
||||
imports = [
|
||||
../module.nix
|
||||
];
|
||||
disko = {
|
||||
enableConfig = false;
|
||||
checkScripts = true;
|
||||
devices = testConfigInstall.disko.devices;
|
||||
};
|
||||
})
|
||||
extraInstallerConfig
|
||||
|
||||
# from base.nix
|
||||
({ config, ... }: {
|
||||
boot.supportedFilesystems =
|
||||
[ "btrfs" "cifs" "f2fs" "jfs" "ntfs" "reiserfs" "vfat" "xfs" ] ++
|
||||
lib.optional (config.networking.hostId != null && lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs";
|
||||
})
|
||||
|
||||
(if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then {
|
||||
boot.swraid.enable = true;
|
||||
} else {
|
||||
boot.initrd.services.swraid.enable = true;
|
||||
})
|
||||
];
|
||||
|
||||
systemd.services.mdmonitor.enable = false; # silence some weird warnings
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.jq
|
||||
];
|
||||
|
||||
# speed-up eval
|
||||
documentation.enable = false;
|
||||
|
||||
nix.settings = {
|
||||
substituters = lib.mkForce [ ];
|
||||
hashed-mirrors = null;
|
||||
connect-timeout = 1;
|
||||
};
|
||||
|
||||
networking.hostId = lib.mkIf
|
||||
(
|
||||
(testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null)
|
||||
)
|
||||
testConfigInstall.networking.hostId;
|
||||
|
||||
virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks;
|
||||
|
||||
# useful for debugging via repl
|
||||
system.build.systemToInstall = installed-system-eval;
|
||||
};
|
||||
|
||||
testScript = { nodes, ... }: ''
|
||||
def disks(oldmachine, num_disks):
|
||||
disk_flags = []
|
||||
for i in range(num_disks):
|
||||
disk_flags += [
|
||||
'-drive',
|
||||
f"file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report",
|
||||
'-device',
|
||||
f"virtio-blk-pci,drive=drive{i + 1}"
|
||||
]
|
||||
return disk_flags
|
||||
|
||||
def create_test_machine(
|
||||
oldmachine=None, **kwargs
|
||||
): # taken from <nixpkgs/nixos/tests/installer.nix>
|
||||
start_command = [
|
||||
"${pkgs.qemu_test}/bin/qemu-kvm",
|
||||
"-cpu",
|
||||
"max",
|
||||
"-m",
|
||||
"1024",
|
||||
"-virtfs",
|
||||
"local,path=/nix/store,security_model=none,mount_tag=nix-store",
|
||||
*disks(oldmachine, ${toString num-disks})
|
||||
]
|
||||
${lib.optionalString efi ''
|
||||
start_command += ["-drive",
|
||||
"if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}",
|
||||
"-drive",
|
||||
"if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
|
||||
]
|
||||
''}
|
||||
machine = create_machine(start_command=" ".join(start_command), **kwargs)
|
||||
driver.machines.append(machine)
|
||||
return machine
|
||||
|
||||
machine.start()
|
||||
machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key")
|
||||
machine.succeed("echo -n 'secretsecret' > /tmp/secret.key")
|
||||
${lib.optionalString (testMode == "direct") ''
|
||||
# running direct mode
|
||||
machine.succeed("${lib.getExe tsp-format}")
|
||||
machine.succeed("${lib.getExe tsp-mount}")
|
||||
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
|
||||
machine.succeed("${lib.getExe tsp-unmount}")
|
||||
machine.succeed("${lib.getExe tsp-unmount}") # verify that umount is idempotent
|
||||
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
|
||||
machine.succeed("${lib.getExe tsp-disko} --yes-wipe-all-disks") # verify that we can destroy and recreate
|
||||
machine.succeed("mkdir -p /mnt/home")
|
||||
machine.succeed("touch /mnt/home/testfile")
|
||||
machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent
|
||||
machine.succeed("test -e /mnt/home/testfile")
|
||||
''}
|
||||
${lib.optionalString (testMode == "module") ''
|
||||
# running module mode
|
||||
machine.succeed("${lib.getExe nodes.machine.system.build.format}")
|
||||
machine.succeed("${lib.getExe nodes.machine.system.build.mount}")
|
||||
machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent
|
||||
machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount} --yes-wipe-all-disks") # verify that we can destroy and recreate again
|
||||
machine.succeed("mkdir -p /mnt/home")
|
||||
machine.succeed("touch /mnt/home/testfile")
|
||||
machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent
|
||||
machine.succeed("test -e /mnt/home/testfile")
|
||||
''}
|
||||
|
||||
${postDisko}
|
||||
|
||||
${lib.optionalString testBoot ''
|
||||
# mount nix-store in /mnt
|
||||
machine.succeed("mkdir -p /mnt/nix/store")
|
||||
machine.succeed("mount --bind /nix/store /mnt/nix/store")
|
||||
|
||||
machine.succeed("nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedTopLevel];}}/registration")
|
||||
|
||||
# fix "this is not a NixOS installation"
|
||||
machine.succeed("mkdir -p /mnt/etc")
|
||||
machine.succeed("touch /mnt/etc/NIXOS")
|
||||
|
||||
machine.succeed("mkdir -p /mnt/nix/var/nix/profiles")
|
||||
machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}")
|
||||
machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot")
|
||||
machine.succeed("sync")
|
||||
machine.shutdown()
|
||||
|
||||
machine = create_test_machine(oldmachine=machine, name="booted_machine")
|
||||
machine.start()
|
||||
${bootCommands}
|
||||
machine.wait_for_unit("local-fs.target")
|
||||
''}
|
||||
|
||||
${extraTestScript}
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
testLib
|
||||
@ -1,272 +0,0 @@
|
||||
{ config, options, diskoLib, lib, rootMountPoint, parent, device, ... }:
|
||||
let
|
||||
swapType = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
size = lib.mkOption {
|
||||
type = lib.types.strMatching "^([0-9]+[KMGTP])?$";
|
||||
description = "Size of the swap file (e.g. 2G)";
|
||||
};
|
||||
|
||||
path = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
description = "Path to the swap file (relative to the mountpoint)";
|
||||
};
|
||||
|
||||
priority = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Specify the priority of the swap file. Priority is a value between 0 and 32767.
|
||||
Higher numbers indicate higher priority.
|
||||
null lets the kernel choose a priority, which will show up as a negative value.
|
||||
'';
|
||||
};
|
||||
|
||||
options = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.nonEmptyStr;
|
||||
default = [ "defaults" ];
|
||||
example = [ "nofail" ];
|
||||
description = "Options used to mount the swap.";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "Swap files";
|
||||
};
|
||||
|
||||
swapConfig = { mountpoint, swap }:
|
||||
{
|
||||
swapDevices = builtins.map
|
||||
(file: {
|
||||
device = "${mountpoint}/${file.path}";
|
||||
inherit (file) priority options;
|
||||
})
|
||||
(lib.attrValues swap);
|
||||
};
|
||||
|
||||
swapCreate = mountpoint: swap:
|
||||
lib.concatMapStringsSep
|
||||
"\n"
|
||||
(file: ''
|
||||
if ! test -e "${mountpoint}/${file.path}"; then
|
||||
btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}"
|
||||
fi
|
||||
'')
|
||||
(lib.attrValues swap);
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "btrfs" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device to use";
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "A list of options to pass to mount.";
|
||||
};
|
||||
subvolumes = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name of the BTRFS subvolume.";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "btrfs_subvol" ];
|
||||
default = "btrfs_subvol";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Options to pass to mount";
|
||||
};
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "Location to mount the subvolume to.";
|
||||
};
|
||||
swap = swapType;
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "Subvolumes to define for BTRFS.";
|
||||
};
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "A path to mount the BTRFS filesystem to.";
|
||||
};
|
||||
swap = swapType;
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = _dev: { };
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
# create the filesystem only if the device seems empty
|
||||
if ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then
|
||||
mkfs.btrfs "${config.device}" ${toString config.extraArgs}
|
||||
fi
|
||||
${lib.optionalString (config.swap != {} || config.subvolumes != {}) ''
|
||||
if (blkid "${config.device}" -o export | grep -q '^TYPE=btrfs$'); then
|
||||
${lib.optionalString (config.swap != {}) ''
|
||||
(
|
||||
MNTPOINT=$(mktemp -d)
|
||||
mount ${device} "$MNTPOINT" -o subvol=/
|
||||
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
|
||||
${swapCreate "$MNTPOINT" config.swap}
|
||||
)
|
||||
''}
|
||||
${lib.concatMapStrings (subvol: ''
|
||||
(
|
||||
MNTPOINT=$(mktemp -d)
|
||||
mount "${config.device}" "$MNTPOINT" -o subvol=/
|
||||
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
|
||||
SUBVOL_ABS_PATH="$MNTPOINT/${subvol.name}"
|
||||
mkdir -p "$(dirname "$SUBVOL_ABS_PATH")"
|
||||
if ! btrfs subvolume show "$SUBVOL_ABS_PATH" > /dev/null 2>&1; then
|
||||
btrfs subvolume create "$SUBVOL_ABS_PATH" ${toString subvol.extraArgs}
|
||||
fi
|
||||
${swapCreate "$SUBVOL_ABS_PATH" subvol.swap}
|
||||
)
|
||||
'') (lib.attrValues config.subvolumes)}
|
||||
fi
|
||||
''}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
subvolMounts = lib.concatMapAttrs
|
||||
(_: subvol:
|
||||
lib.warnIf (subvol.mountOptions != (options.subvolumes.type.getSubOptions [ ]).mountOptions.default && subvol.mountpoint == null)
|
||||
"Subvolume ${subvol.name} has mountOptions but no mountpoint. See upgrade guide (2023-07-09 121df48)."
|
||||
lib.optionalAttrs
|
||||
(subvol.mountpoint != null)
|
||||
{
|
||||
${subvol.mountpoint} = ''
|
||||
if ! findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then
|
||||
mount "${config.device}" "${rootMountPoint}${subvol.mountpoint}" \
|
||||
${lib.concatMapStringsSep " " (opt: "-o ${opt}") (subvol.mountOptions ++ [ "subvol=${subvol.name}" ])} \
|
||||
-o X-mount.mkdir
|
||||
fi
|
||||
'';
|
||||
}
|
||||
)
|
||||
config.subvolumes;
|
||||
in
|
||||
{
|
||||
fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) {
|
||||
${config.mountpoint} = ''
|
||||
if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
|
||||
mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \
|
||||
${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \
|
||||
-o X-mount.mkdir
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
subvolMounts = lib.concatMapAttrs
|
||||
(_: subvol:
|
||||
lib.optionalAttrs
|
||||
(subvol.mountpoint != null)
|
||||
{
|
||||
${subvol.mountpoint} = ''
|
||||
if findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then
|
||||
umount "${rootMountPoint}${subvol.mountpoint}"
|
||||
fi
|
||||
'';
|
||||
}
|
||||
)
|
||||
config.subvolumes;
|
||||
in
|
||||
{
|
||||
fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) {
|
||||
${config.mountpoint} = ''
|
||||
if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
|
||||
umount "${rootMountPoint}${config.mountpoint}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [
|
||||
(map
|
||||
(subvol:
|
||||
lib.optional (subvol.mountpoint != null) {
|
||||
fileSystems.${subvol.mountpoint} = {
|
||||
device = config.device;
|
||||
fsType = "btrfs";
|
||||
options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ];
|
||||
};
|
||||
}
|
||||
)
|
||||
(lib.attrValues config.subvolumes))
|
||||
(lib.optional (config.mountpoint != null) {
|
||||
fileSystems.${config.mountpoint} = {
|
||||
device = config.device;
|
||||
fsType = "btrfs";
|
||||
options = config.mountOptions;
|
||||
};
|
||||
})
|
||||
(map
|
||||
(subvol: swapConfig {
|
||||
inherit (subvol) mountpoint swap;
|
||||
})
|
||||
(lib.attrValues config.subvolumes))
|
||||
(swapConfig {
|
||||
inherit (config) mountpoint swap;
|
||||
})
|
||||
];
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs:
|
||||
[ pkgs.btrfs-progs pkgs.gnugrep ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
{ config, options, lib, diskoLib, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = lib.replaceStrings [ "/" ] [ "_" ] config._module.args.name;
|
||||
description = "Device name";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "disk" ];
|
||||
default = "disk";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = diskoLib.optionTypes.absolute-pathname; # TODO check if subpath of /dev ? - No! eg: /.swapfile
|
||||
description = "Device path";
|
||||
};
|
||||
imageName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config.name;
|
||||
description = ''
|
||||
name of the image when disko images are created
|
||||
is used as an argument to "qemu-img create ..."
|
||||
'';
|
||||
};
|
||||
imageSize = lib.mkOption {
|
||||
type = lib.types.strMatching "[0-9]+[KMGTP]?";
|
||||
description = ''
|
||||
size of the image when disko images are created
|
||||
is used as an argument to "qemu-img create ..."
|
||||
'';
|
||||
default = "2G";
|
||||
};
|
||||
content = diskoLib.deviceType { parent = config; device = config.device; };
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default =
|
||||
lib.optionalAttrs (config.content != null) (config.content._meta [ "disk" config.device ]);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = config.content._create;
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.content != null) config.content._mount;
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.content != null) config.content._unmount;
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default =
|
||||
lib.optional (config.content != null) config.content._config;
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.jq ] ++ lib.optionals (config.content != null) (config.content._pkgs pkgs);
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
{ config, options, lib, diskoLib, rootMountPoint, parent, device, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "filesystem" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device to use";
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Options to pass to mount";
|
||||
};
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "Path to mount the filesystem to";
|
||||
};
|
||||
format = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Format of the filesystem";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = _dev: { };
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! (blkid "${config.device}" | grep -q 'TYPE='); then
|
||||
mkfs.${config.format} \
|
||||
${lib.escapeShellArgs config.extraArgs} \
|
||||
"${config.device}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.mountpoint != null) {
|
||||
fs.${config.mountpoint} = ''
|
||||
if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
|
||||
mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \
|
||||
-t "${config.format}" \
|
||||
${lib.concatMapStringsSep " " (opt: "-o ${lib.escapeShellArg opt}") config.mountOptions} \
|
||||
-o X-mount.mkdir
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.mountpoint != null) {
|
||||
fs.${config.mountpoint} = ''
|
||||
if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
|
||||
umount "${rootMountPoint}${config.mountpoint}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = lib.optional (config.mountpoint != null) {
|
||||
fileSystems.${config.mountpoint} = {
|
||||
device = config.device;
|
||||
fsType = config.format;
|
||||
options = config.mountOptions;
|
||||
};
|
||||
};
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
# type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs:
|
||||
[ pkgs.util-linux pkgs.gnugrep ] ++ (
|
||||
# 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 if (config.format == "bcachefs") then [ pkgs.bcachefs-tools ]
|
||||
else if (config.format == "f2fs") then [ pkgs.f2fs-tools ]
|
||||
else [ ]
|
||||
);
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,297 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
let
|
||||
sortedPartitions = lib.sort (x: y: x.priority < y.priority) (lib.attrValues config.partitions);
|
||||
sortedHybridPartitions = lib.filter (p: p.hybrid != null) sortedPartitions;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "gpt" ];
|
||||
internal = true;
|
||||
description = "Partition table";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device to use for the partition table";
|
||||
};
|
||||
partitions = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@partition: {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type =
|
||||
let
|
||||
hexPattern = len: "[A-Fa-f0-9]{${toString len}}";
|
||||
in
|
||||
lib.types.either
|
||||
(lib.types.strMatching (hexPattern 4))
|
||||
(lib.types.strMatching (lib.concatMapStringsSep "-" hexPattern [ 8 4 4 4 12 ]));
|
||||
default = if partition.config.content != null && partition.config.content.type == "swap" then "8200" else "8300";
|
||||
defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"'';
|
||||
description = ''
|
||||
Filesystem type to use.
|
||||
This can either be an sgdisk-specific short code (run sgdisk -L to see what is available),
|
||||
or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs).
|
||||
'';
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
if config._parent.type == "mdadm" then
|
||||
# workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel
|
||||
"/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}"
|
||||
else
|
||||
"/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}";
|
||||
defaultText = ''
|
||||
if the parent is an mdadm device:
|
||||
/dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index}
|
||||
|
||||
otherwise:
|
||||
/dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label}
|
||||
'';
|
||||
description = "Device to use for the partition";
|
||||
};
|
||||
priority = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default =
|
||||
if partition.config.size or "" == "100%" then
|
||||
9001
|
||||
else if partition.config.type == "EF02" then
|
||||
# Boot partition should be created first, because some BIOS implementations require it.
|
||||
# Priority defaults to 100 here to support any potential use-case for placing partitions prior to EF02
|
||||
100
|
||||
else
|
||||
1000;
|
||||
defaultText = ''
|
||||
1000: normal partitions
|
||||
9001: partitions with 100% size
|
||||
100: boot partitions (EF02)
|
||||
'';
|
||||
description = "Priority of the partition, smaller values are created first";
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Name of the partition";
|
||||
default = name;
|
||||
};
|
||||
label = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
let
|
||||
# 72 bytes is the maximum length of a GPT partition name
|
||||
# the labels seem to be in UTF-16, so 2 bytes per character
|
||||
limit = 36;
|
||||
label = "${config._parent.type}-${config._parent.name}-${partition.config.name}";
|
||||
in
|
||||
if (lib.stringLength label) > limit then
|
||||
builtins.substring 0 limit (builtins.hashString "sha256" label)
|
||||
else
|
||||
label;
|
||||
defaultText = ''
|
||||
''${config._parent.type}-''${config._parent.name}-''${partition.config.name}
|
||||
|
||||
or a truncated hash of the above if it is longer than 36 characters
|
||||
'';
|
||||
};
|
||||
size = lib.mkOption {
|
||||
type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?");
|
||||
default = "0";
|
||||
description = ''
|
||||
Size of the partition, in sgdisk format.
|
||||
sets end automatically with the + prefix
|
||||
can be 100% for the whole remaining disk, will be done last in that case.
|
||||
'';
|
||||
};
|
||||
alignment = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = if (builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start == "s" || (builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s")) then 1 else 0;
|
||||
defaultText = "1 if the unit of start or end is sectors, 0 otherwise";
|
||||
description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1";
|
||||
};
|
||||
start = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "0";
|
||||
description = "Start of the partition, in sgdisk format, use 0 for next available range";
|
||||
};
|
||||
end = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}";
|
||||
defaultText = ''
|
||||
if partition.config.size == "100%" then "-0" else "+''${partition.config.size}";
|
||||
'';
|
||||
description = ''
|
||||
End of the partition, in sgdisk format.
|
||||
Use + for relative sizes from the partitions start
|
||||
or - for relative sizes from the disks end
|
||||
'';
|
||||
};
|
||||
content = diskoLib.partitionType { parent = config; device = partition.config.device; };
|
||||
hybrid = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.submodule ({ ... } @ hp: {
|
||||
options = {
|
||||
mbrPartitionType = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "MBR type code";
|
||||
};
|
||||
mbrBootableFlag = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Set the bootable flag (aka the active flag) on any or all of your hybridized partitions";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
${lib.optionalString (hp.config.mbrPartitionType != null) ''
|
||||
sfdisk --label-nested dos --part-type "${parent.device}" ${(toString partition.config._index)} ${hp.config.mbrPartitionType}
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
''}
|
||||
${lib.optionalString hp.config.mbrBootableFlag ''
|
||||
sfdisk --label-nested dos --activate "${parent.device}" ${(toString partition.config._index)}
|
||||
''}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = null;
|
||||
description = "Entry to add to the Hybrid MBR table";
|
||||
};
|
||||
_index = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
internal = true;
|
||||
default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0;
|
||||
defaultText = null;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "Attrs of partitions to add to the partition table";
|
||||
};
|
||||
efiGptPartitionFirst = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev:
|
||||
lib.foldr lib.recursiveUpdate { } (map
|
||||
(partition:
|
||||
lib.optionalAttrs (partition.content != null) (partition.content._meta dev)
|
||||
)
|
||||
(lib.attrValues config.partitions));
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! blkid "${config.device}" >&2; then
|
||||
sgdisk --clear "${config.device}"
|
||||
fi
|
||||
${lib.concatStrings (map (partition: ''
|
||||
# try to create the partition, if it fails, try to change the type and name
|
||||
if ! sgdisk \
|
||||
--align-end ${lib.optionalString (partition.alignment != 0) ''--set-alignment=${builtins.toString partition.alignment}''} \
|
||||
--new=${toString partition._index}:${partition.start}:${partition.end} \
|
||||
--change-name="${toString partition._index}:${partition.label}" \
|
||||
--typecode=${toString partition._index}:${partition.type} \
|
||||
"${config.device}"
|
||||
then sgdisk \
|
||||
--change-name="${toString partition._index}:${partition.label}" \
|
||||
--typecode=${toString partition._index}:${partition.type} \
|
||||
"${config.device}"
|
||||
fi
|
||||
# ensure /dev/disk/by-path/..-partN exists before continuing
|
||||
partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
'') sortedPartitions)}
|
||||
|
||||
${
|
||||
lib.optionalString (sortedHybridPartitions != [])
|
||||
("sgdisk -h "
|
||||
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
|
||||
+ (
|
||||
lib.optionalString (!config.efiGptPartitionFirst) ":EE "
|
||||
)
|
||||
+ ''"${parent.device}"'')
|
||||
}
|
||||
${lib.concatMapStrings (p:
|
||||
p.hybrid._create
|
||||
)
|
||||
sortedHybridPartitions
|
||||
}
|
||||
|
||||
${lib.concatStrings (map (partition: ''
|
||||
${lib.optionalString (partition.content != null) partition.content._create}
|
||||
'') sortedPartitions)}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
partMounts = lib.foldr lib.recursiveUpdate { } (map
|
||||
(partition:
|
||||
lib.optionalAttrs (partition.content != null) partition.content._mount
|
||||
)
|
||||
(lib.attrValues config.partitions));
|
||||
in
|
||||
{
|
||||
dev = partMounts.dev or "";
|
||||
fs = partMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
partMounts = lib.foldr lib.recursiveUpdate { } (map
|
||||
(partition:
|
||||
lib.optionalAttrs (partition.content != null) partition.content._unmount
|
||||
)
|
||||
(lib.attrValues config.partitions));
|
||||
in
|
||||
{
|
||||
dev = partMounts.dev or "";
|
||||
fs = partMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = (map
|
||||
(partition:
|
||||
lib.optional (partition.content != null) partition.content._config
|
||||
)
|
||||
(lib.attrValues config.partitions))
|
||||
++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) {
|
||||
boot.loader.grub.devices = [ config.device ];
|
||||
});
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs:
|
||||
[
|
||||
pkgs.gptfdisk
|
||||
pkgs.systemdMinimal
|
||||
pkgs.parted # for partprobe
|
||||
] ++ lib.flatten (map
|
||||
(partition:
|
||||
lib.optional (partition.content != null) (partition.content._pkgs pkgs)
|
||||
)
|
||||
(lib.attrValues config.partitions));
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,210 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
let
|
||||
keyFile =
|
||||
if config.settings ? "keyFile"
|
||||
then config.settings.keyFile
|
||||
else if config.askPassword
|
||||
then ''<(set +x; echo -n "$password"; set -x)''
|
||||
else if config.passwordFile != null
|
||||
# do not print the password to the console
|
||||
then ''<(set +x; echo -n "$(cat ${config.passwordFile})"; set -x)''
|
||||
else if config.keyFile != null
|
||||
then
|
||||
lib.warn
|
||||
("The option `keyFile` is deprecated."
|
||||
+ "Use passwordFile instead if you want to use interactive login or settings.keyFile if you want to use key file login")
|
||||
config.keyFile
|
||||
else null;
|
||||
keyFileArgs = ''
|
||||
${lib.optionalString (keyFile != null) "--key-file ${keyFile}"} \
|
||||
${lib.optionalString (lib.hasAttr "keyFileSize" config.settings) "--keyfile-size ${builtins.toString config.settings.keyFileSize}"} \
|
||||
${lib.optionalString (lib.hasAttr "keyFileOffset" config.settings) "--keyfile-offset ${builtins.toString config.settings.keyFileOffset}"} \
|
||||
'';
|
||||
cryptsetupOpen = ''
|
||||
cryptsetup open "${config.device}" "${config.name}" \
|
||||
${lib.optionalString (config.settings.allowDiscards or false) "--allow-discards"} \
|
||||
${lib.optionalString (config.settings.bypassWorkqueues or false) "--perf-no_read_workqueue --perf-no_write_workqueue"} \
|
||||
${toString config.extraOpenArgs} \
|
||||
${keyFileArgs} \
|
||||
'';
|
||||
in
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "luks" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Device to encrypt";
|
||||
default = device;
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Name of the LUKS";
|
||||
};
|
||||
keyFile = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "DEPRECATED use passwordFile or settings.keyFile. Path to the key for encryption";
|
||||
example = "/tmp/disk.key";
|
||||
};
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "Path to the file which contains the password for initial encryption";
|
||||
example = "/tmp/disk.key";
|
||||
};
|
||||
askPassword = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = config.keyFile == null && config.passwordFile == null && (! config.settings ? "keyFile");
|
||||
defaultText = "true if neither keyFile nor passwordFile are set";
|
||||
description = "Whether to ask for a password for initial encryption";
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.anything;
|
||||
default = { };
|
||||
description = "LUKS settings (as defined in configuration.nix in boot.initrd.luks.devices.<name>)";
|
||||
example = ''{
|
||||
keyFile = "/tmp/disk.key";
|
||||
keyFileSize = 2048;
|
||||
keyFileOffset = 1024;
|
||||
fallbackToPassword = true;
|
||||
allowDiscards = true;
|
||||
};
|
||||
'';
|
||||
};
|
||||
additionalKeyFiles = lib.mkOption {
|
||||
type = lib.types.listOf diskoLib.optionTypes.absolute-pathname;
|
||||
default = [ ];
|
||||
description = "Path to additional key files for encryption";
|
||||
example = [ "/tmp/disk2.key" ];
|
||||
};
|
||||
initrdUnlock = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Whether to add a boot.initrd.luks.devices entry for the specified disk.";
|
||||
};
|
||||
extraFormatArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments to pass to `cryptsetup luksFormat` when formatting";
|
||||
example = [ "--pbkdf argon2id" ];
|
||||
};
|
||||
extraOpenArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments to pass to `cryptsetup luksOpen` when opening";
|
||||
example = [ "--timeout 10" ];
|
||||
};
|
||||
content = diskoLib.deviceType { parent = config; device = "/dev/mapper/${config.name}"; };
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev:
|
||||
lib.optionalAttrs (config.content != null) (config.content._meta dev);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! blkid "${config.device}" >/dev/null || ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then
|
||||
${lib.optionalString config.askPassword ''
|
||||
askPassword() {
|
||||
if [ -z ''${IN_DISKO_TEST+x} ]; then
|
||||
set +x
|
||||
echo "Enter password for ${config.device}: "
|
||||
IFS= read -r -s password
|
||||
echo "Enter password for ${config.device} again to be safe: "
|
||||
IFS= read -r -s password_check
|
||||
export password
|
||||
[ "$password" = "$password_check" ]
|
||||
set -x
|
||||
else
|
||||
export password=disko
|
||||
fi
|
||||
}
|
||||
until askPassword; do
|
||||
echo "Passwords did not match, please try again."
|
||||
done
|
||||
''}
|
||||
cryptsetup -q luksFormat "${config.device}" ${toString config.extraFormatArgs} ${keyFileArgs}
|
||||
${cryptsetupOpen} --persistent
|
||||
${toString (lib.forEach config.additionalKeyFiles (keyFile: ''
|
||||
cryptsetup luksAddKey "${config.device}" ${keyFile} ${keyFileArgs}
|
||||
''))}
|
||||
fi
|
||||
${lib.optionalString (config.content != null) config.content._create}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
contentMount = config.content._mount;
|
||||
in
|
||||
{
|
||||
dev = ''
|
||||
if ! cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then
|
||||
${lib.optionalString config.askPassword ''
|
||||
if [ -z ''${IN_DISKO_TEST+x} ]; then
|
||||
set +x
|
||||
echo "Enter password for ${config.device}"
|
||||
IFS= read -r -s password
|
||||
export password
|
||||
set -x
|
||||
else
|
||||
export password=disko
|
||||
fi
|
||||
''}
|
||||
${cryptsetupOpen}
|
||||
fi
|
||||
${lib.optionalString (config.content != null) contentMount.dev or ""}
|
||||
'';
|
||||
fs = lib.optionalAttrs (config.content != null) contentMount.fs or { };
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
contentUnmount = config.content._unmount;
|
||||
in
|
||||
{
|
||||
dev = ''
|
||||
${lib.optionalString (config.content != null) contentUnmount.dev or ""}
|
||||
if cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then
|
||||
cryptsetup close "${config.name}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [ ]
|
||||
# If initrdUnlock is true, then add a device entry to the initrd.luks.devices config.
|
||||
++ (lib.optional config.initrdUnlock [
|
||||
{
|
||||
boot.initrd.luks.devices.${config.name} = {
|
||||
inherit (config) device;
|
||||
} // config.settings;
|
||||
}
|
||||
]) ++ (lib.optional (config.content != null) config.content._config);
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.gnugrep pkgs.cryptsetup ] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs));
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "lvm_pv" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Device";
|
||||
default = device;
|
||||
};
|
||||
vg = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Volume group";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev: {
|
||||
deviceDependencies.lvm_vg.${config.vg} = [ dev ];
|
||||
};
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! (blkid "${config.device}" | grep -q 'TYPE='); then
|
||||
pvcreate "${config.device}"
|
||||
fi
|
||||
echo "${config.device}" >>"$disko_devices_dir"/lvm_${lib.escapeShellArg config.vg}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [ ];
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.gnugrep pkgs.lvm2 ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,183 +0,0 @@
|
||||
{ config, options, lib, diskoLib, ... }:
|
||||
let
|
||||
# Load kernel modules to ensure device mapper types are available
|
||||
kernelModules =
|
||||
[
|
||||
# Prevent unbootable systems if LVM snapshots are present at boot time.
|
||||
"dm-snapshot"
|
||||
] ++
|
||||
lib.filter (x: x != "") (map
|
||||
(lv: lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "dm-${lv.lvm_type}")
|
||||
(lib.attrValues config.lvs));
|
||||
in
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name of the volume group";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "lvm_vg" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
lvs = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@lv: {
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
description = "Name of the logical volume";
|
||||
};
|
||||
priority = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = (if lv.config.lvm_type == "thin-pool" then 501 else 1000) + (if lib.hasInfix "100%" lv.config.size then 251 else 0);
|
||||
defaultText = lib.literalExpression ''
|
||||
if (lib.hasInfix "100%" lv.config.size) then 9001 else 1000
|
||||
'';
|
||||
description = "Priority of the logical volume, smaller values are created first";
|
||||
};
|
||||
size = lib.mkOption {
|
||||
type = lib.types.str; # TODO lvm size type
|
||||
description = "Size of the logical volume";
|
||||
};
|
||||
lvm_type = lib.mkOption {
|
||||
# TODO: add raid10
|
||||
type = lib.types.nullOr (lib.types.enum [ "mirror" "raid0" "raid1" "raid4" "raid5" "raid6" "thin-pool" "thinlv" ]); # TODO add all lib.types
|
||||
default = null; # maybe there is always a default type?
|
||||
description = "LVM type";
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments";
|
||||
};
|
||||
pool = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Name of pool LV that this LV belongs to";
|
||||
};
|
||||
content = diskoLib.partitionType { parent = config; device = "/dev/${config.name}/${lv.config.name}"; };
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "LVS for the volume group";
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default =
|
||||
diskoLib.deepMergeMap
|
||||
(lv:
|
||||
lib.optionalAttrs (lv.content != null) (lv.content._meta [ "lvm_vg" config.name ])
|
||||
)
|
||||
(lib.attrValues config.lvs);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
sortedLvs = lib.sort (a: b: a.priority < b.priority) (lib.attrValues config.lvs);
|
||||
in
|
||||
''
|
||||
${lib.concatMapStringsSep "\n" (k: ''modprobe "${k}"'') kernelModules}
|
||||
readarray -t lvm_devices < <(cat "$disko_devices_dir"/lvm_${lib.escapeShellArg config.name})
|
||||
if ! vgdisplay "${config.name}" >/dev/null; then
|
||||
vgcreate "${config.name}" \
|
||||
"''${lvm_devices[@]}"
|
||||
fi
|
||||
${lib.concatMapStrings (lv: ''
|
||||
if ! lvdisplay "${config.name}/${lv.name}"; then
|
||||
lvcreate \
|
||||
--yes \
|
||||
${if (lv.lvm_type == "thinlv") then "-V"
|
||||
else if lib.hasInfix "%" lv.size then "-l" else "-L"} \
|
||||
${if lib.hasSuffix "%" lv.size then "${lv.size}FREE" else lv.size} \
|
||||
-n "${lv.name}" \
|
||||
${lib.optionalString (lv.lvm_type == "thinlv") "--thinpool=${lv.pool}"} \
|
||||
${lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "--type=${lv.lvm_type}"} \
|
||||
${toString lv.extraArgs} \
|
||||
"${config.name}"
|
||||
fi
|
||||
'') sortedLvs}
|
||||
|
||||
${lib.concatMapStrings (lv: ''
|
||||
${lib.optionalString (lv.content != null) lv.content._create}
|
||||
'') sortedLvs}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
lvMounts = diskoLib.deepMergeMap
|
||||
(lv:
|
||||
lib.optionalAttrs (lv.content != null) lv.content._mount
|
||||
)
|
||||
(lib.attrValues config.lvs);
|
||||
in
|
||||
{
|
||||
dev = ''
|
||||
vgchange -a y
|
||||
${lib.concatMapStrings (x: x.dev or "") (lib.attrValues lvMounts)}
|
||||
'';
|
||||
fs = lvMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
lvMounts = diskoLib.deepMergeMap
|
||||
(lv:
|
||||
lib.optionalAttrs (lv.content != null) lv.content._unmount
|
||||
)
|
||||
(lib.attrValues config.lvs);
|
||||
in {
|
||||
dev = ''
|
||||
${lib.concatMapStrings (x: x.dev or "") (lib.attrValues lvMounts)}
|
||||
vgchange -a n
|
||||
'';
|
||||
fs = lvMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [{ boot.initrd.kernelModules = kernelModules; }] ++
|
||||
map
|
||||
(lv: [
|
||||
(lib.optional (lv.content != null) lv.content._config)
|
||||
(lib.optional (lv.lvm_type != null) {
|
||||
boot.initrd.kernelModules = [
|
||||
(if lv.lvm_type == "mirror" then "dm-mirror" else "dm-raid")
|
||||
]
|
||||
++ lib.optional (lv.lvm_type == "raid0") "raid0"
|
||||
++ lib.optional (lv.lvm_type == "raid1") "raid1"
|
||||
# ++ lib.optional (lv.lvm_type == "raid10") "raid10"
|
||||
++ lib.optional
|
||||
(lv.lvm_type == "raid4" ||
|
||||
lv.lvm_type == "raid5" ||
|
||||
lv.lvm_type == "raid6") "raid456";
|
||||
|
||||
})
|
||||
])
|
||||
(lib.attrValues config.lvs);
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: lib.flatten (map
|
||||
(lv:
|
||||
lib.optional (lv.content != null) (lv.content._pkgs pkgs)
|
||||
)
|
||||
(lib.attrValues config.lvs));
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
{ config, options, lib, diskoLib, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "mdadm" ];
|
||||
default = "mdadm";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
level = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1;
|
||||
description = "mdadm level";
|
||||
};
|
||||
metadata = lib.mkOption {
|
||||
type = lib.types.enum [ "1" "1.0" "1.1" "1.2" "default" "ddf" "imsm" ];
|
||||
default = "default";
|
||||
description = "Metadata";
|
||||
};
|
||||
content = diskoLib.deviceType { parent = config; device = "/dev/md/${config.name}"; };
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default =
|
||||
lib.optionalAttrs (config.content != null) (config.content._meta [ "mdadm" config.name ]);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! test -e "/dev/md/${config.name}"; then
|
||||
readarray -t disk_devices < <(cat "$disko_devices_dir"/raid_${lib.escapeShellArg config.name})
|
||||
echo 'y' | mdadm --create "/dev/md/${config.name}" \
|
||||
--level=${toString config.level} \
|
||||
--raid-devices="$(wc -l "$disko_devices_dir"/raid_${lib.escapeShellArg config.name} | cut -f 1 -d " ")" \
|
||||
--metadata=${config.metadata} \
|
||||
--force \
|
||||
--homehost=any \
|
||||
"''${disk_devices[@]}"
|
||||
partprobe "/dev/md/${config.name}"
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
# for some reason mdadm devices spawn with an existing partition table, so we need to wipe it
|
||||
sgdisk --zap-all "/dev/md/${config.name}"
|
||||
fi
|
||||
${lib.optionalString (config.content != null) config.content._create}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
lib.optionalAttrs (config.content != null) config.content._mount;
|
||||
# TODO we probably need to assemble the mdadm somehow
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = let
|
||||
content = lib.optionalAttrs (config.content != null) config.content._unmount;
|
||||
in {
|
||||
fs = content.fs;
|
||||
dev = ''
|
||||
${content.dev or ""}
|
||||
if [ -e "/dev/md/${config.name}" ]; then
|
||||
mdadm --stop "/dev/md/${config.name}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default =
|
||||
[
|
||||
(if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then {
|
||||
boot.swraid.enable = true;
|
||||
} else {
|
||||
boot.initrd.services.swraid.enable = true;
|
||||
})
|
||||
] ++
|
||||
lib.optional (config.content != null) config.content._config;
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [
|
||||
pkgs.parted # for partprobe
|
||||
] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs));
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "mdraid" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Device";
|
||||
default = device;
|
||||
};
|
||||
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Name";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev: {
|
||||
deviceDependencies.mdadm.${config.name} = [ dev ];
|
||||
};
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
echo "${config.device}" >>"$disko_devices_dir"/raid_${lib.escapeShellArg config.name}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [ ];
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.mdadm ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
{ lib, config, options, diskoLib, rootMountPoint, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "nodev" ];
|
||||
default = "nodev";
|
||||
internal = true;
|
||||
description = "Device type";
|
||||
};
|
||||
fsType = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "File system type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "none";
|
||||
description = "Device to use";
|
||||
};
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = config._module.args.name;
|
||||
description = "Location to mount the file system at";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Options to pass to mount";
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default = { };
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = "";
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.mountpoint != null) {
|
||||
fs.${config.mountpoint} = ''
|
||||
if ! findmnt ${config.fsType} "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
|
||||
mount -t ${config.fsType} "${config.device}" "${rootMountPoint}${config.mountpoint}" \
|
||||
${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \
|
||||
-o X-mount.mkdir
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (config.mountpoint != null) {
|
||||
fs.${config.mountpoint} = ''
|
||||
if findmnt ${config.fsType} "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
|
||||
umount "${rootMountPoint}${config.mountpoint}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = lib.optional (config.mountpoint != null) {
|
||||
fileSystems.${config.mountpoint} = {
|
||||
device = config.device;
|
||||
fsType = config.fsType;
|
||||
options = config.mountOptions;
|
||||
};
|
||||
};
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = _pkgs: [ ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,134 +0,0 @@
|
||||
{ diskoLib, config, options, lib, parent, device, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "swap" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device";
|
||||
};
|
||||
discardPolicy = lib.mkOption {
|
||||
default = null;
|
||||
example = "once";
|
||||
type = lib.types.nullOr (lib.types.enum [ "once" "pages" "both" ]);
|
||||
description = ''
|
||||
Specify the discard policy for the swap device. If "once", then the
|
||||
whole swap space is discarded at swapon invocation. If "pages",
|
||||
asynchronous discard on freed pages is performed, before returning to
|
||||
the available pages pool. With "both", both policies are activated.
|
||||
See swapon(8) for more information.
|
||||
'';
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.nonEmptyStr;
|
||||
default = [ "defaults" ];
|
||||
example = [ "nofail" ];
|
||||
description = "Options used to mount the swap.";
|
||||
};
|
||||
priority = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Specify the priority of the swap device. Priority is a value between 0 and 32767.
|
||||
Higher numbers indicate higher priority.
|
||||
null lets the kernel choose a priority, which will show up as a negative value.
|
||||
'';
|
||||
};
|
||||
randomEncryption = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether to randomly encrypt the swap";
|
||||
};
|
||||
resumeDevice = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether to use this as a boot.resumeDevice";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = _dev: { };
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
# TODO: we don't support encrypted swap yet
|
||||
default = lib.optionalString (!config.randomEncryption) ''
|
||||
if ! blkid "${config.device}" -o export | grep -q '^TYPE='; then
|
||||
mkswap \
|
||||
${toString config.extraArgs} \
|
||||
"${config.device}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
# TODO: we don't support encrypted swap yet
|
||||
default = lib.optionalAttrs (!config.randomEncryption) {
|
||||
fs.${config.device} = ''
|
||||
if test "''${DISKO_SKIP_SWAP:-}" != 1 && ! swapon --show | grep -q "^$(readlink -f "${config.device}") "; then
|
||||
swapon ${
|
||||
lib.optionalString (config.discardPolicy != null)
|
||||
"--discard${lib.optionalString (config.discardPolicy != "both")
|
||||
"=${config.discardPolicy}"
|
||||
}"} ${
|
||||
lib.optionalString (config.priority != null)
|
||||
"--priority=${toString config.priority}"
|
||||
} \
|
||||
--options=${lib.concatStringsSep "," config.mountOptions} \
|
||||
"${config.device}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = lib.optionalAttrs (!config.randomEncryption) {
|
||||
fs.${config.device} = ''
|
||||
if swapon --show | grep -q "^$(readlink -f "${config.device}") "; then
|
||||
swapoff "${config.device}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [{
|
||||
swapDevices = [{
|
||||
device = config.device;
|
||||
inherit (config) discardPolicy priority;
|
||||
randomEncryption = {
|
||||
enable = config.randomEncryption;
|
||||
# forward discard/TRIM attempts through dm-crypt
|
||||
allowDiscards = config.discardPolicy != null;
|
||||
};
|
||||
options = config.mountOptions;
|
||||
}];
|
||||
boot.resumeDevice = lib.mkIf config.resumeDevice config.device;
|
||||
}];
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.gnugrep pkgs.util-linux ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,179 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
{
|
||||
options = lib.warn ''
|
||||
The legacy table is outdated and should not be used. We recommend using the gpt type instead.
|
||||
Please note that certain features, such as the test framework, may not function properly with the legacy table type.
|
||||
If you encounter errors similar to:
|
||||
"error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times,"
|
||||
this is likely due to the use of the legacy table type.
|
||||
for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md
|
||||
''
|
||||
{
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "table" ];
|
||||
internal = true;
|
||||
description = "Partition table";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device to partition";
|
||||
};
|
||||
format = lib.mkOption {
|
||||
type = lib.types.enum [ "gpt" "msdos" ];
|
||||
default = "gpt";
|
||||
description = "The kind of partition table";
|
||||
};
|
||||
partitions = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule ({ name, ... }@partition: {
|
||||
options = {
|
||||
part-type = lib.mkOption {
|
||||
type = lib.types.enum [ "primary" "logical" "extended" ];
|
||||
default = "primary";
|
||||
description = "Partition type";
|
||||
};
|
||||
fs-type = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.enum [ "btrfs" "ext2" "ext3" "ext4" "fat16" "fat32" "hfs" "hfs+" "linux-swap" "ntfs" "reiserfs" "udf" "xfs" ]);
|
||||
default = null;
|
||||
description = "Filesystem type to use";
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = "Name of the partition";
|
||||
};
|
||||
start = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "0%";
|
||||
description = "Start of the partition";
|
||||
};
|
||||
end = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "100%";
|
||||
description = "End of the partition";
|
||||
};
|
||||
flags = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Partition flags";
|
||||
};
|
||||
bootable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether to make the partition bootable";
|
||||
};
|
||||
content = diskoLib.partitionType { parent = config; device = diskoLib.deviceNumbering config.device partition.config._index; };
|
||||
_index = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
internal = true;
|
||||
default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name));
|
||||
defaultText = null;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = [ ];
|
||||
description = "List of partitions to add to the partition table";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev:
|
||||
lib.foldr lib.recursiveUpdate { } (lib.imap
|
||||
(_index: partition:
|
||||
lib.optionalAttrs (partition.content != null) (partition.content._meta dev)
|
||||
)
|
||||
config.partitions);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! blkid "${config.device}" >/dev/null; then
|
||||
parted -s "${config.device}" -- mklabel ${config.format}
|
||||
${lib.concatStrings (map (partition: ''
|
||||
${lib.optionalString (config.format == "gpt") ''
|
||||
parted -s "${config.device}" -- mkpart "${diskoLib.hexEscapeUdevSymlink partition.name}" ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
|
||||
''}
|
||||
${lib.optionalString (config.format == "msdos") ''
|
||||
parted -s "${config.device}" -- mkpart ${partition.part-type} ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
|
||||
''}
|
||||
# ensure /dev/disk/by-path/..-partN exists before continuing
|
||||
partprobe "${config.device}"
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
${lib.optionalString partition.bootable ''
|
||||
parted -s "${config.device}" -- set ${toString partition._index} boot on
|
||||
''}
|
||||
${lib.concatMapStringsSep "" (flag: ''
|
||||
parted -s "${config.device}" -- set ${toString partition._index} ${flag} on
|
||||
'') partition.flags}
|
||||
# ensure further operations can detect new partitions
|
||||
partprobe "${config.device}"
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
'') config.partitions)}
|
||||
fi
|
||||
${lib.concatStrings (map (partition: ''
|
||||
${lib.optionalString (partition.content != null) partition.content._create}
|
||||
'') config.partitions)}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
partMounts = lib.foldr lib.recursiveUpdate { } (map
|
||||
(partition:
|
||||
lib.optionalAttrs (partition.content != null) partition.content._mount
|
||||
)
|
||||
config.partitions);
|
||||
in
|
||||
{
|
||||
dev = partMounts.dev or "";
|
||||
fs = partMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
partMounts = lib.foldr lib.recursiveUpdate { } (map
|
||||
(partition:
|
||||
lib.optionalAttrs (partition.content != null) partition.content._unmount
|
||||
)
|
||||
config.partitions);
|
||||
in
|
||||
{
|
||||
dev = partMounts.dev or "";
|
||||
fs = partMounts.fs or { };
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default =
|
||||
map
|
||||
(partition:
|
||||
lib.optional (partition.content != null) partition.content._config
|
||||
)
|
||||
config.partitions;
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs:
|
||||
[ pkgs.parted pkgs.systemdMinimal ] ++ lib.flatten (map
|
||||
(partition:
|
||||
lib.optional (partition.content != null) (partition.content._pkgs pkgs)
|
||||
)
|
||||
config.partitions);
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, device, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "zfs" ];
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = device;
|
||||
description = "Device";
|
||||
};
|
||||
pool = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Name of the ZFS pool";
|
||||
};
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev: {
|
||||
deviceDependencies.zpool.${config.pool} = [ dev ];
|
||||
};
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
echo "${config.device}" >>"$disko_devices_dir"/zfs_${lib.escapeShellArg config.pool}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = { };
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = [ ];
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.zfs ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,160 +0,0 @@
|
||||
{ config, options, lib, diskoLib, rootMountPoint, parent, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name of the dataset";
|
||||
};
|
||||
|
||||
_name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${config._parent.name}/${config.name}";
|
||||
internal = true;
|
||||
description = "Fully quantified name for dataset";
|
||||
};
|
||||
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "zfs_fs" ];
|
||||
default = "zfs_fs";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
|
||||
options = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
description = "Options to set for the dataset";
|
||||
};
|
||||
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Mount options";
|
||||
};
|
||||
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "Path to mount the dataset to";
|
||||
};
|
||||
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = _dev: { };
|
||||
description = "Metadata";
|
||||
};
|
||||
|
||||
_createFilesystem = lib.mkOption {
|
||||
internal = true;
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
_create = diskoLib.mkCreateOption
|
||||
{
|
||||
inherit config options;
|
||||
# -u prevents mounting newly created datasets, which is
|
||||
# important to prevent accidental shadowing of mount points
|
||||
# since (create order != mount order)
|
||||
# -p creates parents automatically
|
||||
default =
|
||||
let
|
||||
createOptions = (lib.optionalAttrs (config.mountpoint != null) { mountpoint = config.mountpoint; }) // config.options;
|
||||
# All options defined as PROP_ONETIME or PROP_ONETIME_DEFAULT in https://github.com/openzfs/zfs/blob/master/module/zcommon/zfs_prop.c
|
||||
onetimeProperties = [
|
||||
"encryption"
|
||||
"casesensitivity"
|
||||
"utf8only"
|
||||
"normalization"
|
||||
"volblocksize"
|
||||
"pbkdf2iters"
|
||||
"pbkdf2salt"
|
||||
"keyformat"
|
||||
];
|
||||
updateOptions = builtins.removeAttrs createOptions onetimeProperties;
|
||||
in
|
||||
''
|
||||
if ! zfs get type ${config._name} >/dev/null 2>&1; then
|
||||
${if config._createFilesystem then ''
|
||||
zfs create -up ${config._name} \
|
||||
${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") (createOptions))}
|
||||
'' else ''
|
||||
# don't create anything for root dataset of zpools
|
||||
true
|
||||
''}
|
||||
${lib.optionalString (updateOptions != {}) ''
|
||||
else
|
||||
zfs set -u ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${v}") updateOptions)} ${config._name}
|
||||
''}
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
(lib.optionalAttrs (config.options.keylocation or "none" != "none") {
|
||||
dev = ''
|
||||
if [ "$(zfs get keystatus ${config._name} -H -o value)" == "unavailable" ]; then
|
||||
zfs load-key ${config._name}
|
||||
fi
|
||||
'';
|
||||
}) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") {
|
||||
fs.${config.mountpoint} = ''
|
||||
if ! findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
|
||||
mount ${config._name} "${rootMountPoint}${config.mountpoint}" \
|
||||
-o X-mount.mkdir \
|
||||
${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \
|
||||
${lib.optionalString ((config.options.mountpoint or "") != "legacy") "-o zfsutil"} \
|
||||
-t zfs
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
(lib.optionalAttrs (config.options.keylocation or "none" != "none") {
|
||||
dev = "zfs unload-key ${config.name}";
|
||||
}) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") {
|
||||
fs.${config.mountpoint} = ''
|
||||
if findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
|
||||
umount "${rootMountPoint}${config.mountpoint}"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default =
|
||||
lib.optional (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") {
|
||||
fileSystems.${config.mountpoint} = {
|
||||
device = "${config._name}";
|
||||
fsType = "zfs";
|
||||
options = config.mountOptions ++ lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil";
|
||||
};
|
||||
};
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.util-linux ];
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
{ config, options, lib, diskoLib, parent, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name of the dataset";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "zfs_volume" ];
|
||||
default = "zfs_volume";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
options = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
description = "Options to set for the dataset";
|
||||
};
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra arguments passed to `zfs create`";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Mount options";
|
||||
};
|
||||
|
||||
# volume options
|
||||
size = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str; # TODO size
|
||||
default = null;
|
||||
description = "Size of the dataset";
|
||||
};
|
||||
|
||||
content = diskoLib.partitionType { parent = config; device = "/dev/zvol/${config._parent.name}/${config.name}"; };
|
||||
|
||||
_parent = lib.mkOption {
|
||||
internal = true;
|
||||
default = parent;
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo diskoLib.jsonType;
|
||||
default = dev:
|
||||
lib.optionalAttrs (config.content != null) (config.content._meta dev);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default = ''
|
||||
if ! zfs get type "${config._parent.name}/${config.name}" >/dev/null 2>&1; then
|
||||
zfs create "${config._parent.name}/${config.name}" \
|
||||
${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") config.options)} \
|
||||
-V ${config.size} ${toString (builtins.map lib.escapeShellArg config.extraArgs)}
|
||||
zvol_wait
|
||||
partprobe "/dev/zvol/${config._parent.name}/${config.name}"
|
||||
udevadm trigger --subsystem-match=block
|
||||
udevadm settle
|
||||
fi
|
||||
${lib.optionalString (config.content != null) config.content._create}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default = {
|
||||
dev = ''
|
||||
${lib.optionalString (config.options.keylocation or "none" != "none") ''
|
||||
if [ "$(zfs get keystatus ${config.name} -H -o value)" == "unavailable" ]; then
|
||||
zfs load-key ${config.name}
|
||||
fi
|
||||
''}
|
||||
|
||||
${config.content._mount.dev or ""}
|
||||
'';
|
||||
fs = config.content._mount.fs or { };
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = {
|
||||
dev = ''
|
||||
${lib.optionalString (config.options.keylocation or "none" != "none") "zfs unload-key ${config.name}"}
|
||||
|
||||
${config.content._unmount.dev or ""}
|
||||
'';
|
||||
|
||||
fs = config.content._unmount.fs;
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default =
|
||||
lib.optional (config.content != null) config.content._config;
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [
|
||||
pkgs.util-linux
|
||||
pkgs.parted # for partprobe
|
||||
] ++ lib.optionals (config.content != null) (config.content._pkgs pkgs);
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,390 +0,0 @@
|
||||
{ config, options, lib, diskoLib, rootMountPoint, ... }:
|
||||
let
|
||||
# TODO: Consider expanding to handle `file` and `draid` mode options.
|
||||
modeOptions = [
|
||||
""
|
||||
"mirror"
|
||||
"raidz"
|
||||
"raidz1"
|
||||
"raidz2"
|
||||
"raidz3"
|
||||
];
|
||||
in
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config._module.args.name;
|
||||
description = "Name of the ZFS pool";
|
||||
};
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "zpool" ];
|
||||
default = "zpool";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
mode = lib.mkOption {
|
||||
default = "";
|
||||
example = {
|
||||
mode = {
|
||||
topology = {
|
||||
type = "topology";
|
||||
vdev = [
|
||||
{
|
||||
# Members can be either specified by a full path or by a disk name
|
||||
# This is example uses the full path
|
||||
members = [ "/dev/disk/by-id/wwn-0x5000c500af8b2a14" ];
|
||||
}
|
||||
];
|
||||
log = [
|
||||
{
|
||||
# Example using gpt partition labels
|
||||
# This expects an disk called `ssd` with a gpt partition called `zfs`
|
||||
# disko.devices.disk.ssd = {
|
||||
# type = "disk";
|
||||
# device = "/dev/nvme0n1";
|
||||
# content = {
|
||||
# type = "gpt";
|
||||
# partitions = {
|
||||
# zfs = {
|
||||
# size = "100%";
|
||||
# content = {
|
||||
# type = "zfs";
|
||||
# # use your own pool name here
|
||||
# pool = "zroot";
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
members = [ "ssd" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
type = (lib.types.oneOf [
|
||||
(lib.types.enum modeOptions)
|
||||
(lib.types.attrsOf (diskoLib.subType {
|
||||
types = {
|
||||
topology =
|
||||
let
|
||||
vdev = lib.types.submodule ({ ... }: {
|
||||
options = {
|
||||
mode = lib.mkOption {
|
||||
type = lib.types.enum modeOptions;
|
||||
default = "";
|
||||
description = "Mode of the zfs vdev";
|
||||
};
|
||||
members = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Members of the vdev";
|
||||
};
|
||||
};
|
||||
});
|
||||
in
|
||||
lib.types.submodule
|
||||
({ ... }: {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "topology" ];
|
||||
default = "topology";
|
||||
internal = true;
|
||||
description = "Type";
|
||||
};
|
||||
# zfs device types
|
||||
vdev = lib.mkOption {
|
||||
type = lib.types.listOf vdev;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of storage vdevs. See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Virtual_Devices_(vdevs)
|
||||
for details.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "x" "y" ];
|
||||
}
|
||||
{
|
||||
members = [ "z" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
spare = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of devices to use as hot spares. See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Hot_Spares
|
||||
for details.
|
||||
'';
|
||||
example = [ "x" "y" ];
|
||||
};
|
||||
log = lib.mkOption {
|
||||
type = lib.types.listOf vdev;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of vdevs used for the zfs intent log (ZIL). See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Intent_Log
|
||||
for details.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "x" "y" ];
|
||||
}
|
||||
{
|
||||
members = [ "z" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
dedup = lib.mkOption {
|
||||
type = lib.types.listOf vdev;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of vdevs used for the deduplication table. See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#dedup
|
||||
for details.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "x" "y" ];
|
||||
}
|
||||
{
|
||||
members = [ "z" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
special = lib.mkOption {
|
||||
type = lib.types.either (lib.types.listOf vdev) (lib.types.nullOr vdev);
|
||||
default = [ ];
|
||||
description = ''
|
||||
A list of vdevs used as special devices. See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#special
|
||||
for details.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
mode = "mirror";
|
||||
members = [ "x" "y" ];
|
||||
}
|
||||
{
|
||||
members = [ "z" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
cache = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
A dedicated zfs cache device (L2ARC). See
|
||||
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Cache_Devices
|
||||
for details.
|
||||
'';
|
||||
example = [ "x" "y" ];
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
extraArgs.parent = config;
|
||||
}))
|
||||
]);
|
||||
description = "Mode of the ZFS pool";
|
||||
};
|
||||
options = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
description = "Options for the ZFS pool";
|
||||
};
|
||||
rootFsOptions = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
default = { };
|
||||
description = "Options for the root filesystem";
|
||||
};
|
||||
mountpoint = lib.mkOption {
|
||||
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
|
||||
default = null;
|
||||
description = "The mountpoint of the pool";
|
||||
};
|
||||
mountOptions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "defaults" ];
|
||||
description = "Options to pass to mount";
|
||||
};
|
||||
datasets = lib.mkOption {
|
||||
type = lib.types.attrsOf (diskoLib.subType {
|
||||
types = { inherit (diskoLib.types) zfs_fs zfs_volume; };
|
||||
extraArgs.parent = config;
|
||||
});
|
||||
description = "List of datasets to define";
|
||||
};
|
||||
_meta = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = diskoLib.jsonType;
|
||||
default =
|
||||
diskoLib.deepMergeMap (dataset: dataset._meta [ "zpool" config.name ]) (lib.attrValues config.datasets);
|
||||
description = "Metadata";
|
||||
};
|
||||
_create = diskoLib.mkCreateOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
formatOutput = type: mode: members: ''
|
||||
entries+=("${type} ${mode}=${
|
||||
lib.concatMapStringsSep " "
|
||||
(d: if lib.strings.hasPrefix "/" d then d else "/dev/disk/by-partlabel/disk-${d}-zfs") members
|
||||
}")
|
||||
'';
|
||||
formatVdev = type: vdev: formatOutput type vdev.mode vdev.members;
|
||||
formatVdevList = type: vdevs: lib.concatMapStrings
|
||||
(formatVdev type)
|
||||
(builtins.sort (a: _: a.mode == "") vdevs);
|
||||
hasTopology = !(builtins.isString config.mode);
|
||||
mode = if hasTopology then "prescribed" else config.mode;
|
||||
topology = lib.optionalAttrs hasTopology config.mode.topology;
|
||||
in
|
||||
''
|
||||
readarray -t zfs_devices < <(cat "$disko_devices_dir/zfs_${config.name}")
|
||||
if [ ''${#zfs_devices[@]} -eq 0 ]; then
|
||||
echo "no devices found for zpool ${config.name}. Did you misspell the pool name?" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Try importing the pool without mounting anything if it exists.
|
||||
# This allows us to set mounpoints.
|
||||
if zpool import -N -f "${config.name}" || zpool list "${config.name}"; then
|
||||
echo "not creating zpool ${config.name} as a pool with that name already exists" >&2
|
||||
else
|
||||
continue=1
|
||||
for dev in "''${zfs_devices[@]}"; do
|
||||
if ! blkid "$dev" >/dev/null; then
|
||||
# blkid fails, so device seems empty
|
||||
:
|
||||
elif (blkid "$dev" -o export | grep '^PTUUID='); then
|
||||
echo "device $dev already has a partuuid, skipping creating zpool ${config.name}" >&2
|
||||
continue=0
|
||||
elif (blkid "$dev" -o export | grep '^TYPE=zfs_member'); then
|
||||
# zfs_member is a zfs partition, so we try to add the device to the pool
|
||||
:
|
||||
elif (blkid "$dev" -o export | grep '^TYPE='); then
|
||||
echo "device $dev already has a partition, skipping creating zpool ${config.name}" >&2
|
||||
continue=0
|
||||
fi
|
||||
done
|
||||
if [ $continue -eq 1 ]; then
|
||||
topology=""
|
||||
# For shell check
|
||||
mode="${mode}"
|
||||
if [ "$mode" != "prescribed" ]; then
|
||||
topology="${mode} ''${zfs_devices[*]}"
|
||||
else
|
||||
entries=()
|
||||
${lib.optionalString (hasTopology && topology.vdev != null)
|
||||
(formatVdevList "" topology.vdev)}
|
||||
${lib.optionalString (hasTopology && topology.spare != [])
|
||||
(formatOutput "spare" "" topology.spare)}
|
||||
${lib.optionalString (hasTopology && topology.log != [])
|
||||
(formatVdevList "log" topology.log)}
|
||||
${lib.optionalString (hasTopology && topology.dedup != [])
|
||||
(formatVdevList "dedup" topology.dedup)}
|
||||
${lib.optionalString (hasTopology && topology.special != null && topology.special != [])
|
||||
(formatVdevList "special" (lib.lists.toList topology.special))}
|
||||
${lib.optionalString (hasTopology && topology.cache != [])
|
||||
(formatOutput "cache" "" topology.cache)}
|
||||
all_devices=()
|
||||
last_type=
|
||||
for line in "''${entries[@]}"; do
|
||||
# lineformat is type mode=device1 device2 device3
|
||||
mode="''${line%%=*}"
|
||||
type="''${mode%% *}"
|
||||
mode="''${mode#"$type "}"
|
||||
devs="''${line#*=}"
|
||||
IFS=' ' read -r -a devices <<< "$devs"
|
||||
all_devices+=("''${devices[@]}")
|
||||
if ! [ "$type" = "$last_type" ]; then
|
||||
topology+=" $type"
|
||||
last_type="$type"
|
||||
fi
|
||||
topology+=" ''${mode} ''${devices[*]}"
|
||||
done
|
||||
# all_devices sorted should equal zfs_devices sorted
|
||||
all_devices_list=$(echo "''${all_devices[*]}" | tr ' ' '\n' | sort)
|
||||
zfs_devices_list=$(echo "''${zfs_devices[*]}" | tr ' ' '\n' | sort)
|
||||
if [[ "$all_devices_list" != "$zfs_devices_list" ]]; then
|
||||
echo "not all disks accounted for, skipping creating zpool ${config.name}" >&2
|
||||
diff <(echo "$all_devices_list" ) <(echo "$zfs_devices_list") >&2
|
||||
continue=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ $continue -eq 1 ]; then
|
||||
zpool create -f "${config.name}" \
|
||||
-R ${rootMountPoint} \
|
||||
${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") config.options)} \
|
||||
${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-O ${n}=${v}") config.rootFsOptions)} \
|
||||
''${topology:+ $topology}
|
||||
if [[ $(zfs get -H mounted "${config.name}" | cut -f3) == "yes" ]]; then
|
||||
zfs unmount "${config.name}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
${lib.concatMapStrings (dataset: dataset._create) (lib.attrValues config.datasets)}
|
||||
'';
|
||||
};
|
||||
_mount = diskoLib.mkMountOption {
|
||||
inherit config options;
|
||||
default =
|
||||
let
|
||||
datasetFilesystemsMounts = diskoLib.deepMergeMap (dataset: dataset._mount.fs or {}) (lib.attrValues config.datasets);
|
||||
in
|
||||
{
|
||||
dev = ''
|
||||
zpool list "${config.name}" >/dev/null 2>/dev/null ||
|
||||
zpool import -l -R ${rootMountPoint} "${config.name}"
|
||||
|
||||
${lib.concatMapStrings (x: x._mount.dev or "") (lib.attrValues config.datasets)}
|
||||
'';
|
||||
fs = datasetFilesystemsMounts;
|
||||
};
|
||||
};
|
||||
_unmount = diskoLib.mkUnmountOption {
|
||||
inherit config options;
|
||||
default = {
|
||||
dev = ''
|
||||
${lib.concatMapStrings (dataset: dataset._unmount.dev or "") (lib.attrValues config.datasets)}
|
||||
|
||||
if zpool list "${config.name}" >/dev/null 2>/dev/null; then
|
||||
zpool export "${config.name}"
|
||||
fi
|
||||
'';
|
||||
fs = diskoLib.deepMergeMap (dataset: dataset._unmount.fs or {}) (lib.attrValues config.datasets);
|
||||
};
|
||||
};
|
||||
_config = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = map (dataset: dataset._config) (lib.attrValues config.datasets);
|
||||
description = "NixOS configuration";
|
||||
};
|
||||
_pkgs = lib.mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
||||
default = pkgs: [ pkgs.gnugrep pkgs.util-linux ] ++ lib.flatten (map (dataset: dataset._pkgs pkgs) (lib.attrValues config.datasets));
|
||||
description = "Packages";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
datasets."__root" = {
|
||||
_name = config.name;
|
||||
_createFilesystem = false;
|
||||
type = "zfs_fs";
|
||||
mountpoint = config.mountpoint;
|
||||
options = config.rootFsOptions;
|
||||
mountOptions = config.mountOptions;
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,266 +0,0 @@
|
||||
{ config, lib, pkgs, extendModules, diskoLib, ... }:
|
||||
let
|
||||
cfg = config.disko;
|
||||
|
||||
vmVariantWithDisko = extendModules {
|
||||
modules = [
|
||||
./lib/interactive-vm.nix
|
||||
config.disko.tests.extraConfig
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ ./lib/make-disk-image.nix ];
|
||||
|
||||
options.disko = {
|
||||
imageBuilder = {
|
||||
qemu = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
the qemu emulator string used when building disk images via make-disk-image.nix.
|
||||
Useful when using binfmt on your build host, and wanting to build disk
|
||||
images for a foreign architecture
|
||||
'';
|
||||
default = null;
|
||||
example = lib.literalExpression "\${pkgs.qemu_kvm}/bin/qemu-system-aarch64";
|
||||
};
|
||||
|
||||
pkgs = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = ''
|
||||
the pkgs instance used when building disk images via make-disk-image.nix.
|
||||
Useful when the config's kernel won't boot in the image-builder.
|
||||
'';
|
||||
default = pkgs;
|
||||
defaultText = lib.literalExpression "pkgs";
|
||||
example = lib.literalExpression "pkgs";
|
||||
};
|
||||
|
||||
kernelPackages = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = ''
|
||||
the kernel used when building disk images via make-disk-image.nix.
|
||||
Useful when the config's kernel won't boot in the image-builder.
|
||||
'';
|
||||
default = config.boot.kernelPackages;
|
||||
defaultText = lib.literalExpression "config.boot.kernelPackages";
|
||||
example = lib.literalExpression "pkgs.linuxPackages_testing";
|
||||
};
|
||||
|
||||
extraRootModules = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
extra kernel modules to pass to the vmTools.runCommand invocation in the make-disk-image.nix builder
|
||||
'';
|
||||
default = [ ];
|
||||
example = [ "bcachefs" ];
|
||||
};
|
||||
|
||||
extraPostVM = lib.mkOption {
|
||||
type = lib.types.lines;
|
||||
description = ''
|
||||
extra shell code to execute once the disk image(s) have been succesfully created and moved to $out
|
||||
'';
|
||||
default = "";
|
||||
example = lib.literalExpression ''
|
||||
''${pkgs.zstd}/bin/zstd --compress $out/*raw
|
||||
rm $out/*raw
|
||||
'';
|
||||
};
|
||||
|
||||
extraDependencies = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
description = ''
|
||||
list of extra packages to make available in the make-disk-image.nix VM builder, an example might be f2fs-tools
|
||||
'';
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "name for the disk images";
|
||||
default = "${config.networking.hostName}-disko-images";
|
||||
defaultText = "\${config.networking.hostName}-disko-images";
|
||||
};
|
||||
|
||||
copyNixStore = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
description = "whether to copy the nix store into the disk images we just created";
|
||||
default = true;
|
||||
};
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
description = ''
|
||||
Extra NixOS config for your test. Can be used to specify a different luks key for tests.
|
||||
A dummy key is in /tmp/secret.key
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
|
||||
imageFormat = lib.mkOption {
|
||||
type = lib.types.enum [ "raw" "qcow2" ];
|
||||
description = "QEMU image format to use for the disk images";
|
||||
default = "raw";
|
||||
};
|
||||
};
|
||||
|
||||
memSize = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
description = ''
|
||||
size of the memory passed to runInLinuxVM, in megabytes
|
||||
'';
|
||||
default = 1024;
|
||||
};
|
||||
|
||||
devices = lib.mkOption {
|
||||
type = diskoLib.toplevel;
|
||||
default = { };
|
||||
description = "The devices to set up";
|
||||
};
|
||||
|
||||
rootMountPoint = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/mnt";
|
||||
description = "Where the device tree should be mounted by the mountScript";
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
checkScripts = lib.mkOption {
|
||||
description = ''
|
||||
Whether to run shellcheck on script outputs
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
testMode = lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
this is true if the system is being run in test mode.
|
||||
like a vm test or an interactive vm
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
tests = {
|
||||
bootCommands = lib.mkOption {
|
||||
description = ''
|
||||
NixOS test script commands to run after the machine has started. Can
|
||||
be used to enter an interactive password.
|
||||
'';
|
||||
type = lib.types.lines;
|
||||
default = "";
|
||||
};
|
||||
|
||||
efi = lib.mkOption {
|
||||
description = ''
|
||||
Whether efi is enabled for the `system.build.installTest`.
|
||||
We try to automatically detect efi based on the configured bootloader.
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
defaultText = "config.boot.loader.systemd-boot.enable || config.boot.loader.grub.efiSupport";
|
||||
default = config.boot.loader.systemd-boot.enable || config.boot.loader.grub.efiSupport;
|
||||
};
|
||||
|
||||
enableOCR = lib.mkOption {
|
||||
description = ''
|
||||
Sets the enableOCR option in the NixOS VM test driver.
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
extraChecks = lib.mkOption {
|
||||
description = ''
|
||||
extra checks to run in the `system.build.installTest`.
|
||||
'';
|
||||
type = lib.types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
machine.succeed("test -e /var/secrets/my.secret")
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
description = ''
|
||||
Extra NixOS config for your test. Can be used to specify a different luks key for tests.
|
||||
A dummy key is in /tmp/secret.key
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
options.virtualisation.vmVariantWithDisko = lib.mkOption {
|
||||
description = ''
|
||||
Machine configuration to be added for the vm script available at `.system.build.vmWithDisko`.
|
||||
'';
|
||||
inherit (vmVariantWithDisko) type;
|
||||
default = { };
|
||||
visible = "shallow";
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.disko.imageBuilder.qemu != null -> diskoLib.vmToolsSupportsCustomQemu lib;
|
||||
message = ''
|
||||
You have set config.disko.imageBuild.qemu, but vmTools in your nixpkgs version "${lib.version}"
|
||||
does not support overriding the qemu package with the customQemu option yet.
|
||||
Please upgrade nixpkgs so that `lib.version` is at least "24.11.20240709".
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
_module.args.diskoLib = import ./lib {
|
||||
inherit lib;
|
||||
rootMountPoint = config.disko.rootMountPoint;
|
||||
makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix");
|
||||
eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix");
|
||||
};
|
||||
|
||||
system.build = (cfg.devices._scripts { inherit pkgs; checked = cfg.checkScripts; }) // (
|
||||
let
|
||||
throwIfNoDisksDetected = _: v: if cfg.devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v;
|
||||
in
|
||||
lib.mapAttrs throwIfNoDisksDetected {
|
||||
# we keep these old outputs for compatibility
|
||||
disko = builtins.trace "the .disko output is deprecated, please use .diskoScript instead" (cfg.devices._scripts { inherit pkgs; }).diskoScript;
|
||||
diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead" (cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps;
|
||||
|
||||
installTest = diskoLib.testLib.makeDiskoTest {
|
||||
inherit extendModules pkgs;
|
||||
name = "${config.networking.hostName}-disko";
|
||||
disko-config = builtins.removeAttrs config [ "_module" ];
|
||||
testMode = "direct";
|
||||
bootCommands = cfg.tests.bootCommands;
|
||||
efi = cfg.tests.efi;
|
||||
enableOCR = cfg.tests.enableOCR;
|
||||
extraSystemConfig = cfg.tests.extraConfig;
|
||||
extraTestScript = cfg.tests.extraChecks;
|
||||
};
|
||||
|
||||
vmWithDisko = lib.mkDefault config.virtualisation.vmVariantWithDisko.system.build.vmWithDisko;
|
||||
}
|
||||
);
|
||||
|
||||
# we need to specify the keys here, so we don't get an infinite recursion error
|
||||
# Remember to add config keys here if they are added to types
|
||||
fileSystems = lib.mkIf
|
||||
cfg.enableConfig cfg.devices._config.fileSystems or { };
|
||||
boot = lib.mkIf
|
||||
cfg.enableConfig cfg.devices._config.boot or { };
|
||||
swapDevices = lib.mkIf
|
||||
cfg.enableConfig cfg.devices._config.swapDevices or [ ];
|
||||
};
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
{ stdenvNoCC, makeWrapper, lib, path, nix, coreutils, nixos-install-tools, binlore, diskoVersion }:
|
||||
|
||||
let
|
||||
self = stdenvNoCC.mkDerivation (finalAttrs: {
|
||||
name = "disko";
|
||||
src = ./.;
|
||||
nativeBuildInputs = [
|
||||
makeWrapper
|
||||
];
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin $out/share/disko
|
||||
cp -r install-cli.nix cli.nix default.nix disk-deactivate lib $out/share/disko
|
||||
|
||||
for i in disko disko-install; do
|
||||
sed -e "s|libexec_dir=\".*\"|libexec_dir=\"$out/share/disko\"|" "$i" > "$out/bin/$i"
|
||||
chmod 755 "$out/bin/$i"
|
||||
wrapProgram "$out/bin/$i" \
|
||||
--set DISKO_VERSION "${diskoVersion}" \
|
||||
--prefix PATH : ${lib.makeBinPath [ nix coreutils nixos-install-tools ]} \
|
||||
--prefix NIX_PATH : "nixpkgs=${path}"
|
||||
done
|
||||
'';
|
||||
# Otherwise resholve thinks that disko and disko-install might be able to execute their arguments
|
||||
passthru.binlore.out = binlore.synthesize self ''
|
||||
execer cannot bin/.disko-wrapped
|
||||
execer cannot bin/.disko-install-wrapped
|
||||
'';
|
||||
meta = with lib; {
|
||||
description = "Format disks with nix-config";
|
||||
homepage = "https://github.com/nix-community/disko";
|
||||
license = licenses.mit;
|
||||
maintainers = with maintainers; [ lassulus ];
|
||||
platforms = platforms.linux;
|
||||
mainProgram = finalAttrs.name;
|
||||
};
|
||||
});
|
||||
in
|
||||
self
|
||||
@ -1,18 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
writeShellApplication,
|
||||
bash,
|
||||
coreutils,
|
||||
git,
|
||||
nix-fast-build,
|
||||
}:
|
||||
writeShellApplication {
|
||||
name = "create-release";
|
||||
runtimeInputs = [
|
||||
bash
|
||||
git
|
||||
coreutils
|
||||
nix-fast-build
|
||||
];
|
||||
text = lib.readFile ./create-release.sh;
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
# Don't run directly! Instead, use
|
||||
# nix run .#create-release
|
||||
|
||||
version=${1:-}
|
||||
if [[ -z "$version" ]]; then
|
||||
echo "USAGE: nix run .#create-release -- <version>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if we're running from the root of the repository
|
||||
if [[ ! -f "flake.nix" || ! -f "version.nix" ]]; then
|
||||
echo "This script must be run from the root of the repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the version matches the semver pattern (without suffixes)
|
||||
semver_regex="^([0-9]+)\.([0-9]+)\.([0-9]+)$"
|
||||
if [[ ! "$version" =~ $semver_regex ]]; then
|
||||
echo "Version must match the semver pattern (e.g., 1.0.0, 2.3.4)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(git symbolic-ref --short HEAD)" != "master" ]]; then
|
||||
echo "must be on master branch" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure there are no uncommitted or unpushed changes
|
||||
uncommited_changes=$(git diff --compact-summary)
|
||||
if [[ -n "$uncommited_changes" ]]; then
|
||||
echo -e "There are uncommited changes, exiting:\n${uncommited_changes}" >&2
|
||||
exit 1
|
||||
fi
|
||||
git pull git@github.com:nix-community/disko master
|
||||
unpushed_commits=$(git log --format=oneline origin/master..master)
|
||||
if [[ "$unpushed_commits" != "" ]]; then
|
||||
echo -e "\nThere are unpushed changes, exiting:\n$unpushed_commits" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run all tests to ensure we don't release a broken version
|
||||
# Two workers are safe on systems with at least 16GB of RAM
|
||||
nix-fast-build --no-link -j 2 --eval-workers 2 --flake .#checks
|
||||
|
||||
# Update the version file
|
||||
echo "{ version = \"$version\"; released = true; }" > version.nix
|
||||
|
||||
# Commit and tag the release
|
||||
git commit -am "release: v$version"
|
||||
git tag -a "v$version" -m "release: v$version"
|
||||
git tag -d "latest"
|
||||
git tag -a "latest" -m "release: v$version"
|
||||
|
||||
# a revsion suffix when run from the tagged release commit
|
||||
echo "{ version = \"$version\"; released = false; }" > version.nix
|
||||
git commit -am "release: reset released flag"
|
||||
|
||||
echo "Release was prepared successfully!"
|
||||
echo "To push the release, run the following command:"
|
||||
echo
|
||||
echo " git push origin master v$version && git push --force origin latest"
|
||||
echo
|
||||
echo "After that, create a release on GitHub:"
|
||||
echo
|
||||
echo " https://github.com/nix-community/disko/releases/new"
|
||||
@ -1,4 +0,0 @@
|
||||
disabled = [
|
||||
"manual_inherit", # Prefer `inherit types;` instead of `types = types;`
|
||||
"manual_inherit_from", # Prefer `inherit (eval) options;` instead of `options = eval.options`.
|
||||
]
|
||||
@ -1,16 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "bcachefs";
|
||||
disko-config = ../example/bcachefs.nix;
|
||||
extraTestScript = ''
|
||||
machine.succeed("mountpoint /");
|
||||
machine.succeed("lsblk >&2");
|
||||
'';
|
||||
# so that the installer boots with a bcachefs enabled kernel
|
||||
extraInstallerConfig = {
|
||||
boot.supportedFilesystems = [ "bcachefs" ];
|
||||
};
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "boot-raid1";
|
||||
disko-config = ../example/boot-raid1.nix;
|
||||
extraTestScript = ''
|
||||
machine.succeed("test -b /dev/md/boot");
|
||||
machine.succeed("mountpoint /boot");
|
||||
'';
|
||||
extraSystemConfig = {
|
||||
# sadly systemd-boot fails to install to a raid /boot device
|
||||
boot.loader.systemd-boot.enable = false;
|
||||
};
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "btrfs-only-root-subvolume";
|
||||
disko-config = ../example/btrfs-only-root-subvolume.nix;
|
||||
extraTestScript = ''
|
||||
machine.succeed("btrfs subvolume list /");
|
||||
'';
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "btrfs-subvolumes";
|
||||
disko-config = ../example/btrfs-subvolumes.nix;
|
||||
extraTestScript = ''
|
||||
machine.succeed("test ! -e /test");
|
||||
machine.succeed("test -e /home/user");
|
||||
machine.succeed("btrfs subvolume list / | grep -qs 'path test$'");
|
||||
machine.succeed("btrfs subvolume list / | grep -qs 'path nix$'");
|
||||
machine.succeed("btrfs subvolume list / | grep -qs 'path home$'");
|
||||
machine.succeed("test -e /.swapvol/swapfile");
|
||||
machine.succeed("test -e /.swapvol/rel-path");
|
||||
machine.succeed("test -e /partition-root/swapfile");
|
||||
machine.succeed("test -e /partition-root/swapfile1");
|
||||
'';
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "cli";
|
||||
disko-config = ../example/complex.nix;
|
||||
extraInstallerConfig.networking.hostId = "8425e349";
|
||||
extraSystemConfig = {
|
||||
networking.hostId = "8425e349";
|
||||
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||
fileSystems."/zfs_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||
};
|
||||
testMode = "direct";
|
||||
extraTestScript = ''
|
||||
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");
|
||||
'';
|
||||
extraSystemConfig = {
|
||||
imports = [
|
||||
../module.nix
|
||||
];
|
||||
};
|
||||
extraInstallerConfig = {
|
||||
boot.kernelModules = [ "dm-raid" "dm-mirror" ];
|
||||
imports = [
|
||||
../module.nix
|
||||
];
|
||||
};
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, diskoLib ? pkgs.callPackage ../lib { }
|
||||
}:
|
||||
diskoLib.testLib.makeDiskoTest {
|
||||
inherit pkgs;
|
||||
name = "complex";
|
||||
disko-config = ../example/complex.nix;
|
||||
extraInstallerConfig.networking.hostId = "8425e349";
|
||||
extraSystemConfig = {
|
||||
networking.hostId = "8425e349";
|
||||
fileSystems."/zfs_legacy_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||
fileSystems."/zfs_fs".options = [ "nofail" ]; # TODO find out why we need this!
|
||||
};
|
||||
extraTestScript = ''
|
||||
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");
|
||||
|
||||
|
||||
machine.succeed("test -e /ext4_on_lvm/file-from-postMountHook");
|
||||
'';
|
||||
extraInstallerConfig = {
|
||||
boot.kernelModules = [ "dm-raid" "dm-mirror" ];
|
||||
};
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
{ makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>
|
||||
, eval-config ? import <nixpkgs/nixos/lib/eval-config.nix>
|
||||
, pkgs ? import <nixpkgs> { }
|
||||
}:
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
diskoLib = import ../lib { inherit lib makeTest eval-config; };
|
||||
|
||||
allTestFilenames =
|
||||
builtins.map (lib.removeSuffix ".nix") (
|
||||
builtins.filter
|
||||
(x: lib.hasSuffix ".nix" x && x != "default.nix")
|
||||
(lib.attrNames (builtins.readDir ./.))
|
||||
);
|
||||
incompatibleTests = lib.optionals pkgs.stdenv.buildPlatform.isRiscV64 [ "zfs" "zfs-over-legacy" "cli" "module" "complex" ];
|
||||
allCompatibleFilenames = lib.subtractLists incompatibleTests allTestFilenames;
|
||||
|
||||
allTests = lib.genAttrs allCompatibleFilenames (test: import (./. + "/${test}.nix") { inherit diskoLib pkgs; });
|
||||
in
|
||||
allTests
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user