about summary refs log tree commit diff
path: root/modules
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-12-31 17:03:56 +0100
committerMel <einebeere@gmail.com>2024-12-31 17:03:56 +0100
commit9415facde70c0e02af6ff57c3ebfe2d6b7af385e (patch)
tree8a0b96846e8cf7282db2832b3250c3b6ff99bc0e /modules
parente73df329fde2e19f3ab3b2b1ffe217d888383086 (diff)
downloaddeclarative-vm.nix-main.tar.zst
declarative-vm.nix-main.zip
Add basic declarative Incus prototype module from other project HEAD main
Signed-off-by: Mel <einebeere@gmail.com>
Diffstat (limited to 'modules')
-rw-r--r--modules/default.nix3
-rw-r--r--modules/incus.nix150
2 files changed, 153 insertions, 0 deletions
diff --git a/modules/default.nix b/modules/default.nix
index 04618ac..5599639 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1,4 +1,7 @@
 { ... }:
 
 {
+  imports = [
+    ./incus.nix
+  ];
 }
diff --git a/modules/incus.nix b/modules/incus.nix
new file mode 100644
index 0000000..3d64432
--- /dev/null
+++ b/modules/incus.nix
@@ -0,0 +1,150 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  # qemu 9.1.2 no longer supports strings being passed instead of some
+  # integer parameters. incus already has the fix, but it hasn't made it
+  # into a release yet.
+  # see: https://github.com/lxc/incus/issues/1522
+  incusPatch = pkgs.fetchpatch {
+    name = "1531.patch";
+    url = "https://github.com/lxc/incus/pull/1531.patch";
+    sha256 = "sha256-tM/+JRH0OwR3bM8gk3yNo9SSAEMqpS2HP+OzooV3DJY=";
+  };
+  incus = pkgs.incus.overrideAttrs (attrs: {
+    patches = (attrs.patches or [ ]) ++ [ incusPatch ];
+  });
+
+  toYAML = lib.generators.toYAML { };
+
+  cloudInitConfiguration = {
+    users = [
+      {
+        name = "admin";
+        groups = "users";
+        sudo = "ALL=(ALL) NOPASSWD:ALL";
+        plain_text_passwd = "example";
+        lock_passwd = false;
+      }
+    ];
+
+    # ssh configuration
+    allow_public_ssh_keys = true;
+    disable_root = true;
+    packages = [ "openssh-server" ];
+    runcmd = [
+      [
+        "systemctl"
+        "enable"
+        "ssh.service"
+      ]
+    ];
+  };
+in
+{
+  networking.firewall = {
+    # needed so that the nixos firewall does not block
+    # DHCP+DNS requests from incus, and to prevent conflicts
+    # between the two firewalls.
+    trustedInterfaces = [ "incusbr0" ];
+    allowedTCPPorts = [ 23 ];
+  };
+  # needed so inscus instances can connect to the proxy.
+  boot.kernelModules = [ "br_netfilter" ];
+  virtualisation.incus = {
+    enable = true;
+    package = incus;
+    preseed = {
+      networks = [
+        {
+          config = {
+            "ipv4.address" = "10.0.100.1/24";
+            "ipv4.nat" = "true";
+          };
+          name = "incusbr0";
+          type = "bridge";
+        }
+      ];
+      profiles = [
+        # this default profile gets applied to all
+        # new instances without an explicitly set profile.
+        {
+          name = "default";
+          config = { };
+          devices = {
+            eth0 = {
+              name = "eth0";
+              network = "incusbr0";
+              type = "nic";
+            };
+            root = {
+              path = "/";
+              pool = "default";
+              size = "35GiB";
+              type = "disk";
+            };
+          };
+        }
+        # this profile is the one we want to apply to an ubuntu example vm.
+        # it is provisioned with a static ipv4 (for nat-ted proxy)
+        # and cloud-init configuration
+        {
+          name = "vm-1";
+          # config applied to new instances,
+          # this is how we can best control
+          # vm provisioning semi-declaratively.
+          # for options, see: https://linuxcontainers.org/incus/docs/main/reference/instance_options/
+          config = {
+            # `vendor` is usually for defaults, but it doesn't actually matter here.
+            # NOTE: cloud-init requires either the incus-agent to be running,
+            # or that the image is a special cloud image. i.e. `images:ubuntu/22.04/cloud`.
+            "cloud-init.vendor-data" = ''
+              #cloud-config
+              ${toYAML cloudInitConfiguration}
+            '';
+          };
+          devices = {
+            eth0 = {
+              name = "eth0";
+              network = "incusbr0";
+              type = "nic";
+
+              # this is necessary for our nat proxy configuration.
+              # see: https://linuxcontainers.org/incus/docs/main/reference/devices_proxy/#nat-mode
+              "ipv4.address" = "10.0.100.123";
+            };
+            proxy = {
+              type = "proxy";
+              listen = "tcp:127.0.0.1:2222";
+              connect = "tcp:0.0.0.0:22";
+              nat = true;
+            };
+            root = {
+              path = "/";
+              pool = "default";
+              size = "35GiB";
+              type = "disk";
+            };
+          };
+        }
+      ];
+      storage_pools = [
+        {
+          config = {
+            source = "/var/lib/incus/storage-pools/default";
+          };
+          driver = "dir";
+          name = "default";
+        }
+      ];
+    };
+  };
+
+  # `incus-admin` essentially gives you root access anyway,
+  # let users in `wheel` use it freely.
+  users.groups."incus-admin".members = config.users.groups."wheel".members;
+}