Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qemu-vm: remove bootDisk, refactor using make-disk-image with better EFI support #203641

Closed
Closed
1 change: 1 addition & 0 deletions doc/builders/images.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
<xi:include href="images/ocitools.section.xml" />
<xi:include href="images/snaptools.section.xml" />
<xi:include href="images/portableservice.section.xml" />
<xi:include href="images/makediskimage.section.xml" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you change anything about the interface? Otherwise I would pull this out into its own PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I added parameters.

</chapter>
181 changes: 181 additions & 0 deletions doc/builders/images/makediskimage.section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# `<nixpkgs/nixos/lib/make-disk-image.nix>` {#sec-make-disk-image}

`<nixpkgs/nixos/lib/make-disk-image.nix>` is a function to create _disk image_ in multiple formats: raw, QCOW2 (QEMU image format), QCOW2-Compressed (compressed version), VDI (Virtual Box native format), VPC (VirtualPC).

There are two operations mode for this function:

- either, you want only a Nix store disk image, it can be done using `cptofs` without any virtual machine involved ;
- or, you want a full NixOS install on the disk, it will start a virtual machine to perform various tasks such as partitionning, installation and bootloader installation.

When NixOS tests are running, this function gets called to generate potentially two kinds of disk images:

- a Nix-store only disk image: useful when the test _do not need_ bootloader
- a full-fledged NixOS installation disk image: useful when the test _do need_ to test the bootloader

## Features

- whether to produce a Nix-store only image or not, **this can be incompatible with other options**
- arbitrary NixOS configuration
- multiple partition table layouts: EFI, legacy, legacy + GPT, hybrid, none through `partitionTableType` parameter
- automatic or bound disk size: `diskSize` parameter, `additionalSpace` can be set when `diskSize` is `auto` to add a constant of disk space
- boot partition size when partition table is `efi` or `hybrid`
- arbitrary contents with permissions can be placed in the target filesystem using `contents`, incompatible with Nix-store only image
- bootloaders are supported, incompatible with Nix-store only image
- EFI variables can be mutated during image production and the result is exposed in `$out`
- system management mode (SMM) can enabled during virtual machine operations
- OVMF or EFI firmwares and variables templates can be customized
- root filesystem `fsType` can be customized to whatever `mkfs.${fsType}` exist during operations
- root filesystem label can be customized, defaults to `nix-store` if it's a nix store image, otherwise `nixpkgs/nixos`
- a `/etc/nixpkgs/nixos/configuration.nix` can be provided through `configFile`, incompatible with a Nix-store only image
- arbitrary code can be executed after the VM has finished its operations with `postVM`
- the current nixpkgs can be realized as a channel in the disk image, which will change the hash of the image when the sources are updated
- additional store paths can be provided through `additionalPaths`

Images are **NOT** deterministic, please do not hesitate to try to fix this, source of determinisms are (not exhaustive) :

- bootloader installation have timestamps ;
- SQLite Nix store database contain registration times ;
- `/etc/shadow` is in a non-deterministic order

For more, read the function signature source code for documentation on arguments: <https://github.com/NixOS/nixpkgs/blob/master/nixos/lib/make-disk-image.nix>.

## Usage

To produce a Nix-store only image:
```nix
let
pkgs = import <nixpkgs> {};
lib = pkgs.lib;
make-disk-image = import <nixpkgs/nixos/lib/make-disk-image.nix>;
in
make-disk-image {
inherit pkgs lib;
config = {};
additionalPaths = [ ];
format = "qcow2";
onlyNixStore = true;
partitionTableType = "none";
installBootLoader = false;
touchEFIVars = false;
diskSize = "auto";
additionalSpace = "0M"; # Defaults to 512M.
copyChannel = false;
}
```

Some arguments can be left out, they are shown explicitly for the sake of the example.

Building this derivation will provide a QCOW2 disk image containing only the Nix store and its registration information.

