at 25.11-pre 8.7 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 9 cfg = config.virtualbox; 10in 11{ 12 imports = [ 13 ./disk-size-option.nix 14 ../image/file-options.nix 15 (lib.mkRenamedOptionModuleWith { 16 sinceRelease = 2411; 17 from = [ 18 "virtualbox" 19 "baseImageSize" 20 ]; 21 to = [ 22 "virtualisation" 23 "diskSize" 24 ]; 25 }) 26 (lib.mkRenamedOptionModuleWith { 27 sinceRelease = 2505; 28 from = [ 29 "virtualisation" 30 "virtualbox" 31 "vmFileName" 32 ]; 33 to = [ 34 "image" 35 "fileName" 36 ]; 37 }) 38 ]; 39 40 options = { 41 virtualbox = { 42 baseImageFreeSpace = lib.mkOption { 43 type = lib.types.int; 44 default = 30 * 1024; 45 description = '' 46 Free space in the VirtualBox base image in MiB. 47 ''; 48 }; 49 memorySize = lib.mkOption { 50 type = lib.types.int; 51 default = 1536; 52 description = '' 53 The amount of RAM the VirtualBox appliance can use in MiB. 54 ''; 55 }; 56 vmDerivationName = lib.mkOption { 57 type = lib.types.str; 58 default = "nixos-ova-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}"; 59 description = '' 60 The name of the derivation for the VirtualBox appliance. 61 ''; 62 }; 63 vmName = lib.mkOption { 64 type = lib.types.str; 65 default = "${config.system.nixos.distroName} ${config.system.nixos.label} (${pkgs.stdenv.hostPlatform.system})"; 66 description = '' 67 The name of the VirtualBox appliance. 68 ''; 69 }; 70 params = lib.mkOption { 71 type = 72 with lib.types; 73 attrsOf (oneOf [ 74 str 75 int 76 bool 77 (listOf str) 78 ]); 79 example = { 80 audio = "alsa"; 81 rtcuseutc = "on"; 82 usb = "off"; 83 }; 84 description = '' 85 Parameters passed to the Virtualbox appliance. 86 87 Run `VBoxManage modifyvm --help` to see more options. 88 ''; 89 }; 90 exportParams = lib.mkOption { 91 type = 92 with lib.types; 93 listOf (oneOf [ 94 str 95 int 96 bool 97 (listOf str) 98 ]); 99 example = [ 100 "--vsys" 101 "0" 102 "--vendor" 103 "ACME Inc." 104 ]; 105 default = [ ]; 106 description = '' 107 Parameters passed to the Virtualbox export command. 108 109 Run `VBoxManage export --help` to see more options. 110 ''; 111 }; 112 extraDisk = lib.mkOption { 113 description = '' 114 Optional extra disk/hdd configuration. 115 The disk will be an 'ext4' partition on a separate file. 116 ''; 117 default = null; 118 example = { 119 label = "storage"; 120 mountPoint = "/home/demo/storage"; 121 size = 100 * 1024; 122 }; 123 type = lib.types.nullOr ( 124 lib.types.submodule { 125 options = { 126 size = lib.mkOption { 127 type = lib.types.int; 128 description = "Size in MiB"; 129 }; 130 label = lib.mkOption { 131 type = lib.types.str; 132 default = "vm-extra-storage"; 133 description = "Label for the disk partition"; 134 }; 135 mountPoint = lib.mkOption { 136 type = lib.types.str; 137 description = "Path where to mount this disk."; 138 }; 139 }; 140 } 141 ); 142 }; 143 postExportCommands = lib.mkOption { 144 type = lib.types.lines; 145 default = ""; 146 example = '' 147 ${pkgs.cot}/bin/cot edit-hardware "$fn" \ 148 -v vmx-14 \ 149 --nics 2 \ 150 --nic-types VMXNET3 \ 151 --nic-names 'Nic name' \ 152 --nic-networks 'Nic match' \ 153 --network-descriptions 'Nic description' \ 154 --scsi-subtypes VirtualSCSI 155 ''; 156 description = '' 157 Extra commands to run after exporting the OVA to `$fn`. 158 ''; 159 }; 160 storageController = lib.mkOption { 161 type = 162 with lib.types; 163 attrsOf (oneOf [ 164 str 165 int 166 bool 167 (listOf str) 168 ]); 169 example = { 170 name = "SCSI"; 171 add = "scsi"; 172 portcount = 16; 173 bootable = "on"; 174 hostiocache = "on"; 175 }; 176 default = { 177 name = "SATA"; 178 add = "sata"; 179 portcount = 4; 180 bootable = "on"; 181 hostiocache = "on"; 182 }; 183 description = '' 184 Parameters passed to the VirtualBox appliance. Must have at least 185 `name`. 186 187 Run `VBoxManage storagectl --help` to see more options. 188 ''; 189 }; 190 }; 191 }; 192 193 config = { 194 # Use a priority just below mkOptionDefault (1500) instead of lib.mkDefault 195 # to avoid breaking existing configs using that. 196 virtualisation.diskSize = lib.mkOverride 1490 (50 * 1024); 197 198 virtualbox.params = lib.mkMerge [ 199 (lib.mapAttrs (name: lib.mkDefault) { 200 acpi = "on"; 201 vram = 32; 202 nictype1 = "virtio"; 203 nic1 = "nat"; 204 audiocontroller = "ac97"; 205 audio = "alsa"; 206 audioout = "on"; 207 graphicscontroller = "vmsvga"; 208 rtcuseutc = "on"; 209 usb = "on"; 210 usbehci = "on"; 211 mouse = "usbtablet"; 212 }) 213 (lib.mkIf (pkgs.stdenv.hostPlatform.system == "i686-linux") { pae = "on"; }) 214 ]; 215 216 system.nixos.tags = [ "virtualbox" ]; 217 image.extension = "ova"; 218 system.build.image = lib.mkDefault config.system.build.virtualBoxOVA; 219 system.build.virtualBoxOVA = import ../../lib/make-disk-image.nix { 220 name = cfg.vmDerivationName; 221 baseName = config.image.baseName; 222 223 inherit pkgs lib config; 224 partitionTableType = "legacy"; 225 inherit (config.virtualisation) diskSize; 226 additionalSpace = "${toString cfg.baseImageFreeSpace}M"; 227 228 postVM = '' 229 export HOME=$PWD 230 export PATH=${pkgs.virtualbox}/bin:$PATH 231 232 echo "converting image to VirtualBox format..." 233 VBoxManage convertfromraw $diskImage disk.vdi 234 235 ${lib.optionalString (cfg.extraDisk != null) '' 236 echo "creating extra disk: data-disk.raw" 237 dataDiskImage=data-disk.raw 238 truncate -s ${toString cfg.extraDisk.size}M $dataDiskImage 239 240 parted --script $dataDiskImage -- \ 241 mklabel msdos \ 242 mkpart primary ext4 1MiB -1 243 eval $(partx $dataDiskImage -o START,SECTORS --nr 1 --pairs) 244 mkfs.ext4 -F -L ${cfg.extraDisk.label} $dataDiskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K 245 echo "creating extra disk: data-disk.vdi" 246 VBoxManage convertfromraw $dataDiskImage data-disk.vdi 247 ''} 248 249 echo "creating VirtualBox VM..." 250 vmName="${cfg.vmName}"; 251 VBoxManage createvm --name "$vmName" --register \ 252 --ostype ${if pkgs.stdenv.hostPlatform.system == "x86_64-linux" then "Linux26_64" else "Linux26"} 253 VBoxManage modifyvm "$vmName" \ 254 --memory ${toString cfg.memorySize} \ 255 ${lib.cli.toGNUCommandLineShell { } cfg.params} 256 VBoxManage storagectl "$vmName" ${lib.cli.toGNUCommandLineShell { } cfg.storageController} 257 VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 0 --device 0 --type hdd \ 258 --medium disk.vdi 259 ${lib.optionalString (cfg.extraDisk != null) '' 260 VBoxManage storageattach "$vmName" --storagectl ${cfg.storageController.name} --port 1 --device 0 --type hdd \ 261 --medium data-disk.vdi 262 ''} 263 264 echo "exporting VirtualBox VM..." 265 mkdir -p $out 266 fn="$out/${config.image.fileName}" 267 VBoxManage export "$vmName" --output "$fn" --options manifest ${lib.escapeShellArgs cfg.exportParams} 268 ${cfg.postExportCommands} 269 270 rm -v $diskImage 271 272 mkdir -p $out/nix-support 273 echo "file ova $fn" >> $out/nix-support/hydra-build-products 274 ''; 275 }; 276 277 fileSystems = 278 { 279 "/" = { 280 device = "/dev/disk/by-label/nixos"; 281 autoResize = true; 282 fsType = "ext4"; 283 }; 284 } 285 // (lib.optionalAttrs (cfg.extraDisk != null) { 286 ${cfg.extraDisk.mountPoint} = { 287 device = "/dev/disk/by-label/" + cfg.extraDisk.label; 288 autoResize = true; 289 fsType = "ext4"; 290 }; 291 }); 292 293 boot.growPartition = true; 294 boot.loader.grub.device = "/dev/sda"; 295 296 swapDevices = [ 297 { 298 device = "/var/swap"; 299 size = 2048; 300 } 301 ]; 302 303 virtualisation.virtualbox.guest.enable = true; 304 305 }; 306}