at 16.09-beta 12 kB view raw
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) 11major=${version:0:5} 12echo "NixOS version is $version ($major)" 13 14rm -f ec2-amis.nix 15 16types="hvm pv" 17stores="ebs s3" 18regions="eu-west-1 eu-central-1 us-east-1 us-west-1 us-west-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2 sa-east-1 ap-south-1" 19 20for type in $types; do 21 link=$stateDir/$type 22 imageFile=$link/nixos.qcow2 23 system=x86_64-linux 24 arch=x86_64 25 26 # Build the image. 27 if ! [ -L $link ]; then 28 if [ $type = pv ]; then hvmFlag=false; else hvmFlag=true; fi 29 30 echo "building image type '$type'..." 31 nix-build -o $link \ 32 '<nixpkgs/nixos>' \ 33 -A config.system.build.amazonImage \ 34 --arg configuration "{ imports = [ <nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix> ]; ec2.hvm = $hvmFlag; }" 35 fi 36 37 for store in $stores; do 38 39 bucket=nixos-amis 40 bucketDir="$version-$type-$store" 41 42 prevAmi= 43 prevRegion= 44 45 for region in $regions; do 46 47 name=nixos-$version-$arch-$type-$store 48 description="NixOS $system $version ($type-$store)" 49 50 amiFile=$stateDir/$region.$type.$store.ami-id 51 52 if ! [ -e $amiFile ]; then 53 54 echo "doing $name in $region..." 55 56 if [ -n "$prevAmi" ]; then 57 ami=$(aws ec2 copy-image \ 58 --region "$region" \ 59 --source-region "$prevRegion" --source-image-id "$prevAmi" \ 60 --name "$name" --description "$description" | json -q .ImageId) 61 if [ "$ami" = null ]; then break; fi 62 else 63 64 if [ $store = s3 ]; then 65 66 # Bundle the image. 67 imageDir=$stateDir/$type-bundled 68 69 # Convert the image to raw format. 70 rawFile=$stateDir/$type.raw 71 if ! [ -e $rawFile ]; then 72 qemu-img convert -f qcow2 -O raw $imageFile $rawFile.tmp 73 mv $rawFile.tmp $rawFile 74 fi 75 76 if ! [ -d $imageDir ]; then 77 rm -rf $imageDir.tmp 78 mkdir -p $imageDir.tmp 79 ec2-bundle-image \ 80 -d $imageDir.tmp \ 81 -i $rawFile --arch $arch \ 82 --user "$AWS_ACCOUNT" -c "$EC2_CERT" -k "$EC2_PRIVATE_KEY" 83 mv $imageDir.tmp $imageDir 84 fi 85 86 # Upload the bundle to S3. 87 if ! [ -e $imageDir/uploaded ]; then 88 echo "uploading bundle to S3..." 89 ec2-upload-bundle \ 90 -m $imageDir/$type.raw.manifest.xml \ 91 -b "$bucket/$bucketDir" \ 92 -a "$AWS_ACCESS_KEY_ID" -s "$AWS_SECRET_ACCESS_KEY" \ 93 --location EU 94 touch $imageDir/uploaded 95 fi 96 97 extraFlags="--image-location $bucket/$bucketDir/$type.raw.manifest.xml" 98 99 else 100 101 # Convert the image to vhd format so we don't have 102 # to upload a huge raw image. 103 vhdFile=$stateDir/$type.vhd 104 if ! [ -e $vhdFile ]; then 105 qemu-img convert -f qcow2 -O vpc $imageFile $vhdFile.tmp 106 mv $vhdFile.tmp $vhdFile 107 fi 108 109 vhdFileLogicalBytes="$(qemu-img info "$vhdFile" | grep ^virtual\ size: | cut -f 2 -d \( | cut -f 1 -d \ )" 110 vhdFileLogicalGigaBytes=$(((vhdFileLogicalBytes-1)/1024/1024/1024+1)) # Round to the next GB 111 112 echo "Disk size is $vhdFileLogicalBytes bytes. Will be registered as $vhdFileLogicalGigaBytes GB." 113 114 taskId=$(cat $stateDir/$region.$type.task-id 2> /dev/null || true) 115 volId=$(cat $stateDir/$region.$type.vol-id 2> /dev/null || true) 116 snapId=$(cat $stateDir/$region.$type.snap-id 2> /dev/null || true) 117 118 # Import the VHD file. 119 if [ -z "$snapId" -a -z "$volId" -a -z "$taskId" ]; then 120 echo "importing $vhdFile..." 121 taskId=$(ec2-import-volume $vhdFile --no-upload -f vhd \ 122 -O "$AWS_ACCESS_KEY_ID" -W "$AWS_SECRET_ACCESS_KEY" \ 123 -o "$AWS_ACCESS_KEY_ID" -w "$AWS_SECRET_ACCESS_KEY" \ 124 --region "$region" -z "${region}a" \ 125 --bucket "$bucket" --prefix "$bucketDir/" \ 126 | tee /dev/stderr \ 127 | sed 's/.*\(import-vol-[0-9a-z]\+\).*/\1/ ; t ; d') 128 echo -n "$taskId" > $stateDir/$region.$type.task-id 129 fi 130 131 if [ -z "$snapId" -a -z "$volId" ]; then 132 ec2-resume-import $vhdFile -t "$taskId" --region "$region" \ 133 -O "$AWS_ACCESS_KEY_ID" -W "$AWS_SECRET_ACCESS_KEY" \ 134 -o "$AWS_ACCESS_KEY_ID" -w "$AWS_SECRET_ACCESS_KEY" 135 fi 136 137 # Wait for the volume creation to finish. 138 if [ -z "$snapId" -a -z "$volId" ]; then 139 echo "waiting for import to finish..." 140 while true; do 141 volId=$(aws ec2 describe-conversion-tasks --conversion-task-ids "$taskId" --region "$region" | jq -r .ConversionTasks[0].ImportVolume.Volume.Id) 142 if [ "$volId" != null ]; then break; fi 143 sleep 10 144 done 145 146 echo -n "$volId" > $stateDir/$region.$type.vol-id 147 fi 148 149 # Delete the import task. 150 if [ -n "$volId" -a -n "$taskId" ]; then 151 echo "removing import task..." 152 ec2-delete-disk-image -t "$taskId" --region "$region" \ 153 -O "$AWS_ACCESS_KEY_ID" -W "$AWS_SECRET_ACCESS_KEY" \ 154 -o "$AWS_ACCESS_KEY_ID" -w "$AWS_SECRET_ACCESS_KEY" || true 155 rm -f $stateDir/$region.$type.task-id 156 fi 157 158 # Create a snapshot. 159 if [ -z "$snapId" ]; then 160 echo "creating snapshot..." 161 snapId=$(aws ec2 create-snapshot --volume-id "$volId" --region "$region" --description "$description" | jq -r .SnapshotId) 162 if [ "$snapId" = null ]; then exit 1; fi 163 echo -n "$snapId" > $stateDir/$region.$type.snap-id 164 fi 165 166 # Wait for the snapshot to finish. 167 echo "waiting for snapshot to finish..." 168 while true; do 169 status=$(aws ec2 describe-snapshots --snapshot-ids "$snapId" --region "$region" | jq -r .Snapshots[0].State) 170 if [ "$status" = completed ]; then break; fi 171 sleep 10 172 done 173 174 # Delete the volume. 175 if [ -n "$volId" ]; then 176 echo "deleting volume..." 177 aws ec2 delete-volume --volume-id "$volId" --region "$region" || true 178 rm -f $stateDir/$region.$type.vol-id 179 fi 180 181 blockDeviceMappings="DeviceName=/dev/sda1,Ebs={SnapshotId=$snapId,VolumeSize=$vhdFileLogicalGigaBytes,DeleteOnTermination=true,VolumeType=gp2}" 182 extraFlags="" 183 184 if [ $type = pv ]; then 185 extraFlags+=" --root-device-name /dev/sda1" 186 else 187 extraFlags+=" --root-device-name /dev/sda1" 188 extraFlags+=" --sriov-net-support simple" 189 extraFlags+=" --ena-support" 190 fi 191 192 blockDeviceMappings+=" DeviceName=/dev/sdb,VirtualName=ephemeral0" 193 blockDeviceMappings+=" DeviceName=/dev/sdc,VirtualName=ephemeral1" 194 blockDeviceMappings+=" DeviceName=/dev/sdd,VirtualName=ephemeral2" 195 blockDeviceMappings+=" DeviceName=/dev/sde,VirtualName=ephemeral3" 196 fi 197 198 if [ $type = hvm ]; then 199 extraFlags+=" --sriov-net-support simple" 200 extraFlags+=" --ena-support" 201 fi 202 203 # Register the AMI. 204 if [ $type = pv ]; then 205 kernel=$(aws ec2 describe-images --owner amazon --filters "Name=name,Values=pv-grub-hd0_1.04-$arch.gz" | jq -r .Images[0].ImageId) 206 if [ "$kernel" = null ]; then break; fi 207 echo "using PV-GRUB kernel $kernel" 208 extraFlags+=" --virtualization-type paravirtual --kernel $kernel" 209 else 210 extraFlags+=" --virtualization-type hvm" 211 fi 212 213 ami=$(aws ec2 register-image \ 214 --name "$name" \ 215 --description "$description" \ 216 --region "$region" \ 217 --architecture "$arch" \ 218 --block-device-mappings $blockDeviceMappings \ 219 $extraFlags | jq -r .ImageId) 220 if [ "$ami" = null ]; then break; fi 221 fi 222 223 echo -n "$ami" > $amiFile 224 echo "created AMI $ami of type '$type' in $region..." 225 226 else 227 ami=$(cat $amiFile) 228 fi 229 230 echo "region = $region, type = $type, store = $store, ami = $ami" 231 232 if [ -z "$prevAmi" ]; then 233 prevAmi="$ami" 234 prevRegion="$region" 235 fi 236 done 237 238 done 239 240done 241 242for type in $types; do 243 link=$stateDir/$type 244 system=x86_64-linux 245 arch=x86_64 246 247 for store in $stores; do 248 249 for region in $regions; do 250 251 name=nixos-$version-$arch-$type-$store 252 amiFile=$stateDir/$region.$type.$store.ami-id 253 ami=$(cat $amiFile) 254 255 echo "region = $region, type = $type, store = $store, ami = $ami" 256 257 echo -n "waiting for AMI..." 258 while true; do 259 status=$(aws ec2 describe-images --image-ids "$ami" --region "$region" | jq -r .Images[0].State) 260 if [ "$status" = available ]; then break; fi 261 sleep 10 262 echo -n '.' 263 done 264 echo 265 266 # Make the image public. 267 aws ec2 modify-image-attribute \ 268 --image-id "$ami" --region "$region" --launch-permission 'Add={Group=all}' 269 270 echo " \"$major\".$region.$type-$store = \"$ami\";" >> ec2-amis.nix 271 done 272 273 done 274 275done