Files
dotfiles/nixos/cua.nix

249 lines
7.4 KiB
Nix

{
config,
lib,
...
}: let
cfg = config.myModules.cua;
flavorDefaults = {
xfce = {
image = "trycua/cua-xfce:latest";
storageMountPath = "/home/cua/storage";
apiContainerPort = 8000;
noVncContainerPort = 6901;
};
kasm = {
image = "trycua/cua-ubuntu:latest";
storageMountPath = "/home/kasm-user/storage";
apiContainerPort = 8000;
noVncContainerPort = 6901;
};
qemu-linux = {
image = "trycua/cua-qemu-linux:latest";
storageMountPath = "/storage";
apiContainerPort = 5000;
noVncContainerPort = 8006;
};
};
selectedFlavor = flavorDefaults.${cfg.flavor};
usingQemu = cfg.flavor == "qemu-linux";
in {
options.myModules.cua = {
enable = lib.mkEnableOption "Cua Linux computer-use sandbox";
android = {
enable = lib.mkEnableOption "Cua Android QEMU computer-use sandbox";
image = lib.mkOption {
type = lib.types.str;
default = "trycua/cua-qemu-android:latest";
description = "OCI image to run for the Cua Android QEMU sandbox.";
};
bindAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address on which to expose the Cua Android API and VNC web ports.";
};
apiPort = lib.mkOption {
type = lib.types.port;
default = 8001;
description = "Host port for the Cua Android computer-server API.";
};
webVncPort = lib.mkOption {
type = lib.types.port;
default = 6080;
description = "Host port for the Cua Android VNC web UI.";
};
emulatorDevice = lib.mkOption {
type = lib.types.str;
default = "Samsung Galaxy S10";
description = "Android emulator device profile.";
};
autoStart = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to start the Cua Android sandbox automatically.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the Cua Android API and VNC web ports in the firewall.";
};
extraOptions = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra options passed to the Cua Android container runtime.";
};
};
flavor = lib.mkOption {
type = lib.types.enum ["xfce" "kasm" "qemu-linux"];
default = "xfce";
description = "Cua Linux sandbox flavor to run.";
};
image = lib.mkOption {
type = lib.types.str;
default = selectedFlavor.image;
defaultText = "upstream default image for the selected Cua flavor";
description = "OCI image to run for the Cua Linux sandbox.";
};
storageDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/cua/linux";
description = "Host directory used for persistent Cua VM storage.";
};
bindAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address on which to expose the Cua API and noVNC ports.";
};
apiPort = lib.mkOption {
type = lib.types.port;
default = selectedFlavor.apiContainerPort;
defaultText = "upstream API port for the selected Cua flavor";
description = "Host port for the Cua computer-server API.";
};
noVncPort = lib.mkOption {
type = lib.types.port;
default = selectedFlavor.noVncContainerPort;
defaultText = "upstream noVNC port for the selected Cua flavor";
description = "Host port for the Cua noVNC web UI.";
};
vncPort = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = 5901;
description = "Optional host port for direct VNC access. Only used by the XFCE flavor.";
};
vncResolution = lib.mkOption {
type = lib.types.str;
default = "1024x768";
description = "VNC desktop resolution for the Cua XFCE container.";
};
ramSize = lib.mkOption {
type = lib.types.str;
default = "8G";
description = "RAM allocated to the Cua QEMU VM.";
};
cpuCores = lib.mkOption {
type = lib.types.ints.positive;
default = 4;
description = "CPU cores allocated to the Cua QEMU VM.";
};
diskSize = lib.mkOption {
type = lib.types.str;
default = "64G";
description = "Disk size allocated to the Cua QEMU VM. Only used by the QEMU Linux flavor.";
};
shmSize = lib.mkOption {
type = lib.types.str;
default = "512m";
description = "Shared-memory size for non-QEMU Cua desktop containers.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the Cua API and noVNC ports in the firewall.";
};
autoStart = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to start the Cua sandbox container automatically.";
};
extraOptions = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra options passed to the container runtime.";
};
};
config = lib.mkIf cfg.enable {
virtualisation.docker.enable = true;
systemd.tmpfiles.rules = [
"d ${toString cfg.storageDir} 0750 root root -"
];
virtualisation.oci-containers.containers = {
cua-sandbox = {
image = cfg.image;
autoStart = cfg.autoStart;
ports =
[
"${cfg.bindAddress}:${toString cfg.noVncPort}:${toString selectedFlavor.noVncContainerPort}"
"${cfg.bindAddress}:${toString cfg.apiPort}:${toString selectedFlavor.apiContainerPort}"
]
++ lib.optionals (cfg.flavor == "xfce" && cfg.vncPort != null) [
"${cfg.bindAddress}:${toString cfg.vncPort}:5901"
];
volumes = [
"${toString cfg.storageDir}:${selectedFlavor.storageMountPath}"
];
devices = lib.optionals usingQemu [
"/dev/kvm:/dev/kvm"
];
capabilities = lib.optionalAttrs usingQemu {
NET_ADMIN = true;
};
environment =
lib.optionalAttrs usingQemu {
RAM_SIZE = cfg.ramSize;
CPU_CORES = toString cfg.cpuCores;
DISK_SIZE = cfg.diskSize;
}
// lib.optionalAttrs (cfg.flavor == "xfce") {
VNC_RESOLUTION = cfg.vncResolution;
}
// lib.optionalAttrs (cfg.flavor == "kasm") {
VNCOPTIONS = "-disableBasicAuth";
};
extraOptions =
lib.optionals (!usingQemu) ["--shm-size=${cfg.shmSize}"]
++ cfg.extraOptions;
};
cua-android = lib.mkIf cfg.android.enable {
image = cfg.android.image;
autoStart = cfg.android.autoStart;
ports = [
"${cfg.android.bindAddress}:${toString cfg.android.webVncPort}:6080"
"${cfg.android.bindAddress}:${toString cfg.android.apiPort}:8000"
];
devices = [
"/dev/kvm:/dev/kvm"
];
environment = {
EMULATOR_DEVICE = cfg.android.emulatorDevice;
WEB_VNC = "true";
};
extraOptions = cfg.android.extraOptions;
};
};
networking.firewall.allowedTCPPorts =
lib.optionals cfg.openFirewall (
[cfg.apiPort cfg.noVncPort]
++ lib.optional (cfg.flavor == "xfce" && cfg.vncPort != null) cfg.vncPort
)
++ lib.optionals cfg.android.openFirewall [cfg.android.apiPort cfg.android.webVncPort];
};
}