diff options
Diffstat (limited to 'nix/modules')
-rw-r--r-- | nix/modules/goapp-frontend/default.nix | 134 | ||||
-rw-r--r-- | nix/modules/libvirtnix/config.nix | 59 | ||||
-rw-r--r-- | nix/modules/libvirtnix/domain.nix | 1126 | ||||
-rw-r--r-- | nix/modules/libvirtnix/test.nix | 10 | ||||
-rw-r--r-- | nix/modules/libvirtnix/xml.nix | 45 | ||||
-rw-r--r-- | nix/modules/x86_64-linux.nix | 3 |
6 files changed, 704 insertions, 673 deletions
diff --git a/nix/modules/goapp-frontend/default.nix b/nix/modules/goapp-frontend/default.nix new file mode 100644 index 0000000..c5f62aa --- /dev/null +++ b/nix/modules/goapp-frontend/default.nix @@ -0,0 +1,134 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.emile.goapp-frontend; +in +with lib; +{ + options.services.emile.goapp-frontend = { + enable = mkEnableOption "Enable goapp-frontend"; + package = mkPackageOption pkgs "goapp-frontend" { }; + + # ip, port and external host to listen on + host = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "0.0.0.0"; + description = "The host the service listens on"; + }; + port = mkOption { + type = types.int; + default = 8080; + example = 8080; + description = "The port the service listens on"; + }; + public-url = mkOption { + type = types.str; + default = "http://localhost:8080/"; + example = "https://goapp.emile.space/"; + description = '' + The domain that the service can be reached from externally. This is used by oidc for redirects and thus should be set, as you'll probably be running this behind some kind of reverse proxy. + ''; + }; + + # the oidc config + oidc = mkOption { + type = types.submodule { + options = { + id = mkOption { + type = types.str; + default = ""; + example = "AiliavahweiweeG5"; + description = "The oidc id"; + }; + issuer = mkOption { + type = types.str; + default = ""; + example = "https://sso.emile.space"; + description = "The oidc identity provider"; + }; + cookie-name = mkOption { + type = types.str; + default = "oidc-client"; + example = "CookieMcCookieface"; + description = "The oidc cookie name"; + }; + scopes = mkOption { + type = types.listOf types.str; + default = [ "openid" "profile" "email" "groups" ]; + example = [ "openid" "profile" "email" ]; + description = "The openid scopes to request"; + }; + secret-path = mkOption { + type = types.str; + default = ""; + example = "/run/goapp_oidc_secret"; + description = "The path to the oidc secret"; + }; + }; + }; + }; + + # paths to files + session-key-path = mkOption { + type = types.str; + default = ""; + example = "/run/sesionkey"; + description = "The path to a file containing the sessionKey"; + }; + logfile-path = mkOption { + type = types.str; + default = "/var/log/goapp-frontend.log"; + example = "/var/log/goapp-frontend.log"; + description = "The path to where the logfile should be written"; + }; + + database-path = mkOption { + type = types.str; + default = "/var/lib/goapp-frontend/main.db"; + example = "/var/lib/goapp-frontend/main.db"; + description = "The path to the main database"; + }; + sessiondb-path = mkOption { + type = types.str; + default = "/var/lib/goapp-frontend/sessions.db"; + example = "/var/lib/goapp-frontend/sessions.db"; + description = "The path to the sessions database"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.goapp-frontend = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + RestartSec = 5; + Restart = "on-failure"; + }; + environment = { + VERSION = pkgs.goapp-frontend.version; + }; + path = [ pkgs.goapp-frontend ]; + serviceConfig.ExecStart = '' + ${pkgs.goapp-frontend}/bin/frontend \ + --host ${cfg.host} \ + --port ${toString cfg.port} \ + --public-url ${cfg.public-url} \ + --id ${cfg.oidc.id} \ + --issuer ${cfg.oidc.issuer} \ + --cookie-name ${cfg.oidc.cookie-name} \ + --scopes ${concatStringsSep "," cfg.oidc.scopes} \ + --oidc-secret-path ${cfg.oidc.secret-path} \ + --logfilepath ${cfg.logfile-path} \ + --databasepath ${cfg.database-path} \ + --sessiondbpath ${cfg.sessiondb-path} \ + --sessionkeypath ${cfg.session-key-path} \ + --templatespath ${pkgs.goapp-frontend}/templates + ''; + }; + }; +} diff --git a/nix/modules/libvirtnix/config.nix b/nix/modules/libvirtnix/config.nix new file mode 100644 index 0000000..e1a8d28 --- /dev/null +++ b/nix/modules/libvirtnix/config.nix @@ -0,0 +1,59 @@ +{ + services.emile.libvirtnix = { + enable = true; + vm = { + "alan" = { + vm_type = "kvm"; + id = "1337"; + name = "blub"; + uuid = "cafebabe-d474-452b-80f4-c951c39bcf74"; + + metadata.libosinfo = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + metadata.libosinfo_os = "https://nixos.org/nixos/unknown"; + + memory.unit = "KiB"; + memory.value = 2097152; + + currentMemory.unit = "KiB"; + currentMemory.value = 2097152; + + vcpu.placement = "static"; + vcpu.count = 3; + + resource.partition = "/machine"; + + os = { + type = { + arch = "x86_64"; + machine = "pc-q35-3.1"; + value = "hvm"; + }; + + loader = { + readonly = "yes"; + type = "pflash"; + value = "/usr/share/OVMF/OVMF_CODE.fd"; + }; + + nvram.value = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + + boot.dev = "hd"; + }; + + features = { + acpi = true; + apic = true; + vmport = { + state = "off"; + }; + }; + + cpu = { + mode = "host-passthrough"; + check = "none"; + migratable = "on"; + }; + }; + }; + }; +} diff --git a/nix/modules/libvirtnix/domain.nix b/nix/modules/libvirtnix/domain.nix index a028c7d..22cd891 100644 --- a/nix/modules/libvirtnix/domain.nix +++ b/nix/modules/libvirtnix/domain.nix @@ -1,701 +1,483 @@ -{ pkgs, lib, ... }: - +{ config, lib, ... }: + +let + mkTag = import ./xml.nix { inherit lib; }; + pkgs = import <nixpkgs> { }; + + stringOption = + { + default ? "", + }: + lib.mkOption { + type = lib.types.str; + default = "${default}"; + }; +in { - options = with lib; { - - # meta, this allows defining the package used for each vm individually, defaults should be sane - packages = mkOption { - type = types.submodule { - options = { - libvirt = mkPackageOption pkgs "libvirt" { }; - qemu = mkPackageOption pkgs "qemu" { }; + options = { + services.emile.libvirtnix = + let + cpu = lib.mkOption { + type = lib.types.submodule { + options = { + mode = lib.mkOption { + type = lib.types.str; + example = "host-passthrough"; + default = ""; + }; + check = lib.mkOption { + type = lib.types.str; + example = "none"; + default = ""; + }; + migratable = lib.mkOption { + type = lib.types.str; + example = "on"; + default = ""; + }; + }; + }; }; - }; - }; - - # attributs for the root `<domain ...>` node - type = mkOption { - type = types.enum [ - "xen" - "hvm" - "kvm" - "qemu" - "lxc" - ]; - default = "kvm"; - example = "qemu"; - description = '' - hypervisor used for running the domain - allowed values are driver specific, if missing, plz send PR - - hvm since since 8.1.0 and QEMU 2.12 - ''; - }; - - id = mkOption { - type = types.int; - default = 0; - example = 42; - }; + features = lib.mkOption { + type = lib.types.submodule { + options = { + acpi = lib.mkEnableOption "enable acpi"; + apic = lib.mkEnableOption "enable apic"; + + vmport = lib.mkOption { + type = lib.types.submodule { + options = { + state = lib.mkOption { + type = lib.types.str; + example = "off"; + default = ""; + }; + }; + }; + }; + }; + }; + }; + + os_boot = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { + type = lib.types.str; + example = "hd"; + default = ""; + }; + }; + }; + }; + + os_nvram = lib.mkOption { + type = lib.types.submodule { + options = { + value = lib.mkOption { + type = lib.types.str; + example = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + default = ""; + }; + }; + }; + }; + + os_loader = lib.mkOption { + type = lib.types.submodule { + options = { + readonly = lib.mkOption { + type = lib.types.str; + example = "yes"; + default = ""; + }; + type = lib.mkOption { + type = lib.types.str; + example = "pflash"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "/usr/share/OVMF/OVMF_CODE.fd"; + default = ""; + }; + }; + }; + }; + + os_type = lib.mkOption { + type = lib.types.submodule { + options = { + arch = lib.mkOption { + type = lib.types.str; + example = "x86_64"; + default = ""; + }; + machine = lib.mkOption { + type = lib.types.str; + example = "pc-q35-3.1"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "hvm"; + default = ""; + }; + }; + }; + }; - # General metadata - name = mkOption { - type = types.str; - example = "MyGuest"; - }; + os = lib.mkOption { + description = "os"; + type = lib.types.submodule { + options = { + type = os_type; + loader = os_loader; + nvram = os_nvram; + boot = os_boot; + }; + }; + }; - uuid = mkOption { - type = types.str; - example = "3e3fce45-4f53-4fa7-bb32-11f34168b82b"; - }; + resource = lib.mkOption { + description = "resource"; + type = lib.types.submodule { + options = { + partition = lib.mkOption { + type = lib.types.str; + example = "/machine"; + default = ""; + }; + }; + }; + }; - genid = mkOption { - type = types.str; - example = "43dc0cf8-809b-4adb-9bea-a9abb5f3d90e"; - }; + vcpu = lib.mkOption { + description = "vcpu"; + type = lib.types.submodule { + options = { + placement = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ "static" ]; + example = "static"; + default = "static"; + }; + count = lib.mkOption { + type = lib.types.int; + example = 4; + default = 1; + }; + }; + }; + }; - title = mkOption { - type = types.str; - example = "A short description - title - of the domain"; - }; + mem = lib.mkOption { + description = "memory"; + type = lib.types.submodule { + options = { + unit = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ + "KiB" + "MiB" + "GiB" + "TiB" + ]; + example = "KiB"; + default = "KiB"; + }; + value = lib.mkOption { + type = lib.types.int; + example = 2097152; + default = 1000; + }; + }; + }; + }; - description = mkOption { - type = types.str; - example = "Some human readable description"; - }; + memory = mem; + currentMemory = mem; + + metadata = lib.mkOption { + description = "metadata submodule"; + type = lib.types.submodule { + options = { + libosinfo = lib.mkOption { + type = lib.types.str; + example = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + default = ""; + }; + libosinfo_os = lib.mkOption { + type = lib.types.str; + example = "https://nixos.org/nixos/unknown"; + default = ""; + }; + }; + }; + }; - metadata = mkOption { - type = types.str; - default = ""; - example = '' - <metadata> - <app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo> - <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar> - </metadata> - ''; - }; + vm = lib.types.submodule { + options = { + vm_type = stringOption { default = "kvm"; }; + id = stringOption { }; + name = stringOption { }; + uuid = stringOption { }; + + inherit + metadata + memory + currentMemory + vcpu + resource + os + features + cpu + ; + }; + }; + in + { + enable = lib.mkEnableOption "Enable r2wars-web"; + + + # Temporary output we write the domain to, in order to inspect the correctness of + # the generated xml + output.domain = lib.mkOption { type = lib.types.path; }; + + # An attrset of VMs + vm = lib.mkOption { + description = "VMs to define"; + type = lib.types.attrsOf vm; + }; + }; + }; - os = mkOption { - type = types.submodule { - options = { - firmware = mkOption { - type = types.enum [ - "bios" - "efi" + config = lib.mkIf config.services.emile.libvirtnix.enable { + services.emile.libvirtnix = + let + vm = config.services.emile.libvirtnix.vm; + + cpu = + vm_name: + mkTag { + name = "cpu"; + args = let + mode = vm.${vm_name}.cpu.mode; + check = vm.${vm_name}.cpu.check; + migratable= vm.${vm_name}.cpu.migratable; + in [ + (if (mode != null) + then {key = "mode"; val = mode;} + else "") + (if (check != null) + then {key = "check"; val = check;} + else "") + (if (migratable != null) + then {key = "migratable"; val = migratable;} + else "") ]; - default = "efi"; - example = "bios"; + closing = false; }; - type = mkOption { - type = types.enum [ - "hvm" - "linux" + + features = + vm_name: + mkTag { + name = "features"; + children = let + acpi = vm_name: mkTag { + name = "acpi"; + closing = false; + }; + apic = vm_name: mkTag { + name = "apic"; + closing = false; + }; + vmport = vm_name: mkTag { + name = "vmport"; + args = [ + { key = "state"; val = vm.${vm_name}.features.vmport.state; } + ]; + closing = false; + }; + in [ + (if (vm.${vm_name}.features.acpi != false) then (acpi vm_name) else "") + (if (vm.${vm_name}.features.apic != false) then (apic vm_name) else "") + (if (vm.${vm_name}.features.vmport != null) then (vmport vm_name) else "") ]; - default = "hvm"; - example = "linux"; }; - arch = mkOption { type = types.str; }; - machine = mkOption { type = types.str; }; - - # TODO(emile): features - # Search for the following... - # > When using firmware auto-selection there are different features enabled in the firmwares - # ... here: https://libvirt.org/formatdomain.html - # can't bother to implement this now - # features = mkOption { - # type = types.submodule { - # options = { - # enabled = { - # type = types.enum [ "yes" "no" ]; - # }; - # name = {}; - # }; - # }; - # }; - - # such as: - # <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> - loader = mkOption { - type = types.submodule { - options = { - readonly = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - type = mkOption { - type = types.enum [ - "rom" - "pflash" - ]; - }; - secure = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - stateless = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - format = mkOption { - type = types.enum [ - "raw" - "qcow2" - ]; - }; - value = mkOption { - type = types.str; - example = "/usr/share/OVMF/OVMF_CODE.fd"; - }; + os = + vm_name: + mkTag { + name = "os"; + children = let + os_type = vm_name: mkTag { + name = "type"; + args = [ + { key = "arch"; val = vm.${vm_name}.os.type.arch; } + { key = "machine"; val = vm.${vm_name}.os.type.machine; } + ]; + value = vm.${vm_name}.os.type.value; }; - }; + os_loader = vm_name: mkTag { + name = "loader"; + args = [ + { key = "readonly"; val = vm.${vm_name}.os.loader.readonly; } + { key = "pflash"; val = vm.${vm_name}.os.loader.type; } + ]; + value = vm.${vm_name}.os.loader.value; + }; + os_nvram = vm_name: mkTag { + name = "nvram"; + value = vm.${vm_name}.os.nvram.value; + }; + os_boot = vm_name: mkTag { + name = "type"; + args = [ + { key = "dev"; val = vm.${vm_name}.os.boot.dev; } + ]; + closing = false; + }; + in [ + (os_type vm_name) + (os_loader vm_name) + (os_nvram vm_name) + (os_boot vm_name) + ]; }; - # <nvram type='network'> - # <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'> - # <host name='example.com' port='6000'/> - # <auth username='myname'> - # <secret type='iscsi' usage='mycluster_myname'/> - # </auth> - # </source> - # </nvram> - - # nvram = { - # type = "network"; - # source = { - # protocol = "iscsi"; - # name = "iqn.2013-07.com.example:iscsi-nopool/0"; - # }; - # }; - - nvram = mkOption { - type = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "file" - "block" - "dir" - "network" - "volume" - "nvme" - "vhostuser" - "vhostvdpa" - ]; - default = ""; - }; - - source = mkOption { - type = types.submodule { - options = { - # TODO(emile): figure out how to conditionally allow setting the options below - # if the type defined above has been set - - # if type == file - file = mkOption { type = types.str; }; - fdgroup = mkOption { type = types.str; }; - - # if type == block - dev = mkOption { type = types.str; }; - - # if type == dir - dir = mkOption { type = types.str; }; - - # if type == network - protocol = mkOption { - type = types.enum [ - "nbd" - "iscsi" - "rbd" - "sheepdog" - "gluster" - "vxhs" - "nfs" - "http" - "https" - "ftp" - "ftps" - "tftp" - "ssh" - ]; - }; - name = mkOption { type = types.str; }; - tls = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - tlsHostname = mkOption { type = types.str; }; - query = mkOption { type = types.str; }; - - # if type == volume - pool = mkOption { type = types.str; }; - volume = mkOption { type = types.str; }; - mode = mkOption { - type = types.enum [ - "direct" - "host" - ]; - default = "host"; - }; - - # if type == nvme - type = mkOption { - type = types.enum [ "pci" ]; - default = "pci"; - description = '' - When the type is `nvme`, only `pci` is supported - When the type is `vhostuser`, only `unix` is supported - - (I've got not clue how to model this is nix, it's essentially an attribute that is overloaded based on another value) - ''; - }; - managed = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - namespace = mkOption { - type = types.int; - default = 0; - }; - - # if type == vhostuser - # type = see the type in the nvme section above - path = mkOption { type = types.str; }; - - # if type == vhostvdpa - # dev = (defined above in the "type == block" section) - - # if type == file - # if type == block - # if type == volume - seclabel = mkOption { type = types.str; }; - - index = mkOption { - type = types.int; - default = 0; - }; - - # TODO(emile): implement checks here - # start here and scroll down a bit to the table - # https://libvirt.org/formatdomain.html#hard-drives-floppy-disks-cdroms - # if type == network - host = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - port = mkOption { - type = types.int; - default = 0; - }; - transport = mkOption { type = types.str; }; - socket = mkOption { type = types.str; }; - - }; - }; - }; - - snapshot = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - }; - }; - }; - - config = mkOption { - type = types.submodule { - options = { - file = mkOption { type = types.str; }; - }; - }; - }; - - # Since 3.9.0, the auth element is supported for a disk type "network" that is using a source element with the protocol attributes "rbd", "iscsi", or "ssh". - auth = mkOption { - type = types.submodule { - options = { - type = mkOption { - # type = types.enum [ "chap" ]; - # freeform, yet "chap" is one of the allowed options, I don't know others (yet) - type = types.str; - }; - username = mkOption { type = types.str; }; - - # https://libvirt.org/formatsecret.html - secret = mkOption { - type = types.submodule { - options = { - ephemeral = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - private = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - - uuid = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - description = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - - usage = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "volume" - "ceph" - "iscsi" - "tls" - "vtpm" - ]; - default = ""; - }; - value = mkOption { - type = types.str; - default = ""; - }; - - name = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - volume = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - # when using the "iscsi" type - target = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - }; - }; - - }; - }; - }; # end of secret - - }; - }; - }; # end of auth - - # https://libvirt.org/formatstorageencryption.html - encryption = mkOption { - type = types.submodule { - options = { - type = mkOption { type = types.str; }; - - # mandatory - format = mkOption { - type = types.enum [ - "default" - "qcow" - "luks" - "luks2" - "luks-any" - ]; - }; - - engine = mkOption { - type = types.enum [ - "qemu" - "librbd" - ]; - }; - - secrets = mkOption { - type = types.listOf (mkOption { - type = types.submodule { - options = { - - # mandatory - type = mkOption { type = types.enum [ "volume" ]; }; - - # uuid or usage - uuid = mkOption { type = types.str; }; - usage = mkOption { type = types.str; }; - - }; - }; - }); - }; # end of secrets - - cipher = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'aes', 'des', 'cast5', 'serpent', 'twofish', etc."; - }; - size = mkOption { - type = types.str; - example = "'256', '192', '128', etc."; - }; - mode = mkOption { - type = types.str; - example = "'cbc', 'xts', 'ecb', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256', etc."; - }; - }; - }; - }; # end of cipher - - ivgen = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'plain', 'plain64', 'essiv', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256'"; - }; - }; - }; - }; # end of ivygen - }; - }; - }; # end of encryption - - # TODO(emile): reservations - # Looking at the following, it seems like this can use the source element recursively - # Haven't looked into how to define recursive nix options yet... - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L398-L400 - - # TODO(emile): initiator - - # Based on this here: - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L440 - address = mkOption { - type = types.submodule { - options = { - domain = mkOption { type = types.int; }; - bus = mkOption { type = types.int; }; - slot = mkOption { type = types.int; }; - function = mkOption { type = types.int; }; - }; - }; - }; # end of address - - # TODO(emile): slices - # Didn't find any usage of it, why is there documentation for it then? - - ssl = mkOption { - type = types.submodule { - options = { - verify = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - }; - }; - }; # end of ssl - - # TODO(emile): cookies for http and https - - readahead = mkOption { - type = types.submodule { - options = { - size = mkOption { type = types.int; }; - }; - }; - }; # end of readahead - - timeout = mkOption { - type = types.submodule { - options = { - seconds = mkOption { type = types.int; }; - }; - }; - }; # end of timeout - - identity = mkOption { - type = types.submodule { - options = { - user = mkOption { type = types.str; }; - group = mkOption { type = types.str; }; - - # if ssh - # required - username = mkOption { type = types.str; }; - - # one of these: - agentsock = mkOption { type = types.str; }; - keyfile = mkOption { type = types.str; }; - }; - }; - }; # end of identity - - # disk type "vhostuser" - reconnect = mkOption { - type = types.submodule { - options = { - # mandatory - enabled = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - timeout = mkOption { - type = types.int; - description = "seconds"; - }; - - # optional for disk type network and protocol nbd - delay = mkOption { - type = types.int; - default = 0; - description = "seconds"; - }; - }; - }; - }; # end of reconnect - - # disk type "ssh" - knownHosts = mkOption { - type = types.submodule { - options = { - path = mkOption { type = types.str; }; - }; - }; - }; # end of knownHosts - - dataStore = mkOption { - type = types.submodule { - options = { - # TODO(emile): can accept the same types as a `source` element - type = mkOption { type = types.str; }; - - # TODO(emile): can accept format and source subelements - # this is (once again) recursive for the source, stil need to figure - # out how to handle this, just not now - }; - }; - }; # end of dataStore + resource = + vm_name: + mkTag { + name = "resource"; + children = [ + (mkTag { + name = "partition"; + value = "${toString vm.${vm_name}.resource.partition}"; + }) + ]; + }; - startupPolicy = mkOption { - type = types.enum [ - "mandatory" - "requisite" - "optional" - ]; - default = "mandatory"; - }; # end of startupPolicy + vcpu = + vm_name: + mkTag { + name = "vcpu"; + args = [ + { + key = "placement"; + val = vm.${vm_name}.vcpu.placement; + } + ]; + value = "${toString vm.${vm_name}.vcpu.count}"; + }; - backingStore = mkOption { - type = types.submodule { - options = { - type = mkOption { - # TODO(emile): can accept the same types as a `source` element - type = types.str; - }; + currentMemory = + vm_name: + mkTag { + name = "currentMemory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.currentMemory.unit; + } + ]; + value = "${toString vm.${vm_name}.currentMemory.value}"; + }; + memory = + vm_name: + mkTag { + name = "memory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.memory.unit; + } + ]; + value = "${toString vm.${vm_name}.memory.value}"; + }; - index = mkOption { - # TODO(emile): figure out if this can just be an int - type = types.str; - }; + libosinfo_os = + vm_name: + mkTag { + name = "libosinfo:os"; + args = [ + { + key = "id"; + val = vm.${vm_name}.metadata.libosinfo_os; + } + ]; + closing = false; + }; - # TODO(emile): can use the following sub elements: - # - format - # - source - # - backingStore - }; - }; - }; # end of backingStore + libosinfo_libosinfo = + vm_name: + mkTag { + name = "libosinfo:libosinfo"; + args = [ + { + key = "xmlns:libosinfo"; + val = vm.${vm_name}.metadata.libosinfo; + } + ]; + children = [ + (libosinfo_os vm_name) + ]; + }; - mirror = mkOption { - type = types.submodule { - options = { - api = mkOption { - type = types.enum [ - "copy" - "active-commit" - ]; - }; - ready = mkOption { - type = types.enum [ - "yes" - "abort" - "pivot" - ]; - }; - # TODO(emile): can use the following sub elements: - # - type (disk types) - # - format - # - source - # - file - }; - }; - }; # end of mirror + metadata = + vm_name: + mkTag { + name = "metadata"; + children = [ (libosinfo_libosinfo vm_name) ]; + }; - }; - }; - }; # end of source + uuid = + vm_name: + mkTag { + name = "uuid"; + value = vm.${vm_name}.uuid; + }; - }; - }; - }; # end of nvram + name = + vm_name: + mkTag { + name = "name"; + value = vm.${vm_name}.name; + }; - }; + # the vm_name has to be passed in, as we want to accesses the value for the given vm when + # generating the config + domain = + vm_name: + mkTag { + name = "domain"; + args = [ + { + key = "type"; + val = vm.${vm_name}.vm_type; + } + { + key = "id"; + val = vm.${vm_name}.id; + } + ]; + children = [ + (name vm_name) + (uuid vm_name) + (metadata vm_name) + (memory vm_name) + (currentMemory vm_name) + (vcpu vm_name) + (resource vm_name) + (os vm_name) + (features vm_name) + (cpu vm_name) + ]; + }; + in + { + output.domain = pkgs.writeText "libvirt-domain-config.xml" (domain "alan"); }; - }; - - memory = lib.mkOption { - type = lib.types.int; - default = 1024; - example = 2048; - description = '' - The amount of memory to provide to the VM - ''; - }; }; } diff --git a/nix/modules/libvirtnix/test.nix b/nix/modules/libvirtnix/test.nix new file mode 100644 index 0000000..8542b7e --- /dev/null +++ b/nix/modules/libvirtnix/test.nix @@ -0,0 +1,10 @@ +let + pkgs = import <nixpkgs> {}; +in + pkgs.lib.evalModules { + modules = [ + # ./secret.nix + ./domain.nix + ./config.nix + ]; + } diff --git a/nix/modules/libvirtnix/xml.nix b/nix/modules/libvirtnix/xml.nix new file mode 100644 index 0000000..134a878 --- /dev/null +++ b/nix/modules/libvirtnix/xml.nix @@ -0,0 +1,45 @@ +{ lib, ... }: + +# takes a few args and creats a valid xml tag pair out of it +# +# testTag = mkTag { +# name = "name"; +# args = [ +# { +# key = "arg1"; +# val = "arg1val"; +# } +# { +# key = "arg2"; +# val = "arg2val"; +# } +# ]; +# value = "qwe"; +# children = [ +# (mkTag { name = "nested"; args = []; value = "qwe"; children = [];}) +# ]; +# }; +# +# <name arg1=arg1val arg2=arg2val> +# value +# {children} +# </name> +{ + name, # name of the tag to be used, such as `secret`, `description`, ... + args ? [ ], # args, [ { key="a"; val="b"; } { key="c"; val="d"; } ] + value ? "", # the value to place in the middle + children ? [ ], # the child elements + closing ? true, # add a closing tag +}: +let + args_str = + " " + lib.strings.concatStrings (lib.strings.intersperse " " (map (x: "${x.key}='${x.val}'") args)); + child_evaled = lib.strings.concatStrings children; + + cond = condition: value: if condition then value else ""; + + closingTag = if closing == true then "</${name}>" else ""; +in +"<${name}${ + lib.optionalString (args != [ ]) args_str +}${cond (closing == false) "/"}>${value}${child_evaled}${lib.optionalString (closing) closingTag}" diff --git a/nix/modules/x86_64-linux.nix b/nix/modules/x86_64-linux.nix index e5dbc64..62945b3 100644 --- a/nix/modules/x86_64-linux.nix +++ b/nix/modules/x86_64-linux.nix @@ -4,6 +4,7 @@ ./r2wars-web ./remarvin ./filebrowser - ./libvirtnix + # ./libvirtnix + ./goapp-frontend ]; } |