stack.sh
ba23cc73
 #!/usr/bin/env bash
 
0e7e897b
 # **stack.sh** is an opinionated openstack developer installation.
 
ca85b799
 # This script installs and configures *nova*, *glance*, *horizon* and *keystone*
ba23cc73
 
9b353671
 # This script allows you to specify configuration options of what git
5372f433
 # repositories to use, enabled services, network configuration and various
 # passwords.  If you are crafty you can run the script on multiple nodes using
 # shared settings for common resources (mysql, rabbitmq) and build a multi-node
 # developer install.
782b9917
 
38df1228
 # To keep this script simple we assume you are running on an **Ubuntu 11.10
 # Oneiric** machine.  It should work in a VM or physical server.  Additionally
 # we put the list of *apt* and *pip* dependencies and other configuration files
 # in this repo.  So start by grabbing this script and the dependencies.
24859060
 
0e7e897b
 # Learn more and get the most recent version at http://devstack.org
6edd17f7
 
 # Sanity Check
 # ============
 
38df1228
 # Warn users who aren't on oneiric, but allow them to override check and attempt
6edd17f7
 # installation with ``FORCE=yes ./stack``
adfc029a
 DISTRO=$(lsb_release -c -s)
 
38df1228
 if [[ ! ${DISTRO} =~ (oneiric) ]]; then
     echo "WARNING: this script has only been tested on oneiric"
6edd17f7
     if [[ "$FORCE" != "yes" ]]; then
         echo "If you wish to run this script anyway run with FORCE=yes"
         exit 1
     fi
 fi
 
51fb22ef
 # Keep track of the current devstack directory.
 TOP_DIR=$(cd $(dirname "$0") && pwd)
 
40a37006
 # stack.sh keeps the list of **apt** and **pip** dependencies in external
4d282189
 # files, along with config templates and other useful files.  You can find these
40a37006
 # in the ``files`` directory (next to this script).  We will reference this
bf3868d8
 # directory using the ``FILES`` variable in this script.
51fb22ef
 FILES=$TOP_DIR/files
bf3868d8
 if [ ! -d $FILES ]; then
     echo "ERROR: missing devstack/files - did you grab more than just stack.sh?"
6edd17f7
     exit 1
 fi
 
6015c82a
 
9122e7b1
 
 # Settings
 # ========
 
 # This script is customizable through setting environment variables.  If you
 # want to override a setting you can either::
 #
 #     export MYSQL_PASSWORD=anothersecret
 #     ./stack.sh
 #
 # You can also pass options on a single line ``MYSQL_PASSWORD=simple ./stack.sh``
 #
 # Additionally, you can put any local variables into a ``localrc`` file, like::
 #
 #     MYSQL_PASSWORD=anothersecret
 #     MYSQL_USER=hellaroot
 #
 # We try to have sensible defaults, so you should be able to run ``./stack.sh``
 # in most cases.
 #
38df1228
 # We source our settings from ``stackrc``.  This file is distributed with devstack
 # and contains locations for what repositories to use.  If you want to use other
 # repositories and branches, you can add your own settings with another file called
 # ``localrc``
9122e7b1
 #
9b353671
 # If ``localrc`` exists, then ``stackrc`` will load those settings.  This is
3d9c5d5e
 # useful for changing a branch or repository to test other versions.  Also you
9122e7b1
 # can store your other settings like **MYSQL_PASSWORD** or **ADMIN_PASSWORD** instead
 # of letting devstack generate random ones for you.
 source ./stackrc
 
 # Destination path for installation ``DEST``
 DEST=${DEST:-/opt/stack}
 
5855a644
 # Configure services to syslog instead of writing to individual log files
 SYSLOG=${SYSLOG:-False}
 
0a16145a
 # apt-get wrapper to just get arguments set correctly
 function apt_get() {
     local sudo="sudo"
     [ "$(id -u)" = "0" ] && sudo="env"
     $sudo DEBIAN_FRONTEND=noninteractive apt-get \
         --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
 }
 
 
ca85b799
 # OpenStack is designed to be run as a regular user (Horizon will fail to run
782b9917
 # as root, since apache refused to startup serve content from root user).  If
 # stack.sh is run as root, it automatically creates a stack user with
c9e3fff7
 # sudo privileges and runs as that user.
cbe98d56
 
d4622953
 if [[ $EUID -eq 0 ]]; then
92e81992
     ROOTSLEEP=${ROOTSLEEP:-10}
0031df01
     echo "You are running this script as root."
92e81992
     echo "In $ROOTSLEEP seconds, we will create a user 'stack' and run as that user"
     sleep $ROOTSLEEP
782b9917
 
0031df01
     # since this script runs as a normal user, we need to give that user
     # ability to run sudo
c7f72ad8
     dpkg -l sudo || apt_get update && apt_get install sudo
782b9917
 
0d2145a0
     if ! getent passwd stack >/dev/null; then
0031df01
         echo "Creating a user called stack"
9122e7b1
         useradd -U -G sudo -s /bin/bash -d $DEST -m stack
c9e3fff7
     fi
0d2145a0
 
782b9917
     echo "Giving stack user passwordless sudo priviledges"
38df1228
     # some uec images sudoers does not have a '#includedir'. add one.
4bec581e
     grep -q "^#includedir.*/etc/sudoers.d" /etc/sudoers ||
         echo "#includedir /etc/sudoers.d" >> /etc/sudoers
55c9d3f1
     ( umask 226 && echo "stack ALL=(ALL) NOPASSWD:ALL" \
         > /etc/sudoers.d/50_stack_sh )
782b9917
 
c9e3fff7
     echo "Copying files to stack user"
9122e7b1
     STACK_DIR="$DEST/${PWD##*/}"
0d2145a0
     cp -r -f "$PWD" "$STACK_DIR"
5f4ae107
     chown -R stack "$STACK_DIR"
74c084cd
     if [[ "$SHELL_AFTER_RUN" != "no" ]]; then
102e440e
         exec su -c "set -e; cd $STACK_DIR; bash stack.sh; bash" stack
74c084cd
     else
102e440e
         exec su -c "set -e; cd $STACK_DIR; bash stack.sh" stack
74c084cd
     fi
f9da5081
     exit 1
509992fe
 else
3e2b1744
     # Our user needs passwordless priviledges for certain commands which nova
509992fe
     # uses internally.
     # Natty uec images sudoers does not have a '#includedir'. add one.
84a399b4
     sudo grep -q "^#includedir.*/etc/sudoers.d" /etc/sudoers ||
         echo "#includedir /etc/sudoers.d" | sudo tee -a /etc/sudoers
0a16145a
     TEMPFILE=`mktemp`
     cat $FILES/sudo/nova > $TEMPFILE
     sed -e "s,%USER%,$USER,g" -i $TEMPFILE
     chmod 0440 $TEMPFILE
     sudo chown root:root $TEMPFILE
f8c4684b
     sudo mv $TEMPFILE /etc/sudoers.d/stack_sh_nova
d4622953
 fi
 
6f3baafd
 # Set the destination directories for openstack projects
ba23cc73
 NOVA_DIR=$DEST/nova
ca85b799
 HORIZON_DIR=$DEST/horizon
ba23cc73
 GLANCE_DIR=$DEST/glance
 KEYSTONE_DIR=$DEST/keystone
 NOVACLIENT_DIR=$DEST/python-novaclient
2f140207
 OPENSTACKX_DIR=$DEST/openstackx
ba23cc73
 NOVNC_DIR=$DEST/noVNC
28fa4e8d
 SWIFT_DIR=$DEST/swift
45c51137
 SWIFT_KEYSTONE_DIR=$DEST/swift-keystone2
1bfa3d53
 QUANTUM_DIR=$DEST/quantum
 
 # Default Quantum Plugin
 Q_PLUGIN=${Q_PLUGIN:-openvswitch}
a841644e
 
 # Specify which services to launch.  These generally correspond to screen tabs
4982ef90
 ENABLED_SERVICES=${ENABLED_SERVICES:-g-api,g-reg,key,n-api,n-cpu,n-net,n-sch,n-vnc,horizon,mysql,rabbit,openstackx}
ba23cc73
 
d02b7b7b
 # Name of the lvm volume group to use/create for iscsi volumes
 VOLUME_GROUP=${VOLUME_GROUP:-nova-volumes}
 
