incus: move wrapper to nixos module

This commit is contained in:
Adam Stephens 2024-03-18 23:02:30 -04:00
parent bf8c4dafb6
commit deb5be50c4
No known key found for this signature in database
11 changed files with 252 additions and 271 deletions

View File

@ -1,8 +1,80 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.virtualisation.incus;
preseedFormat = pkgs.formats.yaml { };
serverBinPath = ''${pkgs.qemu_kvm}/libexec:${
lib.makeBinPath (
with pkgs;
[
cfg.package
acl
attr
bash
btrfs-progs
cdrkit
coreutils
criu
dnsmasq
e2fsprogs
findutils
getent
gnugrep
gnused
gnutar
gptfdisk
gzip
iproute2
iptables
kmod
lvm2
minio
nftables
qemu_kvm
qemu-utils
rsync
squashfsTools
systemd
thin-provisioning-tools
util-linux
virtiofsd
xz
(writeShellScriptBin "apparmor_parser" ''
exec '${apparmor-parser}/bin/apparmor_parser' -I '${apparmor-profiles}/etc/apparmor.d' "$@"
'')
]
++ lib.optionals config.boot.zfs.enabled [
config.boot.zfs.package
"${config.boot.zfs.package}/lib/udev"
]
++ lib.optionals config.virtualisation.vswitch.enable [ config.virtualisation.vswitch.package ]
)
}'';
# https://github.com/lxc/incus/blob/cff35a29ee3d7a2af1f937cbb6cf23776941854b/internal/server/instance/drivers/driver_qemu.go#L123
ovmf-prefix = if pkgs.stdenv.hostPlatform.isAarch64 then "AAVMF" else "OVMF";
ovmf = pkgs.linkFarm "incus-ovmf" [
{
name = "OVMF_CODE.4MB.fd";
path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_CODE.fd";
}
{
name = "OVMF_VARS.4MB.fd";
path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.4MB.ms.fd";
path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_VARS.fd";
}
];
in
{
meta = {
@ -11,26 +83,29 @@ in
options = {
virtualisation.incus = {
enable = lib.mkEnableOption (lib.mdDoc ''
enable = lib.mkEnableOption ''
incusd, a daemon that manages containers and virtual machines.
Users in the "incus-admin" group can interact with
the daemon (e.g. to start or stop containers) using the
{command}`incus` command line tool, among others.
'');
'';
package = lib.mkPackageOption pkgs "incus" { };
lxcPackage = lib.mkPackageOption pkgs "lxc" { };
clientPackage = lib.mkPackageOption pkgs [
"incus"
"client"
] { };
preseed = lib.mkOption {
type = lib.types.nullOr (
lib.types.submodule { freeformType = preseedFormat.type; }
);
type = lib.types.nullOr (lib.types.submodule { freeformType = preseedFormat.type; });
default = null;
description = lib.mdDoc ''
description = ''
Configuration for Incus preseed, see
<https://linuxcontainers.org/incus/docs/main/howto/initialize/#non-interactive-configuration>
for supported values.
@ -80,18 +155,16 @@ in
};
};
socketActivation = lib.mkEnableOption (
lib.mdDoc ''
socket-activation for starting incus.service. Enabling this option
will stop incus.service from starting automatically on boot.
''
);
socketActivation = lib.mkEnableOption (''
socket-activation for starting incus.service. Enabling this option
will stop incus.service from starting automatically on boot.
'');
startTimeout = lib.mkOption {
type = lib.types.ints.unsigned;
default = 600;
apply = toString;
description = lib.mdDoc ''
description = ''
Time to wait (in seconds) for incusd to become ready to process requests.
If incusd does not reply within the configured time, `incus.service` will be
considered failed and systemd will attempt to restart it.
@ -99,9 +172,12 @@ in
};
ui = {
enable = lib.mkEnableOption (lib.mdDoc "(experimental) Incus UI");
enable = lib.mkEnableOption "(experimental) Incus UI";
package = lib.mkPackageOption pkgs [ "incus" "ui" ] { };
package = lib.mkPackageOption pkgs [
"incus"
"ui"
] { };
};
};
};
@ -109,7 +185,12 @@ in
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !(config.networking.firewall.enable && !config.networking.nftables.enable && config.virtualisation.incus.enable);
assertion =
!(
config.networking.firewall.enable
&& !config.networking.nftables.enable
&& config.virtualisation.incus.enable
);
message = "Incus on NixOS is unsupported using iptables. Set `networking.nftables.enable = true;`";
}
];
@ -137,7 +218,12 @@ in
"vhost_vsock"
] ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ];
environment.systemPackages = [ cfg.package ];
environment.systemPackages = [
cfg.clientPackage
# gui console support
pkgs.spice-gtk
];
# Note: the following options are also declared in virtualisation.lxc, but
# the latter can't be simply enabled to reuse the formers, because it
@ -164,32 +250,24 @@ in
"network-online.target"
"lxcfs.service"
"incus.socket"
]
++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ];
requires = [
"lxcfs.service"
"incus.socket"
]
++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ];
wants = [
"network-online.target"
wants = [ "network-online.target" ];
environment = lib.mkMerge [
{
INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config";
INCUS_OVMF_PATH = ovmf;
PATH = lib.mkForce serverBinPath;
}
(lib.mkIf (cfg.ui.enable) { "INCUS_UI" = cfg.ui.package; })
];
path = lib.optionals config.boot.zfs.enabled [
config.boot.zfs.package
"${config.boot.zfs.package}/lib/udev"
]
++ lib.optional config.virtualisation.vswitch.enable config.virtualisation.vswitch.package;
environment = lib.mkMerge [ {
# Override Path to the LXC template configuration directory
INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config";
} (lib.mkIf (cfg.ui.enable) {
"INCUS_UI" = cfg.ui.package;
}) ];
serviceConfig = {
ExecStart = "${cfg.package}/bin/incusd --group incus-admin";
ExecStartPost = "${cfg.package}/bin/incusd waitready --timeout=${cfg.startTimeout}";
@ -222,15 +300,13 @@ in
systemd.services.incus-preseed = lib.mkIf (cfg.preseed != null) {
description = "Incus initialization with preseed file";
wantedBy = ["incus.service"];
after = ["incus.service"];
bindsTo = ["incus.service"];
partOf = ["incus.service"];
wantedBy = [ "incus.service" ];
after = [ "incus.service" ];
bindsTo = [ "incus.service" ];
partOf = [ "incus.service" ];
script = ''
${cfg.package}/bin/incus admin init --preseed <${
preseedFormat.generate "incus-preseed.yaml" cfg.preseed
}
${cfg.package}/bin/incus admin init --preseed <${preseedFormat.generate "incus-preseed.yaml" cfg.preseed}
'';
serviceConfig = {

View File

@ -1,20 +1,21 @@
import ../make-test-python.nix ({ pkgs, lib, extra ? {}, ... } :
import ../make-test-python.nix ({ pkgs, lib, extra ? {}, name ? "incus-container", ... } :
let
releases = import ../../release.nix {
configuration = {
# Building documentation makes the test unnecessarily take a longer time:
documentation.enable = lib.mkForce false;
configuration = lib.recursiveUpdate {
# Building documentation makes the test unnecessarily take a longer time:
documentation.enable = lib.mkForce false;
boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
} // extra;
boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
}
extra;
};
container-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system};
container-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system};
in
{
name = "incus-container";
inherit name;
meta = {
maintainers = lib.teams.lxc.members;

View File

@ -5,16 +5,22 @@
handleTestOn,
}:
{
container-old-init = import ./container.nix { inherit system pkgs; };
container-new-init = import ./container.nix { inherit system pkgs; extra = {
# Enable new systemd init
boot.initrd.systemd.enable = true;
}; };
container-legacy-init = import ./container.nix {
name = "container-legacy-init";
inherit system pkgs;
};
container-systemd-init = import ./container.nix {
name = "container-systemd-init";
inherit system pkgs;
extra = {
boot.initrd.systemd.enable = true;
};
};
lxd-to-incus = import ./lxd-to-incus.nix { inherit system pkgs; };
openvswitch = import ./openvswitch.nix { inherit system pkgs; };
preseed = import ./preseed.nix { inherit system pkgs; };
socket-activated = import ./socket-activated.nix { inherit system pkgs; };
storage = import ./storage.nix { inherit system pkgs; };
ui = import ./ui.nix {inherit system pkgs;};
ui = import ./ui.nix { inherit system pkgs; };
virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { inherit system pkgs; };
}

View File

@ -95,7 +95,7 @@ import ../make-test-python.nix (
machine.wait_for_unit("incus.service")
with machine.nested("run migration"):
machine.succeed("lxd-to-incus --yes")
machine.succeed("${pkgs.incus}/bin/lxd-to-incus --yes")
with machine.nested("verify resources migrated to incus"):
machine.succeed("incus config show container")

View File

@ -0,0 +1,29 @@
From 32a4beecbf8098fdbb15ef5f36088956922630f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber@stgraber.org>
Date: Fri, 23 Feb 2024 18:47:15 -0500
Subject: [PATCH] incusd/device/disk: Fix incorrect block volume usage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
---
internal/server/device/disk.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/internal/server/device/disk.go b/internal/server/device/disk.go
index 0d19e21139..4f9a3e7c1b 100644
--- a/internal/server/device/disk.go
+++ b/internal/server/device/disk.go
@@ -339,6 +339,11 @@ func (d *disk) validateConfig(instConf instance.ConfigReader) error {
var usedBy []string
err = storagePools.VolumeUsedByInstanceDevices(d.state, d.pool.Name(), storageProjectName, &dbVolume.StorageVolume, true, func(inst db.InstanceArgs, project api.Project, usedByDevices []string) error {
+ // Don't count the current instance.
+ if d.inst != nil && d.inst.Project().Name == inst.Project && d.inst.Name() == inst.Name {
+ return nil
+ }
+
usedBy = append(usedBy, inst.Name)
return nil

View File

@ -1,28 +1,28 @@
{
lts ? false,
meta,
patches,
src,
vendorHash,
version,
lib,
buildGoModule,
fetchpatch,
fetchFromGitHub,
installShellFiles,
}:
let
releaseFile = if lts then ./lts.nix else ./latest.nix;
inherit (import releaseFile { inherit fetchpatch; }) version hash vendorHash;
pname = "incus${lib.optionalString lts "-lts"}-client";
in
buildGoModule rec {
pname = "incus-client";
inherit vendorHash version;
src = fetchFromGitHub {
owner = "lxc";
repo = "incus";
rev = "refs/tags/v${version}";
inherit hash;
};
buildGoModule {
inherit
meta
patches
pname
src
vendorHash
version
;
CGO_ENABLED = 0;
@ -41,14 +41,4 @@ buildGoModule rec {
# don't run the full incus test suite
doCheck = false;
meta = {
description = "Powerful system container and virtual machine manager";
homepage = "https://linuxcontainers.org/incus";
changelog = "https://github.com/lxc/incus/releases/tag/v${version}";
license = lib.licenses.asl20;
maintainers = lib.teams.lxc.members;
platforms = lib.platforms.unix;
mainProgram = "incus";
};
}

View File

@ -1,10 +1,18 @@
{
hash,
lts ? false,
patches,
updateScriptArgs ? "",
vendorHash,
version,
}:
{
callPackage,
lib,
buildGoModule,
fetchpatch,
fetchFromGitHub,
writeScript,
writeShellScript,
acl,
cowsql,
@ -19,31 +27,28 @@
}:
let
releaseFile = if lts then ./lts.nix else ./latest.nix;
inherit (import releaseFile { inherit fetchpatch; })
version
hash
patches
vendorHash
;
name = "incus${lib.optionalString lts "-lts"}";
pname = "incus${lib.optionalString lts "-lts"}";
in
buildGoModule {
pname = "${name}-unwrapped";
inherit patches vendorHash version;
buildGoModule rec {
inherit
patches
pname
vendorHash
version
;
src = fetchFromGitHub {
owner = "lxc";
repo = "incus";
rev = "v${version}";
rev = "refs/tags/v${version}";
inherit hash;
};
# replace with env var > 0.6 https://github.com/lxc/incus/pull/610
postPatch = ''
substituteInPlace internal/usbid/load.go \
--replace "/usr/share/misc/usb.ids" "${hwdata}/share/hwdata/usb.ids"
--replace-fail "/usr/share/misc/usb.ids" "${hwdata}/share/hwdata/usb.ids"
'';
excludedPackages = [
@ -107,12 +112,23 @@ buildGoModule {
'';
passthru = {
tests.incus = nixosTests.incus;
client = callPackage ./client.nix {
inherit
lts
meta
patches
src
vendorHash
version
;
};
updateScript = writeShellScript "update-incus" ''
nix-update ${name}.unwrapped -vr 'v(.*)' --override-filename pkgs/by-name/in/incus/${
if lts then "lts" else "latest"
}.nix
tests = nixosTests.incus;
ui = callPackage ./ui.nix { };
updateScript = writeScript "ovs-update.nu" ''
${./update.nu} ${updateScriptArgs}
'';
};
@ -123,5 +139,6 @@ buildGoModule {
license = lib.licenses.asl20;
maintainers = lib.teams.lxc.members;
platforms = lib.platforms.linux;
mainProgram = "incus";
};
}

View File

@ -1,12 +0,0 @@
{ fetchpatch }:
{
hash = "sha256-tGuAS0lZvoYb+TvmCklQ8TADZhbm4w/lhdI0ycS4/0o=";
version = "0.6.0";
vendorHash = "sha256-+WmgLOEBJ/7GF596iiTgyTPxn8l+hE6RVqjLKfCi5rs=";
patches = [
(fetchpatch {
url = "https://github.com/lxc/incus/pull/529.patch";
hash = "sha256-2aaPrzW/LVJidWeom0rqYOGpT2gvuV1yHLJN/TwQ1fk=";
})
];
}

View File

@ -1,3 +1,3 @@
# this release doesn't exist yet, but satisfay the by-name checks
# will be added as incus-lts in all-packages.nix once ready
_: { }
import ./generic.nix { }

View File

@ -1,157 +1,9 @@
{
lts ? false,
lib,
callPackage,
linkFarm,
makeWrapper,
stdenv,
symlinkJoin,
writeShellScriptBin,
acl,
apparmor-parser,
apparmor-profiles,
attr,
bash,
btrfs-progs,
cdrkit,
criu,
dnsmasq,
e2fsprogs,
getent,
gnutar,
gptfdisk,
gzip,
iproute2,
iptables,
kmod,
lvm2,
minio,
nftables,
OVMF,
qemu_kvm,
qemu-utils,
rsync,
spice-gtk,
squashfsTools,
thin-provisioning-tools,
util-linux,
virtiofsd,
xz,
}:
let
unwrapped = callPackage ./unwrapped.nix { inherit lts; };
client = callPackage ./client.nix { inherit lts; };
name = "incus${lib.optionalString lts "-lts"}";
binPath = lib.makeBinPath [
acl
attr
bash
btrfs-progs
cdrkit
criu
dnsmasq
e2fsprogs
getent
gnutar
gptfdisk
gzip
iproute2
iptables
kmod
lvm2
minio
nftables
qemu_kvm
qemu-utils
rsync
squashfsTools
thin-provisioning-tools
util-linux
virtiofsd
xz
(writeShellScriptBin "apparmor_parser" ''
exec '${apparmor-parser}/bin/apparmor_parser' -I '${apparmor-profiles}/etc/apparmor.d' "$@"
'')
import ./generic.nix {
hash = "sha256-tGuAS0lZvoYb+TvmCklQ8TADZhbm4w/lhdI0ycS4/0o=";
version = "0.6.0";
vendorHash = "sha256-+WmgLOEBJ/7GF596iiTgyTPxn8l+hE6RVqjLKfCi5rs=";
patches = [
# fix storage bug, fixed in > 0.6
./529.patch
];
clientBinPath = [ spice-gtk ];
ovmf-2mb = OVMF.override {
secureBoot = true;
fdSize2MB = true;
};
ovmf-4mb = OVMF.override {
secureBoot = true;
fdSize4MB = true;
};
ovmf-prefix = if stdenv.hostPlatform.isAarch64 then "AAVMF" else "OVMF";
# mimic ovmf from https://github.com/canonical/incus-pkg-snap/blob/3abebe1dfeb20f9b7729556960c7e9fe6ad5e17c/snapcraft.yaml#L378
# also found in /snap/incus/current/share/qemu/ on a snap install
ovmf = linkFarm "incus-ovmf" [
{
name = "OVMF_CODE.2MB.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_CODE.fd";
}
{
name = "OVMF_CODE.4MB.fd";
path = "${ovmf-4mb.fd}/FV/${ovmf-prefix}_CODE.fd";
}
{
name = "OVMF_CODE.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_CODE.fd";
}
{
name = "OVMF_VARS.2MB.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.2MB.ms.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.4MB.fd";
path = "${ovmf-4mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.4MB.ms.fd";
path = "${ovmf-4mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
{
name = "OVMF_VARS.ms.fd";
path = "${ovmf-2mb.fd}/FV/${ovmf-prefix}_VARS.fd";
}
];
in
symlinkJoin {
name = "${name}-${unwrapped.version}";
paths = [ unwrapped ];
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram $out/bin/incusd --prefix PATH : ${lib.escapeShellArg binPath}:${qemu_kvm}/libexec:$out/bin --set INCUS_OVMF_PATH ${ovmf}
wrapProgram $out/bin/incus --prefix PATH : ${lib.makeBinPath clientBinPath}
'';
passthru = {
inherit client unwrapped;
ui = callPackage ./ui.nix {};
inherit (unwrapped) tests;
};
inherit (unwrapped) meta pname version;
}

22
pkgs/by-name/in/incus/update.nu Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env nix-shell
#!nix-shell -i nu -p nushell common-updater-scripts gnused
def main [--lts = false, --regex: string] {
let attr = $"incus(if $lts {"-lts"})"
let file = $"(pwd)/pkgs/by-name/in/incus/(if $lts { "lts" } else { "package" }).nix"
let tags = list-git-tags --url=https://github.com/lxc/incus | lines | sort --natural | str replace v ''
let latest_tag = if $regex == null { $tags } else { $tags | find --regex $regex } | last
let current_version = nix eval --raw -f default.nix $"($attr).version" | str trim
if $latest_tag != $current_version {
update-source-version $attr $latest_tag $"--file=($file)"
let oldVendorHash = nix-instantiate . --eval --strict -A $"($attr).goModules.drvAttrs.outputHash" --json | from json
let vendorHash = do { nix-build -A $"($attr).goModules" } | complete | get stderr | lines | str trim | find --regex 'got:[[:space:]]*sha256' | split row ' ' | last
open $file | str replace $oldVendorHash $vendorHash | save --force $file
}
{"lts?": $lts, before: $current_version, after: $latest_tag}
}