# inspired from https://nixos.wiki/wiki/Virtualization_in_NixOS { config, pkgs, lib, ... }@args: let pools = { niximages = { type = "dir"; target = "/etc/libvirtd/base-images"; }; buildbot-disks = rec { preStart = '' mkdir -p ${target} ''; type = "dir"; target = "/var/lib/libvirt/images/buildbot-disks"; }; zfspool = { # pool-define-as --name zfspool --source-name zpool/libvirt --type zfs type = "zfs"; xml = '' zpool/libvirt ''; }; }; networks = { immae = { bridgeNumber = "1"; ipRange = "192.168.100"; }; }; guests = { caldance = { pool = "zfspool"; cpus = "1"; memory = "2"; network = "immae"; diskSize = "10GiB"; extraDevicesXML = '' ''; }; buildbot = { pool = "zfspool"; cpus = "1"; memory = "3"; network = "immae"; diskSize = "10GiB"; destroyVolumeOnExit = true; }; }; toImage = f: "${import ./vms/base_image.nix f (args // { myEnv = config.myEnv; })}/nixos.qcow2"; in { environment.etc."libvirtd/base-images/nixos.qcow2".source = toImage ./vms/base_configuration.nix; environment.etc."libvirtd/base-images/buildbot.qcow2".source = toImage ./vms/buildbot_configuration.nix; systemd.services = lib.mapAttrs' (name: guest: lib.nameValuePair "libvirtd-guest-${name}" { after = [ "libvirtd.service" "libvirtd-pool-${guest.pool}.service" "libvirtd-network-${guest.network}.service" ]; requires = [ "libvirtd.service" "libvirtd-pool-${guest.pool}.service" "libvirtd-network-${guest.network}.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = let xml = pkgs.writeText "libvirt-guest-${name}.xml" '' ${name} UUID ${guest.memory} ${guest.cpus} hvm /run/current-system/sw/bin/qemu-system-x86_64 ${guest.extraDevicesXML or ""} ''; in guest.preStart or "" + '' if ! ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then ${pkgs.libvirt}/bin/virsh vol-create-as --pool ${guest.pool} --name 'guest-${name}' --capacity '${guest.diskSize}' volume_path=$(${pkgs.libvirt}/bin/virsh vol-path --pool ${guest.pool} --vol 'guest-${name}') ${pkgs.qemu}/bin/qemu-img convert /etc/libvirtd/base-images/nixos.qcow2 $volume_path fi uuid="$(${pkgs.libvirt}/bin/virsh domuuid '${name}' || true)" ${pkgs.libvirt}/bin/virsh define <(sed "s/UUID/$uuid/" '${xml}') ${pkgs.libvirt}/bin/virsh start '${name}' ''; preStop = '' ${pkgs.libvirt}/bin/virsh shutdown '${name}' let "timeout = $(date +%s) + 10" while [ "$(${pkgs.libvirt}/bin/virsh list --name | grep --count '^${name}$')" -gt 0 ]; do if [ "$(date +%s)" -ge "$timeout" ]; then # Meh, we warned it... ${pkgs.libvirt}/bin/virsh destroy '${name}' else # The machine is still running, let's give it some time to shut down sleep 0.5 fi done '' + lib.optionalString (guest.destroyVolumeOnExit or false) '' if ${pkgs.libvirt}/bin/virsh vol-key 'guest-${name}' --pool ${guest.pool} &> /dev/null; then ${pkgs.libvirt}/bin/virsh vol-wipe --pool ${guest.pool} --vol 'guest-${name}' || true ${pkgs.libvirt}/bin/virsh vol-delete --pool ${guest.pool} --vol 'guest-${name}' fi ''; }) guests // (lib.mapAttrs' (name: network: lib.nameValuePair "libvirtd-network-${name}" { after = [ "libvirtd.service" ]; requires = [ "libvirtd.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = let xml = pkgs.writeText "libvirt-network-${name}.xml" '' ${name} UUID ''; in '' uuid="$(${pkgs.libvirt}/bin/virsh net-uuid '${name}' || true)" ${pkgs.libvirt}/bin/virsh net-define <(sed "s/UUID/$uuid/" '${xml}') ${pkgs.libvirt}/bin/virsh net-start '${name}' ''; preStop = '' ${pkgs.libvirt}/bin/virsh net-destroy '${name}' ''; }) networks) // (lib.mapAttrs' (name: pool: lib.nameValuePair "libvirtd-pool-${name}" { after = [ "libvirtd.service" ]; requires = [ "libvirtd.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; }; script = let xml = pkgs.writeText "libvirt-pool-${name}.xml" '' ${name} UUID ${pool.xml or ""} ${if pool ? target then '' ${pool.target} '' else ""} ''; in pool.preStart or "" + '' uuid="$(${pkgs.libvirt}/bin/virsh pool-uuid '${name}' || true)" ${pkgs.libvirt}/bin/virsh pool-define <(sed "s/UUID/$uuid/" '${xml}') ${pkgs.libvirt}/bin/virsh pool-start '${name}' || true ''; }) pools); }