From c452b512786e47611ef264e261615aff0f819b5d Mon Sep 17 00:00:00 2001 From: Dan Carley Date: Thu, 12 Apr 2012 18:32:45 +0100 Subject: [PATCH 01/37] Remove ephemeral mounts It's no longer as simple as determining the instance architecture. Especially as this is the arch of the host instance rather than the guest. Most AMIs handle this with an init process on boot that checks the meta-data service for the instance's block mappings. --- ami_creator/ami_creator.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/ami_creator/ami_creator.py b/ami_creator/ami_creator.py index efae7fb..8246f6c 100755 --- a/ami_creator/ami_creator.py +++ b/ami_creator/ami_creator.py @@ -75,29 +75,6 @@ def __init__(self, *args, **kwargs): self.__modules = ["xenblk", "xen_blkfront"] self.__modules.extend(imgcreate.kickstart.get_modules(self.ks)) - def _get_disk_type(self): - """Get the root disk type (xvd vs sd) - - Older Xen kernels can end up with the rootfs as /dev/sda1 - while newer paravirt ops kernels don't do the major stealing - and instead just end up xvd as you'd maybe expect. - - Return sd or xvd based on the type of kernel being installed - """ - - # if use specify --ondisk, we'll use that as a cue - if len(imgcreate.kickstart.get_partitions(self.ks)) > 0: - for part in imgcreate.kickstart.get_partitions(self.ks): - if part.disk and part.disk.startswith("xvd"): - return "xvd" - elif part.disk and part.disk.startswith("sd"): - return "sd" - - # otherwise, is this a good criteria? it works for centos5 vs f14 - if "kernel-xen" in self.ks.handler.packages.packageList: - return "sd" - return "xvd" - # FIXME: refactor into imgcreate.LoopImageCreator def _get_kernel_options(self): """Return a kernel options string for bootloader configuration.""" @@ -106,17 +83,6 @@ def _get_kernel_options(self): def _get_fstab(self): s = "LABEL=_/ / %s defaults 0 0\n" % self._fstype - - # FIXME: should this be the default? - # Different arch's mnt with different disks. - # Also, only i386 AMI's have swap set up at a3 suffixed disks - disk = self._get_disk_type() - if rpmUtils.arch.getBaseArch() == 'i386': - s += "/dev/%sa2 /mnt ext3 defaults 0 0\n" %(disk,) - s += "/dev/%sa3 swap swap defaults 0 0\n" %(disk,) - elif rpmUtils.arch.getBaseArch() == 'x86_64': - s += "/dev/%sb /mnt ext3 defaults 0 0\n" %(disk,) - s += self._get_fstab_special() return s From 157f7b2f6d24582b650ce12389e2e296b2290892 Mon Sep 17 00:00:00 2001 From: Dan Carley Date: Fri, 13 Apr 2012 07:46:20 +0100 Subject: [PATCH 02/37] Add dual Grub menu entries for EBS and S3 Defaults to EBS. Falls back to S3. The only difference is the root device - (hd0,0) for EBS and (hd0) for S3. Reversed order of cfg and imgtemplate vars to match the real file. --- ami_creator/ami_creator.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ami_creator/ami_creator.py b/ami_creator/ami_creator.py index 8246f6c..bc09b78 100755 --- a/ami_creator/ami_creator.py +++ b/ami_creator/ami_creator.py @@ -87,17 +87,23 @@ def _get_fstab(self): return s def _create_bootconfig(self): - imgtemplate = """title %(title)s %(version)s + cfg = """default=0 +fallback=1 +timeout=%(timeout)s + +""" % { "timeout": imgcreate.kickstart.get_timeout(self.ks, 5) } + + imgtemplate = """title %(title)s %(version)s EBS + root (hd0,0) + kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s + initrd /boot/%(initrdfn)s-%(version)s.img + + title %(title)s %(version)s S3 root (hd0) kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s initrd /boot/%(initrdfn)s-%(version)s.img """ - cfg = """default=0 -timeout=%(timeout)s - -""" % { "timeout": imgcreate.kickstart.get_timeout(self.ks, 5) } - kernels = self._get_kernel_versions() versions = [] for ktype in kernels: From 8d3077d297c205cb2c03b21da4cf63956f3b30e6 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 28 Jan 2014 08:56:11 -0500 Subject: [PATCH 03/37] Use Grub's hiddenmenu option No need/ability to see the "graphical" menu anywhere. --- ami_creator/ami_creator.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ami_creator/ami_creator.py b/ami_creator/ami_creator.py index 1b95de8..c31b4d4 100755 --- a/ami_creator/ami_creator.py +++ b/ami_creator/ami_creator.py @@ -94,20 +94,23 @@ def _get_fstab(self): return s def _create_bootconfig(self): - imgtemplate = """title %(title)s %(version)s EBS - root (hd0,0) - kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s - initrd /boot/%(initrdfn)s-%(version)s.img - - title %(title)s %(version)s S3 - root (hd0) - kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s - initrd /boot/%(initrdfn)s-%(version)s.img + imgtemplate = """ +title %(title)s %(version)s EBS + root (hd0,0) + kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s + initrd /boot/%(initrdfn)s-%(version)s.img + +title %(title)s %(version)s S3 + root (hd0) + kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s + initrd /boot/%(initrdfn)s-%(version)s.img """ - cfg = """default=0 + cfg = """ +default=0 fallback=1 timeout=%(timeout)s +hiddenmenu """ % { "timeout": imgcreate.kickstart.get_timeout(self.ks, 5) } From ccc97015b217ecb7fc089a0ebc9c2f858ab9d63d Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 28 Jan 2014 10:07:19 -0500 Subject: [PATCH 04/37] Attempt consistency in root filesystem label There's something weird going on with the root filesystem label. ExtDiskMount prefixes fslabel with "_". It's not clear why, but in trying to solve some problems booting the AMI built with this image I was frustrated by the inconsistency and wanted to make it a little more transparent (although I didn't make it any less dumb). --- ami_creator/ami_creator.py | 16 +++++++++------- ks-centos6.cfg | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ami_creator/ami_creator.py b/ami_creator/ami_creator.py index c31b4d4..873026a 100755 --- a/ami_creator/ami_creator.py +++ b/ami_creator/ami_creator.py @@ -25,8 +25,6 @@ import imgcreate -import rpmUtils.arch - class Usage(Exception): def __init__(self, msg = None): Exception.__init__(self, msg) @@ -81,6 +79,9 @@ def __init__(self, *args, **kwargs): "sd_mod", "mptsas", "sg" ] self.__modules.extend(imgcreate.kickstart.get_modules(self.ks)) + ## for some reason ExtDiskMount prefixes the fslabel with "_" + self.__real_fslabel = "_" + self.fslabel + # FIXME: refactor into imgcreate.LoopImageCreator def _get_kernel_options(self): """Return a kernel options string for bootloader configuration.""" @@ -88,7 +89,7 @@ def _get_kernel_options(self): return r def _get_fstab(self): - s = "LABEL=_/ / %s defaults 0 0\n" % self._fstype + s = "LABEL=%s / %s defaults 0 0\n" % (self.__real_fslabel, self._fstype) s += self._get_fstab_special() return s @@ -97,12 +98,12 @@ def _create_bootconfig(self): imgtemplate = """ title %(title)s %(version)s EBS root (hd0,0) - kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s + kernel /boot/vmlinuz-%(version)s root=LABEL=%(fslabel)s %(bootargs)s initrd /boot/%(initrdfn)s-%(version)s.img title %(title)s %(version)s S3 root (hd0) - kernel /boot/vmlinuz-%(version)s root=LABEL=_/ %(bootargs)s + kernel /boot/vmlinuz-%(version)s root=LABEL=%(fslabel)s %(bootargs)s initrd /boot/%(initrdfn)s-%(version)s.img """ @@ -128,7 +129,8 @@ def _create_bootconfig(self): cfg += imgtemplate % {"title": self.name, "version": version, "initrdfn": initrdfn, - "bootargs": self._get_kernel_options()} + "bootargs": self._get_kernel_options(), + "fslabel": self.__real_fslabel} with open(self._instroot + "/boot/grub/grub.conf", "w") as grubcfg: grubcfg.write(cfg) @@ -202,7 +204,7 @@ def main(): if options.name: name = options.name - creator = AmiCreator(ks, name, "/") + creator = AmiCreator(ks, name, fslabel="root") creator.tmpdir = os.path.abspath(options.tmpdir) if options.cachedir: options.cachedir = os.path.abspath(options.cachedir) diff --git a/ks-centos6.cfg b/ks-centos6.cfg index 1ddf2e7..1c9977c 100644 --- a/ks-centos6.cfg +++ b/ks-centos6.cfg @@ -19,6 +19,8 @@ rootpw --lock # Define how large you want your rootfs to be # NOTE: S3-backed AMIs have a limit of 10G # +# fs label is not used for the root fs! if you need to refer to the label, use +# "_root". part / --size 768 --fstype ext4 # From 240238e340d8d294677b5b6a95f65a2124dfd1ba Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 28 Jan 2014 10:10:48 -0500 Subject: [PATCH 05/37] Updated CentOS 6 KS config to my liking Took some queues from Bashton's AMIs. --- ks-centos6.cfg | 53 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/ks-centos6.cfg b/ks-centos6.cfg index 1c9977c..007e73a 100644 --- a/ks-centos6.cfg +++ b/ks-centos6.cfg @@ -1,19 +1,30 @@ -# Build a basic CentOS 6 AMI lang en_US.UTF-8 keyboard us -timezone US/Eastern -auth --useshadow --enablemd5 -selinux --permissive -firewall --enabled --ssh -bootloader --timeout=1 --append xen_blkfront.sda_is_xvda=1 +timezone --utc UTC +authconfig --enableshadow --passalgo=sha512 +selinux --disabled +firewall --disabled +firstboot --disabled + +## selinux=0 required to log in via ssh; something missing in this config, I'm +## sure, but I hate/don't understand selinux, so disabling with a vengance. +## modifying /etc/sysconfig/selinux in %post below *should* do the trick, but it +## isn't. punting. + +## "xen_blkfront.sda_is_xvda=1" -- https://bugzilla.redhat.com/show_bug.cgi?id=729586 +## remainder stolen from bashton +## dracut options: http://fedoraproject.org/wiki/Dracut/Options + +bootloader --timeout=1 --append="xen_blkfront.sda_is_xvda=1 selinux=0 rd_NO_LUKS rd_NO_LVM rd_NO_DM rd_NO_MD LANG=en_US.UTF-8 KEYTABLE=us SYSFONT=latarcyrheb-sun16 console=hvc0 crashkernel=auto" + network --bootproto=dhcp --device=eth0 --onboot=on -services --enabled=network +services --enabled=network,sshd,cloud-init # Uncomment the next line to make the root password be password # By default the root password is locked #rootpw password -rootpw --lock +#rootpw --lock # # Define how large you want your rootfs to be @@ -27,7 +38,8 @@ part / --size 768 --fstype ext4 # Repositories repo --name=CentOS6-Base --mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=os repo --name=CentOS6-Updates --mirrorlist=http://mirrorlist.centos.org/?release=6&arch=$basearch&repo=updates -repo --name=EPEL --baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/ +#repo --name=EPEL --baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/ +repo --name=EPEL --baseurl=http://mirror.pnl.gov/epel/6/$basearch/ # @@ -36,8 +48,6 @@ repo --name=EPEL --baseurl=http://download.fedoraproject.org/pub/epel/6/$basearc # %packages --nobase --instLangs=en @core -system-config-securitylevel-tui -system-config-firewall-base audit pciutils bash @@ -55,6 +65,7 @@ acpid openssh-clients openssh-server curl +epel-release cloud-init sudo @@ -66,16 +77,22 @@ iputils # set up ec2-user %post --erroronfail +set -e +set -x +set -u + /usr/sbin/useradd ec2-user echo 'ec2-user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers -%end +## hrm, even with "selinux --disabled" above, selinux still appears to be enabled! +## relevant? https://bugzilla.redhat.com/show_bug.cgi?id=690279 +sed -i -e 's#^SELINUX=.*$#SELINUX=disabled#' /etc/sysconfig/selinux +## only one console needed (if that…) +sed -i -e 's#^ACTIVE_CONSOLES=.*$#ACTIVE_CONSOLES=/dev/tty1#' /etc/sysconfig/init -# -# Add custom post scripts after the base post. -# -%post -%end - +## this could help diagnostics later +sed -i -e 's#^BOOTUP=.*$#BOOTUP=verbose#' /etc/sysconfig/init +yum clean all +%end From f52ba319db387313c8ecd6ecdec1bbb1c2cb1d34 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 28 Jan 2014 10:22:02 -0500 Subject: [PATCH 06/37] capturing some docs and remaining steps --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ create-image.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ prepare-volume.sh | 13 +++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 README.md create mode 100755 create-image.sh create mode 100644 prepare-volume.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3e2453 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# ami-creator + +A simple tool built on python-imgcreate to create CentOS AMIs for EC2 using +Kickstart configs. Supports ebs- and instance-store-backed instances. + +## howto + +1. clone this repo on an EC2 instance +2. attach a 10G EBS volume, attach it so it appears at `/dev/xvdj` +3. create `/media/ephemeral0/build` and `/media/ephemeral0/cache` directories +4. create the base image from a kickstart config: + + sudo ./ami_creator/ami_creator.py -c ks-centos6.cfg -n my-image-name -t /media/ephemeral0/build --cache=/media/ephemeral0/cache + +5. transfer the image to the attached EBS volume: + + sudo prepare-volume.sh + +6. create and launch the instance: + + ./create-image.sh + + +## original `README` + + ami-creator + + A simple tool based on python-imgcreate to create Fedora/Red Hat style + images that can be used as an AMI in EC2. + + Takes a kickstart config like the rest of livecd-creator, etc and spits out a + disk image file that's suitable to upload as an s3 ami. To do the upload right + now, you'll want to run something like + ec2-bundle-image + ec2-upload-bundle + ec2-register + after having created your base image file. + + Tested with the following as guests: + * CentOS 5.5 + * Fedora 14 + See the configs/ directory for example configs that work for each of these. + + + Jeremy Katz + 2010 December 10 + diff --git a/create-image.sh b/create-image.sh new file mode 100755 index 0000000..efe5375 --- /dev/null +++ b/create-image.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +set -x +set -e +set -u + +snap_id=$( aws ec2 create-snapshot --volume-id vol-9c03c3ee | jq -r .SnapshotId ) + +while [ $( aws ec2 describe-snapshots --snapshot-ids ${snap_id} | jq -r .Snapshots[].State ) != "completed" ]; do + sleep 5 +done + +image_id=$( aws ec2 register-image \ + --kernel-id aki-919dcaf8 \ + --name ami-creator-001 \ + --architecture x86_64 \ + --root-device-name /dev/sda1 \ + --block-device-mappings "[{ + \"DeviceName\": \"/dev/sda\", + \"Ebs\": { + \"SnapshotId\": \"${snap_id}\", + \"VolumeSize\": 10 + } + }, + { + \"DeviceName\": \"/dev/sdb\", + \"VirtualName\": \"ephemeral0\" + }]" | jq -r .ImageId ) + +instance_id=$( aws ec2 run-instances --image-id $image_id --instance-type t1.micro --key-name knife | jq -r .Instances[].InstanceId ) + +while [ $( aws ec2 describe-instances --instance-ids $instance_id | jq -r .Reservations[].Instances[].State.Name ) != "running" ]; do + sleep 5 +done + +echo "snap_id=${snap_id}; image_id=${image_id}; instance_id=${instance_id};" + +# aws ec2 get-console-output --instance-id ${instance_id} | jq -r .Output + +# aws ec2 terminate-instances --instance-ids ${instance_id} +# aws ec2 deregister-image --image-id ${image_id} +# aws ec2 delete-snapshot --snapshot-id ${snap_id} + diff --git a/prepare-volume.sh b/prepare-volume.sh new file mode 100644 index 0000000..309c17f --- /dev/null +++ b/prepare-volume.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +## partition disk; single physical partition +sfdisk /dev/xvdj << EOF +0,,83,* +; +; +; +EOF + +time dd if=my-image-name.img of=/dev/xvdj1 bs=8M +e2fsck -f /dev/xvdj1 +resize2fs /dev/xvdj1 From 655851796582cbfc16bb520b55d6bfce2fe7c5e6 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 28 Jan 2014 14:02:38 -0500 Subject: [PATCH 07/37] Adding resource links --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index e3e2453..a176105 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,15 @@ Kickstart configs. Supports ebs- and instance-store-backed instances. ./create-image.sh +## add'l resources + +* [Announcing ami-creator](http://velohacker.com/2010/12/13/announcing-ami-creator/) +* [CentOS AMIs from Kickstart](http://dan.carley.co/blog/2012/04/17/centos-amis-from-kickstart/) +* [How to build your own S3- and EBS-backed instances](http://amazonaws.michael--martinez.com) +* [Using Your Own Linux Kernels - Amazon Elastic Compute Cloud](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html) +* [How to make your own CentOS 6 AMIs](http://www.bashton.com/blog/2012/how-to-make-your-own-centos-6-amis/) +* [CentOS 5 kickstart options](http://www.centos.org/docs/5/html/Installation_Guide-en-US/s1-kickstart2-options.html) + ## original `README` ami-creator From 2931ac5d131f1338dff17e2824975fec440a2b6b Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Wed, 29 Jan 2014 11:01:42 -0500 Subject: [PATCH 08/37] Adding helper scripts create-ami.sh is the beaut. --- create-image.sh | 43 --------------- prepare-volume.sh | 13 ----- utils/create-ami.sh | 89 ++++++++++++++++++++++++++++++++ utils/remove-ami-and-snapshot.sh | 19 +++++++ 4 files changed, 108 insertions(+), 56 deletions(-) delete mode 100755 create-image.sh delete mode 100644 prepare-volume.sh create mode 100755 utils/create-ami.sh create mode 100755 utils/remove-ami-and-snapshot.sh diff --git a/create-image.sh b/create-image.sh deleted file mode 100755 index efe5375..0000000 --- a/create-image.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -set -x -set -e -set -u - -snap_id=$( aws ec2 create-snapshot --volume-id vol-9c03c3ee | jq -r .SnapshotId ) - -while [ $( aws ec2 describe-snapshots --snapshot-ids ${snap_id} | jq -r .Snapshots[].State ) != "completed" ]; do - sleep 5 -done - -image_id=$( aws ec2 register-image \ - --kernel-id aki-919dcaf8 \ - --name ami-creator-001 \ - --architecture x86_64 \ - --root-device-name /dev/sda1 \ - --block-device-mappings "[{ - \"DeviceName\": \"/dev/sda\", - \"Ebs\": { - \"SnapshotId\": \"${snap_id}\", - \"VolumeSize\": 10 - } - }, - { - \"DeviceName\": \"/dev/sdb\", - \"VirtualName\": \"ephemeral0\" - }]" | jq -r .ImageId ) - -instance_id=$( aws ec2 run-instances --image-id $image_id --instance-type t1.micro --key-name knife | jq -r .Instances[].InstanceId ) - -while [ $( aws ec2 describe-instances --instance-ids $instance_id | jq -r .Reservations[].Instances[].State.Name ) != "running" ]; do - sleep 5 -done - -echo "snap_id=${snap_id}; image_id=${image_id}; instance_id=${instance_id};" - -# aws ec2 get-console-output --instance-id ${instance_id} | jq -r .Output - -# aws ec2 terminate-instances --instance-ids ${instance_id} -# aws ec2 deregister-image --image-id ${image_id} -# aws ec2 delete-snapshot --snapshot-id ${snap_id} - diff --git a/prepare-volume.sh b/prepare-volume.sh deleted file mode 100644 index 309c17f..0000000 --- a/prepare-volume.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -## partition disk; single physical partition -sfdisk /dev/xvdj << EOF -0,,83,* -; -; -; -EOF - -time dd if=my-image-name.img of=/dev/xvdj1 bs=8M -e2fsck -f /dev/xvdj1 -resize2fs /dev/xvdj1 diff --git a/utils/create-ami.sh b/utils/create-ami.sh new file mode 100755 index 0000000..8c68667 --- /dev/null +++ b/utils/create-ami.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +set -e +set -u +# set -x + +function die() { + echo "$@" + exit 1 +} + +[ $EUID -eq 0 ] || die "must be root" + +_basedir="$( cd $( dirname -- $0 ) && /bin/pwd )" + +[ $# -eq 3 ] || die "usage: $0 " + +config="${1}" +block_dev="${2}" +vol_id="${3}" + +name="$( basename $config | sed -r -e 's#\.[^.]+$##g' )" +dest_img="${name}.img" + +## check for required programs +which aws >/dev/null 2>&1 || die "need aws" +which curl >/dev/null 2>&1 || die "need curl" +which jq >/dev/null 2>&1 || die "need jq" +which e2fsck >/dev/null 2>&1 || die "need e2fsck" +which resize2fs >/dev/null 2>&1 || die "need resize2fs" +rpm -q python-imgcreate >/dev/null 2>&1 || die "need python-imgcreate package" + +## the block device must exist +[ -e "${block_dev}" ] || die "${block_dev} does not exist" + +## volume should be attached to this instance +my_instance_id="$( curl -s http://169.254.169.254/latest/meta-data/instance-id )" + +## set up/verify aws credentials and settings +## http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html +export AWS_DEFAULT_REGION="$( curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's#.$##g' )" +[ -n "${AWS_ACCESS_KEY_ID}" ] || die "AWS_ACCESS_KEY_ID not set" +[ -n "${AWS_SECRET_ACCESS_KEY}" ] || die "AWS_SECRET_ACCESS_KEY not set" + +if [ "$( aws ec2 describe-volumes --volume-ids ${vol_id} | jq -r .Volumes[].Attachments[].InstanceId )" != "${my_instance_id}" ]; then + die "volume ${vol_id} is not attached to this instance!" +fi + +## create the image +if [ ! -e "${dest_img}" ]; then + ${_basedir}/ami_creator/ami_creator.py -c "${config}" -n "${name}" +else + echo "$dest_img already exists; not recreating" +fi + +## partition volume +sfdisk ${block_dev} << EOF +0,,83,* +; +; +; +EOF + +## write image to volume and resize the filesystem +dd if=${dest_img} of=${block_dev}1 bs=8M +e2fsck -f ${block_dev}1 +resize2fs ${block_dev}1 + +## create a snapshot of the volume +snap_id=$( aws ec2 create-snapshot --volume-id ${vol_id} --description "root image for ${name}" | jq -r .SnapshotId ) + +while [ $( aws ec2 describe-snapshots --snapshot-ids ${snap_id} | jq -r .Snapshots[].State ) != "completed" ]; do + echo "waiting for snapshot ${snap_id} to complete" + sleep 5 +done + +## kernel-id hard-coded +## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html +reg_img_args="--kernel-id aki-919dcaf8 --architecture x86_64" + +reg_img_args="${reg_img_args} --name ${name}" +reg_img_args="${reg_img_args} --root-device-name /dev/sda1" + +## fuck me. +reg_img_args="${reg_img_args} --block-device-mappings [{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" + +image_id=$( aws ec2 register-image ${reg_img_args} | jq -r .ImageId ) + +echo "created AMI with id ${image_id}" diff --git a/utils/remove-ami-and-snapshot.sh b/utils/remove-ami-and-snapshot.sh new file mode 100755 index 0000000..df88609 --- /dev/null +++ b/utils/remove-ami-and-snapshot.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +## deregisters an AMI and removes its associated block device snapshot. Will +## likely fail if there are multiple EBS BlockDeviceMappings. + +set -e +set -u + +[ $# -eq 1 ] || { echo "usage: $0 "; exit 1; } + +image_id="${1}" + +snap_id="$( aws ec2 describe-images --image-ids ${image_id} | jq -r '.Images[].BlockDeviceMappings[] | select(.Ebs).Ebs.SnapshotId' )" + +echo "deregistering ${image_id}" +aws ec2 deregister-image --image-id ${image_id} + +echo "deleting snapshot ${snap_id}" +aws ec2 delete-snapshot --snapshot-id ${snap_id} From f9b48cdeca1633898fbad6e18a17476d92ecdadd Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Thu, 20 Feb 2014 15:37:38 -0500 Subject: [PATCH 09/37] Allow for naming of AMI --- utils/create-ami.sh | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 8c68667..11bd4d0 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -1,5 +1,7 @@ #!/bin/bash +## @todo check if ami name already exists + set -e set -u # set -x @@ -11,13 +13,21 @@ function die() { [ $EUID -eq 0 ] || die "must be root" -_basedir="$( cd $( dirname -- $0 ) && /bin/pwd )" +_basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" + +cachedir="${_basedir}/cache" +[ -d "${cachedir}" ] || mkdir "${cachedir}" + +[ $# -eq 4 ] || die "usage: $0 " -[ $# -eq 3 ] || die "usage: $0 " +config="$( readlink -f ${1} )" +ami_name="${2}" +block_dev="${3}" +vol_id="${4}" -config="${1}" -block_dev="${2}" -vol_id="${3}" +## change to a well-known directory; doesn't have to make sense, just has to be +## consistent. +cd "$( dirname ${config} )" name="$( basename $config | sed -r -e 's#\.[^.]+$##g' )" dest_img="${name}.img" @@ -76,14 +86,7 @@ done ## kernel-id hard-coded ## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html -reg_img_args="--kernel-id aki-919dcaf8 --architecture x86_64" - -reg_img_args="${reg_img_args} --name ${name}" -reg_img_args="${reg_img_args} --root-device-name /dev/sda1" - -## fuck me. -reg_img_args="${reg_img_args} --block-device-mappings [{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" - -image_id=$( aws ec2 register-image ${reg_img_args} | jq -r .ImageId ) +## fuck me, bash space escaping is a pain in the ass. +image_id=$( aws ec2 register-image --kernel-id aki-919dcaf8 --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" | jq -r .ImageId ) echo "created AMI with id ${image_id}" From a6416fc3efbdac15afc28bc9a6eec6adfe352545 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Wed, 2 Apr 2014 16:53:10 -0400 Subject: [PATCH 10/37] Hoping to make dd not exit zero without actually doing its job --- utils/create-ami.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 11bd4d0..3f97897 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -72,7 +72,7 @@ sfdisk ${block_dev} << EOF EOF ## write image to volume and resize the filesystem -dd if=${dest_img} of=${block_dev}1 bs=8M +dd if=${dest_img} conv=fsync of=${block_dev}1 e2fsck -f ${block_dev}1 resize2fs ${block_dev}1 From c2c2d03a441724dd5eda68c7b553aee713a31b20 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Thu, 3 Apr 2014 10:46:12 -0400 Subject: [PATCH 11/37] Work around some very wonky shit with dd --- utils/create-ami.sh | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 3f97897..41d82b8 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -63,6 +63,13 @@ else echo "$dest_img already exists; not recreating" fi +## ok, this is fucked up. the dd writing the image to the volume is exiting +## with zero, but the data isn't getting written. Bringing out the big guns. + +## forcibly corrupt the fucker so we know we're not working with stale data +dd if=/dev/zero of=${block_dev} bs=8M count=10 conv=fsync oflag=sync +sync;sync;sync + ## partition volume sfdisk ${block_dev} << EOF 0,,83,* @@ -71,9 +78,16 @@ sfdisk ${block_dev} << EOF ; EOF -## write image to volume and resize the filesystem -dd if=${dest_img} conv=fsync of=${block_dev}1 -e2fsck -f ${block_dev}1 +## write image to volume +dd if=${dest_img} of=${block_dev}1 conv=fsync oflag=sync bs=8k + +## force-check the filesystem; re-write the image if it fails +if ! fsck.ext4 -n -f ${block_dev}1 ; then + dd if=${dest_img} of=${block_dev}1 conv=fsync oflag=sync bs=8k + fsck.ext4 -n -f ${block_dev}1 +fi + +## resize the filesystem resize2fs ${block_dev}1 ## create a snapshot of the volume From c10b604f66347115162fc2d5899d45551590808b Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Fri, 27 Jun 2014 10:38:25 -0400 Subject: [PATCH 12/37] added --virtualization-type optional parameter which feeds into register-image awscli call at the end of the script --- utils/create-ami.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 41d82b8..57f1990 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -18,12 +18,16 @@ _basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" cachedir="${_basedir}/cache" [ -d "${cachedir}" ] || mkdir "${cachedir}" -[ $# -eq 4 ] || die "usage: $0 " +[ $# -eq 4 -o $# -eq 5 ] || die "usage: $0 []" config="$( readlink -f ${1} )" ami_name="${2}" block_dev="${3}" vol_id="${4}" +virt_type="" +if [ $# -eq 5 ]; then + virt_type="--virtualization-type ${5}" +fi ## change to a well-known directory; doesn't have to make sense, just has to be ## consistent. @@ -101,6 +105,6 @@ done ## kernel-id hard-coded ## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html ## fuck me, bash space escaping is a pain in the ass. -image_id=$( aws ec2 register-image --kernel-id aki-919dcaf8 --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" | jq -r .ImageId ) +image_id=$( aws ec2 register-image --kernel-id aki-919dcaf8 --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) echo "created AMI with id ${image_id}" From 200414c35b06ef01f35aee99b2c6176b4d1536a8 Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Fri, 27 Jun 2014 13:07:00 -0400 Subject: [PATCH 13/37] --kernel-id only set if virtualization_type is NOT hvm --- utils/create-ami.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 57f1990..8ce6c4b 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -25,8 +25,12 @@ ami_name="${2}" block_dev="${3}" vol_id="${4}" virt_type="" +kernel_id="--kernel-id aki-919dcaf8" if [ $# -eq 5 ]; then virt_type="--virtualization-type ${5}" + if [ "${5}" == "hvm" ]; then + kernel_id="" + fi fi ## change to a well-known directory; doesn't have to make sense, just has to be @@ -105,6 +109,6 @@ done ## kernel-id hard-coded ## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html ## fuck me, bash space escaping is a pain in the ass. -image_id=$( aws ec2 register-image --kernel-id aki-919dcaf8 --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) +image_id=$( aws ec2 register-image ${kernel_id} --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) echo "created AMI with id ${image_id}" From 4c84172a600bae9d4427d9a8457aecb1874306e6 Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Fri, 27 Jun 2014 14:02:45 -0400 Subject: [PATCH 14/37] fixed device mapping issue for hvm instances --- utils/create-ami.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 8ce6c4b..05ff1d4 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -26,10 +26,13 @@ block_dev="${3}" vol_id="${4}" virt_type="" kernel_id="--kernel-id aki-919dcaf8" +root_device="/dev/sda" if [ $# -eq 5 ]; then virt_type="--virtualization-type ${5}" if [ "${5}" == "hvm" ]; then kernel_id="" + # need to figure out why we need the 1 at the end... + root_device="/dev/sda1" fi fi @@ -109,6 +112,6 @@ done ## kernel-id hard-coded ## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html ## fuck me, bash space escaping is a pain in the ass. -image_id=$( aws ec2 register-image ${kernel_id} --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"/dev/sda\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) +image_id=$( aws ec2 register-image ${kernel_id} --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"${root_device}\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) echo "created AMI with id ${image_id}" From 7ea2adcb6ce3dd79259ff448a291f4b57f51f5d8 Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Tue, 1 Jul 2014 15:46:04 -0400 Subject: [PATCH 15/37] adding grub patching and installation (needs to be done only if hvm is set, but for now lets just add it and get it working) --- utils/create-ami.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 05ff1d4..4b5c68a 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -101,6 +101,25 @@ fi ## resize the filesystem resize2fs ${block_dev}1 +# patch grub-install then install grub on the volume +# https://bugs.archlinux.org/task/30241 for where and why for the patch +curl -f -L -o /tmp/grub-install.diff https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff + +which patch >/dev/null || yum install -y patch +patch --no-backup-if-mismatch -N -p0 -i /tmp/grub-install.diff /sbin/grub-install + +# mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) +vol_mnt="/mnt/ebs_vol" +mkdir -p ${vol_mnt} +mount -t ext4 ${block_dev}1 ${vol_mnt} + +# make ${vol_mnt}/boot/grub/device.map with contents "(hd0) /dev/xvda" because otherwise grub-install isn't happy, even with --recheck +echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map + +grub-install --root-directory=${vol_mnt} --no-floppy ${block_dev} + +umount ${vol_mnt} + ## create a snapshot of the volume snap_id=$( aws ec2 create-snapshot --volume-id ${vol_id} --description "root image for ${name}" | jq -r .SnapshotId ) From 22875ada5676b35db895db16cc20bd2bfb3b1e50 Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Wed, 2 Jul 2014 11:10:42 -0400 Subject: [PATCH 16/37] if building an hvm ami: patch grub-install for xen device names, install grub, fix device.map, ..., profit --- utils/create-ami.sh | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 4b5c68a..f769bd3 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -101,24 +101,33 @@ fi ## resize the filesystem resize2fs ${block_dev}1 -# patch grub-install then install grub on the volume -# https://bugs.archlinux.org/task/30241 for where and why for the patch -curl -f -L -o /tmp/grub-install.diff https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff +if [ $# -eq 5 ]; then + if [ "${5}" == "hvm" ]; then + ## special hvm ami stuff, all about fixing up the bootloader + + # patch grub-install then install grub on the volume + # https://bugs.archlinux.org/task/30241 for where and why for the patch + curl -f -L -o /tmp/grub-install.diff https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff -which patch >/dev/null || yum install -y patch -patch --no-backup-if-mismatch -N -p0 -i /tmp/grub-install.diff /sbin/grub-install + which patch >/dev/null || yum install -y patch + patch --no-backup-if-mismatch -N -p0 -i /tmp/grub-install.diff /sbin/grub-install -# mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) -vol_mnt="/mnt/ebs_vol" -mkdir -p ${vol_mnt} -mount -t ext4 ${block_dev}1 ${vol_mnt} + # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) + vol_mnt="/mnt/ebs_vol" + mkdir -p ${vol_mnt} + mount -t ext4 ${block_dev}1 ${vol_mnt} -# make ${vol_mnt}/boot/grub/device.map with contents "(hd0) /dev/xvda" because otherwise grub-install isn't happy, even with --recheck -echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map + # make ${vol_mnt}/boot/grub/device.map with contents "(hd0) ${block_dev}" because otherwise grub-install isn't happy, even with --recheck + echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map -grub-install --root-directory=${vol_mnt} --no-floppy ${block_dev} + grub-install --root-directory=${vol_mnt} --no-floppy ${block_dev} -umount ${vol_mnt} + # ok grub is installed, now redo device.map for booting the actual volume... because otherwise this bloody well doesn't work + sed -i -r "s/^(\(hd0\)\s+\/dev\/)[a-z]+$/\1xvda/" ${vol_mnt}/boot/grub/device.map + + umount ${vol_mnt} + fi +fi ## create a snapshot of the volume snap_id=$( aws ec2 create-snapshot --volume-id ${vol_id} --description "root image for ${name}" | jq -r .SnapshotId ) From cbea85923ca554e17f735960246e52d17fa48541 Mon Sep 17 00:00:00 2001 From: Nick Lloyd Date: Wed, 2 Jul 2014 13:45:52 -0400 Subject: [PATCH 17/37] create-ami.sh now prints out its args before executing, for debugging --- utils/create-ami.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index f769bd3..5de3c1c 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -36,6 +36,15 @@ if [ $# -eq 5 ]; then fi fi +echo "executing with..." +echo "config: ${config}" +echo "ami_name: ${ami_name}" +echo "block_dev: ${block_dev}" +echo "vol_id: ${vol_id}" +echo "virt_type: ${virt_type}" +echo "kernel_id: ${kernel_id}" +echo "root_device: ${root_device}" + ## change to a well-known directory; doesn't have to make sense, just has to be ## consistent. cd "$( dirname ${config} )" From a4e48f34674e37f8b9e7ec1517304aa59c006fa2 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 14:57:12 -0400 Subject: [PATCH 18/37] reformat register-image command --- utils/create-ami.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 5de3c1c..cf9433a 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -149,6 +149,15 @@ done ## kernel-id hard-coded ## see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html ## fuck me, bash space escaping is a pain in the ass. -image_id=$( aws ec2 register-image ${kernel_id} --architecture x86_64 --name "${ami_name}" --root-device-name /dev/sda1 --block-device-mappings "[{\"DeviceName\":\"${root_device}\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" ${virt_type} | jq -r .ImageId ) +image_id=$( \ + aws ec2 register-image \ + ${kernel_id} \ + --architecture x86_64 \ + --name "${ami_name}" \ + --root-device-name /dev/sda1 \ + --block-device-mappings "[{\"DeviceName\":\"${root_device}\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" \ + ${virt_type} \ + | jq -r .ImageId +) echo "created AMI with id ${image_id}" From 09e0422a8e31d0641f4daefe52bde8ab98c03407 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 14:59:06 -0400 Subject: [PATCH 19/37] Check ami_name for length --- utils/create-ami.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index cf9433a..33554b4 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -45,6 +45,19 @@ echo "virt_type: ${virt_type}" echo "kernel_id: ${kernel_id}" echo "root_device: ${root_device}" +## A client error (InvalidAMIName.Malformed) occurred when calling the +## RegisterImage operation: AMI names must be between 3 and 128 characters long, +## and may contain letters, numbers, '(', ')', '.', '-', '/' and '_' +if [ ${#ami_name} -lt 3 ] || [ ${#ami_name} -gt 128 ]; then + echo "illegal length for ami_name; must be >= 3, <= 128" + exit 1 +fi + +# if echo $ami_name | egrep -q '[^a-z0-9 ()./_-]' ; then +# echo "illegal characters in ami_name; must be [a-z0-9 ()./_-]" +# exit 1 +# fi + ## change to a well-known directory; doesn't have to make sense, just has to be ## consistent. cd "$( dirname ${config} )" From 173a061d4c61e38d1eaa378c38ff908d381caa7f Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 14:59:29 -0400 Subject: [PATCH 20/37] patch is required (sadly) --- utils/create-ami.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 33554b4..89045d2 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -71,6 +71,7 @@ which curl >/dev/null 2>&1 || die "need curl" which jq >/dev/null 2>&1 || die "need jq" which e2fsck >/dev/null 2>&1 || die "need e2fsck" which resize2fs >/dev/null 2>&1 || die "need resize2fs" +which patch >/dev/null 2>&1 || die "need patch" rpm -q python-imgcreate >/dev/null 2>&1 || die "need python-imgcreate package" ## the block device must exist From 4e59fd15be8f60619583e872632f768b1618c6e5 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 15:05:47 -0400 Subject: [PATCH 21/37] Don't rely on external source for diff --- utils/create-ami.sh | 7 +++---- utils/grub-install.diff | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 utils/grub-install.diff diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 89045d2..310465c 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -130,10 +130,9 @@ if [ $# -eq 5 ]; then # patch grub-install then install grub on the volume # https://bugs.archlinux.org/task/30241 for where and why for the patch - curl -f -L -o /tmp/grub-install.diff https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff - - which patch >/dev/null || yum install -y patch - patch --no-backup-if-mismatch -N -p0 -i /tmp/grub-install.diff /sbin/grub-install + ## https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff + + patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/grub-install.diff /sbin/grub-install # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) vol_mnt="/mnt/ebs_vol" diff --git a/utils/grub-install.diff b/utils/grub-install.diff new file mode 100644 index 0000000..db2bbe1 --- /dev/null +++ b/utils/grub-install.diff @@ -0,0 +1,18 @@ +--- grub-install.orig 2014-01-17 20:18:08.326272350 +0000 ++++ grub-install 2014-01-17 20:18:59.568094231 +0000 +@@ -104,6 +104,7 @@ + grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | + sed -e 's%\([shv]d[a-z]\)[0-9]*$%\1%' \ + -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \ ++ -e 's%\(xvd[a-z]\)[0-9]*$%\1%' \ + -e 's%\(fd[0-9]*\)$%\1%' \ + -e 's%/part[0-9]*$%/disc%' \ + -e 's%\(c[0-7]d[0-9]*\).*$%\1%' \ +@@ -114,6 +115,7 @@ + grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | + sed -e 's%.*/[shv]d[a-z]\([0-9]*\)$%\1%' \ + -e 's%.*d[0-9]*p%%' \ ++ -e 's%.*/xvd[a-z]\([0-9]*\)$%\1%' \ + -e 's%.*/fd[0-9]*$%%' \ + -e 's%.*/floppy/[0-9]*$%%' \ + -e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \ From 676a4e8a4cbb01da10d18f7733cfe0a5b8f394cd Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 15:07:09 -0400 Subject: [PATCH 22/37] Only patch grub-install once Make this script more re-run-able --- utils/create-ami.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 310465c..a03cd39 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -131,8 +131,12 @@ if [ $# -eq 5 ]; then # patch grub-install then install grub on the volume # https://bugs.archlinux.org/task/30241 for where and why for the patch ## https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff - - patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/grub-install.diff /sbin/grub-install + if [ ! -e /sbin/grub-install.orig ]; then + cp /sbin/grub-install /sbin/grub-install.orig + + ## only patch once + patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/grub-install.diff /sbin/grub-install + fi # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) vol_mnt="/mnt/ebs_vol" From dc39b62d7aaf1b35585dd9c11097703850b76f14 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 15:08:27 -0400 Subject: [PATCH 23/37] Who knows what black magic has been performed on this volume previously! --- utils/create-ami.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index a03cd39..ea10fc5 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -112,6 +112,9 @@ sfdisk ${block_dev} << EOF ; EOF +## reread partition table +hdparm -z ${block_dev} + ## write image to volume dd if=${dest_img} of=${block_dev}1 conv=fsync oflag=sync bs=8k From 64881ed83e5e767adfedc4802deecf3a4721c340 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 15:11:38 -0400 Subject: [PATCH 24/37] Normalize reference to ${block_dev}1 --- utils/create-ami.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index ea10fc5..78de07d 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -116,16 +116,17 @@ EOF hdparm -z ${block_dev} ## write image to volume -dd if=${dest_img} of=${block_dev}1 conv=fsync oflag=sync bs=8k +img_target_dev="${block_dev}1" +dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k ## force-check the filesystem; re-write the image if it fails -if ! fsck.ext4 -n -f ${block_dev}1 ; then - dd if=${dest_img} of=${block_dev}1 conv=fsync oflag=sync bs=8k - fsck.ext4 -n -f ${block_dev}1 +if ! fsck.ext4 -n -f ${img_target_dev} ; then + dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k + fsck.ext4 -n -f ${img_target_dev} fi ## resize the filesystem -resize2fs ${block_dev}1 +resize2fs ${img_target_dev} if [ $# -eq 5 ]; then if [ "${5}" == "hvm" ]; then @@ -144,7 +145,7 @@ if [ $# -eq 5 ]; then # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) vol_mnt="/mnt/ebs_vol" mkdir -p ${vol_mnt} - mount -t ext4 ${block_dev}1 ${vol_mnt} + mount -t ext4 ${img_target_dev} ${vol_mnt} # make ${vol_mnt}/boot/grub/device.map with contents "(hd0) ${block_dev}" because otherwise grub-install isn't happy, even with --recheck echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map From b3b8373a86e55a23e665526140e5bff6073ad918 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 16:49:04 -0400 Subject: [PATCH 25/37] fixup 676a4e8a4cbb01da10d18f7733cfe0a5b8f394cd --- utils/create-ami.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 78de07d..539ff64 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -139,7 +139,7 @@ if [ $# -eq 5 ]; then cp /sbin/grub-install /sbin/grub-install.orig ## only patch once - patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/grub-install.diff /sbin/grub-install + patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/utils/grub-install.diff /sbin/grub-install fi # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) From 0456ae61521be9b0ead8fa9e308c3f85c69f51eb Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 16:55:19 -0400 Subject: [PATCH 26/37] fixup 64881ed83e5e767adfedc4802deecf3a4721c340 --- utils/create-ami.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 539ff64..c4d539c 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -23,6 +23,8 @@ cachedir="${_basedir}/cache" config="$( readlink -f ${1} )" ami_name="${2}" block_dev="${3}" +img_target_dev="${block_dev}1" + vol_id="${4}" virt_type="" kernel_id="--kernel-id aki-919dcaf8" @@ -116,7 +118,7 @@ EOF hdparm -z ${block_dev} ## write image to volume -img_target_dev="${block_dev}1" +echo "writing image to ${img_target_dev}" dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k ## force-check the filesystem; re-write the image if it fails From cc71b6d80f2971bf0610110646293224ab70f715 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Fri, 1 Aug 2014 16:57:16 -0400 Subject: [PATCH 27/37] Comments and hvm root device name Per the block-device-mappings.html doc. --- utils/create-ami.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index c4d539c..960597b 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -27,14 +27,20 @@ img_target_dev="${block_dev}1" vol_id="${4}" virt_type="" -kernel_id="--kernel-id aki-919dcaf8" +kernel_id="--kernel-id aki-919dcaf8" ## specific to us-east-1! + +## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html root_device="/dev/sda" + if [ $# -eq 5 ]; then virt_type="--virtualization-type ${5}" + if [ "${5}" == "hvm" ]; then + ## kernel id only applies for paravirtualized instances kernel_id="" - # need to figure out why we need the 1 at the end... - root_device="/dev/sda1" + + ## the root device for the block device mapping + root_device="/dev/xvda" fi fi @@ -123,6 +129,7 @@ dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k ## force-check the filesystem; re-write the image if it fails if ! fsck.ext4 -n -f ${img_target_dev} ; then + echo "well, that didn't work; trying again" dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k fsck.ext4 -n -f ${img_target_dev} fi @@ -177,7 +184,7 @@ image_id=$( \ ${kernel_id} \ --architecture x86_64 \ --name "${ami_name}" \ - --root-device-name /dev/sda1 \ + --root-device-name ${root_device} \ --block-device-mappings "[{\"DeviceName\":\"${root_device}\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" \ ${virt_type} \ | jq -r .ImageId From f1432fe4819b74a2c3ab6e0de4810305d0da1664 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Sat, 2 Aug 2014 07:14:06 -0400 Subject: [PATCH 28/37] Bail if AMI with same name already exists --- utils/create-ami.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 960597b..fe6b385 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -1,7 +1,5 @@ #!/bin/bash -## @todo check if ami name already exists - set -e set -u # set -x @@ -94,6 +92,10 @@ export AWS_DEFAULT_REGION="$( curl -s http://169.254.169.254/latest/meta-data/pl [ -n "${AWS_ACCESS_KEY_ID}" ] || die "AWS_ACCESS_KEY_ID not set" [ -n "${AWS_SECRET_ACCESS_KEY}" ] || die "AWS_SECRET_ACCESS_KEY not set" +if [ "$( aws ec2 describe-images --filters "Name=name,Values=${ami_name}" | jq -r '.Images | length' )" -ne 0 ]; then + die "AMI with that name already exists!" +fi + if [ "$( aws ec2 describe-volumes --volume-ids ${vol_id} | jq -r .Volumes[].Attachments[].InstanceId )" != "${my_instance_id}" ]; then die "volume ${vol_id} is not attached to this instance!" fi From a45f0285a07e60d963dcc5bb125fd84222cb6a1f Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Thu, 4 Sep 2014 16:59:36 -0400 Subject: [PATCH 29/37] CentOS 7 prep * Replace sfdisk with parted * also generate some json --- utils/create-ami.sh | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index fe6b385..26a1b9b 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -114,13 +114,16 @@ fi dd if=/dev/zero of=${block_dev} bs=8M count=10 conv=fsync oflag=sync sync;sync;sync +## reread partition table +hdparm -z ${block_dev} + ## partition volume -sfdisk ${block_dev} << EOF -0,,83,* -; -; -; -EOF +## http://telinit0.blogspot.com/2011/12/scripting-parted.html +## need to leave more space for grub; start partition on 2nd cylinder +## http://serverfault.com/questions/523985/fixing-a-failed-grub-upgrade-on-raid +parted ${block_dev} --script -- mklabel msdos +parted ${block_dev} --script -- mkpart primary ext2 1 -1 ## validated by running grub2-install +parted ${block_dev} --script -- set 1 boot on ## reread partition table hdparm -z ${block_dev} @@ -137,6 +140,7 @@ if ! fsck.ext4 -n -f ${img_target_dev} ; then fi ## resize the filesystem +e2fsck -f ${img_target_dev} resize2fs ${img_target_dev} if [ $# -eq 5 ]; then @@ -193,3 +197,10 @@ image_id=$( \ ) echo "created AMI with id ${image_id}" + +{ + echo "{" + echo " \"snapshot_id\": \"${snap_id}\", " + echo " \"ami_id\": \"${image_id}\"" + echo "}" +} > "${config}.json" From 143091975444da10d5f146c89a1b64b94ab69c97 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Mon, 8 Sep 2014 21:24:15 -0400 Subject: [PATCH 30/37] Add utility scripts for building images in Docker This allows for building images for distributions regardless of the host you're building them on. --- .gitignore | 1 + utils/BUILDING_IN_DOCKER.md | 32 +++++++++++++++++++++ utils/Dockerfile.centos6 | 8 ++++++ utils/Dockerfile.fedora20 | 11 ++++++++ utils/build_in_docker.sh | 56 +++++++++++++++++++++++++++++++++++++ utils/create-ami.sh | 6 +--- 6 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 utils/BUILDING_IN_DOCKER.md create mode 100644 utils/Dockerfile.centos6 create mode 100644 utils/Dockerfile.fedora20 create mode 100755 utils/build_in_docker.sh diff --git a/.gitignore b/.gitignore index 41f0c71..17c08b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.egg-info dist build +work/ diff --git a/utils/BUILDING_IN_DOCKER.md b/utils/BUILDING_IN_DOCKER.md new file mode 100644 index 0000000..a548744 --- /dev/null +++ b/utils/BUILDING_IN_DOCKER.md @@ -0,0 +1,32 @@ +Since `ami_creator` uses the yum on the host system to build an image, you can +run into problems if the host and target distributions don't agree. For +example, CentOS 7 packages use xz compression, but that's not available to yum +on CentOS 6. And it seems plausible that building a CentOS 6 image on CentOS 7 +would result in an RPM database that can't be read by a live CentOS 6 instance. + +Fortunately, we have Docker. + +## `build_in_docker.sh` + +Usage: + + build_in_docker.sh + +`host distro` is matched against the corresponding `Dockerfile.?` in this +directory. `../work/build/.img` is created, which can then be used for an +S3-backed AMI, or written to an EBS volume to be snapshotted and registered as +an EBS-backed AMI. + +## CentOS 6 + +Build CentOS 6 images using a CentOS 6 host environment. + + ./build_in_docker.sh centos6 /path/to/centos6.ks centos6 + +## CentOS 7 + +Build CentOS 7 images using a _Fedora 20_ host environment. CentOS 7 doesn't +have the required `python-imgcreate` package available, either in the base +repository or in EPEL. + + ./build_in_docker.sh fedora20 /path/to/centos7.ks centos7 diff --git a/utils/Dockerfile.centos6 b/utils/Dockerfile.centos6 new file mode 100644 index 0000000..7a481d0 --- /dev/null +++ b/utils/Dockerfile.centos6 @@ -0,0 +1,8 @@ +# -*- Dockerfile -*- +FROM centos:centos6 + +RUN yum -y localinstall http://mirror.pnl.gov/epel/6/i386/epel-release-6-8.noarch.rpm +RUN yum -y install python-imgcreate + +VOLUME [ "/srv/work" ] +WORKDIR /tmp diff --git a/utils/Dockerfile.fedora20 b/utils/Dockerfile.fedora20 new file mode 100644 index 0000000..5178f1d --- /dev/null +++ b/utils/Dockerfile.fedora20 @@ -0,0 +1,11 @@ +# -*- Dockerfile -*- + +## "xz compression not available" from yum building on centos6 +## python-imgcreate not available on centos7 +## fedora:20 is the current stable version, and python-imgcreate *is* available +FROM fedora:20 + +RUN yum -y install python-imgcreate + +VOLUME [ "/srv/work" ] +WORKDIR /tmp diff --git a/utils/build_in_docker.sh b/utils/build_in_docker.sh new file mode 100755 index 0000000..cb8637b --- /dev/null +++ b/utils/build_in_docker.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -e -u + +basedir="$( cd $( dirname $0 )/.. && /bin/pwd -P )" +workdir="${basedir}/work" + +if [ $# -ne 3 ]; then + echo "usage: $0 " + exit 1 +fi + +host_distro="$1" +kickstart_cfg="$2" +name="$3" + +docker_file="${basedir}/utils/Dockerfile.${host_distro}" +docker_image="ami_creator/${host_distro}" + +if [ ! -e "${docker_file}" ]; then + echo "unsupported host distro: ${host_distro}" + exit 1 +fi + +if [ ! -e "${kickstart_cfg}" ]; then + echo "${kickstart_cfg} does not exist" + exit 1 +fi + +kickstart_base="$( basename ${kickstart_cfg} )" +kickstart_root="$( cd $( dirname ${kickstart_cfg} ) && /bin/pwd -P )" + +mkdir -p ${workdir}/{build,cache} + +## build the image if it doesn't already exist +docker inspect ${docker_image} >/dev/null 2>&1 || \ + docker build -t ${docker_image} - < ${docker_file} + +docker run \ + -i -t \ + --rm \ + --privileged \ + --volume=${basedir}:/srv/ami-creator:ro \ + --volume=${kickstart_root}:/srv/image-config:ro \ + --volume=${workdir}:/srv/work \ + ${docker_image} \ + \ + /bin/bash -c " \ + /srv/ami-creator/ami_creator/ami_creator.py \ + -d -v \ + -c /srv/image-config/${kickstart_base} \ + -n ${name} \ + -t /tmp \ + --cache=/srv/work/cache \ + && mv ${name}.img /srv/work/build/ + " diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 26a1b9b..e382bca 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -1,7 +1,6 @@ #!/bin/bash -set -e -set -u +set -e -u # set -x function die() { @@ -13,9 +12,6 @@ function die() { _basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" -cachedir="${_basedir}/cache" -[ -d "${cachedir}" ] || mkdir "${cachedir}" - [ $# -eq 4 -o $# -eq 5 ] || die "usage: $0 []" config="$( readlink -f ${1} )" From e9e00bb68b0ae286f0f47a06c6cffb2f73d679f2 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Mon, 8 Sep 2014 21:44:52 -0400 Subject: [PATCH 31/37] Do not generate image, use pre-generated one Plus other cleanup --- utils/create-ami.sh | 59 ++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index e382bca..d229a00 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -9,37 +9,34 @@ function die() { } [ $EUID -eq 0 ] || die "must be root" +[ $# -eq 5 ] || die "usage: $0 " _basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" -[ $# -eq 4 -o $# -eq 5 ] || die "usage: $0 []" - -config="$( readlink -f ${1} )" +img="$( readlink -f ${1} )" ami_name="${2}" block_dev="${3}" img_target_dev="${block_dev}1" - vol_id="${4}" -virt_type="" -kernel_id="--kernel-id aki-919dcaf8" ## specific to us-east-1! +virt_type="${5}" -## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html -root_device="/dev/sda" +[ "${virt_type}" = "hvm" ] || [ "${virt_type}" = "paravirtual" ] || die "virtualization type must be hvm or paravirtual" -if [ $# -eq 5 ]; then - virt_type="--virtualization-type ${5}" +if [ "${virt_type}" == "paravirtual" ]; then + kernel_id="--kernel-id aki-919dcaf8" ## specific to us-east-1! - if [ "${5}" == "hvm" ]; then - ## kernel id only applies for paravirtualized instances - kernel_id="" - - ## the root device for the block device mapping - root_device="/dev/xvda" - fi + ## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + root_device="/dev/sda" +elif [ "${virt_type}" == "hvm" ]; then + ## kernel id only applies for paravirtualized instances + kernel_id="" + + ## the root device for the block device mapping + root_device="/dev/xvda" fi echo "executing with..." -echo "config: ${config}" +echo "img: ${img}" echo "ami_name: ${ami_name}" echo "block_dev: ${block_dev}" echo "vol_id: ${vol_id}" @@ -60,13 +57,6 @@ fi # exit 1 # fi -## change to a well-known directory; doesn't have to make sense, just has to be -## consistent. -cd "$( dirname ${config} )" - -name="$( basename $config | sed -r -e 's#\.[^.]+$##g' )" -dest_img="${name}.img" - ## check for required programs which aws >/dev/null 2>&1 || die "need aws" which curl >/dev/null 2>&1 || die "need curl" @@ -74,7 +64,6 @@ which jq >/dev/null 2>&1 || die "need jq" which e2fsck >/dev/null 2>&1 || die "need e2fsck" which resize2fs >/dev/null 2>&1 || die "need resize2fs" which patch >/dev/null 2>&1 || die "need patch" -rpm -q python-imgcreate >/dev/null 2>&1 || die "need python-imgcreate package" ## the block device must exist [ -e "${block_dev}" ] || die "${block_dev} does not exist" @@ -96,13 +85,6 @@ if [ "$( aws ec2 describe-volumes --volume-ids ${vol_id} | jq -r .Volumes[].Atta die "volume ${vol_id} is not attached to this instance!" fi -## create the image -if [ ! -e "${dest_img}" ]; then - ${_basedir}/ami_creator/ami_creator.py -c "${config}" -n "${name}" -else - echo "$dest_img already exists; not recreating" -fi - ## ok, this is fucked up. the dd writing the image to the volume is exiting ## with zero, but the data isn't getting written. Bringing out the big guns. @@ -126,12 +108,12 @@ hdparm -z ${block_dev} ## write image to volume echo "writing image to ${img_target_dev}" -dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k +dd if=${img} of=${img_target_dev} conv=fsync oflag=sync bs=8k ## force-check the filesystem; re-write the image if it fails if ! fsck.ext4 -n -f ${img_target_dev} ; then echo "well, that didn't work; trying again" - dd if=${dest_img} of=${img_target_dev} conv=fsync oflag=sync bs=8k + dd if=${img} of=${img_target_dev} conv=fsync oflag=sync bs=8k fsck.ext4 -n -f ${img_target_dev} fi @@ -171,7 +153,7 @@ if [ $# -eq 5 ]; then fi ## create a snapshot of the volume -snap_id=$( aws ec2 create-snapshot --volume-id ${vol_id} --description "root image for ${name}" | jq -r .SnapshotId ) +snap_id=$( aws ec2 create-snapshot --volume-id ${vol_id} --description "root image for ${ami_name}" | jq -r .SnapshotId ) while [ $( aws ec2 describe-snapshots --snapshot-ids ${snap_id} | jq -r .Snapshots[].State ) != "completed" ]; do echo "waiting for snapshot ${snap_id} to complete" @@ -188,15 +170,16 @@ image_id=$( \ --name "${ami_name}" \ --root-device-name ${root_device} \ --block-device-mappings "[{\"DeviceName\":\"${root_device}\",\"Ebs\":{\"SnapshotId\":\"${snap_id}\",\"VolumeSize\":10}},{\"DeviceName\":\"/dev/sdb\",\"VirtualName\":\"ephemeral0\"}]" \ - ${virt_type} \ + --virtualization-type ${virt_type} \ | jq -r .ImageId ) echo "created AMI with id ${image_id}" +## create json file next to input image { echo "{" echo " \"snapshot_id\": \"${snap_id}\", " echo " \"ami_id\": \"${image_id}\"" echo "}" -} > "${config}.json" +} > "${img%.*}.json" From 2363c03a5bd20706e950dc41495377c8f3b193a0 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 08:00:48 -0400 Subject: [PATCH 32/37] Add support for grub2 --- utils/create-ami.sh | 118 ++++++++++++++++++++++++---------------- utils/grub-install.diff | 18 ------ 2 files changed, 71 insertions(+), 65 deletions(-) delete mode 100644 utils/grub-install.diff diff --git a/utils/create-ami.sh b/utils/create-ami.sh index d229a00..4ba32a7 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -8,8 +8,12 @@ function die() { exit 1 } +function usage() { + die "usage: $0 []" +} + [ $EUID -eq 0 ] || die "must be root" -[ $# -eq 5 ] || die "usage: $0 " +[ $# -eq 5 ] || [ $# -eq 6 ] || usage _basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" @@ -19,15 +23,28 @@ block_dev="${3}" img_target_dev="${block_dev}1" vol_id="${4}" virt_type="${5}" +shift 5 [ "${virt_type}" = "hvm" ] || [ "${virt_type}" = "paravirtual" ] || die "virtualization type must be hvm or paravirtual" -if [ "${virt_type}" == "paravirtual" ]; then - kernel_id="--kernel-id aki-919dcaf8" ## specific to us-east-1! +if [ "${virt_type}" = "hvm" ] && [ $# -ne 1 ]; then + usage +fi + +if [ "${virt_type}" = "paravirtual" ]; then + grub_ver="not applicable" + + ## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedKernels.html + ## pv-grub-hd0_1.04-x86_64.gz; specific to us-east-1! + kernel_id="--kernel-id aki-919dcaf8" ## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html root_device="/dev/sda" -elif [ "${virt_type}" == "hvm" ]; then +elif [ "${virt_type}" = "hvm" ]; then + grub_ver="${1}" + + [ "${grub_ver}" = "grub0" ] || [ "${grub_ver}" = "grub2" ] || die "grub version must be grub0 or grub2" + ## kernel id only applies for paravirtualized instances kernel_id="" @@ -35,15 +52,6 @@ elif [ "${virt_type}" == "hvm" ]; then root_device="/dev/xvda" fi -echo "executing with..." -echo "img: ${img}" -echo "ami_name: ${ami_name}" -echo "block_dev: ${block_dev}" -echo "vol_id: ${vol_id}" -echo "virt_type: ${virt_type}" -echo "kernel_id: ${kernel_id}" -echo "root_device: ${root_device}" - ## A client error (InvalidAMIName.Malformed) occurred when calling the ## RegisterImage operation: AMI names must be between 3 and 128 characters long, ## and may contain letters, numbers, '(', ')', '.', '-', '/' and '_' @@ -57,13 +65,22 @@ fi # exit 1 # fi +echo "executing with..." +echo " img: ${img}" +echo " ami_name: ${ami_name}" +echo " block_dev: ${block_dev}" +echo " vol_id: ${vol_id}" +echo " virt_type: ${virt_type}" +echo " grub_ver: ${grub_ver}" +echo " kernel_id: ${kernel_id}" +echo " root_device: ${root_device}" + ## check for required programs -which aws >/dev/null 2>&1 || die "need aws" -which curl >/dev/null 2>&1 || die "need curl" -which jq >/dev/null 2>&1 || die "need jq" -which e2fsck >/dev/null 2>&1 || die "need e2fsck" +which aws >/dev/null 2>&1 || die "need aws" +which curl >/dev/null 2>&1 || die "need curl" +which jq >/dev/null 2>&1 || die "need jq" +which e2fsck >/dev/null 2>&1 || die "need e2fsck" which resize2fs >/dev/null 2>&1 || die "need resize2fs" -which patch >/dev/null 2>&1 || die "need patch" ## the block device must exist [ -e "${block_dev}" ] || die "${block_dev} does not exist" @@ -74,7 +91,7 @@ my_instance_id="$( curl -s http://169.254.169.254/latest/meta-data/instance-id ) ## set up/verify aws credentials and settings ## http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html export AWS_DEFAULT_REGION="$( curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's#.$##g' )" -[ -n "${AWS_ACCESS_KEY_ID}" ] || die "AWS_ACCESS_KEY_ID not set" +[ -n "${AWS_ACCESS_KEY_ID}" ] || die "AWS_ACCESS_KEY_ID not set" [ -n "${AWS_SECRET_ACCESS_KEY}" ] || die "AWS_SECRET_ACCESS_KEY not set" if [ "$( aws ec2 describe-images --filters "Name=name,Values=${ami_name}" | jq -r '.Images | length' )" -ne 0 ]; then @@ -97,7 +114,7 @@ hdparm -z ${block_dev} ## partition volume ## http://telinit0.blogspot.com/2011/12/scripting-parted.html -## need to leave more space for grub; start partition on 2nd cylinder +## need to leave more space for grub2; start partition on 2nd cylinder ## http://serverfault.com/questions/523985/fixing-a-failed-grub-upgrade-on-raid parted ${block_dev} --script -- mklabel msdos parted ${block_dev} --script -- mkpart primary ext2 1 -1 ## validated by running grub2-install @@ -121,35 +138,42 @@ fi e2fsck -f ${img_target_dev} resize2fs ${img_target_dev} -if [ $# -eq 5 ]; then - if [ "${5}" == "hvm" ]; then - ## special hvm ami stuff, all about fixing up the bootloader - - # patch grub-install then install grub on the volume - # https://bugs.archlinux.org/task/30241 for where and why for the patch - ## https://raw.githubusercontent.com/mozilla/build-cloud-tools/master/ami_configs/centos-6-x86_64-hvm-base/grub-install.diff - if [ ! -e /sbin/grub-install.orig ]; then - cp /sbin/grub-install /sbin/grub-install.orig - - ## only patch once - patch --no-backup-if-mismatch -N -p0 -i ${_basedir}/utils/grub-install.diff /sbin/grub-install - fi - - # mount the volume so we can install grub and fix the /boot/grub/device.map file (otherwise grub can't find the device even with --recheck) - vol_mnt="/mnt/ebs_vol" - mkdir -p ${vol_mnt} - mount -t ext4 ${img_target_dev} ${vol_mnt} - - # make ${vol_mnt}/boot/grub/device.map with contents "(hd0) ${block_dev}" because otherwise grub-install isn't happy, even with --recheck - echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map +if [ "${virt_type}" = "hvm" ]; then + ## install grub bootloader for hvm instances; they boot like real hardware - grub-install --root-directory=${vol_mnt} --no-floppy ${block_dev} - - # ok grub is installed, now redo device.map for booting the actual volume... because otherwise this bloody well doesn't work - sed -i -r "s/^(\(hd0\)\s+\/dev\/)[a-z]+$/\1xvda/" ${vol_mnt}/boot/grub/device.map - - umount ${vol_mnt} + # mount the volume so + vol_mnt="/mnt/ebs_vol" + mkdir -p ${vol_mnt} + mount -t ext4 ${img_target_dev} ${vol_mnt} + + ## mount special filesystems so the chroot is like running in a real + ## instance. hopefully this is pretty distro- and kernel-agnostic… + mount -t proc none ${vol_mnt}/proc + mount -o bind /dev ${vol_mnt}/dev + mount -o bind /sys ${vol_mnt}/sys + + if [ ${grub_ver} = "grub0" ]; then + # make ${vol_mnt}/boot/grub/device.map with contents + # (hd0) ${block_dev} + # because otherwise grub-install isn't happy, even with --recheck + echo "(hd0) ${block_dev}" > ${vol_mnt}/boot/grub/device.map + + ## also need to create fake /etc/mtab so grub-install can figure out + ## what device / is + echo "${img_target_dev} / ext4 rw,relatime 0 0" > ${vol_mnt}/etc/mtab + + chroot ${vol_mnt} /sbin/grub-install --no-floppy ${block_dev} + + rm -f ${vol_mnt}/etc/mtab ${vol_mnt}/boot/grub/device.map + elif [ ${grub_ver} = "grub2" ]; then + ## *aaah* so much simpler! + + ## @todo move grub2-mkconfig to ami-creator (add grub2 support) + chroot ${vol_mnt} /sbin/grub2-mkconfig -o /boot/grub2/grub.cfg + chroot ${vol_mnt} /sbin/grub2-install ${block_dev} fi + + umount ${vol_mnt}/{proc,dev,sys,} fi ## create a snapshot of the volume diff --git a/utils/grub-install.diff b/utils/grub-install.diff deleted file mode 100644 index db2bbe1..0000000 --- a/utils/grub-install.diff +++ /dev/null @@ -1,18 +0,0 @@ ---- grub-install.orig 2014-01-17 20:18:08.326272350 +0000 -+++ grub-install 2014-01-17 20:18:59.568094231 +0000 -@@ -104,6 +104,7 @@ - grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | - sed -e 's%\([shv]d[a-z]\)[0-9]*$%\1%' \ - -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \ -+ -e 's%\(xvd[a-z]\)[0-9]*$%\1%' \ - -e 's%\(fd[0-9]*\)$%\1%' \ - -e 's%/part[0-9]*$%/disc%' \ - -e 's%\(c[0-7]d[0-9]*\).*$%\1%' \ -@@ -114,6 +115,7 @@ - grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | - sed -e 's%.*/[shv]d[a-z]\([0-9]*\)$%\1%' \ - -e 's%.*d[0-9]*p%%' \ -+ -e 's%.*/xvd[a-z]\([0-9]*\)$%\1%' \ - -e 's%.*/fd[0-9]*$%%' \ - -e 's%.*/floppy/[0-9]*$%%' \ - -e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \ From 2c26cb173a326ec5c3a52a3368ea5b5572e9ddb1 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 11:20:50 -0400 Subject: [PATCH 33/37] Ensure image exists --- utils/create-ami.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 4ba32a7..af7b5c9 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -17,6 +17,8 @@ function usage() { _basedir="$( cd $( dirname -- $0 )/.. && /bin/pwd )" +[ -e "${1}" ] || die "$1 doesn't exist" + img="$( readlink -f ${1} )" ami_name="${2}" block_dev="${3}" From 4760f8f9ed33d62729304721dbf7c629e1db65c5 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 11:21:16 -0400 Subject: [PATCH 34/37] Ensure all required tools are installed --- utils/create-ami.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index af7b5c9..b1f8933 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -83,6 +83,8 @@ which curl >/dev/null 2>&1 || die "need curl" which jq >/dev/null 2>&1 || die "need jq" which e2fsck >/dev/null 2>&1 || die "need e2fsck" which resize2fs >/dev/null 2>&1 || die "need resize2fs" +which hdparm >/dev/null 2>&1 || die "need hdparm" +which parted >/dev/null 2>&1 || die "need parted" ## the block device must exist [ -e "${block_dev}" ] || die "${block_dev} does not exist" From aa7a3ef9c925d0debe530504baf8ebb8b30b8c0b Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 11:21:40 -0400 Subject: [PATCH 35/37] Retry partition table re-reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saw a transient error… --- utils/create-ami.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index b1f8933..049415c 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -114,7 +114,21 @@ dd if=/dev/zero of=${block_dev} bs=8M count=10 conv=fsync oflag=sync sync;sync;sync ## reread partition table -hdparm -z ${block_dev} +## I've observed this failing when running this script back-to-back; try it a +## couple of times… +reread_count=0 +reread_success=0 +while [ $reread_count -lt 3 ]; do + if hdparm -z ${block_dev} ; then + reread_success=1 + break + fi + + sleep 5 + reread_count=$(( reread_count + 1 )) +done + +[ $reread_success -eq 1 ] || die "failed to reread partition table" ## partition volume ## http://telinit0.blogspot.com/2011/12/scripting-parted.html From 9a7c7d3eae17681d0fe5dd11c956f26e2ea0e4b1 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 11:22:03 -0400 Subject: [PATCH 36/37] Include virtualization type in json --- utils/create-ami.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/create-ami.sh b/utils/create-ami.sh index 049415c..d88710e 100755 --- a/utils/create-ami.sh +++ b/utils/create-ami.sh @@ -221,6 +221,7 @@ echo "created AMI with id ${image_id}" ## create json file next to input image { echo "{" + echo " \"virt_type\": \"${virt_type}\", " echo " \"snapshot_id\": \"${snap_id}\", " echo " \"ami_id\": \"${image_id}\"" echo "}" From a2471315ad10314ffcacba25a1e003a2cb674f00 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 9 Sep 2014 22:39:45 -0400 Subject: [PATCH 37/37] Reduce verbosity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But only a little, really… --- utils/build_in_docker.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/build_in_docker.sh b/utils/build_in_docker.sh index cb8637b..830df16 100755 --- a/utils/build_in_docker.sh +++ b/utils/build_in_docker.sh @@ -47,7 +47,6 @@ docker run \ \ /bin/bash -c " \ /srv/ami-creator/ami_creator/ami_creator.py \ - -d -v \ -c /srv/image-config/${kickstart_base} \ -n ${name} \ -t /tmp \