Merge pull request #294548 from adamcstephens/incus/override

incus: move wrapper to nixos module
This commit is contained in:
Adam C. Stephens 2024-03-25 16:40:14 -04:00 committed by GitHub
commit c9c612f159
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 252 additions and 271 deletions

View file

@ -1,8 +1,80 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.virtualisation.incus; cfg = config.virtualisation.incus;
preseedFormat = pkgs.formats.yaml { }; 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 in
{ {
meta = { meta = {
@ -11,26 +83,29 @@ in
options = { options = {
virtualisation.incus = { virtualisation.incus = {
enable = lib.mkEnableOption (lib.mdDoc '' enable = lib.mkEnableOption ''
incusd, a daemon that manages containers and virtual machines. incusd, a daemon that manages containers and virtual machines.
Users in the "incus-admin" group can interact with Users in the "incus-admin" group can interact with
the daemon (e.g. to start or stop containers) using the the daemon (e.g. to start or stop containers) using the
{command}`incus` command line tool, among others. {command}`incus` command line tool, among others.
''); '';
package = lib.mkPackageOption pkgs "incus" { }; package = lib.mkPackageOption pkgs "incus" { };
lxcPackage = lib.mkPackageOption pkgs "lxc" { }; lxcPackage = lib.mkPackageOption pkgs "lxc" { };
clientPackage = lib.mkPackageOption pkgs [
"incus"
"client"
] { };
preseed = lib.mkOption { preseed = lib.mkOption {
type = lib.types.nullOr ( type = lib.types.nullOr (lib.types.submodule { freeformType = preseedFormat.type; });
lib.types.submodule { freeformType = preseedFormat.type; }
);
default = null; default = null;
description = lib.mdDoc '' description = ''
Configuration for Incus preseed, see Configuration for Incus preseed, see
<https://linuxcontainers.org/incus/docs/main/howto/initialize/#non-interactive-configuration> <https://linuxcontainers.org/incus/docs/main/howto/initialize/#non-interactive-configuration>
for supported values. for supported values.
@ -80,18 +155,16 @@ in
}; };
}; };
socketActivation = lib.mkEnableOption ( socketActivation = lib.mkEnableOption (''
lib.mdDoc '' socket-activation for starting incus.service. Enabling this option
socket-activation for starting incus.service. Enabling this option will stop incus.service from starting automatically on boot.
will stop incus.service from starting automatically on boot. '');
''
);
startTimeout = lib.mkOption { startTimeout = lib.mkOption {
type = lib.types.ints.unsigned; type = lib.types.ints.unsigned;
default = 600; default = 600;
apply = toString; apply = toString;
description = lib.mdDoc '' description = ''
Time to wait (in seconds) for incusd to become ready to process requests. 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 If incusd does not reply within the configured time, `incus.service` will be
considered failed and systemd will attempt to restart it. considered failed and systemd will attempt to restart it.
@ -99,9 +172,12 @@ in
}; };
ui = { 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 { config = lib.mkIf cfg.enable {
assertions = [ 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;`"; message = "Incus on NixOS is unsupported using iptables. Set `networking.nftables.enable = true;`";
} }
]; ];
@ -137,7 +218,12 @@ in
"vhost_vsock" "vhost_vsock"
] ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ]; ] ++ 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 # Note: the following options are also declared in virtualisation.lxc, but
# the latter can't be simply enabled to reuse the formers, because it # the latter can't be simply enabled to reuse the formers, because it
@ -164,32 +250,24 @@ in
"network-online.target" "network-online.target"
"lxcfs.service" "lxcfs.service"
"incus.socket" "incus.socket"
] ] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ];
++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
requires = [ requires = [
"lxcfs.service" "lxcfs.service"
"incus.socket" "incus.socket"
] ] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ];
++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service";
wants = [ wants = [ "network-online.target" ];
"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 = { serviceConfig = {
ExecStart = "${cfg.package}/bin/incusd --group incus-admin"; ExecStart = "${cfg.package}/bin/incusd --group incus-admin";
ExecStartPost = "${cfg.package}/bin/incusd waitready --timeout=${cfg.startTimeout}"; ExecStartPost = "${cfg.package}/bin/incusd waitready --timeout=${cfg.startTimeout}";
@ -222,15 +300,13 @@ in
systemd.services.incus-preseed = lib.mkIf (cfg.preseed != null) { systemd.services.incus-preseed = lib.mkIf (cfg.preseed != null) {
description = "Incus initialization with preseed file"; description = "Incus initialization with preseed file";
wantedBy = ["incus.service"]; wantedBy = [ "incus.service" ];
after = ["incus.service"]; after = [ "incus.service" ];
bindsTo = ["incus.service"]; bindsTo = [ "incus.service" ];
partOf = ["incus.service"]; partOf = [ "incus.service" ];
script = '' script = ''
${cfg.package}/bin/incus admin init --preseed <${ ${cfg.package}/bin/incus admin init --preseed <${preseedFormat.generate "incus-preseed.yaml" cfg.preseed}
preseedFormat.generate "incus-preseed.yaml" cfg.preseed
}
''; '';
serviceConfig = { 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 let
releases = import ../../release.nix { releases = import ../../release.nix {
configuration = { configuration = lib.recursiveUpdate {
# Building documentation makes the test unnecessarily take a longer time: # Building documentation makes the test unnecessarily take a longer time:
documentation.enable = lib.mkForce false; documentation.enable = lib.mkForce false;
boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; boot.kernel.sysctl."net.ipv4.ip_forward" = "1";
} // extra; }
extra;
}; };
container-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system}; container-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system};
container-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system}; container-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system};
in in
{ {
name = "incus-container"; inherit name;
meta = { meta = {
maintainers = lib.teams.lxc.members; maintainers = lib.teams.lxc.members;

View file

@ -5,16 +5,22 @@
handleTestOn, handleTestOn,
}: }:
{ {
container-old-init = import ./container.nix { inherit system pkgs; }; container-legacy-init = import ./container.nix {
container-new-init = import ./container.nix { inherit system pkgs; extra = { name = "container-legacy-init";
# Enable new systemd init inherit system pkgs;
boot.initrd.systemd.enable = true; };
}; }; 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; }; lxd-to-incus = import ./lxd-to-incus.nix { inherit system pkgs; };
openvswitch = import ./openvswitch.nix { inherit system pkgs; }; openvswitch = import ./openvswitch.nix { inherit system pkgs; };
preseed = import ./preseed.nix { inherit system pkgs; }; preseed = import ./preseed.nix { inherit system pkgs; };
socket-activated = import ./socket-activated.nix { inherit system pkgs; }; socket-activated = import ./socket-activated.nix { inherit system pkgs; };
storage = import ./storage.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; }; 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") machine.wait_for_unit("incus.service")
with machine.nested("run migration"): 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"): with machine.nested("verify resources migrated to incus"):
machine.succeed("incus config show container") 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, lts ? false,
meta,
patches,
src,
vendorHash,
version,
lib, lib,
buildGoModule, buildGoModule,
fetchpatch,
fetchFromGitHub,
installShellFiles, installShellFiles,
}: }:
let let
releaseFile = if lts then ./lts.nix else ./latest.nix; pname = "incus${lib.optionalString lts "-lts"}-client";
inherit (import releaseFile { inherit fetchpatch; }) version hash vendorHash;
in in
buildGoModule rec { buildGoModule {
pname = "incus-client"; inherit
meta
inherit vendorHash version; patches
pname
src = fetchFromGitHub { src
owner = "lxc"; vendorHash
repo = "incus"; version
rev = "refs/tags/v${version}"; ;
inherit hash;
};
CGO_ENABLED = 0; CGO_ENABLED = 0;
@ -41,14 +41,4 @@ buildGoModule rec {
# don't run the full incus test suite # don't run the full incus test suite
doCheck = false; 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, lts ? false,
patches,
updateScriptArgs ? "",
vendorHash,
version,
}:
{
callPackage,
lib, lib,
buildGoModule, buildGoModule,
fetchpatch,
fetchFromGitHub, fetchFromGitHub,
writeScript,
writeShellScript, writeShellScript,
acl, acl,
cowsql, cowsql,
@ -19,31 +27,28 @@
}: }:
let let
releaseFile = if lts then ./lts.nix else ./latest.nix; pname = "incus${lib.optionalString lts "-lts"}";
inherit (import releaseFile { inherit fetchpatch; })
version
hash
patches
vendorHash
;
name = "incus${lib.optionalString lts "-lts"}";
in in
buildGoModule { buildGoModule rec {
pname = "${name}-unwrapped"; inherit
patches
inherit patches vendorHash version; pname
vendorHash
version
;
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "lxc"; owner = "lxc";
repo = "incus"; repo = "incus";
rev = "v${version}"; rev = "refs/tags/v${version}";
inherit hash; inherit hash;
}; };
# replace with env var > 0.6 https://github.com/lxc/incus/pull/610
postPatch = '' postPatch = ''
substituteInPlace internal/usbid/load.go \ 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 = [ excludedPackages = [
@ -107,12 +112,23 @@ buildGoModule {
''; '';
passthru = { passthru = {
tests.incus = nixosTests.incus; client = callPackage ./client.nix {
inherit
lts
meta
patches
src
vendorHash
version
;
};
updateScript = writeShellScript "update-incus" '' tests = nixosTests.incus;
nix-update ${name}.unwrapped -vr 'v(.*)' --override-filename pkgs/by-name/in/incus/${
if lts then "lts" else "latest" ui = callPackage ./ui.nix { };
}.nix
updateScript = writeScript "ovs-update.nu" ''
${./update.nu} ${updateScriptArgs}
''; '';
}; };
@ -123,5 +139,6 @@ buildGoModule {
license = lib.licenses.asl20; license = lib.licenses.asl20;
maintainers = lib.teams.lxc.members; maintainers = lib.teams.lxc.members;
platforms = lib.platforms.linux; 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 # this release doesn't exist yet, but satisfay the by-name checks
# will be added as incus-lts in all-packages.nix once ready # will be added as incus-lts in all-packages.nix once ready
_: { } import ./generic.nix { }

View file

@ -1,157 +1,9 @@
{ import ./generic.nix {
lts ? false, hash = "sha256-tGuAS0lZvoYb+TvmCklQ8TADZhbm4w/lhdI0ycS4/0o=";
version = "0.6.0";
lib, vendorHash = "sha256-+WmgLOEBJ/7GF596iiTgyTPxn8l+hE6RVqjLKfCi5rs=";
callPackage, patches = [
linkFarm, # fix storage bug, fixed in > 0.6
makeWrapper, ./529.patch
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' "$@"
'')
]; ];
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}
}