1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.amazonImage;
7 amiBootMode = if config.ec2.efi then "uefi" else "legacy-bios";
8
9in {
10
11 imports = [ ../../../modules/virtualisation/amazon-image.nix ];
12
13 # Amazon recommends setting this to the highest possible value for a good EBS
14 # experience, which prior to 4.15 was 255.
15 # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html#timeout-nvme-ebs-volumes
16 config.boot.kernelParams =
17 let timeout =
18 if pkgs.lib.versionAtLeast config.boot.kernelPackages.kernel.version "4.15"
19 then "4294967295"
20 else "255";
21 in [ "nvme_core.io_timeout=${timeout}" ];
22
23 options.amazonImage = {
24 name = mkOption {
25 type = types.str;
26 description = lib.mdDoc "The name of the generated derivation";
27 default = "nixos-amazon-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
28 };
29
30 contents = mkOption {
31 example = literalExpression ''
32 [ { source = pkgs.memtest86 + "/memtest.bin";
33 target = "boot/memtest.bin";
34 }
35 ]
36 '';
37 default = [];
38 description = lib.mdDoc ''
39 This option lists files to be copied to fixed locations in the
40 generated image. Glob patterns work.
41 '';
42 };
43
44 sizeMB = mkOption {
45 type = with types; either (enum [ "auto" ]) int;
46 default = 3072;
47 example = 8192;
48 description = lib.mdDoc "The size in MB of the image";
49 };
50
51 format = mkOption {
52 type = types.enum [ "raw" "qcow2" "vpc" ];
53 default = "vpc";
54 description = lib.mdDoc "The image format to output";
55 };
56 };
57
58 config.system.build.amazonImage = let
59 configFile = pkgs.writeText "configuration.nix"
60 ''
61 { modulesPath, ... }: {
62 imports = [ "''${modulesPath}/virtualisation/amazon-image.nix" ];
63 ${optionalString config.ec2.efi ''
64 ec2.efi = true;
65 ''}
66 ${optionalString config.ec2.zfs.enable ''
67 ec2.zfs.enable = true;
68 networking.hostId = "${config.networking.hostId}";
69 ''}
70 }
71 '';
72
73 zfsBuilder = import ../../../lib/make-multi-disk-zfs-image.nix {
74 inherit lib config configFile;
75 inherit (cfg) contents format name;
76 pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
77
78 includeChannel = true;
79
80 bootSize = 1000; # 1G is the minimum EBS volume
81
82 rootSize = cfg.sizeMB;
83 rootPoolProperties = {
84 ashift = 12;
85 autoexpand = "on";
86 };
87
88 datasets = config.ec2.zfs.datasets;
89
90 postVM = ''
91 extension=''${rootDiskImage##*.}
92 friendlyName=$out/${cfg.name}
93 rootDisk="$friendlyName.root.$extension"
94 bootDisk="$friendlyName.boot.$extension"
95 mv "$rootDiskImage" "$rootDisk"
96 mv "$bootDiskImage" "$bootDisk"
97
98 mkdir -p $out/nix-support
99 echo "file ${cfg.format} $bootDisk" >> $out/nix-support/hydra-build-products
100 echo "file ${cfg.format} $rootDisk" >> $out/nix-support/hydra-build-products
101
102 ${pkgs.jq}/bin/jq -n \
103 --arg system_label ${lib.escapeShellArg config.system.nixos.label} \
104 --arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
105 --arg root_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
106 --arg boot_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
107 --arg boot_mode "${amiBootMode}" \
108 --arg root "$rootDisk" \
109 --arg boot "$bootDisk" \
110 '{}
111 | .label = $system_label
112 | .boot_mode = $boot_mode
113 | .system = $system
114 | .disks.boot.logical_bytes = $boot_logical_bytes
115 | .disks.boot.file = $boot
116 | .disks.root.logical_bytes = $root_logical_bytes
117 | .disks.root.file = $root
118 ' > $out/nix-support/image-info.json
119 '';
120 };
121
122 extBuilder = import ../../../lib/make-disk-image.nix {
123 inherit lib config configFile;
124
125 inherit (cfg) contents format name;
126 pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
127
128 fsType = "ext4";
129 partitionTableType = if config.ec2.efi then "efi" else "legacy+gpt";
130
131 diskSize = cfg.sizeMB;
132
133 postVM = ''
134 extension=''${diskImage##*.}
135 friendlyName=$out/${cfg.name}.$extension
136 mv "$diskImage" "$friendlyName"
137 diskImage=$friendlyName
138
139 mkdir -p $out/nix-support
140 echo "file ${cfg.format} $diskImage" >> $out/nix-support/hydra-build-products
141
142 ${pkgs.jq}/bin/jq -n \
143 --arg system_label ${lib.escapeShellArg config.system.nixos.label} \
144 --arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
145 --arg logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
146 --arg boot_mode "${amiBootMode}" \
147 --arg file "$diskImage" \
148 '{}
149 | .label = $system_label
150 | .boot_mode = $boot_mode
151 | .system = $system
152 | .logical_bytes = $logical_bytes
153 | .file = $file
154 | .disks.root.logical_bytes = $logical_bytes
155 | .disks.root.file = $file
156 ' > $out/nix-support/image-info.json
157 '';
158 };
159 in if config.ec2.zfs.enable then zfsBuilder else extBuilder;
160}