From a90385c62b75df48f3ebd29f99d017f06966c569 Mon Sep 17 00:00:00 2001 From: Adam Stephens Date: Mon, 4 Sep 2023 11:58:53 -0400 Subject: [PATCH] nixos/lxd: add preseed option --- nixos/modules/virtualisation/lxd.nix | 75 ++++++++++++++++++++++++++++ nixos/tests/lxd/container.nix | 3 ++ nixos/tests/lxd/default.nix | 1 + nixos/tests/lxd/preseed.nix | 71 ++++++++++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 nixos/tests/lxd/preseed.nix diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index 11ac692d120d..e30fbebb662c 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -4,6 +4,7 @@ let cfg = config.virtualisation.lxd; + preseedFormat = pkgs.formats.yaml {}; in { imports = [ (lib.mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally") @@ -73,6 +74,65 @@ in { ''; }; + preseed = lib.mkOption { + type = lib.types.nullOr (lib.types.submodule { + freeformType = preseedFormat.type; + }); + + default = null; + + description = lib.mdDoc '' + Configuration for LXD preseed, see + + for supported values. + + Changes to this will be re-applied to LXD which will overwrite existing entities or create missing ones, + but entities will *not* be removed by preseed. + ''; + + example = lib.literalExpression '' + { + networks = [ + { + name = "lxdbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "default"; + devices = { + eth0 = { + name = "eth0"; + network = "lxdbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "default"; + driver = "dir"; + config = { + source = "/var/lib/lxd/storage-pools/default"; + }; + } + ]; + } + ''; + }; + startTimeout = lib.mkOption { type = lib.types.int; default = 600; @@ -176,6 +236,21 @@ in { }; }; + systemd.services.lxd-preseed = lib.mkIf (cfg.preseed != null) { + description = "LXD initialization with preseed file"; + wantedBy = ["multi-user.target"]; + requires = ["lxd.service"]; + after = ["lxd.service"]; + + script = '' + ${pkgs.coreutils}/bin/cat ${preseedFormat.generate "lxd-preseed.yaml" cfg.preseed} | ${cfg.package}/bin/lxd init --preseed + ''; + + serviceConfig = { + Type = "oneshot"; + }; + }; + users.groups.lxd = {}; users.users.root = { diff --git a/nixos/tests/lxd/container.nix b/nixos/tests/lxd/container.nix index a2b61b78f7d6..bdaaebfc0028 100644 --- a/nixos/tests/lxd/container.nix +++ b/nixos/tests/lxd/container.nix @@ -49,6 +49,9 @@ in { # Wait for lxd to settle machine.succeed("lxd waitready") + # no preseed should mean no service + machine.fail("systemctl status lxd-preseed.service") + machine.succeed("lxd init --minimal") machine.succeed( diff --git a/nixos/tests/lxd/default.nix b/nixos/tests/lxd/default.nix index 8ca591211a06..e63e199aca90 100644 --- a/nixos/tests/lxd/default.nix +++ b/nixos/tests/lxd/default.nix @@ -5,6 +5,7 @@ }: { container = import ./container.nix {inherit system pkgs;}; nftables = import ./nftables.nix {inherit system pkgs;}; + preseed = import ./preseed.nix {inherit system pkgs;}; ui = import ./ui.nix {inherit system pkgs;}; virtual-machine = import ./virtual-machine.nix { inherit system pkgs; }; } diff --git a/nixos/tests/lxd/preseed.nix b/nixos/tests/lxd/preseed.nix new file mode 100644 index 000000000000..7d89b9f56daa --- /dev/null +++ b/nixos/tests/lxd/preseed.nix @@ -0,0 +1,71 @@ +import ../make-test-python.nix ({ pkgs, lib, ... } : + +{ + name = "lxd-preseed"; + + meta = { + maintainers = with lib.maintainers; [ adamcstephens ]; + }; + + nodes.machine = { lib, ... }: { + virtualisation = { + diskSize = 4096; + + lxc.lxcfs.enable = true; + lxd.enable = true; + + lxd.preseed = { + networks = [ + { + name = "nixostestbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "nixostest_default"; + devices = { + eth0 = { + name = "eth0"; + network = "nixostestbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "nixostest_pool"; + driver = "dir"; + } + ]; + }; + }; + }; + + testScript = '' + def wait_for_preseed(_) -> bool: + _, output = machine.systemctl("is-active lxd-preseed.service") + return ("inactive" in output) + + machine.wait_for_unit("sockets.target") + machine.wait_for_unit("lxd.service") + with machine.nested("Waiting for preseed to complete"): + retry(wait_for_preseed) + + with subtest("Verify preseed resources created"): + machine.succeed("lxc profile show nixostest_default") + machine.succeed("lxc network info nixostestbr0") + machine.succeed("lxc storage show nixostest_pool") + ''; +})