Bring across disk image code.
This commit is contained in:
parent
10b9c660d6
commit
5cc195e391
40 changed files with 1112 additions and 0 deletions
100
README.md
Normal file
100
README.md
Normal file
|
@ -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.
|
79
bin/disk-image-create
Executable file
79
bin/disk-image-create
Executable file
|
@ -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
|
43
docs/ci.md
Normal file
43
docs/ci.md
Normal file
|
@ -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.
|
2
flavours/devstack/README.md
Normal file
2
flavours/devstack/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Creates an image prepped to make a devstack baremetal cloud. See
|
||||
demo/scripts/demo within the built image.
|
12
flavours/devstack/install.d/50-user
Executable file
12
flavours/devstack/install.d/50-user
Executable file
|
@ -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 <<EOF
|
||||
stack
|
||||
stack
|
||||
EOF
|
||||
|
12
flavours/devstack/install.d/51-grub
Executable file
12
flavours/devstack/install.d/51-grub
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
# Configure grub
|
||||
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
# XXX: grub-probe on the nbd0 device returns nothing - workaround, manually
|
||||
# specify modules. https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1073731
|
||||
grub-install --modules="biosdisk part_msdos" /dev/nbd0
|
||||
# XXX: Undiagnosed, but the LABEL=cloudimg-rootfs isn't being picked up: workaround it.
|
||||
sed -i 's%/dev/nbd0p1%LABEL=cloudimg-rootfs%' /boot/grub/grub.cfg
|
10
flavours/devstack/install.d/52-image-toolchain
Executable file
10
flavours/devstack/install.d/52-image-toolchain
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
# Install the image creation toolchain so folk can create their own images
|
||||
# (also includes the bootstrap-from-devstack facilities needed until we have
|
||||
# full image mastering of openstack).
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
apt-get -y install git
|
||||
sudo -Hiu stack git clone git://github.com/tripleo/demo.git
|
7
flavours/devstack/install.d/97-haveged
Executable file
7
flavours/devstack/install.d/97-haveged
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
# Install the haveged daemon so ssh config on startup isn't glacial.
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
apt-get -y install haveged
|
26
flavours/devstack/install.d/98-baremetal-network
Executable file
26
flavours/devstack/install.d/98-baremetal-network
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
# Configure eth1, the baremetal network.
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
cat << EOF >> /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
|
8
flavours/devstack/install.d/99-ssh
Executable file
8
flavours/devstack/install.d/99-ssh
Executable file
|
@ -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
|
2
flavours/local-config/README.md
Normal file
2
flavours/local-config/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Copies local user settings such as .ssh/authorized\_keys and $http\_proxy into
|
||||
the image.
|
11
flavours/local-config/extra-data.d/62-ssh-key
Executable file
11
flavours/local-config/extra-data.d/62-ssh-key
Executable file
|
@ -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
|
16
flavours/local-config/install.d/61-http-proxy
Executable file
16
flavours/local-config/install.d/61-http-proxy
Executable file
|
@ -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
|
10
flavours/local-config/install.d/62-ssh-key
Executable file
10
flavours/local-config/install.d/62-ssh-key
Executable file
|
@ -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
|
1
flavours/nova-vm/README.md
Normal file
1
flavours/nova-vm/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Sets up a nova (kvm) install in the image.
|
5
flavours/nova-vm/first-boot.d/05-ipforwarding
Executable file
5
flavours/nova-vm/first-boot.d/05-ipforwarding
Executable file
|
@ -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
|
11
flavours/nova-vm/first-boot.d/10-ntp
Executable file
11
flavours/nova-vm/first-boot.d/10-ntp
Executable file
|
@ -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
|
43
flavours/nova-vm/first-boot.d/15-mysql
Executable file
43
flavours/nova-vm/first-boot.d/15-mysql
Executable file
|
@ -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 <<EOF > $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 <<EOF > $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
|
8
flavours/nova-vm/first-boot.d/20-rabbitmq
Executable file
8
flavours/nova-vm/first-boot.d/20-rabbitmq
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
source $(dirname $0)/defaults
|
||||
#RABBIT_PASS
|
||||
|
||||
rabbitmqctl change_password guest $̣{RABBIT_PASS}
|
19
flavours/nova-vm/first-boot.d/30-keystone
Executable file
19
flavours/nova-vm/first-boot.d/30-keystone
Executable file
|
@ -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
|
72
flavours/nova-vm/first-boot.d/31-keystone-data
Executable file
72
flavours/nova-vm/first-boot.d/31-keystone-data
Executable file
|
@ -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
|
68
flavours/nova-vm/first-boot.d/32-keystone-endpoints
Executable file
68
flavours/nova-vm/first-boot.d/32-keystone-endpoints
Executable file
|
@ -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
|
35
flavours/nova-vm/first-boot.d/40-glance
Executable file
35
flavours/nova-vm/first-boot.d/40-glance
Executable file
|
@ -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
|
85
flavours/nova-vm/first-boot.d/50-nova
Executable file
85
flavours/nova-vm/first-boot.d/50-nova
Executable file
|
@ -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
|
27
flavours/nova-vm/first-boot.d/defaults
Normal file
27
flavours/nova-vm/first-boot.d/defaults
Normal file
|
@ -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}}
|
8
flavours/nova-vm/install.d/05-controller-code-deps
Executable file
8
flavours/nova-vm/install.d/05-controller-code-deps
Executable file
|
@ -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
|
9
flavours/nova-vm/install.d/10-controller-openstack-deps
Executable file
9
flavours/nova-vm/install.d/10-controller-openstack-deps
Executable file
|
@ -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
|
||||
|
27
flavours/nova-vm/install.d/20-dkms-iscsi
Executable file
27
flavours/nova-vm/install.d/20-dkms-iscsi
Executable file
|
@ -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
|
||||
|
||||
|
||||
|
10
flavours/nova-vm/install.d/99-clean-apt
Executable file
10
flavours/nova-vm/install.d/99-clean-apt
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Build iscsi modules with installed kernel
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
apt-get clean
|
||||
|
||||
|
1
flavours/salt/README.md
Normal file
1
flavours/salt/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Adds salt, a config-management tool, to the image.
|
7
flavours/salt/install.d/10-salt
Executable file
7
flavours/salt/install.d/10-salt
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
apt-get -y install salt-minion
|
||||
|
8
flavours/salt/pre-install.d/10-salt
Executable file
8
flavours/salt/pre-install.d/10-salt
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
# Add the salt PPA
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
add-apt-repository -y ppa:saltstack/salt
|
||||
|
1
flavours/swift/README.md
Normal file
1
flavours/swift/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Sets up a swift install in the image.
|
9
flavours/swift/install.d/10-swift-deps
Executable file
9
flavours/swift/install.d/10-swift-deps
Executable file
|
@ -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
|
||||
|
2
flavours/vm/README.md
Normal file
2
flavours/vm/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Sets up a partitioned disk (rather than building just one filesystem with no
|
||||
partition table).
|
16
flavours/vm/block-device.d/10-partition
Executable file
16
flavours/vm/block-device.d/10-partition
Executable file
|
@ -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"
|
9
lib/die
Normal file
9
lib/die
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Prints "message" and exits
|
||||
# Usage: die "message"
|
||||
function die() {
|
||||
local exitcode=$?
|
||||
set +o xtrace
|
||||
echo $@
|
||||
exit $exitcode
|
||||
}
|
||||
|
14
lib/img-defaults
Normal file
14
lib/img-defaults
Normal file
|
@ -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
|
251
lib/img-functions
Normal file
251
lib/img-functions
Normal file
|
@ -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 <<EOF
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
run-parts -v /etc/first-boot.d
|
||||
rm -fr /etc/first-boot.d
|
||||
mv /etc/rc.local.REAL /etc/rc.local
|
||||
exit 0
|
||||
EOF
|
||||
run_in_target chmod 755 /etc/rc.local
|
||||
fi
|
||||
}
|
||||
|
||||
function finalise_base () {
|
||||
# Undo our proxy support
|
||||
sudo rm -f $TMP_MOUNT_PATH/etc/apt/apt.conf.d/60img-build-proxy
|
||||
# Now remove the resolv.conf we created above
|
||||
sudo rm -f $TMP_MOUNT_PATH/etc/resolv.conf
|
||||
# The we need to recreate it as a link
|
||||
sudo ln -sf ../run/resolvconf/resolv.conf $TMP_MOUNT_PATH/etc/resolv.conf
|
||||
}
|
||||
|
||||
function compress_image () {
|
||||
# Recreate our image to throw away unnecessary data
|
||||
qemu-img convert -c $TMP_IMAGE_PATH -O qcow2 $TMP_IMAGE_PATH-new
|
||||
rm $TMP_IMAGE_PATH
|
||||
mv $TMP_IMAGE_PATH-new $TMP_IMAGE_PATH
|
||||
}
|
||||
|
||||
function save_image () {
|
||||
# TODO: this really should rename the old file
|
||||
if [ -f $1 ] ; then
|
||||
echo "Old Image file Found REMOVING"
|
||||
rm -f $1
|
||||
fi
|
||||
|
||||
cp $TMP_IMAGE_PATH $1
|
||||
rm -r $TMP_BUILD_DIR
|
||||
# All done!
|
||||
trap EXIT
|
||||
echo "Image file $1 created..."
|
||||
}
|
||||
|
||||
function block_apt_translations () {
|
||||
# Configure APT not to fetch translations files
|
||||
sudo dd of=$TMP_MOUNT_PATH/etc/apt/apt.conf.d/95no-translations <<EOF
|
||||
APT::Acquire::Languages "none";
|
||||
EOF
|
||||
|
||||
# And now make sure that we don't fall foul of Debian bug 641967
|
||||
find $TMP_MOUNT_PATH/var/lib/apt/lists/ -type f -name '*_i18n_Translation-*' -exec sudo rm -f {} \;
|
||||
}
|
||||
|
||||
function block_daemons () {
|
||||
# Prevent package installs from starting daemons
|
||||
sudo mv $TMP_MOUNT_PATH/sbin/start-stop-daemon $TMP_MOUNT_PATH/sbin/start-stop-daemon.REAL
|
||||
sudo dd of=$TMP_MOUNT_PATH/sbin/start-stop-daemon <<EOF
|
||||
#!/bin/sh
|
||||
echo
|
||||
echo "Warning: Fake start-stop-daemon called, doing nothing"
|
||||
EOF
|
||||
sudo chmod 755 $TMP_MOUNT_PATH/sbin/start-stop-daemon
|
||||
|
||||
sudo mv $TMP_MOUNT_PATH/sbin/initctl $TMP_MOUNT_PATH/sbin/initctl.REAL
|
||||
sudo dd of=$TMP_MOUNT_PATH/sbin/initctl <<EOF
|
||||
#!/bin/sh
|
||||
echo "initctl (tripleo 1.0)"
|
||||
echo "Warning: Fake initctl called, doing nothing"
|
||||
EOF
|
||||
sudo chmod 755 $TMP_MOUNT_PATH/sbin/initctl
|
||||
|
||||
sudo mv $TMP_MOUNT_PATH/usr/sbin/invoke-rc.d $TMP_MOUNT_PATH/usr/sbin/invoke-rc.d.REAL
|
||||
sudo dd of=$TMP_MOUNT_PATH/usr/sbin/invoke-rc.d <<EOF
|
||||
#!/bin/sh
|
||||
echo "invoke-rc.d (tripleo 1.0)"
|
||||
echo "Warning: Fake inovke-rc.d called, doing nothing"
|
||||
EOF
|
||||
sudo chmod 755 $TMP_MOUNT_PATH/usr/sbin/invoke-rc.d
|
||||
}
|
||||
|
||||
function unblock_daemons () {
|
||||
sudo mv $TMP_MOUNT_PATH/sbin/start-stop-daemon.REAL $TMP_MOUNT_PATH/sbin/start-stop-daemon
|
||||
sudo mv $TMP_MOUNT_PATH/sbin/initctl.REAL $TMP_MOUNT_PATH/sbin/initctl
|
||||
sudo mv $TMP_MOUNT_PATH/usr/sbin/invoke-rc.d.REAL $TMP_MOUNT_PATH/usr/sbin/invoke-rc.d
|
||||
}
|
||||
|
||||
function do_pre_install () {
|
||||
block_daemons
|
||||
block_apt_translations
|
||||
# Install baseline packages and tools
|
||||
run_in_target apt-get -y update
|
||||
run_in_target apt-get -y install python-software-properties
|
||||
run_in_target add-apt-repository -y ppa:tripleo/demo
|
||||
# Uncomment to get the bleeding edge - this should be a flavour thing.
|
||||
# run_in_target add-apt-repository -y ppa:tripleo/demo-staging
|
||||
# Run pre-install scripts. These do things that prepare the chroot for package installs
|
||||
run_d_in_target pre-install
|
||||
run_in_target apt-get -y update
|
||||
}
|
||||
|
||||
function do_install () {
|
||||
# These are useful, or at worst not harmful, for all imges we build.
|
||||
run_in_target apt-get -y install linux-image-generic vlan open-iscsi
|
||||
# Call install scripts to pull in the software users want.
|
||||
run_d_in_target install
|
||||
unblock_daemons
|
||||
}
|
28
sudoers.d/img-build-sudoers
Normal file
28
sudoers.d/img-build-sudoers
Normal file
|
@ -0,0 +1,28 @@
|
|||
ALL ALL=(root) NOPASSWD: /bin/chmod * /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/dd of=/tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/ln -sf * /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/mkdir -p /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/mkdir /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount --bind /dev /tmp/*/mnt/dev
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount --bind /tmp/*/hooks /tmp/*/mnt/tmp/in_target.d
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount -o remount\,ro\,bind /tmp/*/hooks /tmp/*/mnt/tmp/in_target.d
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount -t proc none /tmp/*/mnt/proc
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount -t sysfs none /tmp/*/mnt/sys
|
||||
ALL ALL=(root) NOPASSWD: /bin/mount /dev/nbd0p1 /tmp/*/mnt
|
||||
ALL ALL=(root) NOPASSWD: /bin/mv /tmp/*/mnt/* /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/rm -* /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/rmdir /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/tar -C /tmp/*/mnt -xzf /*/.cache/image-create/*
|
||||
ALL ALL=(root) NOPASSWD: /bin/umount -f /tmp/*/mnt
|
||||
ALL ALL=(root) NOPASSWD: /bin/umount -f /tmp/*/mnt/dev
|
||||
ALL ALL=(root) NOPASSWD: /bin/umount -f /tmp/*/mnt/proc
|
||||
ALL ALL=(root) NOPASSWD: /bin/umount -f /tmp/*/mnt/sys
|
||||
ALL ALL=(root) NOPASSWD: /bin/umount -f /tmp/*/mnt/tmp/in_target.d
|
||||
ALL ALL=(root) NOPASSWD: /sbin/mkfs -F -t ext4 -L cloudimg-rootfs /dev/nbd0p1
|
||||
ALL ALL=(root) NOPASSWD: /sbin/modprobe nbd max_part=16
|
||||
ALL ALL=(root) NOPASSWD: /sbin/sfdisk /dev/nbd0
|
||||
ALL ALL=(root) NOPASSWD: /usr/bin/qemu-nbd -c /dev/nbd0 --cache=writeback /tmp/*/image
|
||||
ALL ALL=(root) NOPASSWD: /usr/bin/qemu-nbd -d /dev/nbd0
|
||||
ALL ALL=(root) NOPASSWD: /usr/bin/touch /tmp/*/mnt/*
|
||||
ALL ALL=(root) NOPASSWD: /usr/bin/unlink /tmp/*/mnt/*
|
||||
ALL ALL=(root) SETENV: NOPASSWD: /usr/sbin/chroot /tmp/*/mnt *
|
Loading…
Reference in a new issue