b62b4ca2
 # Nova hypervisor configuration.  We default to libvirt whth  **kvm** but will
 # drop back to **qemu** if we are unable to load the kvm module.  Stack.sh can
 # also install an **LXC** based system.
 VIRT_DRIVER=${VIRT_DRIVER:-libvirt}
782b9917
 LIBVIRT_TYPE=${LIBVIRT_TYPE:-kvm}
 
cbe98d56
 # nova supports pluggable schedulers.  ``SimpleScheduler`` should work in most
 # cases unless you are working on multi-zone mode.
782b9917
 SCHEDULER=${SCHEDULER:-nova.scheduler.simple.SimpleScheduler}
 
7c259cea
 # Use the eth0 IP unless an explicit is set by ``HOST_IP`` environment variable
ba23cc73
 if [ ! -n "$HOST_IP" ]; then
7c259cea
     HOST_IP=`LC_ALL=C /sbin/ifconfig eth0 | grep -m 1 'inet addr:'| cut -d: -f2 | awk '{print $1}'`
a3475e53
     if [ "$HOST_IP" = "" ]; then
857035dc
         echo "Could not determine host ip address."
         echo "If this is not your first run of stack.sh, it is "
         echo "possible that nova moved your eth0 ip address to the FLAT_NETWORK_BRIDGE."
         echo "Please specify your HOST_IP in your localrc."
7c259cea
         exit 1
     fi
ba23cc73
 fi
 
2bbcd682
 # Service startup timeout
 SERVICE_TIMEOUT=${SERVICE_TIMEOUT:-60}
 
7a549f40
 # Generic helper to configure passwords
 function read_password {
     set +o xtrace
     var=$1; msg=$2
     pw=${!var}
 
b4db2254
     localrc=$TOP_DIR/localrc
6015c82a
 
7a549f40
     # If the password is not defined yet, proceed to prompt user for a password.
     if [ ! $pw ]; then
         # If there is no localrc file, create one
b4db2254
         if [ ! -e $localrc ]; then
             touch $localrc
7a549f40
         fi
 
9b353671
         # Presumably if we got this far it can only be that our localrc is missing
7a549f40
         # the required password.  Prompt user for a password and write to localrc.
b4db2254
         echo ''
         echo '################################################################################'
         echo $msg
         echo '################################################################################'
         echo "This value will be written to your localrc file so you don't have to enter it again."
         echo "It is probably best to avoid spaces and weird characters."
         echo "If you leave this blank, a random default value will be used."
         echo "Enter a password now:"
         read $var
         pw=${!var}
         if [ ! $pw ]; then
             pw=`openssl rand -hex 10`
7a549f40
         fi
b4db2254
         eval "$var=$pw"
         echo "$var=$pw" >> $localrc
7a549f40
     fi
     set -o xtrace
 }
 
 
782b9917
 # Nova Network Configuration
 # --------------------------
 
9b353671
 # FIXME: more documentation about why these are important flags.  Also
5372f433
 # we should make sure we use the same variable names as the flag names.
 
eb31af87
 # Allow the use of an alternate hostname (such as localhost/127.0.0.1) for service endpoints.
 SERVICE_HOST=${SERVICE_HOST:-$HOST_IP}
b1bdd5e2
 PUBLIC_INTERFACE=${PUBLIC_INTERFACE:-eth0}
b5197e40
 FIXED_RANGE=${FIXED_RANGE:-10.0.0.0/24}
 FIXED_NETWORK_SIZE=${FIXED_NETWORK_SIZE:-256}
0e74ecb4
 FLOATING_RANGE=${FLOATING_RANGE:-172.24.4.224/28}
a72f7ad3
 NET_MAN=${NET_MAN:-FlatDHCPManager}
eb31af87
 EC2_DMZ_HOST=${EC2_DMZ_HOST:-$SERVICE_HOST}
b1bdd5e2
 FLAT_NETWORK_BRIDGE=${FLAT_NETWORK_BRIDGE:-br100}
cbe98d56
 VLAN_INTERFACE=${VLAN_INTERFACE:-$PUBLIC_INTERFACE}
 
 # Multi-host is a mode where each compute node runs its own network node.  This
 # allows network operations and routing for a VM to occur on the server that is
 # running the VM - removing a SPOF and bandwidth bottleneck.
5f039326
 MULTI_HOST=${MULTI_HOST:-False}
30f68e96
 
d74257d0
 # If you are using FlatDHCP on multiple hosts, set the ``FLAT_INTERFACE``
 # variable but make sure that the interface doesn't already have an
 # ip or you risk breaking things.
5372f433
 #
9b353671
 # **DHCP Warning**:  If your flat interface device uses DHCP, there will be a
 # hiccup while the network is moved from the flat interface to the flat network
 # bridge.  This will happen when you launch your first instance.  Upon launch
 # you will lose all connectivity to the node, and the vm launch will probably
5372f433
 # fail.
9b353671
 #
 # If you are running on a single node and don't need to access the VMs from
5372f433
 # devices other than that node, you can set the flat interface to the same
9b353671
 # value as ``FLAT_NETWORK_BRIDGE``.  This will stop the network hiccup from
3d9c5d5e
 # occurring.
8ff5dbc2
 FLAT_INTERFACE=${FLAT_INTERFACE:-eth0}
ba23cc73
 
cbe98d56
 ## FIXME(ja): should/can we check that FLAT_INTERFACE is sane?
 
1bfa3d53
 # Using Quantum networking:
 #
 # Make sure that q-svc is enabled in ENABLED_SERVICES.  If it is the network
 # manager will be set to the QuantumManager.
 #
 # If you're planning to use the Quantum openvswitch plugin, set Q_PLUGIN to
 # "openvswitch" and make sure the q-agt service is enabled in
 # ENABLED_SERVICES.
 #
 # With Quantum networking the NET_MAN variable is ignored.
 
d74257d0
 
782b9917
 # MySQL & RabbitMQ
 # ----------------
 
ca85b799
 # We configure Nova, Horizon, Glance and Keystone to use MySQL as their
782b9917
 # database server.  While they share a single server, each has their own
 # database and tables.
 
9b353671
 # By default this script will install and configure MySQL.  If you want to
782b9917
 # use an existing server, you can pass in the user/password/host parameters.
7a549f40
 # You will need to send the same ``MYSQL_PASSWORD`` to every host if you are doing
782b9917
 # a multi-node devstack installation.
a50a3461
 MYSQL_HOST=${MYSQL_HOST:-localhost}
320412b2
 MYSQL_USER=${MYSQL_USER:-root}
7a549f40
 read_password MYSQL_PASSWORD "ENTER A PASSWORD TO USE FOR MYSQL."
782b9917
 
a841644e
 # don't specify /db in this string, so we can use it for multiple services