To produce a NixOS installation image disk with UEFI and bootloader installed:
```nix
let
pkgs = import <nixpkgs> {};
lib = pkgs.lib;
make-disk-image = import <nixpkgs/nixos/lib/make-disk-image.nix>;
evalConfig = import <nixpkgs/nixos/lib/eval-config.nix>;
in
make-disk-image {
inherit pkgs lib;
config = evalConfig {
modules = [
{
fileSystems."/" = { device = "/dev/vda"; fsType = "ext4"; autoFormat = true; };
boot.grub.device = "/dev/vda";
}
];
};
format = "qcow2";
onlyNixStore = false;
partitionTableType = "legacy+gpt";
installBootLoader = true;
touchEFIVars = true;
diskSize = "auto";
additionalSpace = "0M"; # Defaults to 512M.
copyChannel = false;
}
```

## Technical details

`make-disk-image` has a bit of magic to minimize the amount of work to do in a virtual machine.

It relies on the [LKL (Linux Kernel Library) project](https://github.com/lkl/linux) which provides Linux kernel as userspace library.

::: {.note}
The Nix-store only image only need to run LKL tools to produce an image and will never spawn a virtual machine, whereas full images will always require a virtual machine, but also use LKL.
:::

### Image preparation phase

Image preparation phase will produce the initial image layout in a folder:

- devise a root folder based on `$PWD`
- preparing the contents by copying and restoring ACLs in this root folder
- load in the Nix store database all additional paths computed by `pkgs.closureInfo` in a temporary Nix store
- run `nixos-install` in a temporary folder
- transfer from the temporary store the additional paths registered to the installed NixOS
- do fancy computations for the size of the disk image based on the apparent size of the root folder
- partition the disk image using the corresponding script according to the partition table type
- format the partitions if needed
- use `cptofs` (LKL tool) to copy the root folder inside the disk image

At this step, the disk image contains already the Nix store, it only needs to be converted to the desired format to be used.

### Image conversion phase

Using `qemu-img`, the disk image is converted from a raw format to the desired format: qcow2(-compressed), vdi, vpc.

### Partitionning script based on layouts

#### `none`

No partition table layout is written.

#### `legacy`

This partition table type is composed of a MBR and one primary ext4 partition starting at 1MiB extending to the full disk image.

It is unsuitable for UEFI.

#### `legacy+gpt`

This partition table type uses GPT and:

- create a "no filesystem" partition from 1MiB to 2MiB ;
- set `bios_grub` flag on this "no filesystem" partition, which marks it as a [GRUB BIOS partition](https://www.gnu.org/software/parted/manual/html_node/set.html) ;
- create a primary ext4 partition starting at 2MiB and extending to the full disk image ;
- perform optimal alignments checks on each partition

This partition has no ESP partition, it is unsuitable for EFI boot which requires an ESP partition, but it can work with CSM (Compatibility Support Module) which emulates BIOS for UEFI.

#### `efi`

This partition table type uses GPT and:

- creates an FAT32 ESP partition from 8MiB to specified `bootSize` parameter (256MiB by default), set it bootable ;
- create a primary ext4 partition starting after the boot one and extending to the full disk image

#### `hybrid`

This partition table type uses GPT and:

- creates a "no filesystem" partition from 0 to 1MiB, set `bios_grub` flag on it ;
- creates an FAT32 ESP partition from 8MiB to specified `bootSize` parameter (256MiB by default), set it bootable ;
- creates a primary ext4 partition starting after the boot one and extending to the full disk image

This partition could be booted by a BIOS able to understand GPT layouts and recognizing the MBR at the start.

### How to run determinism analysis on results?

Run your derivation with `--check` to rebuild it and verify it is the same.

Once it fails, you will be left with two folders with one having `.check`.

`diffoscope` is not able at the moment to diff two QCOW2 filesystems, it is advised to use raw format.

But even with raw formats, `diffoscope` cannot diff the partition table and partitions recursively.

For this, you can run `fdisk -l $image` and generate `dd if=$image of=$image-p$i.raw skip=$start count=$sectors` for each `(start, sectors)` listed in the `fdisk` output.

With this, you will have each partition as a separate file and you can diffoscope pairs of them to use `diffoscope` ability to read filesystems.
23 changes: 22 additions & 1 deletion nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,18 @@
for more details on the included changes.
</para>
</listitem>
<listitem>
<para>
<literal>hardware.nvidia</literal> has a new option
<literal>open</literal> that can be used to opt in the
opensource version of NVIDIA kernel driver. Note that the
driver’s support for GeForce and Workstation GPUs is still
alpha quality, see
<link xlink:href="https://developer.nvidia.com/blog/nvidia-releases-open-source-gpu-kernel-modules/">NVIDIA
Releases Open-Source GPU Kernel Modules</link> for the
official announcement.
</para>
</listitem>
<listitem>
<para>
Cinnamon has been updated to 5.4, and the Cinnamon module now
Expand Down Expand Up @@ -1052,7 +1064,16 @@ services.github-runner.serviceOverrides.SupplementaryGroups = [
</listitem>
<listitem>
<para>
Synapse’s systemd unit has been hardened.
<literal>pkgs.OVMF.fd</literal> exposes
<literal>firmware</literal> and <literal>variables</literal>
which points to your host architecture binaries for the
correspoding UEFI artifacts.
</para>
</listitem>
<listitem>
<para>
The <literal>services.matrix-synapse</literal> systemd unit
has been hardened.
</para>
</listitem>
<listitem>
Expand Down
36 changes: 36 additions & 0 deletions nixos/doc/manual/from_md/release-notes/rl-2305.section.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@
been changed to <literal>null</literal>.
</para>
</listitem>
<listitem>
<para>
Disk layout in NixOS tests has changed when using bootloaders:
instead of two disks <literal>/dev/vda</literal> and
<literal>/dev/vdb</literal>, there is only a unified
<literal>/dev/vda</literal> with multiple partitions. This
require you to change <literal>/dev/vdc</literal> to
<literal>/dev/vdb</literal> and so on if you were using
<literal>emptyDiskImages</literal> which creates disks in
order, as <literal>/dev/vdb</literal> has disappeared, every
disk has to start over from <literal>/dev/vdb</literal> rather
than <literal>/dev/vdc</literal>, see the
<link xlink:href="https://github.com/NixOS/nixpkgs/pull/203641">#203641
PR in nixpkgs</link> to learn about examples for your
migration. In addition,
<literal>virtualisation.rootDevice</literal> option was
introduced and should be used instead of
<literal>virtualisation.bootDevice</literal> in many cases.
</para>
</listitem>
<listitem>
<para>
The <literal>nix.readOnlyStore</literal> option has been
Expand Down Expand Up @@ -240,6 +260,22 @@
remote <literal>PostgreSQL</literal> database.
</para>
</listitem>
<listitem>
<para>
QEMU test architecture supports running System Management
Enforcement (SMM), useful to lock down UEFI authenticated
variables. At the moment, it seems to prevent any change to
UEFI platform, breaking disk production and tests, if enabled.
</para>
</listitem>
<listitem>
<para>
<literal>nixos/lib/make-disk-image.nix</literal> can now
mutate EFI variables, run user-provided EFI firmware or
variable templates. As a result, NixOS tests have better
support of UEFI platforms tests such as SecureBoot tests.
</para>
</listitem>
<listitem>
<para>
A new <literal>virtualisation.rosetta</literal> module was
Expand Down
6 changes: 5 additions & 1 deletion nixos/doc/manual/release-notes/rl-2211.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ In addition to numerous new and upgraded packages, this release includes the fol

- KDE Plasma has been upgraded from v5.24 to v5.26. Please see the release notes for [v5.25](https://kde.org/announcements/plasma/5/5.25.0/) and [v5.26](https://kde.org/announcements/plasma/5/5.26.0/) for more details on the included changes.

- `hardware.nvidia` has a new option `open` that can be used to opt in the opensource version of NVIDIA kernel driver. Note that the driver's support for GeForce and Workstation GPUs is still alpha quality, see [NVIDIA Releases Open-Source GPU Kernel Modules](https://developer.nvidia.com/blog/nvidia-releases-open-source-gpu-kernel-modules/) for the official announcement.

- Cinnamon has been updated to 5.4, and the Cinnamon module now defaults to
Blueman as the Bluetooth manager and slick-greeter as the LightDM greeter, to match upstream.

Expand Down Expand Up @@ -305,7 +307,9 @@ In addition to numerous new and upgraded packages, this release includes the fol

- The `bloat` package has been updated from unstable-2022-03-31 to unstable-2022-10-25, which brings a breaking change. See [this upstream commit message](https://git.freesoftwareextremist.com/bloat/commit/?id=887ed241d64ba5db3fd3d87194fb5595e5ad7d73) for details.

- Synapse's systemd unit has been hardened.
- `pkgs.OVMF.fd` exposes `firmware` and `variables` which points to your host architecture binaries for the correspoding UEFI artifacts.

- The `services.matrix-synapse` systemd unit has been hardened.
RaitoBezarius marked this conversation as resolved.
Show resolved Hide resolved

- The module `services.grafana` was refactored to be compliant with [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md). To be precise, this means that the following things have changed:
- The newly introduced option [](#opt-services.grafana.settings) is an attribute-set that
Expand Down
11 changes: 11 additions & 0 deletions nixos/doc/manual/release-notes/rl-2305.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ In addition to numerous new and upgraded packages, this release has the followin

- In `mastodon` it is now necessary to specify location of file with `PostgreSQL` database password. In `services.mastodon.database.passwordFile` parameter default value `/var/lib/mastodon/secrets/db-password` has been changed to `null`.

- Disk layout in NixOS tests has changed when using bootloaders: instead of two disks `/dev/vda` and `/dev/vdb`, there is only a unified `/dev/vda` with multiple partitions.
This require you to change `/dev/vdc` to `/dev/vdb` and so on if you were using `emptyDiskImages` which creates disks in order, as `/dev/vdb` has disappeared, every disk
has to start over from `/dev/vdb` rather than `/dev/vdc`, see the [#203641 PR in nixpkgs](https://github.com/NixOS/nixpkgs/pull/203641) to learn about examples for your migration.
In addition, `virtualisation.rootDevice` option was introduced and should be used instead of `virtualisation.bootDevice` in many cases.

- The `nix.readOnlyStore` option has been renamed to `boot.readOnlyNixStore` to clarify that it configures the NixOS boot process, not the Nix daemon.

## Other Notable Changes {#sec-release-23.05-notable-changes}
Expand All @@ -72,6 +77,12 @@ In addition to numerous new and upgraded packages, this release has the followin

- `mastodon` now supports connection to a remote `PostgreSQL` database.

- QEMU test architecture supports running System Management Enforcement (SMM), useful to lock down UEFI authenticated variables.
At the moment, it seems to prevent any change to UEFI platform, breaking disk production and tests, if enabled.

- `nixos/lib/make-disk-image.nix` can now mutate EFI variables, run user-provided EFI firmware or variable templates.
As a result, NixOS tests have better support of UEFI platforms tests such as SecureBoot tests.

- A new `virtualisation.rosetta` module was added to allow running `x86_64` binaries through [Rosetta](https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment) inside virtualised NixOS guests on Apple silicon. This feature works by default with the [UTM](https://docs.getutm.app/) virtualisation [package](https://search.nixos.org/packages?channel=unstable&show=utm&from=0&size=1&sort=relevance&type=packages&query=utm).

- The new option `users.motdFile` allows configuring a Message Of The Day that can be updated dynamically.
Expand Down