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