at 18.09-beta 7.1 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.virtualisation.libvirtd; 8 vswitch = config.virtualisation.vswitch; 9 configFile = pkgs.writeText "libvirtd.conf" '' 10 unix_sock_group = "libvirtd" 11 unix_sock_rw_perms = "0770" 12 auth_unix_ro = "none" 13 auth_unix_rw = "none" 14 ${cfg.extraConfig} 15 ''; 16 qemuConfigFile = pkgs.writeText "qemu.conf" '' 17 ${optionalString cfg.qemuOvmf '' 18 nvram = ["/run/libvirt/nix-ovmf/OVMF_CODE.fd:/run/libvirt/nix-ovmf/OVMF_VARS.fd"] 19 ''} 20 ${optionalString (!cfg.qemuRunAsRoot) '' 21 user = "qemu-libvirtd" 22 group = "qemu-libvirtd" 23 ''} 24 ${cfg.qemuVerbatimConfig} 25 ''; 26 27in { 28 29 ###### interface 30 31 options = { 32 33 virtualisation.libvirtd.enable = mkOption { 34 type = types.bool; 35 default = false; 36 description = '' 37 This option enables libvirtd, a daemon that manages 38 virtual machines. Users in the "libvirtd" group can interact with 39 the daemon (e.g. to start or stop VMs) using the 40 <command>virsh</command> command line tool, among others. 41 ''; 42 }; 43 44 virtualisation.libvirtd.qemuPackage = mkOption { 45 type = types.package; 46 default = pkgs.qemu; 47 description = '' 48 Qemu package to use with libvirt. 49 `pkgs.qemu` can emulate alien architectures (e.g. aarch64 on x86) 50 `pkgs.qemu_kvm` saves disk space allowing to emulate only host architectures. 51 ''; 52 }; 53 54 virtualisation.libvirtd.extraConfig = mkOption { 55 type = types.lines; 56 default = ""; 57 description = '' 58 Extra contents appended to the libvirtd configuration file, 59 libvirtd.conf. 60 ''; 61 }; 62 63 virtualisation.libvirtd.qemuRunAsRoot = mkOption { 64 type = types.bool; 65 default = true; 66 description = '' 67 If true, libvirtd runs qemu as root. 68 If false, libvirtd runs qemu as unprivileged user qemu-libvirtd. 69 Changing this option to false may cause file permission issues 70 for existing guests. To fix these, manually change ownership 71 of affected files in /var/lib/libvirt/qemu to qemu-libvirtd. 72 ''; 73 }; 74 75 virtualisation.libvirtd.qemuVerbatimConfig = mkOption { 76 type = types.lines; 77 default = '' 78 namespaces = [] 79 ''; 80 description = '' 81 Contents written to the qemu configuration file, qemu.conf. 82 Make sure to include a proper namespace configuration when 83 supplying custom configuration. 84 ''; 85 }; 86 87 virtualisation.libvirtd.qemuOvmf = mkOption { 88 type = types.bool; 89 default = true; 90 description = '' 91 Allows libvirtd to take advantage of OVMF when creating new 92 QEMU VMs with UEFI boot. 93 ''; 94 }; 95 96 virtualisation.libvirtd.extraOptions = mkOption { 97 type = types.listOf types.str; 98 default = [ ]; 99 example = [ "--verbose" ]; 100 description = '' 101 Extra command line arguments passed to libvirtd on startup. 102 ''; 103 }; 104 105 virtualisation.libvirtd.onShutdown = mkOption { 106 type = types.enum ["shutdown" "suspend" ]; 107 default = "suspend"; 108 description = '' 109 When shutting down / restarting the host what method should 110 be used to gracefully halt the guests. Setting to "shutdown" 111 will cause an ACPI shutdown of each guest. "suspend" will 112 attempt to save the state of the guests ready to restore on boot. 113 ''; 114 }; 115 116 }; 117 118 119 ###### implementation 120 121 config = mkIf cfg.enable { 122 123 environment.systemPackages = with pkgs; [ libvirt libressl.nc cfg.qemuPackage ]; 124 125 boot.kernelModules = [ "tun" ]; 126 127 users.groups.libvirtd.gid = config.ids.gids.libvirtd; 128 129 # libvirtd runs qemu as this user and group by default 130 users.extraGroups.qemu-libvirtd.gid = config.ids.gids.qemu-libvirtd; 131 users.extraUsers.qemu-libvirtd = { 132 uid = config.ids.uids.qemu-libvirtd; 133 isNormalUser = false; 134 group = "qemu-libvirtd"; 135 }; 136 137 systemd.packages = [ pkgs.libvirt ]; 138 139 systemd.services.libvirtd = { 140 description = "Libvirt Virtual Machine Management Daemon"; 141 142 wantedBy = [ "multi-user.target" ]; 143 after = [ "systemd-udev-settle.service" ] 144 ++ optional vswitch.enable "vswitchd.service"; 145 146 environment.LIBVIRTD_ARGS = ''--config "${configFile}" ${concatStringsSep " " cfg.extraOptions}''; 147 148 path = [ cfg.qemuPackage ] # libvirtd requires qemu-img to manage disk images 149 ++ optional vswitch.enable vswitch.package; 150 151 preStart = '' 152 mkdir -p /var/log/libvirt/qemu -m 755 153 rm -f /var/run/libvirtd.pid 154 155 mkdir -p /var/lib/libvirt 156 mkdir -p /var/lib/libvirt/dnsmasq 157 158 chmod 755 /var/lib/libvirt 159 chmod 755 /var/lib/libvirt/dnsmasq 160 161 # Copy default libvirt network config .xml files to /var/lib 162 # Files modified by the user will not be overwritten 163 for i in $(cd ${pkgs.libvirt}/var/lib && echo \ 164 libvirt/qemu/networks/*.xml libvirt/qemu/networks/autostart/*.xml \ 165 libvirt/nwfilter/*.xml ); 166 do 167 mkdir -p /var/lib/$(dirname $i) -m 755 168 cp -npd ${pkgs.libvirt}/var/lib/$i /var/lib/$i 169 done 170 171 # Copy generated qemu config to libvirt directory 172 cp -f ${qemuConfigFile} /var/lib/libvirt/qemu.conf 173 174 # stable (not GC'able as in /nix/store) paths for using in <emulator> section of xml configs 175 mkdir -p /run/libvirt/nix-emulators 176 for emulator in ${pkgs.libvirt}/libexec/libvirt_lxc ${cfg.qemuPackage}/bin/qemu-kvm ${cfg.qemuPackage}/bin/qemu-system-*; do 177 ln -s --force "$emulator" /run/libvirt/nix-emulators/ 178 done 179 180 ${optionalString cfg.qemuOvmf '' 181 mkdir -p /run/libvirt/nix-ovmf 182 ln -s --force ${pkgs.OVMF.fd}/FV/OVMF_CODE.fd /run/libvirt/nix-ovmf/ 183 ln -s --force ${pkgs.OVMF.fd}/FV/OVMF_VARS.fd /run/libvirt/nix-ovmf/ 184 ''} 185 ''; 186 187 serviceConfig = { 188 Type = "notify"; 189 KillMode = "process"; # when stopping, leave the VMs alone 190 Restart = "no"; 191 }; 192 restartIfChanged = false; 193 }; 194 195 systemd.services.libvirt-guests = { 196 wantedBy = [ "multi-user.target" ]; 197 path = with pkgs; [ coreutils libvirt gawk ]; 198 restartIfChanged = false; 199 }; 200 201 systemd.sockets.virtlogd = { 202 description = "Virtual machine log manager socket"; 203 wantedBy = [ "sockets.target" ]; 204 listenStreams = [ "/run/libvirt/virtlogd-sock" ]; 205 }; 206 207 systemd.services.virtlogd = { 208 description = "Virtual machine log manager"; 209 serviceConfig.ExecStart = "@${pkgs.libvirt}/sbin/virtlogd virtlogd"; 210 restartIfChanged = false; 211 }; 212 213 systemd.sockets.virtlockd = { 214 description = "Virtual machine lock manager socket"; 215 wantedBy = [ "sockets.target" ]; 216 listenStreams = [ "/run/libvirt/virtlockd-sock" ]; 217 }; 218 219 systemd.services.virtlockd = { 220 description = "Virtual machine lock manager"; 221 serviceConfig.ExecStart = "@${pkgs.libvirt}/sbin/virtlockd virtlockd"; 222 restartIfChanged = false; 223 }; 224 }; 225}