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