From 5cc195e3917043be8fad023b28766922d8e65736 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Sat, 10 Nov 2012 00:04:13 +1300 Subject: [PATCH] Bring across disk image code. --- README.md | 100 +++++++ bin/disk-image-create | 79 ++++++ docs/ci.md | 43 +++ flavours/devstack/README.md | 2 + flavours/devstack/install.d/50-user | 12 + flavours/devstack/install.d/51-grub | 12 + .../devstack/install.d/52-image-toolchain | 10 + flavours/devstack/install.d/97-haveged | 7 + .../devstack/install.d/98-baremetal-network | 26 ++ flavours/devstack/install.d/99-ssh | 8 + flavours/local-config/README.md | 2 + flavours/local-config/extra-data.d/62-ssh-key | 11 + flavours/local-config/install.d/61-http-proxy | 16 ++ flavours/local-config/install.d/62-ssh-key | 10 + flavours/nova-vm/README.md | 1 + flavours/nova-vm/first-boot.d/05-ipforwarding | 5 + flavours/nova-vm/first-boot.d/10-ntp | 11 + flavours/nova-vm/first-boot.d/15-mysql | 43 +++ flavours/nova-vm/first-boot.d/20-rabbitmq | 8 + flavours/nova-vm/first-boot.d/30-keystone | 19 ++ .../nova-vm/first-boot.d/31-keystone-data | 72 +++++ .../first-boot.d/32-keystone-endpoints | 68 +++++ flavours/nova-vm/first-boot.d/40-glance | 35 +++ flavours/nova-vm/first-boot.d/50-nova | 85 ++++++ flavours/nova-vm/first-boot.d/defaults | 27 ++ .../nova-vm/install.d/05-controller-code-deps | 8 + .../install.d/10-controller-openstack-deps | 9 + flavours/nova-vm/install.d/20-dkms-iscsi | 27 ++ flavours/nova-vm/install.d/99-clean-apt | 10 + flavours/salt/README.md | 1 + flavours/salt/install.d/10-salt | 7 + flavours/salt/pre-install.d/10-salt | 8 + flavours/swift/README.md | 1 + flavours/swift/install.d/10-swift-deps | 9 + flavours/vm/README.md | 2 + flavours/vm/block-device.d/10-partition | 16 ++ lib/die | 9 + lib/img-defaults | 14 + lib/img-functions | 251 ++++++++++++++++++ sudoers.d/img-build-sudoers | 28 ++ 40 files changed, 1112 insertions(+) create mode 100644 README.md create mode 100755 bin/disk-image-create create mode 100644 docs/ci.md create mode 100644 flavours/devstack/README.md create mode 100755 flavours/devstack/install.d/50-user create mode 100755 flavours/devstack/install.d/51-grub create mode 100755 flavours/devstack/install.d/52-image-toolchain create mode 100755 flavours/devstack/install.d/97-haveged create mode 100755 flavours/devstack/install.d/98-baremetal-network create mode 100755 flavours/devstack/install.d/99-ssh create mode 100644 flavours/local-config/README.md create mode 100755 flavours/local-config/extra-data.d/62-ssh-key create mode 100755 flavours/local-config/install.d/61-http-proxy create mode 100755 flavours/local-config/install.d/62-ssh-key create mode 100644 flavours/nova-vm/README.md create mode 100755 flavours/nova-vm/first-boot.d/05-ipforwarding create mode 100755 flavours/nova-vm/first-boot.d/10-ntp create mode 100755 flavours/nova-vm/first-boot.d/15-mysql create mode 100755 flavours/nova-vm/first-boot.d/20-rabbitmq create mode 100755 flavours/nova-vm/first-boot.d/30-keystone create mode 100755 flavours/nova-vm/first-boot.d/31-keystone-data create mode 100755 flavours/nova-vm/first-boot.d/32-keystone-endpoints create mode 100755 flavours/nova-vm/first-boot.d/40-glance create mode 100755 flavours/nova-vm/first-boot.d/50-nova create mode 100644 flavours/nova-vm/first-boot.d/defaults create mode 100755 flavours/nova-vm/install.d/05-controller-code-deps create mode 100755 flavours/nova-vm/install.d/10-controller-openstack-deps create mode 100755 flavours/nova-vm/install.d/20-dkms-iscsi create mode 100755 flavours/nova-vm/install.d/99-clean-apt create mode 100644 flavours/salt/README.md create mode 100755 flavours/salt/install.d/10-salt create mode 100755 flavours/salt/pre-install.d/10-salt create mode 100644 flavours/swift/README.md create mode 100755 flavours/swift/install.d/10-swift-deps create mode 100644 flavours/vm/README.md create mode 100755 flavours/vm/block-device.d/10-partition create mode 100644 lib/die create mode 100644 lib/img-defaults create mode 100644 lib/img-functions create mode 100644 sudoers.d/img-build-sudoers diff --git a/README.md b/README.md new file mode 100644 index 00000000..c1b8a2f6 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +Image building tools for Openstack +================================== + +These tools are the components of tripleo (https://github.com/tripleo/demo) +that do the plumbing involved in building disk images. Specific configs live +in the demo repository, while the reusable tools live here. + +What tools are there? +--------------------- + +* disk-image-create -o filename {flavour} [{flavour} ...] : Create an image of + flavour {flavour}, optionally mixing in other flavours. + +* ramdisk-image-create -o filename {flavour} [{flavour} ...] : Create a kernel+ + ramdisk pair for running maintenance on bare metal machines (deployment, + inventory, burnin etc). + +* disk-image-get-kernel filename : Extract the appropriate kernel and ramdisk + to use when doing PXE boot using filename as the image for a machine. + +* flavours can be found in the top level flavours directory. + +Why? +---- + +Automation: While users and operators can manually script or put together ram +disks and disk images, mature automation makes customisation and testing easier. + +Design +====== + +Still brief - more details needed. + +Images are built using a chroot and bind mounted /proc /sys and /dev. The goal +of the image building process is to produce blank slate machines that have all +the necessary bits to fulfill a specific purpose in the running of an Openstack +cloud: e.g. a nova-compute node. + +A flavour is a particular set of code that alters how the image is built, or +runs within the chroot to prepare the image. E.g. the local-config flavour +copies in the http proxy and ssh keys of the user running the image build +process into the image, whereas the vm flavour makes the image build a regular +VM image with partition table and installed grub boot sector. + +Existing flavours +----------------- + +Flavours are found in the subdirectory flavours. Each flavour is in a directory +named after the flavour itself. Flavours *should* have a README.md in the root +of the flavour directory describing what it is for. + +Writing a flavour +----------------- + +Make as many of the following subdirectories as you need, depending on what +part of the process you need to customise: + +* block-device.d: customise the block device that the image will be made on + (e.g. to make partitions). + + * outputs: $IMAGE\_BLOCK\_DEVICE={path} + * inputs: $IMAGE\_BLOCK\_DEVICE={path} + +* extra-data.d: pull in extra data from the host environment that hooks may + need during image creation. This should copy any data (such as SSH keys, + http proxy settings and the like) somewhere under $TMP\_HOOKS\_PATH. + + * outputs: None + * inputs: $TMP\_HOOKS\_PATH + +* pre-install.d: Run code in the chroot before customisation or packages are + installed. A good place to add apt repositories. + +* install.d: Runs after pre-install.d in the chroot. This is a good place to + install packages, chain into configuration management tools or do other + image specific operations. + +* first-boot.d: Runs inside the image before rc.local. Scripts from here are + good for doing per-instance configuration based on cloud metadata. + +Third party flavours +-------------------- + +Pending implementation. The idea is to have a search path for flavours. + +Installation +============ + +* Clone the repository locally, then add bin to your path. + +* Copy sudoers.d/\* into your /etc/sudoers.d/. (Warning, use visudo -c -f + {filename} to check that each one parses successfully on your machine, so you + don't break your machine). + +Invocation +========== + +The scripts can generally just be run. Options can be set on the command line +or by exporting variables to override those present in lib/img-defaults. -h to +get help. diff --git a/bin/disk-image-create b/bin/disk-image-create new file mode 100755 index 00000000..b2dbdea4 --- /dev/null +++ b/bin/disk-image-create @@ -0,0 +1,79 @@ +#!/bin/bash + +set -e + +SCRIPTNAME=$(basename $0) +export _LIB=$(dirname $0)/../lib +source $_LIB/die + +function show_options () { + echo "Options:" + echo " -a i386|amd64 -- set the architecture of the image" + echo " -o filename -- set the name of the output file" + echo " -x -- turn on tracing" + exit 0 +} + +TEMP=`getopt -o a:ho:x -n $SCRIPTNAME -- "$@"` +echo "XXX $TEMP" +if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi + +# Note the quotes around `$TEMP': they are essential! +eval set -- "$TEMP" + +while true ; do + case "$1" in + -a) export ARCH=$2; shift 2 ;; + -o) export IMAGE_NAME=$2; shift 2 ;; + -h) show_options;; + -x) shift; set -x;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac +done +for arg do IMAGE_FLAVOUR="$IMAGE_FLAVOUR $arg" ; done + +source $_LIB/img-defaults +source $_LIB/img-functions + +echo "Building flavours: $IMAGE_FLAVOUR" +echo "If prompted for sudo, install sudoers.d/img-build-sudoers into /etc/sudoers.d and restart the build." +mkdir -p $IMG_PATH + +# TODO: make a flavour. +ensure_nbd + +mk_build_dir +ensure_base_available + +qemu-img create -f qcow2 $TMP_IMAGE_PATH ${IMAGE_SIZE}G + +# Should have a grab-next-dev helper ? +NBD_DEV=/dev/nbd0 +if [[ $(qemu-nbd --help | grep cache) == *writeback* ]] ; then + CACHE="--cache=writeback" +else + echo "Warning: qemu-nbd without --cache=writeback is /slow/." + CACHE="" +fi +sudo qemu-nbd -c $NBD_DEV $CACHE $TMP_IMAGE_PATH +export EXTRA_UNMOUNT="sudo qemu-nbd -d $NBD_DEV" +export IMAGE_BLOCK_DEVICE=$NBD_DEV +TEMP=`run_d block-device` +echo "$TEMP" +TEMP=`echo "$TEMP" | grep "IMAGE_BLOCK_DEVICE="` +eval "$TEMP" + +sudo mkfs -F -t $FS_TYPE -L cloudimg-rootfs ${IMAGE_BLOCK_DEVICE} + +mount_tmp_image ${IMAGE_BLOCK_DEVICE} + +create_base +run_d extra-data +do_pre_install +do_install +prepare_first_boot +finalise_base +unmount_image +compress_image +save_image $IMAGE_NAME.$IMAGE_TYPE diff --git a/docs/ci.md b/docs/ci.md new file mode 100644 index 00000000..c46d4cc1 --- /dev/null +++ b/docs/ci.md @@ -0,0 +1,43 @@ +CI needs for image building +=========================== + +Eventually, if/when TripleO becomes an official Openstack project, all CI for +it should be on Openstack systems. Until then we still need CI. + +Jenkins +------- + +* Jenkins from jenkins apt repo. +* IRC notification service, notify-only on #triple on freenode, port 7000 ssl. +* Github OAuth plugin, permit all from tripleo organisation, and organisation + members as service admins. +* Grant jenkin builders sudo [may want lxc containers or cloud instances for + security isolation] +* Jobs to build: + * bootstrap VM from-scratch (archive bootstrap.qcow2). + + disk-image-create vm devstack -o bootstrap.qcow2 -a i386 + + * devstack nova-bm execution (archive the resulting image). + Chained off of the bootstrap vm build + + ssh into the node, run demo/scripts/demo + + * bootstrap VM via image-build chain (archive bm-cloud.qcow2). + + disk-image-create vm glance nova-bm swift mysql haproxy-api \ + haproxy-mysql cinder quantum rabbitmq -o bootstrap-prod.qcow2 + + * baremetal SPOF node build (archive the resulting image). + + disk-image-create mysql haproxy-mysql haproxy-api local-boot \ + rabbitmq -o baremetal-spof.qcow2 + + * baremetal demo node build (archive the resulting image). + + disk-image-create vm glance nova-bm swift cinder quantum \ + -o bootstrap-prod.qcow2 + + * Tempest w/baremetal using libvirt networking as the power API. + take a bootstrap baremetal devstack from above, N VM 'bare metal' nodes, + and run tempest in that environment. diff --git a/flavours/devstack/README.md b/flavours/devstack/README.md new file mode 100644 index 00000000..6f0e3ae6 --- /dev/null +++ b/flavours/devstack/README.md @@ -0,0 +1,2 @@ +Creates an image prepped to make a devstack baremetal cloud. See +demo/scripts/demo within the built image. diff --git a/flavours/devstack/install.d/50-user b/flavours/devstack/install.d/50-user new file mode 100755 index 00000000..872ddb94 --- /dev/null +++ b/flavours/devstack/install.d/50-user @@ -0,0 +1,12 @@ +#!/bin/bash +# Add the stack user we recommend folk use. + +set -e +set -o xtrace + +useradd -G admin -m stack -s /bin/bash +passwd stack <> /etc/network/interfaces + +auto eth1 +iface eth1 inet static + # This matches the localrc we have configured for demo environments. + # It is unroutable and not suitable for production: it is a test network. + address 192.0.2.1 + netmask 255.255.255.0 + # Expose the metadata service needed by the nodes as they boot. + up iptables -t nat -A PREROUTING -d 169.254.169.254 -p tcp -m tcp --dport 80 -j REDIRECT --to-port 8775 + # Grant access to the rest of the world by routing via the bootstrap node + # (libvirt rejects traffic from unknown ip addresses, meaning that using + # the default libvirt nat environment requires the MASQUERADE for the bare + # metal nodes unless you reconfigure libvirt as well). Alternatively you + # can create a second bridge on your machine and attached eth0 to that + # (with an appropriate static config (or dhcp on the bridge). + up iptables -t nat -A POSTROUTING -s 192.0.2.0/24 -o eth0 -j MASQUERADE + # This matches the client range defined in localrc. + up ip addr add 192.0.2.33/29 dev eth1 +EOF diff --git a/flavours/devstack/install.d/99-ssh b/flavours/devstack/install.d/99-ssh new file mode 100755 index 00000000..2134c198 --- /dev/null +++ b/flavours/devstack/install.d/99-ssh @@ -0,0 +1,8 @@ +#!/bin/bash +# Regenerate host keys now. XXX: Really should be a cloud-init task, should get +# that working. + +set -e +set -o xtrace + +dpkg-reconfigure openssh-server diff --git a/flavours/local-config/README.md b/flavours/local-config/README.md new file mode 100644 index 00000000..990c58af --- /dev/null +++ b/flavours/local-config/README.md @@ -0,0 +1,2 @@ +Copies local user settings such as .ssh/authorized\_keys and $http\_proxy into +the image. diff --git a/flavours/local-config/extra-data.d/62-ssh-key b/flavours/local-config/extra-data.d/62-ssh-key new file mode 100755 index 00000000..0d5ed71d --- /dev/null +++ b/flavours/local-config/extra-data.d/62-ssh-key @@ -0,0 +1,11 @@ +#!/bin/bash +# Save user SSH public key if available. +# (Obviously not suitable for downloadable images). + +set -e +source $_LIB/die +[ -n "$TMP_HOOKS_PATH." ] || die "Temp hook path not set" + +if [ -e ~/.ssh/authorized_keys ]; then + cat ~/.ssh/authorized_keys > $TMP_HOOKS_PATH/ssh-authorized-keys +fi diff --git a/flavours/local-config/install.d/61-http-proxy b/flavours/local-config/install.d/61-http-proxy new file mode 100755 index 00000000..a7df942a --- /dev/null +++ b/flavours/local-config/install.d/61-http-proxy @@ -0,0 +1,16 @@ +#!/bin/bash +# Save the HTTP if one is available. +# XXX: Obviously not suitable for downloadable images. + +set -e +set -o xtrace + +if [ -n "$http_proxy" ]; then + sudo -Hiu stack dd of=~stack/.profile oflag=append conv=notrunc << EOF +export no_proxy=192.0.2.1 +export http_proxy=$http_proxy +EOF + sudo dd of=/etc/apt/apt.conf.d/61-use-http-proxy << _EOF_ + Acquire::http::Proxy "$http_proxy"; +_EOF_ +fi diff --git a/flavours/local-config/install.d/62-ssh-key b/flavours/local-config/install.d/62-ssh-key new file mode 100755 index 00000000..1f31ef81 --- /dev/null +++ b/flavours/local-config/install.d/62-ssh-key @@ -0,0 +1,10 @@ +#!/bin/bash +# Save user SSH public key if available. +# XXX: Obviously not suitable for downloadable images. + +set -e + +if [ -e "/tmp/in_target.d/ssh-authorized-keys" ]; then + sudo -u stack mkdir ~stack/.ssh + sudo -Hiu stack dd of=~stack/.ssh/authorized_keys oflag=append conv=notrunc if=/tmp/in_target.d/ssh-authorized-keys +fi diff --git a/flavours/nova-vm/README.md b/flavours/nova-vm/README.md new file mode 100644 index 00000000..3af65995 --- /dev/null +++ b/flavours/nova-vm/README.md @@ -0,0 +1 @@ +Sets up a nova (kvm) install in the image. diff --git a/flavours/nova-vm/first-boot.d/05-ipforwarding b/flavours/nova-vm/first-boot.d/05-ipforwarding new file mode 100755 index 00000000..4824cfcf --- /dev/null +++ b/flavours/nova-vm/first-boot.d/05-ipforwarding @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +set -o xtrace +sed -i -r 's/^\s*#(net\.ipv4\.ip_forward=1.*)/\1/' /etc/sysctl.conf +echo 1 > /proc/sys/net/ipv4/ip_forward diff --git a/flavours/nova-vm/first-boot.d/10-ntp b/flavours/nova-vm/first-boot.d/10-ntp new file mode 100755 index 00000000..860e3fb2 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/10-ntp @@ -0,0 +1,11 @@ +#!/bin/bash +ntpfile=`mktemp` +cat << EOF > $ntpfile +server ntp.ubuntu.com iburst +server 127.127.1.0 +fudge 127.127.1.0 stratum 10 +EOF + +mv /etc/ntp.conf /etc/ntp.conf.orig +mv $ntpfile /etc/ntp.conf +service ntp restart diff --git a/flavours/nova-vm/first-boot.d/15-mysql b/flavours/nova-vm/first-boot.d/15-mysql new file mode 100755 index 00000000..fc89f0e2 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/15-mysql @@ -0,0 +1,43 @@ +#!/bin/bash +set -e +set -o xtrace + +source $(dirname $0)/defaults +#MYSQL_ADMPASS +#MYSQL_NOVAPASS +#MYSQL_GLANCEPASS +#MYSQL_KEYSTONEPASS +#MYSQL_CINDERPASS + + +service mysql stop || true +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables" +sqltfile=`mktemp` +cat < $sqltfile +USE mysql; +UPDATE user SET password=PASSWORD("$MYSQL_ADMPASS") WHERE user='root'; +EOF +$MYSQL_BOOTSTRAP < $sqltfile +rm -f $sqltfile +sed -i 's/^bind-address/#bind-address/' /etc/mysql/my.cnf +service mysql start + +sqltfile=`mktemp` +cat < $sqltfile +CREATE DATABASE IF NOT EXISTS nova; +GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY '${MYSQL_NOVAPASS}'; + +CREATE DATABASE IF NOT EXISTS cinder; +GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' IDENTIFIED BY '${MYSQL_CINDERPASS}'; + +CREATE DATABASE IF NOT EXISTS keystone; +GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY '${MYSQL_KEYSTONEPASS}'; + +CREATE DATABASE IF NOT EXISTS glance; +GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' IDENTIFIED BY '${MYSQL_GLANCEPASS}'; + +FLUSH PRIVILEGES; +EOF + +mysql -uroot --password=$MYSQL_ADMPASS < $sqltfile +rm -f sqltfile diff --git a/flavours/nova-vm/first-boot.d/20-rabbitmq b/flavours/nova-vm/first-boot.d/20-rabbitmq new file mode 100755 index 00000000..892f1654 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/20-rabbitmq @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +set -o xtrace + +source $(dirname $0)/defaults +#RABBIT_PASS + +rabbitmqctl change_password guest $̣{RABBIT_PASS} diff --git a/flavours/nova-vm/first-boot.d/30-keystone b/flavours/nova-vm/first-boot.d/30-keystone new file mode 100755 index 00000000..88e70074 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/30-keystone @@ -0,0 +1,19 @@ +#!/bin/bash +set -e +set -o xtrace + +source $(dirname $0)/defaults +#AUTH_TOKEN +#MYSQL_KEYSTONEPASS +#ADMIN_PASSWORD +#HOST_IP + +KEYSTONE_FILE="/etc/keystone/keystone.conf" + +SQL_CONNECTION="mysql://keystone:${MYSQL_KEYSTONEPASS}@localhost:3306/keystone" + +sed -e "s,^connection\s*=\s*.\+$,connection = $SQL_CONNECTION," -i ${KEYSTONE_FILE} +sed -e 's|^[#]*[ \t]*admin_token[ \t]*=.*|admin_token = '${AUTH_TOKEN}'|' -i ${KEYSTONE_FILE} + +service keystone restart +keystone-manage db_sync diff --git a/flavours/nova-vm/first-boot.d/31-keystone-data b/flavours/nova-vm/first-boot.d/31-keystone-data new file mode 100755 index 00000000..e67187a6 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/31-keystone-data @@ -0,0 +1,72 @@ +#!/bin/sh +# +# Keystone Datas +# +# Description: Fill Keystone with datas. + +# Mainly inspired by http://www.hastexo.com/resources/docs/installing-openstack-essex-20121-ubuntu-1204-precise-pangolin +# Written by Martin Gerhard Loschwitz / Hastexo +# Modified by Emilien Macchi / StackOps +# +# Support: openstack@lists.launchpad.net +# License: Apache Software License (ASL) 2.0 +# + +source $(dirname $0)/defaults + +export OS_TENANT_NAME=admin +export OS_USER_NAME=admin +export OS_PASSWORD=${ADMIN_PASSWORD} +export OS_AUTH_URL="http://localhost:5000/v2.0/" +export SERVICE_ENDPOINT="http://localhost:35357/v2.0" +SERVICE_TENANT_NAME=${SERVICE_TENANT_NAME:-service} + +get_id () { + echo `$@ | awk '/ id / { print $4 }'` +} + +# Tenants +ADMIN_TENANT=$(get_id keystone tenant-create --name=admin) +SERVICE_TENANT=$(get_id keystone tenant-create --name=$SERVICE_TENANT_NAME) +DEMO_TENANT=$(get_id keystone tenant-create --name=demo) +INVIS_TENANT=$(get_id keystone tenant-create --name=invisible_to_admin) + +# Users +ADMIN_USER=$(get_id keystone user-create --name=admin --pass="$ADMIN_PASSWORD" --email=admin@domain.com) +#DEMO_USER=$(get_id keystone user-create --name=demo --pass="$ADMIN_PASSWORD" --email=demo@domain.com) + +# Roles +ADMIN_ROLE=$(get_id keystone role-create --name=admin) +KEYSTONEADMIN_ROLE=$(get_id keystone role-create --name=KeystoneAdmin) +KEYSTONESERVICE_ROLE=$(get_id keystone role-create --name=KeystoneServiceAdmin) + +# Add Roles to Users in Tenants +keystone user-role-add --user-id $ADMIN_USER --role-id $ADMIN_ROLE --tenant-id $ADMIN_TENANT +#keystone user-role-add --user-id $ADMIN_USER --role-id $ADMIN_ROLE --tenant-id $DEMO_TENANT +keystone user-role-add --user-id $ADMIN_USER --role-id $KEYSTONEADMIN_ROLE --tenant-id $ADMIN_TENANT +keystone user-role-add --user-id $ADMIN_USER --role-id $KEYSTONESERVICE_ROLE --tenant-id $ADMIN_TENANT + +# The Member role is used by Horizon and Swift +MEMBER_ROLE=$(get_id keystone role-create --name=Member) +#keystone user-role-add --user-id $DEMO_USER --role-id $MEMBER_ROLE --tenant-id $INVIS_TENANT +#keystone user-role-add --user-id $DEMO_USER --role-id $MEMBER_ROLE --tenant-id $DEMO_TENANT +keystone user-role-add --user-id $ADMIN_USER --role-id $MEMBER_ROLE --tenant-id $ADMIN_TENANT + +# Configure service users/roles +NOVA_USER=$(get_id keystone user-create --name=nova --pass="$NOVA_PASS" --tenant-id $SERVICE_TENANT --email=nova@domain.com) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $NOVA_USER --role-id $ADMIN_ROLE + +GLANCE_USER=$(get_id keystone user-create --name=glance --pass="$GLANCE_PASSWORD" --tenant-id $SERVICE_TENANT --email=glance@domain.com) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $GLANCE_USER --role-id $ADMIN_ROLE + +SWIFT_USER=$(get_id keystone user-create --name=swift --pass="$SWIFT_PASSWORD" --tenant-id $SERVICE_TENANT --email=swift@domain.com) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $SWIFT_USER --role-id $ADMIN_ROLE + +RESELLER_ROLE=$(get_id keystone role-create --name=ResellerAdmin) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $NOVA_USER --role-id $RESELLER_ROLE + +QUANTUM_USER=$(get_id keystone user-create --name=quantum --pass="$QUANTUM_PASSWORD" --tenant-id $SERVICE_TENANT --email=quantum@domain.com) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $QUANTUM_USER --role-id $ADMIN_ROLE + +CINDER_USER=$(get_id keystone user-create --name=cinder --pass="$CINDER_PASSWORD" --tenant-id $SERVICE_TENANT --email=cinder@domain.com) +keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $CINDER_USER --role-id $ADMIN_ROLE diff --git a/flavours/nova-vm/first-boot.d/32-keystone-endpoints b/flavours/nova-vm/first-boot.d/32-keystone-endpoints new file mode 100755 index 00000000..4d8bc29a --- /dev/null +++ b/flavours/nova-vm/first-boot.d/32-keystone-endpoints @@ -0,0 +1,68 @@ +#!/bin/sh +# +# Keystone Endpoints +# +# Description: Create Services Endpoints + +# Mainly inspired by http://www.hastexo.com/resources/docs/installing-openstack-essex-20121-ubuntu-1204-precise-pangolin +# Written by Martin Gerhard Loschwitz / Hastexo +# Modified by Emilien Macchi / StackOps +# +# Support: openstack@lists.launchpad.net +# License: Apache Software License (ASL) 2.0 +# + +source $(dirname $0)/defaults + +# MySQL definitions +MYSQL_USER=keystone +MYSQL_DATABASE=keystone +MYSQL_HOST=localhost + +# Keystone definitions +KEYSTONE_REGION=RegionOne +SERVICE_TOKEN=password +SERVICE_ENDPOINT="http://localhost:35357/v2.0" + +keystone service-create --name nova --type compute --description 'OpenStack Compute Service' +keystone service-create --name cinder --type volume --description 'OpenStack Volume Service' +keystone service-create --name glance --type image --description 'OpenStack Image Service' +keystone service-create --name swift --type object-store --description 'OpenStack Storage Service' +keystone service-create --name keystone --type identity --description 'OpenStack Identity' +keystone service-create --name ec2 --type ec2 --description 'OpenStack EC2 service' +keystone service-create --name quantum --type network --description 'OpenStack Networking service' + +create_endpoint () { + case $1 in + compute) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"${HOST_IP}"':8774/v2/$(tenant_id)s' --adminurl 'http://'"$HOST_IP"':8774/v2/$(tenant_id)s' --internalurl 'http://'"$HOST_IP"':8774/v2/$(tenant_id)s' + ;; + volume) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':8776/v1/$(tenant_id)s' --adminurl 'http://'"$HOST_IP"':8776/v1/$(tenant_id)s' --internalurl 'http://'"$HOST_IP"':8776/v1/$(tenant_id)s' + ;; + image) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':9292/v2' --adminurl 'http://'"$HOST_IP"':9292/v2' --internalurl 'http://'"$HOST_IP"':9292/v2' + ;; + object-store) + if [ $SWIFT_HOST_IP ]; then + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$SWIFT_HOST_IP"':8080/v1/AUTH_$(tenant_id)s' --adminurl 'http://'"$SWIFT_HOST_IP"':8080/v1' --internalurl 'http://'"$SWIFT_HOST_IP"':8080/v1/AUTH_$(tenant_id)s' + else + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':8080/v1/AUTH_$(tenant_id)s' --adminurl 'http://'"$HOST_IP"':8080/v1' --internalurl 'http://'"$HOST_IP"':8080/v1/AUTH_$(tenant_id)s' + fi + ;; + identity) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':5000/v2.0' --adminurl 'http://'"$HOST_IP"':35357/v2.0' --internalurl 'http://'"$HOST_IP"':5000/v2.0' + ;; + ec2) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':8773/services/Cloud' --adminurl 'http://'"$HOST_IP"':8773/services/Admin' --internalurl 'http://'"$HOST_IP"':8773/services/Cloud' + ;; + network) + keystone endpoint-create --region $KEYSTONE_REGION --service-id $2 --publicurl 'http://'"$HOST_IP"':9696/' --adminurl 'http://'"$HOST_IP"':9696/' --internalurl 'http://'"$HOST_IP"':9696/' + ;; + esac +} + +for i in compute volume image object-store identity ec2 network; do + id=`mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_KEYSTONEPASS" "$MYSQL_DATABASE" -ss -e "SELECT id FROM service WHERE type='"$i"';"` || exit 1 + create_endpoint $i $id +done diff --git a/flavours/nova-vm/first-boot.d/40-glance b/flavours/nova-vm/first-boot.d/40-glance new file mode 100755 index 00000000..2f0b46e7 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/40-glance @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +set -o xtrace + +source $(dirname $0)/defaults +#MYSQL_GLANCEPASS +#GLANCE_PASS +#RABBIT_PASS + +GLANCE_DIR="/etc/glance/" + +SQL_CONNECTION="mysql://glance:${MYSQL_GLANCEPASS}@localhost:3306/glance" + +sed -e "s,^sql_connection\s*=\s*.\+$,sql_connection = $SQL_CONNECTION," -i ${GLANCE_DIR}/glance-api.conf +sed -e "s,^sql_connection\s*=\s*.\+$,sql_connection = $SQL_CONNECTION," -i ${GLANCE_DIR}/glance-registry.conf + +sed -e "s,^admin_tenant_name\s*=\s*.\+$,admin_tenant_name = service," -i ${GLANCE_DIR}/glance-api.conf +sed -e "s,^admin_tenant_name\s*=\s*.\+$,admin_tenant_name = service," -i ${GLANCE_DIR}/glance-registry.conf + +sed -e "s,^admin_user\s*=\s*.\+$,admin_user = glance," -i ${GLANCE_DIR}/glance-api.conf +sed -e "s,^admin_user\s*=\s*.\+$,admin_user = glance," -i ${GLANCE_DIR}/glance-registry.conf + +sed -e "s,^admin_password\s*=\s*.\+$,admin_password = ${GLANCE_PASS}," -i ${GLANCE_DIR}/glance-api.conf +sed -e "s,^admin_password\s*=\s*.\+$,admin_password = ${GLANCE_PASS}," -i ${GLANCE_DIR}/glance-registry.conf + +sed -e "s,^notifier_strategy\s*=\s*.\+$,notifier_strategy = rabbit," -i ${GLANCE_DIR}/glance-api.conf +sed -e "s,^rabbit_password\s*=\s*.\+$,rabbit_password = ${RABBIT_PASS}," -i ${GLANCE_DIR}/glance-api.conf + +service glance-api restart +service glance-registry restart +glance-manage db_sync + +#wget http://uec-images.ubuntu.com/releases/precise/release/ubuntu-12.04-server-cloudimg-amd64.tar.gz +#tar xzvf ubuntu-12.04-server-cloudimg-amd64.tar.gz +#glance image-create --name="Ubuntu 12.04 UEC" --public --container-format=ovf --disk-format=qcow2 < precise-server-cloudimg-amd64.img diff --git a/flavours/nova-vm/first-boot.d/50-nova b/flavours/nova-vm/first-boot.d/50-nova new file mode 100755 index 00000000..76ecf58b --- /dev/null +++ b/flavours/nova-vm/first-boot.d/50-nova @@ -0,0 +1,85 @@ +#!/bin/bash +set -e +set -o xtrace + +source $(dirname $0)/defaults +#HOST_IP + +NOVA_DIR="/etc/nova/" + +SQL_CONNECTION="mysql://nova:${MYSQL_NOVAPASS}d@localhost:3306/nova" + + +sed -e "s,^admin_tenant_name\s*=\s*.\+$,admin_tenant_name = service," -i ${NOVA_DIR}/api-paste.ini +sed -e "s,^admin_user\s*=\s*.\+$,admin_user = nova," -i ${NOVA_DIR}/api-paste.ini +sed -e "s,^admin_password\s*=\s*.\+$,admin_password = ${NOVA_PASS}," -i ${NOVA_DIR}/api-paste.ini + +sed -i '/volume/d' /etc/nova/api-paste.ini + +cat << EOF > ${NOVA_DIR}/nova.conf +[DEFAULT] +# MySQL Connection # +sql_connection=mysql://nova:password@${HOST_IP}/nova + +# nova-scheduler # +rabbit_password=${RABBIT_PASS} +scheduler_driver=nova.scheduler.simple.SimpleScheduler + +# nova-api # +cc_host=${HOST_IP} +auth_strategy=keystone +s3_host=${HOST_IP} +ec2_host=${HOST_IP} +nova_url=http://${HOST_IP}:8774/v1.1/ +ec2_url=http://${HOST_IP}:8773/services/Cloud +keystone_ec2_url=http://${HOST_IP}:5000/v2.0/ec2tokens +api_paste_config=/etc/nova/api-paste.ini +allow_admin_api=true +use_deprecated_auth=false +ec2_private_dns_show_ip=True +dmz_cidr=169.254.169.254/32 +ec2_dmz_host=${HOST_IP} +metadata_host=${HOST_IP} +metadata_listen=0.0.0.0 +enabled_apis=ec2,osapi_compute,metadata + +# Networking # +#network_api_class=nova.network.quantumv2.api.API +#quantum_url=http://${HOST_IP}:9696 +#quantum_auth_strategy=keystone +#quantum_admin_tenant_name=service +#quantum_admin_username=quantum +#quantum_admin_password=password +#quantum_admin_auth_url=http://${HOST_IP}:35357/v2.0 +#libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver +#linuxnet_interface_driver=nova.network.linux_net.LinuxOVSInterfaceDriver +#firewall_driver=nova.virt.libvirt.firewall.IptablesFirewallDriver + +# Cinder # +volume_api_class=nova.volume.cinder.API + +# Glance # +glance_api_servers=${HOST_IP}:9292 +image_service=nova.image.glance.GlanceImageService + +# novnc # +novnc_enable=true +novncproxy_base_url=http://${HOST_IP}:6080/vnc_auto.html +vncserver_proxyclient_address=127.0.0.1 +vncserver_listen=0.0.0.0 + +# Misc # +logdir=/var/log/nova +state_path=/var/lib/nova +lock_path=/var/lock/nova +root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf +verbose=true +EOF + +nova-manage db sync +service nova-api restart +service nova-cert restart +service nova-consoleauth restart +service nova-scheduler restart +service novnc restart +service nova-network restart diff --git a/flavours/nova-vm/first-boot.d/defaults b/flavours/nova-vm/first-boot.d/defaults new file mode 100644 index 00000000..6ce09d56 --- /dev/null +++ b/flavours/nova-vm/first-boot.d/defaults @@ -0,0 +1,27 @@ +set -e + +DEFAULT_PASSWORD=${DEFAULT_PASSWORD:-password} + +# HOST_IP +# Find the interface used for the default route +HOST_IP_IFACE=${HOST_IP_IFACE:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }')} +# Search for an IP unless an explicit is set by ``HOST_IP`` environment variable +HOST_IP=`LC_ALL=C ip -f inet addr show ${HOST_IP_IFACE} | awk '/inet/ {split($2,parts,"/"); print parts[1]}'` + +# Mysql Passwords +MYSQL_ADMPASS=${MYSQL_ADMPASS:-$ {DEFAULT_PASSWORD}} +MYSQL_NOVAPASS=${MYSQL_NOVAPASS:-$MYSQL_ADMPASS} +MYSQL_GLANCEPASS=${MYSQL_GLANCEPASS:-$MYSQL_ADMPASS} +MYSQL_KEYSTONEPASS=${MYSQL_KEYSTONEPASS:-$MYSQL_ADMPASS} +MYSQL_CINDERPASS=${MYSQL_CINDERPASS:-$MYSQL_ADMPASS} + +#Rabbitmq Passwords +RABBIT_PASS=${RABBIT_PASS:-${DEFAULT_PASSWORD}} + +#Keystone +AUTH_TOKEN=${AUTH_TOKEN:-${DEFAULT_PASSWORD}} +SERVICE_TOKEN=${AUTH_TOKEN} +ADMIN_PASSWORD=${ADMIN_PASSWORD:-${DEFAULT_PASSWORD}} + +#Glance +GLANCE_PASS=${GLANCE_PASS:-${DEFAULT_PASSWORD}} diff --git a/flavours/nova-vm/install.d/05-controller-code-deps b/flavours/nova-vm/install.d/05-controller-code-deps new file mode 100755 index 00000000..08ce8ef7 --- /dev/null +++ b/flavours/nova-vm/install.d/05-controller-code-deps @@ -0,0 +1,8 @@ +#!/bin/sh + +# Install controller base requiered packages + +set -e +set -o xtrace + +DEBIAN_FRONTEND=noninteractive apt-get -y install haproxy rabbitmq-server mysql-server ntp dkms diff --git a/flavours/nova-vm/install.d/10-controller-openstack-deps b/flavours/nova-vm/install.d/10-controller-openstack-deps new file mode 100755 index 00000000..83947cd6 --- /dev/null +++ b/flavours/nova-vm/install.d/10-controller-openstack-deps @@ -0,0 +1,9 @@ +#!/bin/sh + +# Install controller openstack packages + +set -e +set -o xtrace + +apt-get -y install keystone glance nova-api nova-cert nova-common nova-scheduler python-nova python-novaclient nova-consoleauth novnc nova-novncproxy cinder-api cinder-scheduler cinder-volume iscsitarget open-iscsi iscsitarget-dkms python-cinderclient nova-network + diff --git a/flavours/nova-vm/install.d/20-dkms-iscsi b/flavours/nova-vm/install.d/20-dkms-iscsi new file mode 100755 index 00000000..6cd4906a --- /dev/null +++ b/flavours/nova-vm/install.d/20-dkms-iscsi @@ -0,0 +1,27 @@ +#!/bin/sh + +# Build iscsi modules with installed kernel + +set -e +set -o xtrace + +package=iscsitarget-dkms +name=iscsitarget + +kernel_version=`ls /boot/vmlinuz-* -r -1| head -n1 | xargs basename |sed 's/vmlinuz-//'` + +version=`dpkg-query -W -f='${Version}' "$package" \ + |rev|cut -d- -f2-|rev|cut -d':' -f2|tr -d "\n"` + +isadded=`dkms status -m "$cd name" -v "$version"` + + + +if [ "x${isadded}" = "x" ] ; then + dkms add -m "$name" -v "$version" -k "$kernel_version" || true +fi + +dkms build -m "$name" -v "$version" -k "$kernel_version" && dkms install -m "$name" -v "$version" -k "$kernel_version" || true + + + diff --git a/flavours/nova-vm/install.d/99-clean-apt b/flavours/nova-vm/install.d/99-clean-apt new file mode 100755 index 00000000..14aff99e --- /dev/null +++ b/flavours/nova-vm/install.d/99-clean-apt @@ -0,0 +1,10 @@ +#!/bin/sh + +# Build iscsi modules with installed kernel + +set -e +set -o xtrace + +apt-get clean + + diff --git a/flavours/salt/README.md b/flavours/salt/README.md new file mode 100644 index 00000000..2f191bbe --- /dev/null +++ b/flavours/salt/README.md @@ -0,0 +1 @@ +Adds salt, a config-management tool, to the image. diff --git a/flavours/salt/install.d/10-salt b/flavours/salt/install.d/10-salt new file mode 100755 index 00000000..a1529060 --- /dev/null +++ b/flavours/salt/install.d/10-salt @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e +set -o xtrace + +apt-get -y install salt-minion + diff --git a/flavours/salt/pre-install.d/10-salt b/flavours/salt/pre-install.d/10-salt new file mode 100755 index 00000000..dd1389a7 --- /dev/null +++ b/flavours/salt/pre-install.d/10-salt @@ -0,0 +1,8 @@ +#!/bin/bash +# Add the salt PPA + +set -e +set -o xtrace + +add-apt-repository -y ppa:saltstack/salt + diff --git a/flavours/swift/README.md b/flavours/swift/README.md new file mode 100644 index 00000000..8527ab3b --- /dev/null +++ b/flavours/swift/README.md @@ -0,0 +1 @@ +Sets up a swift install in the image. diff --git a/flavours/swift/install.d/10-swift-deps b/flavours/swift/install.d/10-swift-deps new file mode 100755 index 00000000..ba0add10 --- /dev/null +++ b/flavours/swift/install.d/10-swift-deps @@ -0,0 +1,9 @@ +#!/bin/sh + +# Install controller openstack packages + +set -e +set -o xtrace + +apt-get -y install swift rsync memcached python-netifaces python-xattr python-memcache + diff --git a/flavours/vm/README.md b/flavours/vm/README.md new file mode 100644 index 00000000..ecc8eaf6 --- /dev/null +++ b/flavours/vm/README.md @@ -0,0 +1,2 @@ +Sets up a partitioned disk (rather than building just one filesystem with no +partition table). diff --git a/flavours/vm/block-device.d/10-partition b/flavours/vm/block-device.d/10-partition new file mode 100755 index 00000000..13a69523 --- /dev/null +++ b/flavours/vm/block-device.d/10-partition @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e +source $_LIB/die +[ -n "$IMAGE_BLOCK_DEVICE" ] || die "Image block device not set" + +# Create 1 partition far enough up the disk to permit grub to be installed on +# the MBR. +sudo sfdisk $IMAGE_BLOCK_DEVICE << EOF +1 - - * +0 0; +0 0; +0 0; +EOF + +echo "IMAGE_BLOCK_DEVICE=${IMAGE_BLOCK_DEVICE}p1" diff --git a/lib/die b/lib/die new file mode 100644 index 00000000..9d3dddc2 --- /dev/null +++ b/lib/die @@ -0,0 +1,9 @@ +# Prints "message" and exits +# Usage: die "message" +function die() { + local exitcode=$? + set +o xtrace + echo $@ + exit $exitcode +} + diff --git a/lib/img-defaults b/lib/img-defaults new file mode 100644 index 00000000..a693fe14 --- /dev/null +++ b/lib/img-defaults @@ -0,0 +1,14 @@ +# options for create-baremetal-image.sh +ARCH=${ARCH:-$(dpkg --print-architecture)} +RELEASE=${RELEASE:-quantal} +BASE_IMAGE_FILE=${BASE_IMAGE_FILE:-$RELEASE-server-cloudimg-$ARCH-root.tar.gz} +CLOUD_IMAGES=${CLOUD_IMAGES:-http://cloud-images.ubuntu.com/} +FS_TYPE=${FS_TYPE:-ext4} +# Used to set the file extension only at this stage. +IMAGE_TYPE=${IMAGE_TYPE:-qcow2} +IMAGE_NAME=${IMAGE_NAME:-image} +IMAGE_SIZE=${IMAGE_SIZE:-1} # N.B. This size is in GB +# Set via the CLI normally. +# IMAGE_FLAVOUR= +IMG_PATH=~/.cache/image-create +FLAVOURS_DIR=$(dirname $0)/../flavours diff --git a/lib/img-functions b/lib/img-functions new file mode 100644 index 00000000..926b5f5e --- /dev/null +++ b/lib/img-functions @@ -0,0 +1,251 @@ +function unmount_image () { + # unmount from the chroot + # Don't use TMP_MOUNT_PATH here, it might not have been set. + sudo umount -f $TMP_BUILD_DIR/mnt/sys || true + sudo umount -f $TMP_BUILD_DIR/mnt/proc || true + sudo umount -f $TMP_BUILD_DIR/mnt/dev || true + sudo umount -f $TMP_BUILD_DIR/mnt/tmp/in_target.d || true + # give it a second (ok really 5) to umount XXX - why? should instead track + # the mount data / lsof etc. + sleep 5 + # oh ya don't want to forget to unmount the image + sudo umount -f $TMP_BUILD_DIR/mnt || true + # having disk corruption issues; one possibility is qemu-nbd not flush dirty + # pages on disconnect? + sync + if [ -n "$EXTRA_UNMOUNT" ]; then + $EXTRA_UNMOUNT + fi +} + +function cleanup () { + unmount_image + rm -rf $TMP_BUILD_DIR +} + +function mk_build_dir () { + export TMP_BUILD_DIR=$(mktemp -t -d image.XXXXXXXX) + [ $? -eq 0 ] || die "Failed to create tmp directory" + trap cleanup EXIT + echo Building in $TMP_BUILD_DIR + export TMP_IMAGE_PATH=$TMP_BUILD_DIR/image + export TMP_HOOKS_PATH=$TMP_BUILD_DIR/hooks +} + +function ensure_nbd () { + NBD=`which qemu-nbd` + if [ -z "$NBD" ]; then + echo "Need qemu-nbd to build qcow2 files." + sudo apt-get install qemu-utils + fi + # prep nbd for mounting + (lsmod | grep '^nbd ') || sudo modprobe nbd max_part=16 +} + +function ensure_base_available () { + # TODO: don't cache -current forever. + if [ ! -f $IMG_PATH/$BASE_IMAGE_FILE ] ; then + echo "Fetching Base Image" + wget $CLOUD_IMAGES/$RELEASE/current/$BASE_IMAGE_FILE -O $IMG_PATH/$BASE_IMAGE_FILE.tmp + mv $IMG_PATH/$BASE_IMAGE_FILE.tmp $IMG_PATH/$BASE_IMAGE_FILE + fi +} + +function ensure_sudo () { + sudo echo "Ensuring sudo is available" +} + +function mount_tmp_image () { + mkdir $TMP_BUILD_DIR/mnt + sudo mount $@ $TMP_BUILD_DIR/mnt + [ $? -eq 0 ] || die "Failed to mount image" + export TMP_MOUNT_PATH=$TMP_BUILD_DIR/mnt +} + +function create_base () { + # Extract the base image + sudo tar -C $TMP_MOUNT_PATH -xzf $IMG_PATH/$BASE_IMAGE_FILE + + # Configure Image + # Setup resolv.conf so we can chroot to install some packages + # XXXX: Should store the old state rather than unlink; then restore later. + if [ -L $TMP_MOUNT_PATH/etc/resolv.conf ] ; then + sudo unlink $TMP_MOUNT_PATH/etc/resolv.conf + fi + + if [ -f $TMP_MOUNT_PATH/etc/resolv.conf ] ; then + sudo rm -f $TMP_MOUNT_PATH/etc/resolv.conf + fi + + # Recreate resolv.conf + sudo touch $TMP_MOUNT_PATH/etc/resolv.conf + sudo chmod 777 $TMP_MOUNT_PATH/etc/resolv.conf + echo nameserver 8.8.8.8 > $TMP_MOUNT_PATH/etc/resolv.conf + + # supporting kernel file systems + sudo mount -t proc none $TMP_MOUNT_PATH/proc + sudo mount --bind /dev $TMP_MOUNT_PATH/dev + sudo mount -t sysfs none $TMP_MOUNT_PATH/sys + + # If we have a network proxy, use it. + if [ -n "$http_proxy" ] ; then + sudo dd of=$TMP_MOUNT_PATH/etc/apt/apt.conf.d/60img-build-proxy << _EOF_ + Acquire::http::Proxy "$http_proxy"; +_EOF_ + fi +} + +# Helper function to run a command inside the chroot +function run_in_target() { + # -E to preserve http_proxy + sudo -E chroot $TMP_MOUNT_PATH "$@" +} + +function generate_hooks () { + mkdir -p $TMP_HOOKS_PATH + for _FLAVOUR in $IMAGE_FLAVOUR ; do + [ -d $FLAVOURS_DIR/$_FLAVOUR ] || die "The flavour does not exist." ; + cp -t $TMP_HOOKS_PATH -a $FLAVOURS_DIR/$_FLAVOUR/* ; + done +} + +# Check that a real flavour has been chosen (prevents foot-guns) +function check_flavour () { + [ -d $TMP_HOOKS_PATH ] || generate_hooks +} + +# Helper function to run a directory of scripts inside the chroot +function run_d_in_target() { + check_flavour + # If we can find a directory of hooks to run in the target filesystem, bind + # mount it into the target and then execute run-parts in a chroot + if [ -d ${TMP_HOOKS_PATH}/$1.d ] ; then + sudo mkdir $TMP_MOUNT_PATH/tmp/in_target.d + sudo mount --bind ${TMP_HOOKS_PATH} $TMP_MOUNT_PATH/tmp/in_target.d + sudo mount -o remount,ro,bind ${TMP_HOOKS_PATH} $TMP_MOUNT_PATH/tmp/in_target.d + run_in_target run-parts -v /tmp/in_target.d/$1.d + sudo umount -f $TMP_MOUNT_PATH/tmp/in_target.d + sudo rmdir $TMP_MOUNT_PATH/tmp/in_target.d + fi +} + +# Run a directory of hooks outside the target. +function run_d() { + check_flavour + if [ -d ${TMP_HOOKS_PATH}/$1.d ] ; then + run-parts ${TMP_HOOKS_PATH}/$1.d + fi +} + +function prepare_first_boot () { + if [ -d ${TMP_HOOKS_PATH}/first-boot.d ] ; then + sudo cp -t $TMP_MOUNT_PATH/etc/ -a $TMP_HOOKS_PATH/first-boot.d + run_in_target mv /etc/rc.local /etc/rc.local.REAL + sudo dd of=$TMP_MOUNT_PATH/etc/rc.local <