Update AMI generator

The EBS and S3 (instance-store) AMIs are now created from the same
image. HVM instance-store AMIs are also generated.

Disk image generation has been factored out into a function
(nixos/lib/make-disk-image.nix) that can be used to build other kinds
of images.

+105
nixos/lib/make-disk-image.nix
···
···
+
{ pkgs
+
, lib
+
+
, # The NixOS configuration to be installed onto the disk image.
+
config
+
+
, # The size of the disk, in megabytes.
+
diskSize
+
+
, # Whether the disk should be partitioned (with a single partition
+
# containing the root filesystem) or contain the root filesystem
+
# directly.
+
partitioned ? true
+
+
, # The root file system type.
+
fsType ? "ext4"
+
+
, # The initial NixOS configuration file to be copied to
+
# /etc/nixos/configuration.nix.
+
configFile ? null
+
+
}:
+
+
with lib;
+
+
pkgs.vmTools.runInLinuxVM (
+
pkgs.runCommand "nixos-disk-image"
+
{ preVM =
+
''
+
mkdir $out
+
diskImage=$out/nixos.img
+
${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "${toString diskSize}M"
+
mv closure xchg/
+
'';
+
buildInputs = [ pkgs.utillinux pkgs.perl pkgs.e2fsprogs pkgs.parted ];
+
exportReferencesGraph =
+
[ "closure" config.system.build.toplevel ];
+
}
+
''
+
${if partitioned then ''
+
# Create a single / partition.
+
parted /dev/vda mklabel msdos
+
parted /dev/vda -- mkpart primary ext2 1M -1s
+
. /sys/class/block/vda1/uevent
+
mknod /dev/vda1 b $MAJOR $MINOR
+
rootDisk=/dev/vda1
+
'' else ''
+
rootDisk=/dev/vda
+
''}
+
+
# Create an empty filesystem and mount it.
+
mkfs.${fsType} -L nixos $rootDisk
+
${optionalString (fsType == "ext4") ''
+
tune2fs -c 0 -i 0 $rootDisk
+
''}
+
mkdir /mnt
+
mount $rootDisk /mnt
+
+
# The initrd expects these directories to exist.
+
mkdir /mnt/dev /mnt/proc /mnt/sys
+
+
mount -o bind /proc /mnt/proc
+
mount -o bind /dev /mnt/dev
+
mount -o bind /sys /mnt/sys
+
+
# Copy all paths in the closure to the filesystem.
+
storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
+
+
mkdir -p /mnt/nix/store
+
echo "copying everything (will take a while)..."
+
cp -prd $storePaths /mnt/nix/store/
+
+
# Register the paths in the Nix database.
+
printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
+
chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group ""
+
+
# Create the system profile to allow nixos-rebuild to work.
+
chroot /mnt ${config.nix.package}/bin/nix-env --option build-users-group "" \
+
-p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
+
+
# `nixos-rebuild' requires an /etc/NIXOS.
+
mkdir -p /mnt/etc
+
touch /mnt/etc/NIXOS
+
+
# `switch-to-configuration' requires a /bin/sh
+
mkdir -p /mnt/bin
+
ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
+
+
# Install a configuration.nix.
+
mkdir -p /mnt/etc/nixos
+
${optionalString (configFile != null) ''
+
cp ${configFile} /mnt/etc/nixos/configuration.nix
+
''}
+
+
# Generate the GRUB menu.
+
ln -s vda /dev/xvda
+
chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
+
+
umount /mnt/proc /mnt/dev /mnt/sys
+
umount /mnt
+
+
# Do an fsck to make sure resize2fs works.
+
fsck.${fsType} -f -y $rootDisk
+
''
+
)
-5
nixos/maintainers/scripts/ec2/amazon-base-config.nix
···
-
{ modulesPath, ...}:
-
{
-
imports = [ "${modulesPath}/virtualisation/amazon-init.nix" ];
-
services.journald.rateLimitBurst = 0;
-
}
···
-5
nixos/maintainers/scripts/ec2/amazon-hvm-config.nix
···
-
{ config, pkgs, ...}:
-
{
-
imports = [ ./amazon-base-config.nix ];
-
ec2.hvm = true;
-
}
···
-34
nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix
···
-
{ config, pkgs, lib, ...}:
-
let
-
cloudUtils = pkgs.fetchurl {
-
url = "https://launchpad.net/cloud-utils/trunk/0.27/+download/cloud-utils-0.27.tar.gz";
-
sha256 = "16shlmg36lidp614km41y6qk3xccil02f5n3r4wf6d1zr5n4v8vd";
-
};
-
growpart = pkgs.stdenv.mkDerivation {
-
name = "growpart";
-
src = cloudUtils;
-
buildPhase = ''
-
cp bin/growpart $out
-
sed -i 's|awk|gawk|' $out
-
sed -i 's|sed|gnused|' $out
-
'';
-
dontInstall = true;
-
dontPatchShebangs = true;
-
};
-
in
-
{
-
imports = [ ./amazon-base-config.nix ];
-
ec2.hvm = true;
-
boot.loader.grub.device = lib.mkOverride 0 "/dev/xvdg";
-
boot.kernelParams = [ "console=ttyS0" ];
-
-
boot.initrd.extraUtilsCommands = ''
-
copy_bin_and_libs ${pkgs.gawk}/bin/gawk
-
copy_bin_and_libs ${pkgs.gnused}/bin/sed
-
copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
-
cp -v ${growpart} $out/bin/growpart
-
'';
-
boot.initrd.postDeviceCommands = ''
-
[ -e /dev/xvda ] && [ -e /dev/xvda1 ] && TMPDIR=/run sh $(type -P growpart) /dev/xvda 1
-
'';
-
}
···
+27
nixos/maintainers/scripts/ec2/amazon-image.nix
···
···
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
+
{
+
+
imports =
+
[ ../../../modules/installer/cd-dvd/channel.nix
+
../../../modules/virtualisation/amazon-image.nix
+
];
+
+
system.build.amazonImage = import ../../../lib/make-disk-image.nix {
+
inherit pkgs lib config;
+
partitioned = config.ec2.hvm;
+
diskSize = 8192;
+
configFile = pkgs.writeText "configuration.nix"
+
''
+
{
+
imports = [ <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> ];
+
${optionalString config.ec2.hvm ''
+
ec2.hvm = true;
+
''}
+
}
+
'';
+
};
+
+
}
+217
nixos/maintainers/scripts/ec2/create-amis.sh
···
···
+
#! /bin/sh -e
+
+
set -o pipefail
+
#set -x
+
+
stateDir=${TMPDIR:-/tmp}/ec2-image
+
echo "keeping state in $stateDir"
+
mkdir -p $stateDir
+
+
version=$(nix-instantiate --eval --strict '<nixpkgs>' -A lib.nixpkgsVersion | sed s/'"'//g)
+
echo "NixOS version is $version"
+
+
rm -f ec2-amis.nix
+
+
+
for type in hvm pv; do
+
link=$stateDir/$type
+
imageFile=$link/nixos.img
+
system=x86_64-linux
+
arch=x86_64
+
+
# Build the image.
+
if ! [ -L $link ]; then
+
if [ $type = pv ]; then hvmFlag=false; else hvmFlag=true; fi
+
+
echo "building image type '$type'..."
+
nix-build -o $link \
+
'<nixpkgs/nixos>' \
+
-A config.system.build.amazonImage \
+
--arg configuration "{ imports = [ <nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix> ]; ec2.hvm = $hvmFlag; }"
+
fi
+
+
for store in ebs s3; do
+
+
bucket=nixos-amis
+
bucketDir="$version-$type-$store"
+
+
prevAmi=
+
prevRegion=
+
+
#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
+
for region in eu-west-1 us-east-1; do
+
+
name=nixos-$version-$arch-$type-$store
+
description="NixOS $system $version ($type-$store)"
+
+
amiFile=$stateDir/$region.$type.$store.ami-id
+
+
if ! [ -e $amiFile ]; then
+
+
echo "doing $name in $region..."
+
+
if [ -n "$prevAmi" ]; then
+
ami=$(ec2-copy-image \
+
--region "$region" \
+
--source-region "$prevRegion" --source-ami-id "$prevAmi" \
+
--name "$name" --description "$description" | cut -f 2)
+
else
+
+
if [ $store = s3 ]; then
+
+
# Bundle the image.
+
imageDir=$stateDir/$type-bundled
+
+
if ! [ -d $imageDir ]; then
+
rm -rf $imageDir.tmp
+
mkdir -p $imageDir.tmp
+
ec2-bundle-image \
+
-d $imageDir.tmp \
+
-i $imageFile --arch $arch \
+
--user "$AWS_ACCOUNT" -c "$EC2_CERT" -k "$EC2_PRIVATE_KEY"
+
mv $imageDir.tmp $imageDir
+
fi
+
+
# Upload the bundle to S3.
+
if ! [ -e $imageDir/uploaded ]; then
+
echo "uploading bundle to S3..."
+
ec2-upload-bundle \
+
-m $imageDir/nixos.img.manifest.xml \
+
-b "$bucket/$bucketDir" \
+
-a "$EC2_ACCESS_KEY" -s "$EC2_SECRET_KEY" \
+
--location EU
+
touch $imageDir/uploaded
+
fi
+
+
extraFlags="$bucket/$bucketDir/nixos.img.manifest.xml"
+
+
else
+
+
# Convert the image to vhd format so we don't have
+
# to upload a huge raw image.
+
vhdFile=$stateDir/$type.vhd
+
if ! [ -e $vhdFile ]; then
+
qemu-img convert -O vpc $imageFile $vhdFile.tmp
+
mv $vhdFile.tmp $vhdFile
+
fi
+
+
taskId=$(cat $stateDir/$region.$type.task-id 2> /dev/null || true)
+
volId=$(cat $stateDir/$region.$type.vol-id 2> /dev/null || true)
+
snapId=$(cat $stateDir/$region.$type.snap-id 2> /dev/null || true)
+
+
# Import the VHD file.
+
if [ -z "$snapId" -a -z "$volId" -a -z "$taskId" ]; then
+
echo "importing $vhdFile..."
+
taskId=$(ec2-import-volume $vhdFile --no-upload -f vhd \
+
-o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY" \
+
--region "$region" -z "${region}a" \
+
--bucket "$bucket" --prefix "$bucketDir/" \
+
| tee /dev/stderr \
+
| sed 's/.*\(import-vol-[0-9a-z]\+\).*/\1/ ; t ; d')
+
echo -n "$taskId" > $stateDir/$region.$type.task-id
+
fi
+
+
if [ -z "$snapId" -a -z "$volId" ]; then
+
ec2-resume-import $vhdFile -t "$taskId" --region "$region" \
+
-o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY"
+
fi
+
+
# Wait for the volume creation to finish.
+
if [ -z "$snapId" -a -z "$volId" ]; then
+
echo "waiting for import to finish..."
+
while true; do
+
volId=$(ec2-describe-conversion-tasks "$taskId" --region "$region" | sed 's/.*VolumeId.*\(vol-[0-9a-f]\+\).*/\1/ ; t ; d')
+
if [ -n "$volId" ]; then break; fi
+
sleep 10
+
done
+
+
echo -n "$volId" > $stateDir/$region.$type.vol-id
+
fi
+
+
# Delete the import task.
+
if [ -n "$volId" -a -n "$taskId" ]; then
+
echo "removing import task..."
+
ec2-delete-disk-image -t "$taskId" --region "$region" -o "$EC2_ACCESS_KEY" -w "$EC2_SECRET_KEY" || true
+
rm -f $stateDir/$region.$type.task-id
+
fi
+
+
# Create a snapshot.
+
if [ -z "$snapId" ]; then
+
echo "creating snapshot..."
+
snapId=$(ec2-create-snapshot "$volId" --region "$region" | cut -f 2)
+
echo -n "$snapId" > $stateDir/$region.$type.snap-id
+
ec2-create-tags "$snapId" -t "Name=$description" --region "$region"
+
fi
+
+
# Wait for the snapshot to finish.
+
echo "waiting for snapshot to finish..."
+
while true; do
+
status=$(ec2-describe-snapshots "$snapId" --region "$region" | head -n1 | cut -f 4)
+
if [ "$status" = completed ]; then break; fi
+
sleep 10
+
done
+
+
# Delete the volume.
+
if [ -n "$volId" ]; then
+
echo "deleting volume..."
+
ec2-delete-volume "$volId" --region "$region" || true
+
rm -f $stateDir/$region.$type.vol-id
+
fi
+
+
extraFlags="-b /dev/sda1=$snapId:20:true:gp2"
+
+
if [ $type = pv ]; then
+
extraFlags+=" --root-device-name=/dev/sda1"
+
fi
+
+
extraFlags+=" -b /dev/sdb=ephemeral0 -b /dev/sdc=ephemeral1 -b /dev/sdd=ephemeral2 -b /dev/sde=ephemeral3"
+
fi
+
+
# Register the AMI.
+
if [ $type = pv ]; then
+
kernel=$(ec2-describe-images -o amazon --filter "manifest-location=*pv-grub-hd0_1.04-$arch*" --region "$region" | cut -f 2)
+
[ -n "$kernel" ]
+
echo "using PV-GRUB kernel $kernel"
+
extraFlags+=" --virtualization-type paravirtual --kernel $kernel"
+
else
+
extraFlags+=" --virtualization-type hvm"
+
fi
+
+
set -x
+
ami=$(ec2-register \
+
-n "$name" \
+
-d "$description" \
+
--region "$region" \
+
--architecture "$arch" \
+
$extraFlags | cut -f 2)
+
fi
+
+
echo -n "$ami" > $amiFile
+
echo "created AMI $ami of type '$type' in $region..."
+
+
else
+
ami=$(cat $amiFile)
+
fi
+
+
echo "waiting for AMI..."
+
while true; do
+
status=$(ec2-describe-images "$ami" --region "$region" | head -n1 | cut -f 5)
+
if [ "$status" = available ]; then break; fi
+
sleep 10
+
done
+
+
ec2-modify-image-attribute \
+
--region "$region" "$ami" -l -a all
+
+
echo "region = $region, type = $type, store = $store, ami = $ami"
+
if [ -z "$prevAmi" ]; then
+
prevAmi="$ami"
+
prevRegion="$region"
+
fi
+
+
echo " \"15.09\".$region.$type-$store = \"$ami\";" >> ec2-amis.nix
+
done
+
+
done
+
+
done
-216
nixos/maintainers/scripts/ec2/create-ebs-amis.py
···
-
#! /usr/bin/env python
-
-
import os
-
import sys
-
import time
-
import argparse
-
import nixops.util
-
from nixops import deployment
-
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
-
import boto.ec2
-
from nixops.statefile import StateFile, get_default_state_file
-
-
parser = argparse.ArgumentParser(description='Create an EBS-backed NixOS AMI')
-
parser.add_argument('--region', dest='region', required=True, help='EC2 region to create the image in')
-
parser.add_argument('--channel', dest='channel', default="14.12", help='Channel to use')
-
parser.add_argument('--keep', dest='keep', action='store_true', help='Keep NixOps machine after use')
-
parser.add_argument('--hvm', dest='hvm', action='store_true', help='Create HVM image')
-
parser.add_argument('--key', dest='key_name', action='store_true', help='Keypair used for HVM instance creation', default="rob")
-
args = parser.parse_args()
-
-
instance_type = "m3.medium" if args.hvm else "m1.small"
-
-
if args.hvm:
-
virtualization_type = "hvm"
-
root_block = "/dev/sda1"
-
image_type = 'hvm'
-
else:
-
virtualization_type = "paravirtual"
-
root_block = "/dev/sda"
-
image_type = 'ebs'
-
-
ebs_size = 20
-
-
# Start a NixOS machine in the given region.
-
f = open("ebs-creator-config.nix", "w")
-
f.write('''{{
-
resources.ec2KeyPairs.keypair.accessKeyId = "lb-nixos";
-
resources.ec2KeyPairs.keypair.region = "{0}";
-
-
machine =
-
{{ pkgs, ... }}:
-
{{
-
deployment.ec2.accessKeyId = "lb-nixos";
-
deployment.ec2.region = "{0}";
-
deployment.ec2.blockDeviceMapping."/dev/xvdg".size = pkgs.lib.mkOverride 10 {1};
-
}};
-
}}
-
'''.format(args.region, ebs_size))
-
f.close()
-
-
db = StateFile(get_default_state_file())
-
try:
-
depl = db.open_deployment("ebs-creator")
-
except Exception:
-
depl = db.create_deployment()
-
depl.name = "ebs-creator"
-
depl.logger.set_autoresponse("y")
-
depl.nix_exprs = [os.path.abspath("./ebs-creator.nix"), os.path.abspath("./ebs-creator-config.nix")]
-
if not args.keep: depl.destroy_resources()
-
depl.deploy(allow_reboot=True)
-
-
m = depl.machines['machine']
-
-
# Do the installation.
-
device="/dev/xvdg"
-
if args.hvm:
-
m.run_command('parted -s /dev/xvdg -- mklabel msdos')
-
m.run_command('parted -s /dev/xvdg -- mkpart primary ext2 1M -1s')
-
device="/dev/xvdg1"
-
-
m.run_command("if mountpoint -q /mnt; then umount /mnt; fi")
-
m.run_command("mkfs.ext4 -L nixos {0}".format(device))
-
m.run_command("mkdir -p /mnt")
-
m.run_command("mount {0} /mnt".format(device))
-
m.run_command("touch /mnt/.ebs")
-
m.run_command("mkdir -p /mnt/etc/nixos")
-
-
m.run_command("nix-channel --add https://nixos.org/channels/nixos-{} nixos".format(args.channel))
-
m.run_command("nix-channel --update")
-
-
version = m.run_command("nix-instantiate --eval-only -A lib.nixpkgsVersion '<nixpkgs>'", capture_stdout=True).split(' ')[0].replace('"','').strip()
-
print >> sys.stderr, "NixOS version is {0}".format(version)
-
if args.hvm:
-
m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/amazon-base-config.nix")
-
m.upload_file("./amazon-hvm-config.nix", "/mnt/etc/nixos/configuration.nix")
-
m.upload_file("./amazon-hvm-install-config.nix", "/mnt/etc/nixos/amazon-hvm-install-config.nix")
-
m.run_command("NIXOS_CONFIG=/etc/nixos/amazon-hvm-install-config.nix nixos-install")
-
else:
-
m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/configuration.nix")
-
m.run_command("nixos-install")
-
-
m.run_command("umount /mnt")
-
-
if args.hvm:
-
ami_name = "nixos-{0}-x86_64-hvm".format(version)
-
description = "NixOS {0} (x86_64; EBS root; hvm)".format(version)
-
else:
-
ami_name = "nixos-{0}-x86_64-ebs".format(version)
-
description = "NixOS {0} (x86_64; EBS root)".format(version)
-
-
-
# Wait for the snapshot to finish.
-
def check():
-
status = snapshot.update()
-
print >> sys.stderr, "snapshot status is {0}".format(status)
-
return status == '100%'
-
-
m.connect()
-
volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
-
-
# Create a snapshot.
-
snapshot = volume.create_snapshot(description=description)
-
print >> sys.stderr, "created snapshot {0}".format(snapshot.id)
-
-
nixops.util.check_wait(check, max_tries=120)
-
-
m._conn.create_tags([snapshot.id], {'Name': ami_name})
-
-
if not args.keep: depl.destroy_resources()
-
-
# Register the image.
-
aki = m._conn.get_all_images(filters={'manifest-location': 'ec2*pv-grub-hd0_1.03-x86_64*'})[0]
-
print >> sys.stderr, "using kernel image {0} - {1}".format(aki.id, aki.location)
-
-
block_map = BlockDeviceMapping()
-
block_map[root_block] = BlockDeviceType(snapshot_id=snapshot.id, delete_on_termination=True, size=ebs_size, volume_type="gp2")
-
block_map['/dev/sdb'] = BlockDeviceType(ephemeral_name="ephemeral0")
-
block_map['/dev/sdc'] = BlockDeviceType(ephemeral_name="ephemeral1")
-
block_map['/dev/sdd'] = BlockDeviceType(ephemeral_name="ephemeral2")
-
block_map['/dev/sde'] = BlockDeviceType(ephemeral_name="ephemeral3")
-
-
common_args = dict(
-
name=ami_name,
-
description=description,
-
architecture="x86_64",
-
root_device_name=root_block,
-
block_device_map=block_map,
-
virtualization_type=virtualization_type,
-
delete_root_volume_on_termination=True
-
)
-
if not args.hvm:
-
common_args['kernel_id']=aki.id
-
-
ami_id = m._conn.register_image(**common_args)
-
-
print >> sys.stderr, "registered AMI {0}".format(ami_id)
-
-
print >> sys.stderr, "sleeping a bit..."
-
time.sleep(30)
-
-
print >> sys.stderr, "setting image name..."
-
m._conn.create_tags([ami_id], {'Name': ami_name})
-
-
print >> sys.stderr, "making image public..."
-
image = m._conn.get_all_images(image_ids=[ami_id])[0]
-
image.set_launch_permissions(user_ids=[], group_names=["all"])
-
-
# Do a test deployment to make sure that the AMI works.
-
f = open("ebs-test.nix", "w")
-
f.write(
-
'''
-
{{
-
network.description = "NixOS EBS test";
-
-
resources.ec2KeyPairs.keypair.accessKeyId = "lb-nixos";
-
resources.ec2KeyPairs.keypair.region = "{0}";
-
-
machine = {{ config, pkgs, resources, ... }}: {{
-
deployment.targetEnv = "ec2";
-
deployment.ec2.accessKeyId = "lb-nixos";
-
deployment.ec2.region = "{0}";
-
deployment.ec2.instanceType = "{2}";
-
deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name;
-
deployment.ec2.securityGroups = [ "public-ssh" ];
-
deployment.ec2.ami = "{1}";
-
}};
-
}}
-
'''.format(args.region, ami_id, instance_type))
-
f.close()
-
-
test_depl = db.create_deployment()
-
test_depl.auto_response = "y"
-
test_depl.name = "ebs-creator-test"
-
test_depl.nix_exprs = [os.path.abspath("./ebs-test.nix")]
-
test_depl.deploy(create_only=True)
-
test_depl.machines['machine'].run_command("nixos-version")
-
-
# Log the AMI ID.
-
f = open("ec2-amis.nix".format(args.region, image_type), "w")
-
f.write("{\n")
-
-
for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1', 'eu-central-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1']:
-
copy_image = None
-
if args.region != dest:
-
try:
-
print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest)
-
conn = boto.ec2.connect_to_region(dest)
-
copy_image = conn.copy_image(args.region, ami_id, ami_name, description=None, client_token=None)
-
except :
-
print >> sys.stderr, "FAILED!"
-
-
# Log the AMI ID.
-
if copy_image != None:
-
f.write(' "{0}"."{1}".{2} = "{3}";\n'.format(args.channel,dest,"hvm" if args.hvm else "ebs",copy_image.image_id))
-
else:
-
f.write(' "{0}"."{1}".{2} = "{3}";\n'.format(args.channel,args.region,"hvm" if args.hvm else "ebs",ami_id))
-
-
-
f.write("}\n")
-
f.close()
-
-
if not args.keep:
-
test_depl.logger.set_autoresponse("y")
-
test_depl.destroy_resources()
-
test_depl.delete()
-
···
-53
nixos/maintainers/scripts/ec2/create-s3-amis.sh
···
-
#! /bin/sh -e
-
-
export NIXOS_CONFIG=$(dirname $(readlink -f $0))/amazon-base-config.nix
-
-
version=$(nix-instantiate --eval-only '<nixpkgs/nixos>' -A config.system.nixosVersion | sed s/'"'//g)
-
echo "NixOS version is $version"
-
-
buildAndUploadFor() {
-
system="$1"
-
arch="$2"
-
-
echo "building $system image..."
-
nix-build '<nixpkgs/nixos>' \
-
-A config.system.build.amazonImage --argstr system "$system" -o ec2-ami
-
-
ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \
-
-c "$EC2_CERT" -k "$EC2_PRIVATE_KEY"
-
-
for region in eu-west-1; do
-
echo "uploading $system image for $region..."
-
-
name=nixos-$version-$arch-s3
-
bucket="$(echo $name-$region | tr '[A-Z]_' '[a-z]-')"
-
-
if [ "$region" = eu-west-1 ]; then s3location=EU;
-
elif [ "$region" = us-east-1 ]; then s3location=US;
-
else s3location="$region"
-
fi
-
-
ec2-upload-bundle -b "$bucket" -m /tmp/nixos.img.manifest.xml \
-
-a "$EC2_ACCESS_KEY" -s "$EC2_SECRET_KEY" --location "$s3location" \
-
--url http://s3.amazonaws.com
-
-
kernel=$(ec2-describe-images -o amazon --filter "manifest-location=*pv-grub-hd0_1.04-$arch*" --region "$region" | cut -f 2)
-
echo "using PV-GRUB kernel $kernel"
-
-
ami=$(ec2-register "$bucket/nixos.img.manifest.xml" -n "$name" -d "NixOS $system r$revision" -O "$EC2_ACCESS_KEY" -W "$EC2_SECRET_KEY" \
-
--region "$region" --kernel "$kernel" | cut -f 2)
-
-
echo "AMI ID is $ami"
-
-
echo " \"14.12\".\"$region\".s3 = \"$ami\";" >> ec2-amis.nix
-
-
ec2-modify-image-attribute --region "$region" "$ami" -l -a all -O "$EC2_ACCESS_KEY" -W "$EC2_SECRET_KEY"
-
-
for cp_region in us-east-1 us-west-1 us-west-2 eu-central-1 ap-southeast-1 ap-southeast-2 ap-northeast-1 sa-east-1; do
-
new_ami=$(aws ec2 copy-image --source-image-id $ami --source-region $region --region $cp_region --name "$name" | json ImageId)
-
echo " \"14.12\".\"$cp_region\".s3 = \"$new_ami\";" >> ec2-amis.nix
-
done
-
done
-
}
-
-
buildAndUploadFor x86_64-linux x86_64
···
-13
nixos/maintainers/scripts/ec2/ebs-creator.nix
···
-
{
-
network.description = "NixOS EBS creator";
-
-
machine =
-
{ config, pkgs, resources, ... }:
-
{ deployment.targetEnv = "ec2";
-
deployment.ec2.instanceType = "c3.large";
-
deployment.ec2.securityGroups = [ "public-ssh" ];
-
deployment.ec2.ebsBoot = false;
-
deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name;
-
environment.systemPackages = [ pkgs.parted ];
-
};
-
}
···
-3
nixos/modules/virtualisation/amazon-config.nix
···
-
{
-
imports = [ <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> ];
-
}
···
+47
nixos/modules/virtualisation/amazon-grow-partition.nix
···
···
+
# This module automatically grows the root partition on Amazon EC2 HVM
+
# instances. This allows an instance to be created with a bigger root
+
# filesystem than provided by the AMI.
+
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
+
let
+
+
growpart = pkgs.stdenv.mkDerivation {
+
name = "growpart";
+
src = pkgs.fetchurl {
+
url = "https://launchpad.net/cloud-utils/trunk/0.27/+download/cloud-utils-0.27.tar.gz";
+
sha256 = "16shlmg36lidp614km41y6qk3xccil02f5n3r4wf6d1zr5n4v8vd";
+
};
+
patches = [ ./growpart-util-linux-2.26.patch ];
+
buildPhase = ''
+
cp bin/growpart $out
+
sed -i 's|awk|gawk|' $out
+
sed -i 's|sed|gnused|' $out
+
'';
+
dontInstall = true;
+
dontPatchShebangs = true;
+
};
+
+
in
+
+
{
+
+
config = mkIf config.ec2.hvm {
+
+
boot.initrd.extraUtilsCommands = ''
+
copy_bin_and_libs ${pkgs.gawk}/bin/gawk
+
copy_bin_and_libs ${pkgs.gnused}/bin/sed
+
copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
+
cp -v ${growpart} $out/bin/growpart
+
ln -s sed $out/bin/gnused
+
'';
+
+
boot.initrd.postDeviceCommands = ''
+
[ -e /dev/xvda ] && [ -e /dev/xvda1 ] && TMPDIR=/run sh $(type -P growpart) /dev/xvda 1
+
'';
+
+
};
+
+
}
+15 -82
nixos/modules/virtualisation/amazon-image.nix
···
{ config, lib, pkgs, ... }:
with lib;
-
let
-
cfg = config.ec2;
-
in
{
-
imports = [ ../profiles/headless.nix ./ec2-data.nix ];
config = {
-
system.build.amazonImage =
-
pkgs.vmTools.runInLinuxVM (
-
pkgs.runCommand "amazon-image"
-
{ preVM =
-
''
-
mkdir $out
-
diskImage=$out/nixos.img
-
${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "8G"
-
mv closure xchg/
-
'';
-
buildInputs = [ pkgs.utillinux pkgs.perl ];
-
exportReferencesGraph =
-
[ "closure" config.system.build.toplevel ];
-
}
-
''
-
${if cfg.hvm then ''
-
# Create a single / partition.
-
${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
-
${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s
-
. /sys/class/block/vda1/uevent
-
mknod /dev/vda1 b $MAJOR $MINOR
-
# Create an empty filesystem and mount it.
-
${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
-
${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
-
mkdir /mnt
-
mount /dev/vda1 /mnt
-
'' else ''
-
# Create an empty filesystem and mount it.
-
${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda
-
${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda
-
mkdir /mnt
-
mount /dev/vda /mnt
-
''}
-
-
# The initrd expects these directories to exist.
-
mkdir /mnt/dev /mnt/proc /mnt/sys
-
-
mount -o bind /proc /mnt/proc
-
mount -o bind /dev /mnt/dev
-
mount -o bind /sys /mnt/sys
-
-
# Copy all paths in the closure to the filesystem.
-
storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
-
-
mkdir -p /mnt/nix/store
-
echo "copying everything (will take a while)..."
-
cp -prd $storePaths /mnt/nix/store/
-
-
# Register the paths in the Nix database.
-
printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
-
chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group ""
-
-
# Create the system profile to allow nixos-rebuild to work.
-
chroot /mnt ${config.nix.package}/bin/nix-env --option build-users-group "" \
-
-p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
-
-
# `nixos-rebuild' requires an /etc/NIXOS.
-
mkdir -p /mnt/etc
-
touch /mnt/etc/NIXOS
-
-
# `switch-to-configuration' requires a /bin/sh
-
mkdir -p /mnt/bin
-
ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
-
-
# Install a configuration.nix.
-
mkdir -p /mnt/etc/nixos
-
cp ${./amazon-config.nix} /mnt/etc/nixos/configuration.nix
-
-
# Generate the GRUB menu.
-
ln -s vda /dev/xvda
-
chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
-
-
umount /mnt/proc /mnt/dev /mnt/sys
-
umount /mnt
-
''
-
);
-
-
fileSystems."/".device = "/dev/disk/by-label/nixos";
boot.initrd.kernelModules = [ "xen-blkfront" ];
boot.kernelModules = [ "xen-netfront" ];
# Prevent the nouveau kernel module from being loaded, as it
# interferes with the nvidia/nvidia-uvm modules needed for CUDA.
···
+
# Configuration for Amazon EC2 instances. (Note that this file is a
+
# misnomer - it should be "amazon-config.nix" or so, not
+
# "amazon-image.nix", since it's used not only to build images but
+
# also to reconfigure instances. However, we can't rename it because
+
# existing "configuration.nix" files on EC2 instances refer to it.)
+
{ config, lib, pkgs, ... }:
with lib;
+
+
let cfg = config.ec2; in
+
{
+
imports = [ ../profiles/headless.nix ./ec2-data.nix ./amazon-grow-partition.nix ];
config = {
+
fileSystems."/" = {
+
device = "/dev/disk/by-label/nixos";
+
autoResize = true;
+
};
boot.initrd.kernelModules = [ "xen-blkfront" ];
boot.kernelModules = [ "xen-netfront" ];
+
boot.kernelParams = mkIf cfg.hvm [ "console=ttyS0" ];
# Prevent the nouveau kernel module from being loaded, as it
# interferes with the nvidia/nvidia-uvm modules needed for CUDA.
+88
nixos/modules/virtualisation/growpart-util-linux-2.26.patch
···
···
+
From 1895d10a7539d055a4e0206af1e7a9e5ea32a4f7 Mon Sep 17 00:00:00 2001
+
From: Juerg Haefliger <juerg.haefliger@hp.com>
+
Date: Wed, 25 Mar 2015 13:59:20 +0100
+
Subject: [PATCH] Support new sfdisk version 2.26
+
+
The sfdisk usage with version 2.26 changed. Specifically, the option
+
--show-pt-geometry and functionality for CHS have been removed.
+
Also, restoring a backup MBR now needs to be done using dd.
+
---
+
bin/growpart | 28 ++++++++++------------------
+
1 file changed, 10 insertions(+), 18 deletions(-)
+
+
diff --git a/bin/growpart b/bin/growpart
+
index 595c40b..d4c995b 100755
+
--- a/bin/growpart
+
+++ b/bin/growpart
+
@@ -28,7 +28,6 @@ PART=""
+
PT_UPDATE=false
+
DRY_RUN=0
+
+
-MBR_CHS=""
+
MBR_BACKUP=""
+
GPT_BACKUP=""
+
_capture=""
+
@@ -133,7 +132,8 @@ bad_Usage() {
+
}
+
+
mbr_restore() {
+
- sfdisk --no-reread "${DISK}" ${MBR_CHS} -I "${MBR_BACKUP}"
+
+ dd if="${MBR_BACKUP}-${DISK#/dev/}-0x00000000.bak" of="${DISK}" bs=1 \
+
+ conv=notrunc
+
}
+
+
sfdisk_worked_but_blkrrpart_failed() {
+
@@ -148,34 +148,26 @@ sfdisk_worked_but_blkrrpart_failed() {
+
+
mbr_resize() {
+
RESTORE_HUMAN="${TEMP_D}/recovery"
+
- MBR_BACKUP="${TEMP_D}/orig.save"
+
+ MBR_BACKUP="${TEMP_D}/backup"
+
+
local change_out=${TEMP_D}/change.out
+
local dump_out=${TEMP_D}/dump.out
+
local new_out=${TEMP_D}/new.out
+
local dump_mod=${TEMP_D}/dump.mod
+
- local tmp="${TEMP_D}/tmp.out"
+
- local err="${TEMP_D}/err.out"
+
+
- local _devc cyl _w1 heads _w2 sectors _w3 tot dpart
+
+ local tot dpart
+
local pt_start pt_size pt_end max_end new_size change_info
+
+
- # --show-pt-geometry outputs something like
+
- # /dev/sda: 164352 cylinders, 4 heads, 32 sectors/track
+
- rqe sfd_geom sfdisk "${DISK}" --show-pt-geometry >"${tmp}" &&
+
- read _devc cyl _w1 heads _w2 sectors _w3 <"${tmp}" &&
+
- MBR_CHS="-C ${cyl} -H ${heads} -S ${sectors}" ||
+
- fail "failed to get CHS from ${DISK}"
+
+ tot=$(sfdisk --list "${DISK}" | awk '{ print $(NF-1) ; exit }') ||
+
+ fail "failed to get total number of sectors from ${DISK}"
+
+
- tot=$((${cyl}*${heads}*${sectors}))
+
+ debug 1 "total number of sectors of ${DISK} is ${tot}"
+
+
- debug 1 "geometry is ${MBR_CHS}. total size=${tot}"
+
- rqe sfd_dump sfdisk ${MBR_CHS} --unit=S --dump "${DISK}" \
+
+ rqe sfd_dump sfdisk --dump "${DISK}" \
+
>"${dump_out}" ||
+
fail "failed to dump sfdisk info for ${DISK}"
+
-
+
{
+
- echo "## sfdisk ${MBR_CHS} --unit=S --dump ${DISK}"
+
+ echo "## sfdisk --dump ${DISK}"
+
cat "${dump_out}"
+
} >"${RESTORE_HUMAN}"
+
[ $? -eq 0 ] || fail "failed to save sfdisk -d output"
+
@@ -237,7 +229,7 @@ mbr_resize() {
+
exit 0
+
fi
+
+
- LANG=C sfdisk --no-reread "${DISK}" ${MBR_CHS} --force \
+
+ LANG=C sfdisk --no-reread "${DISK}" --force \
+
-O "${MBR_BACKUP}" <"${new_out}" >"${change_out}" 2>&1
+
ret=$?
+
[ $ret -eq 0 ] || RESTORE_FUNC="mbr_restore"
+
--
+
2.1.4
+