7a549f40
 BASE_SQL_CONN=${BASE_SQL_CONN:-mysql://$MYSQL_USER:$MYSQL_PASSWORD@$MYSQL_HOST}
a841644e
 
 # Rabbit connection info
 RABBIT_HOST=${RABBIT_HOST:-localhost}
7a549f40
 read_password RABBIT_PASSWORD "ENTER A PASSWORD TO USE FOR RABBIT."
ba23cc73
 
377aae6f
 # Glance connection info.  Note the port must be specified.
eb31af87
 GLANCE_HOSTPORT=${GLANCE_HOSTPORT:-$SERVICE_HOST:9292}
377aae6f
 
28fa4e8d
 # SWIFT
 # -----
3d9c5d5e
 # TODO: implement glance support
 # TODO: add logging to different location.
b93478f6
 
3d9c5d5e
 # By default the location of swift drives and objects is located inside
38750150
 # the swift source directory. SWIFT_DATA_LOCATION variable allow you to redefine
3d9c5d5e
 # this.
38750150
 SWIFT_DATA_LOCATION=${SWIFT_DATA_LOCATION:-${SWIFT_DIR}/data}
28fa4e8d
 
3a64826b
 # We are going to have the configuration files inside the source
 # directory, change SWIFT_CONFIG_LOCATION if you want to adjust that.
 SWIFT_CONFIG_LOCATION=${SWIFT_CONFIG_LOCATION:-${SWIFT_DIR}/config}
28fa4e8d
 
3d9c5d5e
 # devstack will create a loop-back disk formatted as XFS to store the
 # swift data. By default the disk size is 1 gigabyte. The variable
 # SWIFT_LOOPBACK_DISK_SIZE specified in bytes allow you to change
 # that.
28fa4e8d
 SWIFT_LOOPBACK_DISK_SIZE=${SWIFT_LOOPBACK_DISK_SIZE:-1000000}
7a549f40
 
3d9c5d5e
 # The ring uses a configurable number of bits from a path’s MD5 hash as
 # a partition index that designates a device. The number of bits kept
 # from the hash is known as the partition power, and 2 to the partition
 # power indicates the partition count. Partitioning the full MD5 hash
 # ring allows other parts of the cluster to work in batches of items at
 # once which ends up either more efficient or at least less complex than
 # working with each item separately or the entire cluster all at once.
 # By default we define 9 for the partition count (which mean 512).
a2118984
 SWIFT_PARTITION_POWER_SIZE=${SWIFT_PARTITION_POWER_SIZE:-9}
 
b2857e4d
 # We only ask for Swift Hash if we have enabled swift service.
 if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
     # SWIFT_HASH is a random unique string for a swift cluster that
     # can never change.
     read_password SWIFT_HASH "ENTER A RANDOM SWIFT HASH."
 fi
5f039326
 
782b9917
 # Keystone
 # --------
 
b96871e4
 # Service Token - Openstack components need to have an admin token
 # to validate user tokens.
7a549f40
 read_password SERVICE_TOKEN "ENTER A SERVICE_TOKEN TO USE FOR THE SERVICE ADMIN TOKEN."
ca85b799
 # Horizon currently truncates usernames and passwords at 20 characters
 read_password ADMIN_PASSWORD "ENTER A PASSWORD TO USE FOR HORIZON AND KEYSTONE (20 CHARS OR LESS)."
b96871e4
 
f9da5081
 LOGFILE=${LOGFILE:-"$PWD/stack.sh.$$.log"}
 (
 # So that errors don't compound we exit on any errors so you see only the
3d9c5d5e
 # first error that occurred.
f9da5081
 trap failed ERR
 failed() {
     local r=$?
     set +o xtrace
     [ -n "$LOGFILE" ] && echo "${0##*/} failed: full log in $LOGFILE"
     exit $r
 }
 
 # Print the commands being run so that we can see the command that triggers
 # an error.  It is also useful for following along as the install occurs.
 set -o xtrace
 
fe95e0fe
 # create the destination directory and ensure it is writable by the user
f9da5081
 sudo mkdir -p $DEST
fe95e0fe
 if [ ! -w $DEST ]; then
     sudo chown `whoami` $DEST
 fi
53ed387d
 
30f68e96
 # Install Packages
d74257d0
 # ================
30f68e96
 #
 # Openstack uses a fair number of other projects.
 
0277d5b9
 # - We are going to install packages only for the services needed.
 # - We are parsing the packages files and detecting metadatas.
a6353c62
 #  - If there is a NOPRIME as comment mean we are not doing the install
 #    just yet.
0277d5b9
 #  - If we have the meta-keyword distro:DISTRO or
 #    distro:DISTRO1,DISTRO2 it will be installed only for those
 #    distros (case insensitive).
 function get_packages() {
     local file_to_parse="general"
     local service
38df1228
 
0277d5b9
     for service in ${ENABLED_SERVICES//,/ }; do
         if [[ $service == n-* ]]; then
f990ded5
             if [[ ! $file_to_parse =~ nova ]]; then
0277d5b9
                 file_to_parse="${file_to_parse} nova"
             fi
f990ded5
         elif [[ $service == g-* ]]; then
             if [[ ! $file_to_parse =~ glance ]]; then
0277d5b9
                 file_to_parse="${file_to_parse} glance"
             fi
f990ded5
         elif [[ $service == key* ]]; then
             if [[ ! $file_to_parse =~ keystone ]]; then
0277d5b9
                 file_to_parse="${file_to_parse} keystone"
             fi
f990ded5
         elif [[ -e $FILES/apts/${service} ]]; then
0277d5b9
             file_to_parse="${file_to_parse} $service"
         fi
     done
 
f990ded5
     for file in ${file_to_parse}; do
0277d5b9
         local fname=${FILES}/apts/${file}
         local OIFS line package distros distro
         [[ -e $fname ]] || { echo "missing: $fname"; exit 1 ;}
 
         OIFS=$IFS
         IFS=$'\n'
2d1a8b34
         for line in $(<${fname}); do
a6353c62
             if [[ $line =~ "NOPRIME" ]]; then
                 continue
             fi
 
f990ded5
             if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then # We are using BASH regexp matching feature.
0277d5b9
                         package=${BASH_REMATCH[1]}
                         distros=${BASH_REMATCH[2]}
f990ded5
                         for distro in ${distros//,/ }; do  #In bash ${VAR,,} will lowecase VAR
0277d5b9
                             [[ ${distro,,} == ${DISTRO,,} ]] && echo $package
                         done
                         continue
             fi
 
             echo ${line%#*}
         done
         IFS=$OIFS
     done
 }
75a37653
 
 # install apt requirements
ee1b495d
 apt_get update
0277d5b9
 apt_get install $(get_packages)
75a37653
 
 # install python requirements
9bb1a3c5
 sudo PIP_DOWNLOAD_CACHE=/var/cache/pip pip install --use-mirrors `cat $FILES/pips/*`
75a37653
 
d61db859
 # git clone only if directory doesn't exist already.  Since ``DEST`` might not
 # be owned by the installation user, we create the directory and change the
 # ownership to the proper user.
6163257a
 function git_clone {
1f273600
 
917c6658
     GIT_REMOTE=$1
     GIT_DEST=$2
     GIT_BRANCH=$3
 
eeec0206
     # do a full clone only if the directory doesn't exist
917c6658
     if [ ! -d $GIT_DEST ]; then
         git clone $GIT_REMOTE $GIT_DEST
2f140207
         cd $2
303233e2
         # This checkout syntax works for both branches and tags
917c6658
         git checkout $GIT_BRANCH
eeec0206
     elif [[ "$RECLONE" == "yes" ]]; then
         # if it does exist then simulate what clone does if asked to RECLONE
480644bd
         cd $GIT_DEST
eeec0206
         # set the url to pull from and fetch
917c6658
         git remote set-url origin $GIT_REMOTE
eeec0206
         git fetch origin
9fef844f
         # remove the existing ignored files (like pyc) as they cause breakage
         # (due to the py files having older timestamps than our pyc, so python
         # thinks the pyc files are correct using them)
6b8855cd
         find $GIT_DEST -name '*.pyc' -delete
917c6658
         git checkout -f origin/$GIT_BRANCH
e09a6e4a
         # a local branch might not exist
917c6658
         git branch -D $GIT_BRANCH || true
         git checkout -b $GIT_BRANCH
6163257a
     fi
 }
 
75a37653
 # compute service
2f140207
 git_clone $NOVA_REPO $NOVA_DIR $NOVA_BRANCH
ca85b799
 # python client library to nova that horizon (and others) use
2f140207
 git_clone $NOVACLIENT_REPO $NOVACLIENT_DIR $NOVACLIENT_BRANCH
38df1228
 
 # glance, swift middleware and nova api needs keystone middleware
411b3c67
 if [[ "$ENABLED_SERVICES" =~ "key" ||
       "$ENABLED_SERVICES" =~ "g-api" ||
       "$ENABLED_SERVICES" =~ "n-api" ||
38df1228
       "$ENABLED_SERVICES" =~ "swift" ]]; then
     # unified auth system (manages accounts/tokens)
     git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH
 fi
e7ce24fc
 if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
     # storage service
     git_clone $SWIFT_REPO $SWIFT_DIR $SWIFT_BRANCH
     # swift + keystone middleware
     git_clone $SWIFT_KEYSTONE_REPO $SWIFT_KEYSTONE_DIR $SWIFT_KEYSTONE_BRANCH
 fi
38df1228
 if [[ "$ENABLED_SERVICES" =~ "g-api" ||
       "$ENABLED_SERVICES" =~ "n-api" ]]; then
e7ce24fc
     # image catalog service
     git_clone $GLANCE_REPO $GLANCE_DIR $GLANCE_BRANCH
 fi
 if [[ "$ENABLED_SERVICES" =~ "n-vnc" ]]; then
     # a websockets/html5 or flash powered VNC console for vm instances
     git_clone $NOVNC_REPO $NOVNC_DIR $NOVNC_BRANCH
 fi
 if [[ "$ENABLED_SERVICES" =~ "horizon" ]]; then
     # django powered web control panel for openstack
     git_clone $HORIZON_REPO $HORIZON_DIR $HORIZON_BRANCH $HORIZON_TAG
 fi
 if [[ "$ENABLED_SERVICES" =~ "openstackx" ]]; then
     # openstackx is a collection of extensions to openstack.compute & nova
     # that is *deprecated*.  The code is being moved into python-novaclient & nova.
     git_clone $OPENSTACKX_REPO $OPENSTACKX_DIR $OPENSTACKX_BRANCH
 fi
 if [[ "$ENABLED_SERVICES" =~ "quantum" ]]; then
     # quantum
     git_clone $QUANTUM_REPO $QUANTUM_DIR $QUANTUM_BRANCH
 fi
75a37653
 
30f68e96
 # Initialization
d74257d0
 # ==============
30f68e96
 
d1879c5c
 
75a37653
 # setup our checkouts so they are installed into python path
d74257d0
 # allowing ``import nova`` or ``import glance.client``
411b3c67
 if [[ "$ENABLED_SERVICES" =~ "key" ||
       "$ENABLED_SERVICES" =~ "g-api" ||
       "$ENABLED_SERVICES" =~ "n-api" ||
38df1228
       "$ENABLED_SERVICES" =~ "swift" ]]; then
e7ce24fc
     cd $KEYSTONE_DIR; sudo python setup.py develop
 fi
 if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
     cd $SWIFT_DIR; sudo python setup.py develop
     cd $SWIFT_KEYSTONE_DIR; sudo python setup.py develop
 fi
38df1228
 if [[ "$ENABLED_SERVICES" =~ "g-api" ||
       "$ENABLED_SERVICES" =~ "n-api" ]]; then
e7ce24fc
     cd $GLANCE_DIR; sudo python setup.py develop
 fi
aa8bb244
 cd $NOVACLIENT_DIR; sudo python setup.py develop
 cd $NOVA_DIR; sudo python setup.py develop
e7ce24fc
 if [[ "$ENABLED_SERVICES" =~ "openstackx" ]]; then
     cd $OPENSTACKX_DIR; sudo python setup.py develop
 fi
 if [[ "$ENABLED_SERVICES" =~ "horizon" ]]; then
     cd $HORIZON_DIR/django-openstack; sudo python setup.py develop
     cd $HORIZON_DIR/openstack-dashboard; sudo python setup.py develop
 fi
 if [[ "$ENABLED_SERVICES" =~ "quantum" ]]; then
     cd $QUANTUM_DIR; sudo python setup.py develop
 fi
75a37653
 
6edd17f7
 # Add a useful screenrc.  This isn't required to run openstack but is we do
40a37006
 # it since we are going to run the services in screen for simple
bf3868d8
 cp $FILES/screenrc ~/.screenrc
dfcd2003
 
a09ae2ff
 # Rabbit
 # ---------
cbe98d56
 
a09ae2ff
 if [[ "$ENABLED_SERVICES" =~ "rabbit" ]]; then
     # Install and start rabbitmq-server
199d76e2
     # the temp file is necessary due to LP: #878600
     tfile=$(mktemp)
ee1b495d
     apt_get install rabbitmq-server > "$tfile" 2>&1
199d76e2
     cat "$tfile"
     rm -f "$tfile"
53ed387d
     # change the rabbit password since the default is "guest"
     sudo rabbitmqctl change_password guest $RABBIT_PASSWORD
a09ae2ff
 fi
ba23cc73
 
24859060
 # Mysql
 # ---------
cbe98d56
 
24859060
 if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then
cbe98d56
 
     # Seed configuration with mysql password so that apt-get install doesn't
     # prompt us for a password upon install.
     cat <<MYSQL_PRESEED | sudo debconf-set-selections
7a549f40
 mysql-server-5.1 mysql-server/root_password password $MYSQL_PASSWORD
 mysql-server-5.1 mysql-server/root_password_again password $MYSQL_PASSWORD
cbe98d56
 mysql-server-5.1 mysql-server/start_on_boot boolean true
 MYSQL_PRESEED
 
2e536a3f
     # while ``.my.cnf`` is not needed for openstack to function, it is useful
     # as it allows you to access the mysql databases via ``mysql nova`` instead
     # of having to specify the username/password each time.
d5d5b680
     if [[ ! -e $HOME/.my.cnf ]]; then
         cat <<EOF >$HOME/.my.cnf
 [client]
 user=$MYSQL_USER
cf145b77
 password=$MYSQL_PASSWORD
d5d5b680
 host=$MYSQL_HOST
 EOF
         chmod 0600 $HOME/.my.cnf
     fi
 
a09ae2ff
     # Install and start mysql-server
ee1b495d
     apt_get install mysql-server
24859060
     # Update the DB to give user ‘$MYSQL_USER’@’%’ full control of the all databases:
92e81992
     sudo mysql -uroot -p$MYSQL_PASSWORD -h127.0.0.1 -e "GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'%' identified by '$MYSQL_PASSWORD';"
24859060
 
     # Edit /etc/mysql/my.cnf to change ‘bind-address’ from localhost (127.0.0.1) to any (0.0.0.0) and restart the mysql service:
     sudo sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mysql/my.cnf
     sudo service mysql restart
 fi
 
 
ca85b799
 # Horizon
d74257d0
 # ---------
cbe98d56
 
ca85b799
 # Setup the django horizon application to serve via apache/wsgi
75a37653
 
ca85b799
 if [[ "$ENABLED_SERVICES" =~ "horizon" ]]; then
24859060
 
38df1228
     # Install apache2, which is NOPRIME'd
     apt_get install apache2 libapache2-mod-wsgi
 
ca85b799
     # Horizon currently imports quantum even if you aren't using it.  Instead
40a37006
     # of installing quantum we can create a simple module that will pass the
24859060
     # initial imports
ca85b799
     mkdir -p  $HORIZON_DIR/openstack-dashboard/quantum || true
     touch $HORIZON_DIR/openstack-dashboard/quantum/__init__.py
     touch $HORIZON_DIR/openstack-dashboard/quantum/client.py
70dc5e05
 
40a37006
 
ca85b799
     # ``local_settings.py`` is used to override horizon default settings.
     cp $FILES/horizon_settings.py $HORIZON_DIR/openstack-dashboard/local/local_settings.py
9337b339
 
ca85b799
     # Initialize the horizon database (it stores sessions and notices shown to
51fb22ef
     # users).  The user system is external (keystone).
ca85b799
     cd $HORIZON_DIR/openstack-dashboard
70dc5e05
     dashboard/manage.py syncdb
 
     # create an empty directory that apache uses as docroot
ca85b799
     sudo mkdir -p $HORIZON_DIR/.blackhole
70dc5e05
 
ca85b799
     ## Configure apache's 000-default to run horizon
bf3868d8
     sudo cp $FILES/000-default.template /etc/apache2/sites-enabled/000-default
8f3e28ce
     sudo sed -e "s,%USER%,$USER,g" -i /etc/apache2/sites-enabled/000-default
ca85b799
     sudo sed -e "s,%HORIZON_DIR%,$HORIZON_DIR,g" -i /etc/apache2/sites-enabled/000-default
c96b0247
     sudo service apache2 restart
70dc5e05
 fi
1c1d1505
 
18d350da
 
d74257d0
 # Glance
 # ------
 
70dc5e05
 if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then
c8357620
     GLANCE_IMAGE_DIR=$DEST/glance/images
a531b772
     # Delete existing images
     rm -rf $GLANCE_IMAGE_DIR
 
     # Use local glance directories
     mkdir -p $GLANCE_IMAGE_DIR
 
70dc5e05
     # (re)create glance database
7a549f40
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'DROP DATABASE IF EXISTS glance;'
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'CREATE DATABASE glance;'
51fb22ef
 
     # Copy over our glance configurations and update them
70dc5e05
     GLANCE_CONF=$GLANCE_DIR/etc/glance-registry.conf
bf3868d8
     cp $FILES/glance-registry.conf $GLANCE_CONF
70dc5e05
     sudo sed -e "s,%SQL_CONN%,$BASE_SQL_CONN/glance,g" -i $GLANCE_CONF
b96871e4
     sudo sed -e "s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g" -i $GLANCE_CONF
a531b772
     sudo sed -e "s,%DEST%,$DEST,g" -i $GLANCE_CONF
5855a644
     sudo sed -e "s,%SYSLOG%,$SYSLOG,g" -i $GLANCE_CONF
f12d3ab0
 
     GLANCE_API_CONF=$GLANCE_DIR/etc/glance-api.conf
     cp $FILES/glance-api.conf $GLANCE_API_CONF
a531b772
     sudo sed -e "s,%DEST%,$DEST,g" -i $GLANCE_API_CONF
b96871e4
     sudo sed -e "s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g" -i $GLANCE_API_CONF
5855a644
     sudo sed -e "s,%SYSLOG%,$SYSLOG,g" -i $GLANCE_API_CONF
70dc5e05
 fi
75a37653
 
d74257d0
 # Nova
 # ----
 
f70569e3
 if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then
9812ffb9
     # We are going to use a sample http middleware configuration based on the
     # one from the keystone project to launch nova.  This paste config adds
     # the configuration required for nova to validate keystone tokens. We add
     # our own service token to the configuration.
     cp $FILES/nova-api-paste.ini $NOVA_DIR/bin
     sed -e "s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g" -i $NOVA_DIR/bin/nova-api-paste.ini
f70569e3
 fi
75a37653
 
70dc5e05
 if [[ "$ENABLED_SERVICES" =~ "n-cpu" ]]; then
dfcd2003
 
cbe98d56
     # Virtualization Configuration
     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
     # attempt to load modules: network block device - used to manage qcow images
70dc5e05
     sudo modprobe nbd || true
c6d3042e
 
9b353671
     # Check for kvm (hardware based virtualization).  If unable to initialize
     # kvm, we drop back to the slower emulation mode (qemu).  Note: many systems
51fb22ef
     # come with hardware virtualization disabled in BIOS.
2abbdd47
     if [[ "$LIBVIRT_TYPE" == "kvm" ]]; then
a6353c62
         apt_get install libvirt-bin
cbe98d56
         sudo modprobe kvm || true
c6d3042e
         if [ ! -e /dev/kvm ]; then
cbe98d56
             echo "WARNING: Switching to QEMU"
c6d3042e
             LIBVIRT_TYPE=qemu
         fi
     fi
 
cbe98d56
     # Install and configure **LXC** if specified.  LXC is another approach to
     # splitting a system into many smaller parts.  LXC uses cgroups and chroot
     # to simulate multiple systems.
2abbdd47
     if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
ee1b495d
         apt_get install lxc
51fb22ef
         # lxc uses cgroups (a kernel interface via virtual filesystem) configured
         # and mounted to ``/cgroup``
c6d3042e
         sudo mkdir -p /cgroup
         if ! grep -q cgroup /etc/fstab; then
c315ebfd
             echo none /cgroup cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0 | sudo tee -a /etc/fstab
c6d3042e
         fi
e4304238
         if ! mount -n | grep -q cgroup; then
             sudo mount /cgroup
         fi
d1879c5c
     fi
c6d3042e
 
51fb22ef
     # The user that nova runs as needs to be member of libvirtd group otherwise
     # nova-compute will be unable to use libvirt.
70dc5e05
     sudo usermod -a -G libvirtd `whoami`
9b353671
     # libvirt detects various settings on startup, as we potentially changed
51fb22ef
     # the system configuration (modules, filesystems), we need to restart
     # libvirt to detect those changes.
70dc5e05
     sudo /etc/init.d/libvirt-bin restart
dfcd2003
 
cbe98d56
 
     # Instance Storage
     # ~~~~~~~~~~~~~~~~
 
     # Nova stores each instance in its own directory.
70dc5e05
     mkdir -p $NOVA_DIR/instances
75a37653
 
51fb22ef
     # You can specify a different disk to be mounted and used for backing the
9b353671
     # virtual machines.  If there is a partition labeled nova-instances we
51fb22ef
     # mount it (ext filesystems can be labeled via e2label).
70dc5e05
     if [ -L /dev/disk/by-label/nova-instances ]; then
38df1228
         if ! mount -n | grep -q $NOVA_DIR/instances; then
51fb22ef
             sudo mount -L nova-instances $NOVA_DIR/instances
             sudo chown -R `whoami` $NOVA_DIR/instances
         fi
70dc5e05
     fi
 
cbe98d56
     # Clean out the instances directory.
461bfdc8
     sudo rm -rf $NOVA_DIR/instances/*
70dc5e05
 fi
 
 if [[ "$ENABLED_SERVICES" =~ "n-net" ]]; then
     # delete traces of nova networks from prior runs
09fde81c
     sudo killall dnsmasq || true
70dc5e05
     rm -rf $NOVA_DIR/networks
     mkdir -p $NOVA_DIR/networks
 fi
 
28fa4e8d
 # Storage Service
537ddff2
 if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
3d9c5d5e
     # We first do a bit of setup by creating the directories and
     # changing the permissions so we can run it as our user.
 
067163df
     USER_GROUP=$(id -g)
38750150
     sudo mkdir -p ${SWIFT_DATA_LOCATION}/drives
     sudo chown -R $USER:${USER_GROUP} ${SWIFT_DATA_LOCATION}/drives
5f039326
 
3d9c5d5e
     # We then create a loopback disk and format it to XFS.
f990ded5
     if [[ ! -e ${SWIFT_DATA_LOCATION}/drives/images/swift.img ]]; then
38750150
         mkdir -p  ${SWIFT_DATA_LOCATION}/drives/images
         sudo touch  ${SWIFT_DATA_LOCATION}/drives/images/swift.img
         sudo chown $USER: ${SWIFT_DATA_LOCATION}/drives/images/swift.img
5f039326
 
38750150
         dd if=/dev/zero of=${SWIFT_DATA_LOCATION}/drives/images/swift.img \
b93478f6
             bs=1024 count=0 seek=${SWIFT_LOOPBACK_DISK_SIZE}
38750150
         mkfs.xfs -f -i size=1024  ${SWIFT_DATA_LOCATION}/drives/images/swift.img
28fa4e8d
     fi
 
3d9c5d5e
     # After the drive being created we mount the disk with a few mount
     # options to make it most efficient as possible for swift.
38750150
     mkdir -p ${SWIFT_DATA_LOCATION}/drives/sdb1
f990ded5
     if ! egrep -q ${SWIFT_DATA_LOCATION}/drives/sdb1 /proc/mounts; then
b93478f6
         sudo mount -t xfs -o loop,noatime,nodiratime,nobarrier,logbufs=8  \
38750150
             ${SWIFT_DATA_LOCATION}/drives/images/swift.img ${SWIFT_DATA_LOCATION}/drives/sdb1
a03f0056
     fi
28fa4e8d
 
3d9c5d5e
     # We then create link to that mounted location so swift would know
     # where to go.
38750150
     for x in {1..4}; do sudo ln -sf ${SWIFT_DATA_LOCATION}/drives/sdb1/$x ${SWIFT_DATA_LOCATION}/$x; done
5f039326
 
3d9c5d5e
     # We now have to emulate a few different servers into one we
5f039326
     # create all the directories needed for swift
e1d2bcb1
     tmpd=""
3a64826b
     for d in ${SWIFT_DATA_LOCATION}/drives/sdb1/{1..4} \
         ${SWIFT_CONFIG_LOCATION}/{object,container,account}-server \
f990ded5
         ${SWIFT_DATA_LOCATION}/{1..4}/node/sdb1 /var/run/swift; do
e1d2bcb1
         [[ -d $d ]] && continue
067163df
         sudo install -o ${USER} -g $USER_GROUP -d $d
e1d2bcb1
     done
 
3a64826b
    # We do want to make sure this is all owned by our user.
    sudo chown -R $USER: ${SWIFT_DATA_LOCATION}/{1..4}/node
    sudo chown -R $USER: ${SWIFT_CONFIG_LOCATION}
28fa4e8d
 
3a64826b
    # swift-init has a bug using /etc/swift until bug #885595 is fixed
    # we have to create a link
2f2160ea
    sudo ln -sf ${SWIFT_CONFIG_LOCATION} /etc/swift
5f039326
 
3d9c5d5e
    # Swift use rsync to syncronize between all the different
    # partitions (which make more sense when you have a multi-node
    # setup) we configure it with our version of rsync.
38750150
    sed -e "s/%GROUP%/${USER_GROUP}/;s/%USER%/$USER/;s,%SWIFT_DATA_LOCATION%,$SWIFT_DATA_LOCATION," $FILES/swift/rsyncd.conf | sudo tee /etc/rsyncd.conf
e1d2bcb1
    sudo sed -i '/^RSYNC_ENABLE=false/ { s/false/true/ }' /etc/default/rsync
45c51137
 
3d9c5d5e
    # By default Swift will be installed with the tempauth middleware
    # which has some default username and password if you have
    # configured keystone it will checkout the directory.
45c51137
    if [[ "$ENABLED_SERVICES" =~ "key" ]]; then
        swift_auth_server=keystone
904b0d7d
 
        # We install the memcache server as this is will be used by the
        # middleware to cache the tokens auths for a long this is needed.
        apt_get install memcached
 
3d9c5d5e
        # We need a special version of bin/swift which understand the
        # OpenStack api 2.0, we download it until this is getting
        # integrated in swift.
45c51137
        sudo curl -s -o/usr/local/bin/swift \
            'https://review.openstack.org/gitweb?p=openstack/swift.git;a=blob_plain;f=bin/swift;hb=48bfda6e2fdf3886c98bd15649887d54b9a2574e'
    else
        swift_auth_server=tempauth
    fi
 
3d9c5d5e
    # We do the install of the proxy-server and swift configuration
    # replacing a few directives to match our configuration.
3a64826b
    sed "s,%SWIFT_CONFIG_LOCATION%,${SWIFT_CONFIG_LOCATION},;s/%USER%/$USER/;s/%SERVICE_TOKEN%/${SERVICE_TOKEN}/;s/%AUTH_SERVER%/${swift_auth_server}/" \
        $FILES/swift/proxy-server.conf|sudo tee  ${SWIFT_CONFIG_LOCATION}/proxy-server.conf
28fa4e8d
 
3a64826b
    sed -e "s/%SWIFT_HASH%/$SWIFT_HASH/" $FILES/swift/swift.conf > ${SWIFT_CONFIG_LOCATION}/swift.conf
28fa4e8d
 
    # We need to generate a object/account/proxy configuration
3d9c5d5e
    # emulating 4 nodes on different ports we have a little function
28fa4e8d
    # that help us doing that.
    function generate_swift_configuration() {
        local server_type=$1
        local bind_port=$2
        local log_facility=$3
45c51137
        local node_number
5f039326
 
f990ded5
        for node_number in {1..4}; do
38750150
            node_path=${SWIFT_DATA_LOCATION}/${node_number}
3a64826b
            sed -e "s,%SWIFT_CONFIG_LOCATION%,${SWIFT_CONFIG_LOCATION},;s,%USER%,$USER,;s,%NODE_PATH%,${node_path},;s,%BIND_PORT%,${bind_port},;s,%LOG_FACILITY%,${log_facility}," \
                $FILES/swift/${server_type}-server.conf > ${SWIFT_CONFIG_LOCATION}/${server_type}-server/${node_number}.conf
28fa4e8d
            bind_port=$(( ${bind_port} + 10 ))
            log_facility=$(( ${log_facility} + 1 ))
        done
    }
    generate_swift_configuration object 6010 2
    generate_swift_configuration container 6011 2
    generate_swift_configuration account 6012 2
a03f0056
 
3d9c5d5e
    # We create two helper scripts :
    #
    # - swift-remakerings
    #   Allow to recreate rings from scratch.
    # - swift-startmain
    #   Restart your full cluster.
    #
3a64826b
    sed -e "s,%SWIFT_CONFIG_LOCATION%,${SWIFT_CONFIG_LOCATION},;s/%SWIFT_PARTITION_POWER_SIZE%/$SWIFT_PARTITION_POWER_SIZE/" $FILES/swift/swift-remakerings | \
a2118984
        sudo tee /usr/local/bin/swift-remakerings
537ddff2
    sudo install -m755 $FILES/swift/swift-startmain /usr/local/bin/
a2118984
    sudo chmod +x /usr/local/bin/swift-*
 
3d9c5d5e
    # We then can start rsync.
e1d2bcb1
    sudo /etc/init.d/rsync restart || :
5f039326
 
3d9c5d5e
    # Create our ring for the object/container/account.
d5651bb5
    /usr/local/bin/swift-remakerings
 
3d9c5d5e
    # And now we launch swift-startmain to get our cluster running
    # ready to be tested.
d5651bb5
    /usr/local/bin/swift-startmain || :
5f039326
 
45c51137
    unset s swift_hash swift_auth_server tmpd
28fa4e8d
 fi
 
acff87a2
 # Volume Service
 # --------------
 
 if [[ "$ENABLED_SERVICES" =~ "n-vol" ]]; then
     #
     # Configure a default volume group called 'nova-volumes' for the nova-volume
     # service if it does not yet exist.  If you don't wish to use a file backed
     # volume group, create your own volume group called 'nova-volumes' before
     # invoking stack.sh.
     #
     # By default, the backing file is 2G in size, and is stored in /opt/stack.
38df1228
 
     apt_get install iscsitarget-dkms iscsitarget
 
d02b7b7b
     if ! sudo vgdisplay | grep -q $VOLUME_GROUP; then
b244ef34
         VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DEST/nova-volumes-backing-file}
b22263a6
         VOLUME_BACKING_FILE_SIZE=${VOLUME_BACKING_FILE_SIZE:-2052M}
acff87a2
         truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE
         DEV=`sudo losetup -f --show $VOLUME_BACKING_FILE`
d02b7b7b
         sudo vgcreate $VOLUME_GROUP $DEV
acff87a2
     fi
 
     # Configure iscsitarget
     sudo sed 's/ISCSITARGET_ENABLE=false/ISCSITARGET_ENABLE=true/' -i /etc/default/iscsitarget
     sudo /etc/init.d/iscsitarget restart
 fi
 
d1879c5c
 function add_nova_flag {
     echo "$1" >> $NOVA_DIR/bin/nova.conf
 }
 
 # (re)create nova.conf
 rm -f $NOVA_DIR/bin/nova.conf
 add_nova_flag "--verbose"
293c2ef6
 add_nova_flag "--allow_admin_api"
8ff5dbc2
 add_nova_flag "--scheduler_driver=$SCHEDULER"
d1879c5c
 add_nova_flag "--dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf"
9720eb8a
 add_nova_flag "--fixed_range=$FIXED_RANGE"
1bfa3d53
 if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then
     add_nova_flag "--network_manager=nova.network.quantum.manager.QuantumManager"
     if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
         add_nova_flag "--libvirt_vif_type=ethernet"
         add_nova_flag "--libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtOpenVswitchDriver"
     fi
 else
     add_nova_flag "--network_manager=nova.network.manager.$NET_MAN"
 fi
d02b7b7b
 if [[ "$ENABLED_SERVICES" =~ "n-vol" ]]; then
     add_nova_flag "--volume_group=$VOLUME_GROUP"
 fi
d1879c5c
 add_nova_flag "--my_ip=$HOST_IP"
b1bdd5e2
 add_nova_flag "--public_interface=$PUBLIC_INTERFACE"
 add_nova_flag "--vlan_interface=$VLAN_INTERFACE"
d1879c5c
 add_nova_flag "--sql_connection=$BASE_SQL_CONN/nova"
 add_nova_flag "--libvirt_type=$LIBVIRT_TYPE"
e7ce24fc
 if [[ "$ENABLED_SERVICES" =~ "openstackx" ]]; then
     add_nova_flag "--osapi_extensions_path=$OPENSTACKX_DIR/extensions"
 fi
 if [[ "$ENABLED_SERVICES" =~ "n-vnc" ]]; then
eb31af87
     add_nova_flag "--vncproxy_url=http://$SERVICE_HOST:6080"
e7ce24fc
     add_nova_flag "--vncproxy_wwwroot=$NOVNC_DIR/"
 fi
42dc9a77
 add_nova_flag "--api_paste_config=$NOVA_DIR/bin/nova-api-paste.ini"
d1879c5c
 add_nova_flag "--image_service=nova.image.glance.GlanceImageService"
 add_nova_flag "--ec2_dmz_host=$EC2_DMZ_HOST"
 add_nova_flag "--rabbit_host=$RABBIT_HOST"
53ed387d
 add_nova_flag "--rabbit_password=$RABBIT_PASSWORD"
d1879c5c
 add_nova_flag "--glance_api_servers=$GLANCE_HOSTPORT"
7e436c21
 add_nova_flag "--force_dhcp_release"
3e2b1744
 if [ -n "$INSTANCES_PATH" ]; then
     add_nova_flag "--instances_path=$INSTANCES_PATH"
e72bdb09
 fi
5f039326
 if [ "$MULTI_HOST" != "False" ]; then
     add_nova_flag "--multi_host"
     add_nova_flag "--send_arp_for_ha"
d1879c5c
 fi
5855a644
 if [ "$SYSLOG" != "False" ]; then
5f039326
     add_nova_flag "--use_syslog"
5855a644
 fi
d1879c5c
 
38df1228
 # You can define extra nova conf flags by defining the array EXTRA_FLAGS,
 # For Example: EXTRA_FLAGS=(--foo --bar=2)
 for I in "${EXTRA_FLAGS[@]}"; do
411b3c67
     add_nova_flag $I
38df1228
 done
 
b62b4ca2
 # XenServer
 # ---------
 
 if [ "$VIRT_DRIVER" = 'xenserver' ]; then
     read_password XENAPI_PASSWORD "ENTER A PASSWORD TO USE FOR XEN."
     add_nova_flag "--connection_type=xenapi"
     add_nova_flag "--xenapi_connection_url=http://169.254.0.1"
     add_nova_flag "--xenapi_connection_username=root"
     add_nova_flag "--xenapi_connection_password=$XENAPI_PASSWORD"
     add_nova_flag "--flat_injected=False"
     add_nova_flag "--flat_interface=eth1"
ea1290a9
     add_nova_flag "--flat_network_bridge=xenbr1"
b62b4ca2
     add_nova_flag "--public_interface=eth3"
 else
     add_nova_flag "--flat_network_bridge=$FLAT_NETWORK_BRIDGE"
     if [ -n "$FLAT_INTERFACE" ]; then
         add_nova_flag "--flat_interface=$FLAT_INTERFACE"
     fi
 fi
 
cbe98d56
 # Nova Database
 # ~~~~~~~~~~~~~
 
 # All nova components talk to a central database.  We will need to do this step
 # only once for an entire cluster.
 
a074800c
 if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then
     # (re)create nova database
7a549f40
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'DROP DATABASE IF EXISTS nova;'
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'CREATE DATABASE nova;'
cbe98d56
 
     # (re)create nova database
a074800c
     $NOVA_DIR/bin/nova-manage db sync
 fi
 
 
e8d9cd8b
 # Keystone
 # --------
 
70dc5e05
 if [[ "$ENABLED_SERVICES" =~ "key" ]]; then
     # (re)create keystone database
7a549f40
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'DROP DATABASE IF EXISTS keystone;'
     mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'CREATE DATABASE keystone;'
75a37653
 
70dc5e05
     # FIXME (anthony) keystone should use keystone.conf.example
     KEYSTONE_CONF=$KEYSTONE_DIR/etc/keystone.conf
bf3868d8
     cp $FILES/keystone.conf $KEYSTONE_CONF
70dc5e05
     sudo sed -e "s,%SQL_CONN%,$BASE_SQL_CONN/keystone,g" -i $KEYSTONE_CONF
e8fed48e
     sudo sed -e "s,%DEST%,$DEST,g" -i $KEYSTONE_CONF
3a093127
 
cbe98d56
     # keystone_data.sh creates our admin user and our ``SERVICE_TOKEN``.
ec21d937
     KEYSTONE_DATA=$KEYSTONE_DIR/bin/keystone_data.sh
     cp $FILES/keystone_data.sh $KEYSTONE_DATA
eb31af87
     sudo sed -e "s,%SERVICE_HOST%,$SERVICE_HOST,g" -i $KEYSTONE_DATA
b96871e4
     sudo sed -e "s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g" -i $KEYSTONE_DATA
89358afe
     sudo sed -e "s,%ADMIN_PASSWORD%,$ADMIN_PASSWORD,g" -i $KEYSTONE_DATA
70dc5e05
     # initialize keystone with default users/endpoints
ec21d937
     BIN_DIR=$KEYSTONE_DIR/bin bash $KEYSTONE_DATA
70dc5e05
 fi
75a37653
 
 
d74257d0
 # Launch Services
 # ===============
30f68e96
 
1c1d1505
 # nova api crashes if we start it with a regular screen command,
 # so send the start command by forcing text into the window.
dfcd2003
 # Only run the services specified in ``ENABLED_SERVICES``
 
1f717601
 # our screen helper to launch a service in a hidden named screen
1c1d1505
 function screen_it {
1f717601
     NL=`echo -ne '\015'`
292e46d0
     if [[ "$ENABLED_SERVICES" =~ "$1" ]]; then
3ad59ea1
         if [[ "$USE_TMUX" =~ "yes" ]]; then
             tmux new-window -t stack -a -n "$1" "bash"
             tmux send-keys "$2" C-M
         else
             screen -S stack -X screen -t $1
             # sleep to allow bash to be ready to be send the command - we are
             # creating a new window in screen and then sends characters, so if
             # bash isn't running by the time we send the command, nothing happens
             sleep 1
             screen -S stack -p $1 -X stuff "$2$NL"
         fi
292e46d0
     fi
1c1d1505
 }
 
a16e5e9c
 # create a new named screen to run processes in
de8b9a23
 screen -d -m -S stack -t stack
a16e5e9c
 sleep 1
 
3d9c5d5e
 # launch the glance registry service
d000b22d
 if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then
     screen_it g-reg "cd $GLANCE_DIR; bin/glance-registry --config-file=etc/glance-registry.conf"
 fi
 
644b8e83
 # launch the glance api and wait for it to answer before continuing
d000b22d
 if [[ "$ENABLED_SERVICES" =~ "g-api" ]]; then
     screen_it g-api "cd $GLANCE_DIR; bin/glance-api --config-file=etc/glance-api.conf"
92e81992
     echo "Waiting for g-api ($GLANCE_HOSTPORT) to start..."
2bbcd682
     if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget -q -O- http://$GLANCE_HOSTPORT; do sleep 1; done"; then
92e81992
       echo "g-api did not start"
       exit 1
     fi
d000b22d
 fi
 
644b8e83
 # launch the keystone and wait for it to answer before continuing
d000b22d
 if [[ "$ENABLED_SERVICES" =~ "key" ]]; then
f33796e0
     screen_it key "cd $KEYSTONE_DIR && $KEYSTONE_DIR/bin/keystone --config-file $KEYSTONE_CONF -d"
92e81992
     echo "Waiting for keystone to start..."
2bbcd682
     if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget -q -O- http://127.0.0.1:5000; do sleep 1; done"; then
92e81992
       echo "keystone did not start"
       exit 1
     fi
d000b22d
 fi
 
644b8e83
 # launch the nova-api and wait for it to answer before continuing
d000b22d
 if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then
9bf3d767
     screen_it n-api "cd $NOVA_DIR && $NOVA_DIR/bin/nova-api"
92e81992
     echo "Waiting for nova-api to start..."
2bbcd682
     if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget -q -O- http://127.0.0.1:8774; do sleep 1; done"; then
92e81992
       echo "nova-api did not start"
       exit 1
     fi
d000b22d
 fi
1bfa3d53
 
 # Quantum
 if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then
bdc254eb
     # Install deps
0c3b60ce
     # FIXME add to files/apts/quantum, but don't install if not needed!
ae7f2649
     apt_get install openvswitch-switch openvswitch-datapath-dkms
bdc254eb
 
1bfa3d53
     # Create database for the plugin/agent
     if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
         if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then
             mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'CREATE DATABASE IF NOT EXISTS ovs_quantum;'
         else
d9e544e5
             echo "mysql must be enabled in order to use the $Q_PLUGIN Quantum plugin."
             exit 1
1bfa3d53
         fi
     fi
 
     QUANTUM_PLUGIN_INI_FILE=$QUANTUM_DIR/quantum/plugins.ini
     # Make sure we're using the openvswitch plugin
     sed -i -e "s/^provider =.*$/provider = quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPlugin/g" $QUANTUM_PLUGIN_INI_FILE
     screen_it q-svc "cd $QUANTUM_DIR && export PYTHONPATH=.:$PYTHONPATH; python $QUANTUM_DIR/bin/quantum $QUANTUM_DIR/etc/quantum.conf"
 fi
 
 # Quantum agent (for compute nodes)
 if [[ "$ENABLED_SERVICES" =~ "q-agt" ]]; then
     if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
         # Set up integration bridge
         OVS_BRIDGE=${OVS_BRIDGE:-br-int}
         sudo ovs-vsctl --no-wait -- --if-exists del-br $OVS_BRIDGE
         sudo ovs-vsctl --no-wait add-br $OVS_BRIDGE
         sudo ovs-vsctl --no-wait br-set-external-id $OVS_BRIDGE bridge-id br-int
     fi
 
     # Start up the quantum <-> openvswitch agent
     screen_it q-agt "sleep 4; sudo python $QUANTUM_DIR/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py $QUANTUM_DIR/quantum/plugins/openvswitch/ovs_quantum_plugin.ini -v"
 fi
 
d9e544e5
 # If we're using Quantum (i.e. q-svc is enabled), network creation has to
 # happen after we've started the Quantum service.
1bfa3d53
 if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then
     # create a small network
     $NOVA_DIR/bin/nova-manage network create private $FIXED_RANGE 1 $FIXED_NETWORK_SIZE
 
     if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then
         echo "Not creating floating IPs (not supported by QuantumManager)"
     else
         # create some floating ips
         $NOVA_DIR/bin/nova-manage floating create $FLOATING_RANGE
     fi
 fi
 
40a37006
 # Launching nova-compute should be as simple as running ``nova-compute`` but
 # have to do a little more than that in our script.  Since we add the group
1f717601
 # ``libvirtd`` to our user in this script, when nova-compute is run it is
40a37006
 # within the context of our original shell (so our groups won't be updated).
8ab1ade4
 # Use 'sg' to execute nova-compute as a member of the libvirtd group.
 screen_it n-cpu "cd $NOVA_DIR && sg libvirtd $NOVA_DIR/bin/nova-compute"
acff87a2
 screen_it n-vol "cd $NOVA_DIR && $NOVA_DIR/bin/nova-volume"
9bf3d767
 screen_it n-net "cd $NOVA_DIR && $NOVA_DIR/bin/nova-network"
 screen_it n-sch "cd $NOVA_DIR && $NOVA_DIR/bin/nova-scheduler"
e7ce24fc
 if [[ "$ENABLED_SERVICES" =~ "n-vnc" ]]; then
     screen_it n-vnc "cd $NOVNC_DIR && ./utils/nova-wsproxy.py --flagfile $NOVA_DIR/bin/nova.conf --web . 6080"
 fi
 if [[ "$ENABLED_SERVICES" =~ "horizon" ]]; then
     screen_it horizon "cd $HORIZON_DIR && sudo tail -f /var/log/apache2/error.log"
 fi
75a37653
 
d74257d0
 # Install Images
 # ==============
e49b8bd6
 
0ab1d46e
 # Upload an image to glance.
5372f433
 #
0ab1d46e
 # The default image is a small ***TTY*** testing image, which lets you login
 # the username/password of root/password.
 #
 # TTY also uses cloud-init, supporting login via keypair and sending scripts as
 # userdata.  See https://help.ubuntu.com/community/CloudInit for more on cloud-init
 #
3d9c5d5e
 # Override ``IMAGE_URLS`` with a comma-separated list of uec images.
aab7eae0
 #
 #  * **natty**: http://uec-images.ubuntu.com/natty/current/natty-server-cloudimg-amd64.tar.gz
 #  * **oneiric**: http://uec-images.ubuntu.com/oneiric/current/oneiric-server-cloudimg-amd64.tar.gz
08e8b745
 
85d9be3a
 if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then
7a8989e9
     # Create a directory for the downloaded image tarballs.
08e8b745
     mkdir -p $FILES/images
 
b62b4ca2
     # Option to upload legacy ami-tty, which works with xenserver
     if [ $UPLOAD_LEGACY_TTY ]; then
         if [ ! -f $FILES/tty.tgz ]; then
             wget -c http://images.ansolabs.com/tty.tgz -O $FILES/tty.tgz
         fi
 
         tar -zxf $FILES/tty.tgz -C $FILES/images
         RVAL=`glance add -A $SERVICE_TOKEN name="tty-kernel" is_public=true container_format=aki disk_format=aki < $FILES/images/aki-tty/image`
         KERNEL_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "`
         RVAL=`glance add -A $SERVICE_TOKEN name="tty-ramdisk" is_public=true container_format=ari disk_format=ari < $FILES/images/ari-tty/image`
         RAMDISK_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "`
         glance add -A $SERVICE_TOKEN name="tty" is_public=true container_format=ami disk_format=ami kernel_id=$KERNEL_ID ramdisk_id=$RAMDISK_ID < $FILES/images/ami-tty/image
     fi
 
120f4860
     for image_url in ${IMAGE_URLS//,/ }; do
         # Downloads the image (uec ami+aki style), then extracts it.
ac1831e0
         IMAGE_FNAME=`basename "$image_url"`
216ad694
         IMAGE_NAME=`basename "$IMAGE_FNAME" .tar.gz`
120f4860
         if [ ! -f $FILES/$IMAGE_FNAME ]; then
             wget -c $image_url -O $FILES/$IMAGE_FNAME
         fi
e49b8bd6
 
120f4860
         # Extract ami and aki files
         tar -zxf $FILES/$IMAGE_FNAME -C $FILES/images
e49b8bd6
 
120f4860
         # Use glance client to add the kernel the root filesystem.
         # We parse the results of the first upload to get the glance ID of the
         # kernel for use when uploading the root filesystem.
         RVAL=`glance add -A $SERVICE_TOKEN name="$IMAGE_NAME-kernel" is_public=true container_format=aki disk_format=aki < $FILES/images/$IMAGE_NAME-vmlinuz*`
         KERNEL_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "`
         glance add -A $SERVICE_TOKEN name="$IMAGE_NAME" is_public=true container_format=ami disk_format=ami kernel_id=$KERNEL_ID < $FILES/images/$IMAGE_NAME.img
     done
70dc5e05
 fi
24859060
 
b94f4bf3
 # Fin
 # ===
 
 
 ) 2>&1 | tee "${LOGFILE}"
 
 # Check that the left side of the above pipe succeeded
 for ret in "${PIPESTATUS[@]}"; do [ $ret -eq 0 ] || exit $ret; done
 
 (
24859060
 # Using the cloud
 # ===============
 
e19d8847
 echo ""
 echo ""
 echo ""
 
ca85b799
 # If you installed the horizon on this server, then you should be able
40a37006
 # to access the site using your browser.
ca85b799
 if [[ "$ENABLED_SERVICES" =~ "horizon" ]]; then
eb31af87
     echo "horizon is now available at http://$SERVICE_HOST/"
24859060
 fi
 
 # If keystone is present, you can point nova cli to this server
 if [[ "$ENABLED_SERVICES" =~ "key" ]]; then
eb31af87
     echo "keystone is serving at http://$SERVICE_HOST:5000/v2.0/"
24859060
     echo "examples on using novaclient command line is in exercise.sh"
89358afe
     echo "the default users are: admin and demo"
     echo "the password: $ADMIN_PASSWORD"
24859060
 fi
523c405f
 
c4e47ab8
 # indicate how long this took to run (bash maintained variable 'SECONDS')
b94f4bf3
 echo "stack.sh completed in $SECONDS seconds."
7c481189
 
b94f4bf3
 ) | tee -a "$LOGFILE"