1#! /bin/sh -e
2
3set -o pipefail
4#set -x
5
6stateDir=${TMPDIR:-/tmp}/ec2-image
7echo "keeping state in $stateDir"
8mkdir -p $stateDir
9
10version=$(nix-instantiate --eval --strict '<nixpkgs>' -A lib.nixpkgsVersion | sed s/'"'//g)
11echo "NixOS version is $version"
12
13rm -f ec2-amis.nix
14
15
16for type in hvm pv; do
17 link=$stateDir/$type
18 imageFile=$link/nixos.img
19 system=x86_64-linux
20 arch=x86_64
21
22 # Build the image.
23 if ! [ -L $link ]; then
24 if [ $type = pv ]; then hvmFlag=false; else hvmFlag=true; fi
25
26 echo "building image type '$type'..."
27 nix-build -o $link \
28 '<nixpkgs/nixos>' \
29 -A config.system.build.amazonImage \
30 --arg configuration "{ imports = [ <nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix> ]; ec2.hvm = $hvmFlag; }"
31 fi
32
33 for store in ebs s3; do
34
35 bucket=nixos-amis
36 bucketDir="$version-$type-$store"
37
38 prevAmi=
39 prevRegion=
40
41 for region in eu-west-1 eu-central-1 us-east-1 us-west-1 us-west-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 sa-east-1; do
42
43 name=nixos-$version-$arch-$type-$store
44 description="NixOS $system $version ($type-$store)"
45
46 amiFile=$stateDir/$region.$type.$store.ami-id
47
48 if ! [ -e $amiFile ]; then
49
50 echo "doing $name in $region..."
51
52 if [ -n "$prevAmi" ]; then
53 ami=$(ec2-copy-image \
54 --region "$region" \
55 --source-region "$prevRegion" --source-ami-id "$prevAmi" \
56 --name "$name" --description "$description" | cut -f 2)
57 else
58
59 if [ $store = s3 ]; then
60
61 # Bundle the image.
62 imageDir=$stateDir/$type-bundled
63
64 if ! [ -d $imageDir ]; then
65 rm -rf $imageDir.tmp
66 mkdir -p $imageDir.tmp
67 ec2-bundle-image \
68 -d $imageDir.tmp \
69 -i $imageFile --arch $arch \
70 --user "$AWS_ACCOUNT" -c "$EC2_CERT" -k "$EC2_PRIVATE_KEY"
71 mv $imageDir.tmp $imageDir
72 fi
73
74 # Upload the bundle to S3.
75 if ! [ -e $imageDir/uploaded ]; then
76 echo "uploading bundle to S3..."
77 ec2-upload-bundle \
78 -m $imageDir/nixos.img.manifest.xml \
79 -b "$bucket/$bucketDir" \
80 -a "$EC2_ACCESS_KEY" -s "$EC2_SECRET_KEY" \
81 --location EU
82 touch $imageDir/uploaded
83 fi
84
85 extraFlags="$bucket/$bucketDir/nixos.img.manifest.xml"
86
87 else
88
89 # Convert the image to vhd format so we don't have
90 # to upload a huge raw image.
91 vhdFile=$stateDir/$type.vhd
92 if ! [ -e $vhdFile ]; then
93 qemu-img convert -O vpc $imageFile $vhdFile.tmp
94 mv $vhdFile.tmp $vhdFile
95 fi
96
97 taskId=$(cat $stateDir/$region.$type.task-id 2> /dev/null || true)
98 volId=$(cat $stateDir/$region.$type.vol-id 2> /dev/null || true)
99 snapId=$(cat $stateDir/$region.$type.snap-id 2> /dev/null || true)
100
101 # Import the VHD file.
102 if [ -z "$snapId" -a -z "$volId" -a -z "$taskId" ]; then
103 echo "importing $vhdFile..."
104 taskId=$(ec2-import-volume $vhdFile --no-upload -f vhd \
105 -o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY" \
106 --region "$region" -z "${region}a" \
107 --bucket "$bucket" --prefix "$bucketDir/" \
108 | tee /dev/stderr \
109 | sed 's/.*\(import-vol-[0-9a-z]\+\).*/\1/ ; t ; d')
110 echo -n "$taskId" > $stateDir/$region.$type.task-id
111 fi
112
113 if [ -z "$snapId" -a -z "$volId" ]; then
114 ec2-resume-import $vhdFile -t "$taskId" --region "$region" \
115 -o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY"
116 fi
117
118 # Wait for the volume creation to finish.
119 if [ -z "$snapId" -a -z "$volId" ]; then
120 echo "waiting for import to finish..."
121 while true; do
122 volId=$(ec2-describe-conversion-tasks "$taskId" --region "$region" | sed 's/.*VolumeId.*\(vol-[0-9a-f]\+\).*/\1/ ; t ; d')
123 if [ -n "$volId" ]; then break; fi
124 sleep 10
125 done
126
127 echo -n "$volId" > $stateDir/$region.$type.vol-id
128 fi
129
130 # Delete the import task.
131 if [ -n "$volId" -a -n "$taskId" ]; then
132 echo "removing import task..."
133 ec2-delete-disk-image -t "$taskId" --region "$region" -o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY" || true
134 rm -f $stateDir/$region.$type.task-id
135 fi
136
137 # Create a snapshot.
138 if [ -z "$snapId" ]; then
139 echo "creating snapshot..."
140 snapId=$(ec2-create-snapshot "$volId" --region "$region" | cut -f 2)
141 echo -n "$snapId" > $stateDir/$region.$type.snap-id
142 ec2-create-tags "$snapId" -t "Name=$description" --region "$region"
143 fi
144
145 # Wait for the snapshot to finish.
146 echo "waiting for snapshot to finish..."
147 while true; do
148 status=$(ec2-describe-snapshots "$snapId" --region "$region" | head -n1 | cut -f 4)
149 if [ "$status" = completed ]; then break; fi
150 sleep 10
151 done
152
153 # Delete the volume.
154 if [ -n "$volId" ]; then
155 echo "deleting volume..."
156 ec2-delete-volume "$volId" --region "$region" || true
157 rm -f $stateDir/$region.$type.vol-id
158 fi
159
160 extraFlags="-b /dev/sda1=$snapId:20:true:gp2"
161
162 if [ $type = pv ]; then
163 extraFlags+=" --root-device-name=/dev/sda1"
164 fi
165
166 extraFlags+=" -b /dev/sdb=ephemeral0 -b /dev/sdc=ephemeral1 -b /dev/sdd=ephemeral2 -b /dev/sde=ephemeral3"
167 fi
168
169 # Register the AMI.
170 if [ $type = pv ]; then
171 kernel=$(ec2-describe-images -o amazon --filter "manifest-location=*pv-grub-hd0_1.04-$arch*" --region "$region" | cut -f 2)
172 [ -n "$kernel" ]
173 echo "using PV-GRUB kernel $kernel"
174 extraFlags+=" --virtualization-type paravirtual --kernel $kernel"
175 else
176 extraFlags+=" --virtualization-type hvm"
177 fi
178
179 ami=$(ec2-register \
180 -n "$name" \
181 -d "$description" \
182 --region "$region" \
183 --architecture "$arch" \
184 $extraFlags | cut -f 2)
185 fi
186
187 echo -n "$ami" > $amiFile
188 echo "created AMI $ami of type '$type' in $region..."
189
190 else
191 ami=$(cat $amiFile)
192 fi
193
194 if [ -z "$NO_WAIT" -o -z "$prevAmi" ]; then
195 echo "waiting for AMI..."
196 while true; do
197 status=$(ec2-describe-images "$ami" --region "$region" | head -n1 | cut -f 5)
198 if [ "$status" = available ]; then break; fi
199 sleep 10
200 done
201
202 ec2-modify-image-attribute \
203 --region "$region" "$ami" -l -a all
204 fi
205
206 echo "region = $region, type = $type, store = $store, ami = $ami"
207 if [ -z "$prevAmi" ]; then
208 prevAmi="$ami"
209 prevRegion="$region"
210 fi
211
212 echo " \"15.09\".$region.$type-$store = \"$ami\";" >> ec2-amis.nix
213 done
214
215 done
216
217done