libnvidia-container: include binaries from driver package (#372320)
[NixPkgs.git] / nixos / modules / virtualisation / virtualbox-image.nix
blob26633731f647a265b0a21a45867853d207f17f7e
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
9   cfg = config.virtualbox;
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   ];
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.
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.
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`.
187           Run `VBoxManage storagectl --help` to see more options.
188         '';
189       };
190     };
191   };
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);
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     ];
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;
223       inherit pkgs lib config;
224       partitionTableType = "legacy";
225       inherit (config.virtualisation) diskSize;
226       additionalSpace = "${toString cfg.baseImageFreeSpace}M";
228       postVM = ''
229         export HOME=$PWD
230         export PATH=${pkgs.virtualbox}/bin:$PATH
232         echo "converting image to VirtualBox format..."
233         VBoxManage convertfromraw $diskImage disk.vdi
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
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         ''}
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         ''}
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}
270         rm -v $diskImage
272         mkdir -p $out/nix-support
273         echo "file ova $fn" >> $out/nix-support/hydra-build-products
274       '';
275     };
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       });
293     boot.growPartition = true;
294     boot.loader.grub.device = "/dev/sda";
296     swapDevices = [
297       {
298         device = "/var/swap";
299         size = 2048;
300       }
301     ];
303     virtualisation.virtualbox.guest.enable = true;
305   };