Skip to content

Instantly share code, notes, and snippets.

@matsuu
Created March 15, 2011 14:40
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matsuu/870789 to your computer and use it in GitHub Desktop.
Save matsuu/870789 to your computer and use it in GitHub Desktop.
#!/bin/sh
#===============================================================================
#
# USAGE
# =====
#
# Get your X.509 Certificates and Private Key
# -------------------------------------------
# http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key
# Download your cert-*.pem and pk-*.pem.
#
# Launch Amazon Linux AMI instance
# --------------------------------
# If you want:
# - Gentoo x86 AMI, select 'Basic 32-bit Amazon Linux AMI'.
# - Gentoo amd64 AMI, select 'Basic 64-bit Amazon Linux AMI'.
#
# Copy this program and X.509 Certificates to your AMI instance
# -------------------------------------------------------------
# $ scp -i your_ssh_key.pem create_gentoo_ami.sh ec2-user@<your.instance>
# $ scp -i your_ssh_key.pem pk-*.pem ec2-user@<your.instance>
# $ scp -i your_ssh_key.pem cert-*.pem ec2-user@<your.instance>
#
# Login your AMI instance and execute this program
# ------------------------------------------------
# Login as ec2-user.
#
# $ ssh -i your_ssh_key.pem ec2-user@<your.instance>
# $ sudo sh create_gentoo_ami.sh
# ...
# Finished!
#
# Launch your Gentoo instance
# ---------------------------
# You can boot Gentoo instance from IMAGES/AMIs.
#
# Login your Gentoo instance
# --------------------------
# Login as root.
#
# $ ssh -i your_ssh_key.pem root@<your.instance>
#
# Emerge logger and cron
# ----------------------
# # emerge --sync
# # emerge syslog-ng
# # rc-update add syslog-ng default
# # emerge vixie-cron
# # rc-update add vixie-cron default
#
#
#===============================================================================
#AMI_NAME_SUFFIX="matsuu@gentoo.org"
EC2_PRIVATE_KEY="`ls /home/ec2-user/pk-*.pem | head -n 1`"
EC2_CERT="`ls /home/ec2-user/cert-*.pem | head -n 1`"
#EC2_PRIVATE_KEY="/home/ec2-user/pk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem"
#EC2_CERT="/home/ec2-user/cert-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem"
# ftp:// is required for glob
GENTOO_MIRROR="ftp://ftp.iij.ad.jp/pub/linux/gentoo"
# Set AMI HDD size. default is 8GB
VOLUME_SIZE=8
# Set timeszone. cf. /usr/share/zoneinfo/
TIMEZONE="UTC"
#TIMEZONE="Asia/Tokyo"
#===============================================================================
die() {
echo $@
exit 1
}
EC2_INSTANCE_ID="`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`"
test -n "$EC2_INSTANCE_ID" || die 'cannot obtain instance-id'
EC2_KERNEL_ID="`wget -q -O - http://169.254.169.254/latest/meta-data/kernel-id`"
test -n "$EC2_KERNEL_ID" || die 'cannot obtain kernel-id'
EC2_AVAIL_ZONE="`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone`"
test -n "$EC2_AVAIL_ZONE" || die 'cannot obtain availability-zone'
EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\([0-9]\+\)[a-z]*\$:\\1:'`"
EC2_URL="https://ec2.${EC2_REGION}.amazonaws.com"
EC2_HOME="/opt/aws/apitools/ec2"
JAVA_HOME="/usr/lib/jvm/jre"
export EC2_PRIVATE_KEY EC2_CERT EC2_URL EC2_HOME JAVA_HOME
create_ami() {
local PROFILE=$1
local STAGE_FILE
local ESELECT_PROFILE
if [ "${PROFILE}" = "hardened" ] ; then
STAGE_FILE="hardened/stage3-${STAGE_ARCH}-hardened"
ESELECT_PROFILE="hardened/linux/${ARCH}"
elif [ "${PROFILE}" = "hardened-no-multilib" ] ; then
STAGE_FILE="hardened/stage3-${STAGE_ARCH}-hardened+nomultilib"
ESELECT_PROFILE="hardened/linux/${ARCH}/no-multilib"
elif [ "${PROFILE}" = "server" ] ; then
STAGE_FILE="stage3-${STAGE_ARCH}"
ESELECT_PROFILE="default/linux/${ARCH}/10.0/server"
elif [ "${PROFILE}" = "no-multilib" ] ; then
STAGE_FILE="stage3-${STAGE_ARCH}"
ESELECT_PROFILE="default/linux/${ARCH}/10.0/no-multilib"
fi
STAGE_TARBALL="${GENTOO_MIRROR}/releases/${ARCH}/current-stage3/${STAGE_FILE}-*.tar.bz2"
echo "create volume"
EC2_VOLUME_ID="`/opt/aws/bin/ec2-create-volume -s ${VOLUME_SIZE} -z \"${EC2_AVAIL_ZONE}\" | cut -f2`" || die "ec2-create-volume failed"
counter=0
while [ $counter -lt 60 ] ; do
echo "get volume ${EC2_VOLUME_ID} status..."
status="`/opt/aws/bin/ec2-describe-volumes ${EC2_VOLUME_ID}| cut -f6`" || die "ec2-describe-volumes failed"
echo "volume status...$status"
if [ -z "$status" ] ; then
die "ec2-describe-volumes status failed"
fi
if [ "$status" = "available" ] ; then
break
fi
sleep 1
counter=`expr $counter + 1`
done
if [ $counter -ge 60 ] ; then
die "ec2-volume-snapshots timeout"
fi
echo "attach volume ${EC2_VOLUME_ID}"
/opt/aws/bin/ec2-attach-volume "${EC2_VOLUME_ID}" -i "${EC2_INSTANCE_ID}" -d "${VOLUME_DEVICE}" || die "ec2-attach-volume failed"
counter=0
while [ $counter -lt 60 ] ; do
echo "checking ${VOLUME_DEVICE}..."
if [ -e "${VOLUME_DEVICE}" ] ; then
break
fi
sleep 3
counter=`expr $counter + 1`
done
if [ ! -e "${VOLUME_DEVICE}" ] ; then
die "${VOLUME_DEVICE} not found"
fi
mkfs.ext4 -j -L / "${VOLUME_DEVICE}" || die "mke2fs failed"
mkdir -p "${MOUNT_POINT}" || die "mkdir mountpoint failed"
mount "${VOLUME_DEVICE}" "${MOUNT_POINT}" || die "mount mountpoint failed"
cd "${MOUNT_POINT}" || die "cd mountpoint failed"
if [ ! -d "usr" ] ; then
wget "${STAGE_TARBALL}" || die "wget stage file failed"
tar jxpf stage3*.bz2 || die "unpack stage file failed"
fi
if [ ! -d "usr/portage" ] ; then
wget "${PORTAGE_SNAPSHOT}" || die "wget stage file failed"
tar jxf portage-latest.tar.bz2 -C "${MOUNT_POINT}/usr" || die "unpack stage file failed"
# sed -i -e "s/-march=[^ ]*/-march=core2/" "${MOUNT_POINT}/etc/make.conf"
echo "USE=\"\${USE} perl python\"" >> "${MOUNT_POINT}/etc/make.conf"
# echo "USE=\"\${USE} -gpm -pppd\"" >> "${MOUNT_POINT}/etc/make.conf"
fi
cp -L /etc/resolv.conf "${MOUNT_POINT}/etc/resolv.conf" || die "cp resolv.conf failed"
rsync -avz /boot/ "${MOUNT_POINT}/boot/" || die "rsync /boot failed"
rsync -avz /lib/modules/ "${MOUNT_POINT}/lib/modules/" || die "rsync /lib/modules failed"
sed -i \
-e "s/Amazon/Gentoo/" \
-e "/^kernel/s/$/ xencons=hvc0/" \
"${MOUNT_POINT}/boot/grub/grub.conf" || die "sed failed"
mount -t proc none "${MOUNT_POINT}/proc" || die "mount /proc failed"
mount -o bind /dev "${MOUNT_POINT}/dev" || die "mount /dev failed"
cat > "${MOUNT_POINT}/install.sh" <<EOF
#!/bin/sh
die() {
echo \$@
exit 1
}
/usr/sbin/env-update
source /etc/profile
emerge --sync # || die "emerge --sync failed"
eselect profile set ${ESELECT_PROFILE} || die "eselect profile failed"
if [ -n "${TIMEZONE}" ] ; then
cp "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime || die "cp localtime failed"
fi
mkdir -p /etc/portage
echo "app-admin/amazon-ec2-init ~${ARCH}" > /etc/portage/package.keywords
emerge amazon-ec2-init || die "emerge amazon tools failed"
rc-update add amazon-ec2 boot || die "rc-update amazon-ec2 failed"
depmod -a
cat > /etc/fstab << CHROOT_EOF
LABEL=/ / ext4 defaults,noatime 0 1
proc /proc proc defaults 0 0
shm /dev/shm tmpfs nodev,nosuid,noexec 0 0
CHROOT_EOF
sed -i -e 's/#rc_sys=""/rc_sys="xenU"/' /etc/rc.conf
#cat > /etc/conf.d/net << CHROOT_EOF
#config_eth0="dhcp"
#CHROOT_EOF
if [ ! -e /etc/init.d/net.eth0 ] ; then
ln -s net.lo /etc/init.d/net.eth0
fi
rc-update add net.eth0 default || die "rc-update net.eth0 failed"
#emerge syslog-ng || die "emerge syslog-ng failed"
#rc-update add syslog-ng default || die "rc-update syslog-ng failed"
#emerge vixie-cron || die "emerge vixie-cron failed"
#rc-update add vixie-cron default || die "rc-update vixie-cron failed"
rc-update add sshd default || die "rc-update sshd failed"
emerge dhcpcd || die "emerge dhcpcd failed"
# Amazon specific setting
echo "PermitRootLogin without-password" >> /etc/ssh/sshd_config || die "sshd_config setting failed"
echo "UseDNS no" >> /etc/ssh/sshd_config || die "sshd_config setting failed"
if [ -n "${TIMEZONE}" ] ; then
sed -i \
-e "/^clock=/s:=.*:=\"local\":" \
/etc/conf.d/hwclock || die "clock setting failed"
echo "${TIMEZONE}" >> /etc/timezone || die "timezone setting failed"
fi
if [ -e /etc/conf.d/local ] ; then
sed -i \
-e "/on startup/a pkill -9 nash" \
/etc/conf.d/local || die "sed /etc/conf.d/local failed"
fi
if [ -e /etc/conf.d/local.start ] ; then
echo "pkill -9 nash" >> /etc/conf.d/local.start || die "added to /etc/conf.d/local.start failed"
fi
if [ -d /etc/local.d/ ] ; then
echo "pkill -9 nash" > /etc/local.d/kill_nash.start || die "generate /etc/local.d/kill_nash.start failed"
chmod +x /etc/local.d/kill_nash.start || die "chmod /etc/local.d/kill_nash.start failed"
fi
grep -v rootfs /proc/mounts > /etc/mtab || die "override /etc/mtab failed"
cat > /etc/motd << CHROOT_EOF
At first, emerge logger and cron.
# emerge --sync
# emerge syslog-ng
# rc-update add syslog-ng default
# emerge vixie-cron
# rc-update add vixie-cron default
# rm /etc/motd
CHROOT_EOF
rm -f /usr/portage/distfiles/*
exit 0
EOF
chmod +x "${MOUNT_POINT}/install.sh" || die "chmod install.sh failed"
LANG=en_US.UTF-8 chroot "${MOUNT_POINT}" "/install.sh" || die "chroot failed"
if [ $? != 0 ] ; then
die "chroot failed"
fi
rm "${MOUNT_POINT}/install.sh" || die "rm install.sh failed"
rm "${MOUNT_POINT}/"stage3* || die "rm stage3 failed"
rm "${MOUNT_POINT}/portage-latest.tar.bz2" || die "rm portage-latest failed"
cd `dirname "${MOUNT_POINT}"`
umount "${MOUNT_POINT}/dev" "${MOUNT_POINT}/proc" "${MOUNT_POINT}" || die "umount failed"
rmdir "${MOUNT_POINT}" || die "rmdir mount_point failed"
DESCRIPTION="gentoo-${OS_BIT}-${PROFILE}-`date +%Y%m%d`${AMI_NAME_SUFFIX:+-}${AMI_NAME_SUFFIX}"
echo "create snapshot"
EC2_SNAPSHOT_ID="`/opt/aws/bin/ec2-create-snapshot -d \"${DESCRIPTION}\" \"${EC2_VOLUME_ID}\" | cut -f2`" || die "ec2-create-snapshot failed"
counter=0
while [ $counter -lt 60 ] ; do
echo "get snapshot status..."
status="`/opt/aws/bin/ec2-describe-snapshots -F snapshot-id=${EC2_SNAPSHOT_ID} | cut -f4`" || die "ec2-describe-snapshots failed"
echo "snapshot status...$status"
if [ -z "$status" ] ; then
die "ec2-describe-snapshots status failed"
fi
if [ "$status" = "completed" ] ; then
break
fi
sleep 1
counter=`expr $counter + 1`
done
if [ $counter -ge 60 ] ; then
die "ec2-describe-snapshots timeout"
fi
echo "register AMI"
/opt/aws/bin/ec2-register -n "${DESCRIPTION}" -d "Gentoo Linux ${ARCH} ${PROFILE}" -a "${EC2_ARCH}" --kernel "${EC2_KERNEL_ID}" -b "/dev/sda1=${EC2_SNAPSHOT_ID}" || die "ec2-register failed"
echo "detach volume"
/opt/aws/bin/ec2-detach-volume "${EC2_VOLUME_ID}" || die "ec2-detach-volume failed"
counter=0
while [ $counter -lt 60 ] ; do
echo "get volume ${EC2_VOLUME_ID} status..."
status="`/opt/aws/bin/ec2-describe-volumes ${EC2_VOLUME_ID}| cut -f6`" || die "ec2-describe-volumes failed"
echo "volume status...$status"
if [ -z "$status" ] ; then
die "ec2-describe-volumes status failed"
fi
if [ "$status" = "available" ] ; then
break
fi
sleep 1
counter=`expr $counter + 1`
done
/opt/aws/bin/ec2-delete-volume "${EC2_VOLUME_ID}" || die "ec2-delete-volume failed"
# echo "delete snapshot ${EC2_SNAPSHOT_ID}"
# /opt/aws/bin/ec2-delete-snapshot "${EC2_SNAPSHOT_ID}" || die "ec2-delete-snapshot failed"
}
VOLUME_DEVICE="/dev/sdb"
MOUNT_POINT="/mnt"
PORTAGE_SNAPSHOT="${GENTOO_MIRROR}/snapshots/portage-latest.tar.bz2"
AMI_ARCH="`uname -m`"
if [ "${AMI_ARCH}" = "i686" ] ; then
ARCH="x86"
STAGE_ARCH="${AMI_ARCH}"
OS_BIT=32
EC2_ARCH="i386"
create_ami server
create_ami hardened
elif [ "${AMI_ARCH}" = "x86_64" ] ; then
ARCH="amd64"
STAGE_ARCH="amd64"
OS_BIT=64
EC2_ARCH="x86_64"
create_ami server
create_ami no-multilib
create_ami hardened
create_ami hardened-no-multilib
else
die "unknown architecture"
fi
echo "Finished!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment