blob: 2a1bc808eb3f4258d14951e480975bc602dd0d28 [file] [log] [blame]
Jesse Andrewse97a2e72011-10-30 18:37:49 -07001#!/usr/bin/env bash
2
3# exit on error to stop unexpected errors
4set -o errexit
5
6# Make sure that we have the proper version of ubuntu
7UBUNTU_VERSION=`cat /etc/lsb-release | grep CODENAME | sed 's/.*=//g'`
8if [ ! "oneiric" = "$UBUNTU_VERSION" ]; then
9 if [ ! "natty" = "$UBUNTU_VERSION" ]; then
10 echo "This script only works with oneiric and natty"
11 exit 1
12 fi
13fi
14
15# Echo commands
16set -o xtrace
17
18# Keep track of the current directory
19TOOLS_DIR=$(cd $(dirname "$0") && pwd)
20TOP_DIR=$TOOLS_DIR/..
21
22# Where to store files and instances
23WORK_DIR=${WORK_DIR:-$TOP_DIR/work}
24
25# Where to store images
26IMAGES_DIR=$WORK_DIR/images
27
28# Create images dir
29mkdir -p $IMAGES_DIR
30
31# Abort if localrc is not set
32if [ ! -e $TOP_DIR/localrc ]; then
33 echo "You must have a localrc with ALL necessary passwords defined before proceeding."
34 echo "See stack.sh for required passwords."
35 exit 1
36fi
37
38# Source params
39source ./stackrc
40
41# Configure the root password of the vm to be the same as ``ADMIN_PASSWORD``
42ROOT_PASSWORD=${ADMIN_PASSWORD:-password}
43
44
45# Base image (natty by default)
46DIST_NAME=${DIST_NAME:-natty}
47IMAGE_FNAME=$DIST_NAME.raw
48
49# Name of our instance, used by libvirt
50GUEST_NAME=${GUEST_NAME:-devstack}
51
52# Original version of built image
53BASE_IMAGE=$WORK_DIR/images/$DIST_NAME.raw
54
55# Copy of base image, which we pre-install with tasty treats
56VM_IMAGE=$IMAGES_DIR/$DIST_NAME.$GUEST_NAME.raw
57
58# Mop up after previous runs
59virsh destroy $GUEST_NAME || true
60
61# Where this vm is stored
62VM_DIR=$WORK_DIR/instances/$GUEST_NAME
63
64# Create vm dir
65mkdir -p $VM_DIR
66
67# Mount point into copied base image
68COPY_DIR=$VM_DIR/copy
69mkdir -p $COPY_DIR
70
71# Create the base image if it does not yet exist
72if [ ! -e $IMAGES_DIR/$IMAGE_FNAME ]; then
73 cd $TOOLS_DIR
74 ./make_image.sh -m -r 5000 $DIST_NAME raw
75 mv $DIST_NAME.raw $BASE_IMAGE
76 cd $TOP_DIR
77fi
78
79# Create a copy of the base image
80if [ ! -e $VM_IMAGE ]; then
81 cp -p $BASE_IMAGE $VM_IMAGE
82fi
83
84# Unmount the copied base image
85function unmount_images() {
86 # unmount the filesystem
87 while df | grep -q $COPY_DIR; do
88 umount $COPY_DIR || echo 'ok'
89 sleep 1
90 done
91}
92
93# Unmount from failed runs
94unmount_images
95
96# Ctrl-c catcher
97function kill_unmount() {
98 unmount_images
99 exit 1
100}
101
102# Install deps if needed
103dpkg -l kvm libvirt-bin kpartx || apt-get install -y --force-yes kvm libvirt-bin kpartx
104
105# Let Ctrl-c kill tail and exit
106trap kill_unmount SIGINT
107
108# Where Openstack code will live in image
109DEST=${DEST:-/opt/stack}
110
111# Mount the file system
112mount -o loop,offset=32256 $VM_IMAGE $COPY_DIR
113
114# git clone only if directory doesn't exist already. Since ``DEST`` might not
115# be owned by the installation user, we create the directory and change the
116# ownership to the proper user.
117function git_clone {
118 if [ ! -d $2 ]; then
119 sudo mkdir $2
120 sudo chown `whoami` $2
121 git clone $1 $2
122 cd $2
123 # This checkout syntax works for both branches and tags
124 git checkout $3
125 fi
126}
127
128# Make sure that base requirements are installed
129cp /etc/resolv.conf $COPY_DIR/etc/resolv.conf
130chroot $COPY_DIR apt-get update
131chroot $COPY_DIR apt-get install -y --force-yes `cat files/apts/* | cut -d\# -f1 | egrep -v "(rabbitmq|libvirt-bin|mysql-server)"`
132chroot $COPY_DIR apt-get install -y --download-only rabbitmq-server libvirt-bin mysql-server
133chroot $COPY_DIR pip install `cat files/pips/*`
134
135# Clean out code repos if directed to do so
136if [ "$CLEAN" = "1" ]; then
137 rm -rf $COPY_DIR/$DEST
138fi
139
140# Cache openstack code
141mkdir -p $COPY_DIR/$DEST
142git_clone $NOVA_REPO $COPY_DIR/$DEST/nova $NOVA_BRANCH
143git_clone $GLANCE_REPO $COPY_DIR/$DEST/glance $GLANCE_BRANCH
144git_clone $KEYSTONE_REPO $COPY_DIR/$DESTkeystone $KEYSTONE_BRANCH
145git_clone $NOVNC_REPO $COPY_DIR/$DEST/noVNC $NOVNC_BRANCH
146git_clone $HORIZON_REPO $COPY_DIR/$DEST/horizon $HORIZON_BRANCH $HORIZON_TAG
147git_clone $NOVACLIENT_REPO $COPY_DIR/$DEST/python-novaclient $NOVACLIENT_BRANCH
148git_clone $OPENSTACKX_REPO $COPY_DIR/$DEST/openstackx $OPENSTACKX_BRANCH
149git_clone $KEYSTONE_REPO $COPY_DIR/$DEST/keystone $KEYSTONE_BRANCH
150git_clone $NOVNC_REPO $COPY_DIR/$DEST/noVNC $NOVNC_BRANCH
151
152# Back to devstack
153cd $TOP_DIR
154
155# Unmount the filesystems
156unmount_images
157
158# Network configuration variables
Jesse Andrewse97a2e72011-10-30 18:37:49 -0700159GUEST_NETWORK=${GUEST_NETWORK:-1}
160
161GUEST_IP=${GUEST_IP:-192.168.$GUEST_NETWORK.50}
162GUEST_CIDR=${GUEST_CIDR:-$GUEST_IP/24}
163GUEST_NETMASK=${GUEST_NETMASK:-255.255.255.0}
164GUEST_GATEWAY=${GUEST_GATEWAY:-192.168.$GUEST_NETWORK.1}
165GUEST_MAC=${GUEST_MAC:-"02:16:3e:07:69:`printf '%02X' $GUEST_NETWORK`"}
166GUEST_RAM=${GUEST_RAM:-1524288}
167GUEST_CORES=${GUEST_CORES:-1}
168
169# libvirt.xml configuration
170NET_XML=$VM_DIR/net.xml
171cat > $NET_XML <<EOF
172<network>
173 <name>devstack-$GUEST_NETWORK</name>
174 <bridge name="stackbr%d" />
175 <forward/>
176 <ip address="$GUEST_GATEWAY" netmask="$GUEST_NETMASK" />
177</network>
178EOF
179
180virsh net-destroy devstack-$GUEST_NETWORK || true
181virsh net-create $VM_DIR/net.xml
182
183# libvirt.xml configuration
184LIBVIRT_XML=$VM_DIR/libvirt.xml
185cat > $LIBVIRT_XML <<EOF
186<domain type='kvm'>
187 <name>$GUEST_NAME</name>
188 <memory>$GUEST_RAM</memory>
189 <os>
190 <type>hvm</type>
191 <bootmenu enable='yes'/>
192 </os>
193 <features>
194 <acpi/>
195 </features>
196 <vcpu>$GUEST_CORES</vcpu>
197 <devices>
198 <disk type='file'>
199 <driver type='qcow2'/>
200 <source file='$VM_DIR/disk'/>
201 <target dev='vda' bus='virtio'/>
202 </disk>
203
204 <interface type='network'>
205 <source network='devstack-$GUEST_NETWORK'/>
206 </interface>
207
208 <!-- The order is significant here. File must be defined first -->
209 <serial type="file">
210 <source path='$VM_DIR/console.log'/>
211 <target port='1'/>
212 </serial>
213
214 <console type='pty' tty='/dev/pts/2'>
215 <source path='/dev/pts/2'/>
216 <target port='0'/>
217 </console>
218
219 <serial type='pty'>
220 <source path='/dev/pts/2'/>
221 <target port='0'/>
222 </serial>
223
224 <graphics type='vnc' port='-1' autoport='yes' keymap='en-us' listen='0.0.0.0'/>
225 </devices>
226</domain>
227EOF
228
229# Mount point for instance fs
230ROOTFS=$VM_DIR/root
231mkdir -p $ROOTFS
232
233# Make sure we have nbd-ness
234modprobe nbd max_part=63
235
236# Which NBD device to use?
237NBD=${NBD:-/dev/nbd5}
238
239# Clean up from previous runs
240umount $ROOTFS || echo 'ok'
241qemu-nbd -d $NBD || echo 'ok'
242
243# Clean up old runs
244cd $VM_DIR
245rm -f $VM_DIR/disk
246
247# Create our instance fs
248qemu-img create -f qcow2 -b $VM_IMAGE disk
249
250# Connect our nbd and wait till it is mountable
251qemu-nbd -c $NBD disk
252NBD_DEV=`basename $NBD`
253if ! timeout 60 sh -c "while ! [ -e /sys/block/$NBD_DEV/pid ]; do sleep 1; done"; then
254 echo "Couldn't connect $NBD"
255 exit 1
256fi
257
258# Mount the instance
259mount $NBD $ROOTFS -o offset=32256 -t ext4
260
261# Configure instance network
262INTERFACES=$ROOTFS/etc/network/interfaces
263cat > $INTERFACES <<EOF
264auto lo
265iface lo inet loopback
266
267auto eth0
268iface eth0 inet static
269 address $GUEST_IP
270 netmask $GUEST_NETMASK
271 gateway $GUEST_GATEWAY
272EOF
273
274# User configuration for the instance
275chroot $ROOTFS groupadd libvirtd || true
276chroot $ROOTFS useradd stack -s /bin/bash -d $DEST -G libvirtd
277cp -pr $TOOLS_DIR/.. $ROOTFS/$DEST/devstack
278echo "root:$ROOT_PASSWORD" | chroot $ROOTFS chpasswd
279echo "stack:pass" | chroot $ROOTFS chpasswd
280echo "stack ALL=(ALL) NOPASSWD: ALL" >> $ROOTFS/etc/sudoers
281
282# Gracefully cp only if source file/dir exists
283function cp_it {
284 if [ -e $1 ] || [ -d $1 ]; then
285 cp -pRL $1 $2
286 fi
287}
288
289# Copy over your ssh keys and env if desired
290COPYENV=${COPYENV:-1}
291if [ "$COPYENV" = "1" ]; then
292 cp_it ~/.ssh $ROOTFS/$DEST/.ssh
293 cp_it ~/.ssh/id_rsa.pub $ROOTFS/$DEST/.ssh/authorized_keys
294 cp_it ~/.gitconfig $ROOTFS/$DEST/.gitconfig
295 cp_it ~/.vimrc $ROOTFS/$DEST/.vimrc
296 cp_it ~/.bashrc $ROOTFS/$DEST/.bashrc
297fi
298
299# pre-cache uec images
300for image_url in ${IMAGE_URLS//,/ }; do
301 IMAGE_FNAME=`basename "$image_url"`
302 if [ ! -f $IMAGES_DIR/$IMAGE_FNAME ]; then
303 wget -c $image_url -O $IMAGES_DIR/$IMAGE_FNAME
304 fi
305 cp $IMAGES_DIR/$IMAGE_FNAME $ROOTFS/$DEST/devstack/files
306done
307
308# Configure the runner
309RUN_SH=$ROOTFS/$DEST/run.sh
310cat > $RUN_SH <<EOF
311#!/usr/bin/env bash
312
313# Kill any existing screens
314killall screen
315
316# Install and run stack.sh
317sudo apt-get update
318sudo apt-get -y --force-yes install git-core vim-nox sudo
319if [ ! -d "$DEST/devstack" ]; then
320 git clone git://github.com/cloudbuilders/devstack.git $DEST/devstack
321fi
322cd $DEST/devstack && $STACKSH_PARAMS FORCE=yes ./stack.sh > /$DEST/run.sh.log
323echo >> /$DEST/run.sh.log
324echo >> /$DEST/run.sh.log
325echo "All done! Time to start clicking." >> /$DEST/run.sh.log
326cat $DEST/run.sh.log
327EOF
328chmod 755 $RUN_SH
329
330# Make runner launch on boot
331RC_LOCAL=$ROOTFS/etc/init.d/local
332cat > $RC_LOCAL <<EOF
333#!/bin/sh -e
334# Reboot if this is our first run to enable console log on $DIST_NAME :(
335if [ ! -e /root/firstlaunch ]; then
336 touch /root/firstlaunch
337 reboot -f
338 exit 0
339fi
340su -c "$DEST/run.sh" stack
341EOF
342chmod +x $RC_LOCAL
343chroot $ROOTFS sudo update-rc.d local defaults 80
344
345# Make our ip address hostnames look nice at the command prompt
346echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $ROOTFS/$DEST/.bashrc
347echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $ROOTFS/etc/profile
348
349# Give stack ownership over $DEST so it may do the work needed
350chroot $ROOTFS chown -R stack $DEST
351
352# Change boot params so that we get a console log
353sudo sed -e "s/quiet splash/splash console=ttyS0 console=ttyS1,19200n8/g" -i $ROOTFS/boot/grub/menu.lst
354sudo sed -e "s/^hiddenmenu//g" -i $ROOTFS/boot/grub/menu.lst
355
356# Set the hostname
357echo $GUEST_NAME > $ROOTFS/etc/hostname
358
359# We need the hostname to resolve for rabbit to launch
360if ! grep -q $GUEST_NAME $ROOTFS/etc/hosts; then
361 echo "$GUEST_IP $GUEST_NAME" >> $ROOTFS/etc/hosts
362fi
363
364# Unmount
365umount $ROOTFS || echo 'ok'
366qemu-nbd -d $NBD
367
368# Create the instance
369cd $VM_DIR && virsh create libvirt.xml
370
371# Tail the console log till we are done
372WAIT_TILL_LAUNCH=${WAIT_TILL_LAUNCH:-1}
373if [ "$WAIT_TILL_LAUNCH" = "1" ]; then
374 # Done creating the container, let's tail the log
375 echo
376 echo "============================================================="
377 echo " -- YAY! --"
378 echo "============================================================="
379 echo
380 echo "We're done launching the vm, about to start tailing the"
381 echo "stack.sh log. It will take a second or two to start."
382 echo
383 echo "Just CTRL-C at any time to stop tailing."
384
385 while [ ! -e "$VM_DIR/console.log" ]; do
386 sleep 1
387 done
388
389 tail -F $VM_DIR/console.log &
390
391 TAIL_PID=$!
392
393 function kill_tail() {
394 kill $TAIL_PID
395 exit 1
396 }
397
398 # Let Ctrl-c kill tail and exit
399 trap kill_tail SIGINT
400
401 echo "Waiting stack.sh to finish..."
402 while ! cat $VM_DIR/console.log | grep -q 'All done' ; do
403 sleep 5
404 done
405
406 kill $TAIL_PID
407
408 if grep -q "stack.sh failed" $VM_DIR/console.log; then
409 exit 1
410 fi
411 echo ""
412 echo "Finished - Zip-a-dee Doo-dah!"
413fi