functions
7f9aa71b
 # functions - Common functions used by DevStack components
13dc5ccd
 #
4a43b7bd
 # The following variables are assumed to be defined by certain functions:
 # ``ENABLED_SERVICES``
 # ``EROR_ON_CLONE``
 # ``FILES``
 # ``GLANCE_HOSTPORT``
 # ``OFFLINE``
 # ``PIP_DOWNLOAD_CACHE``
 # ``RECLONE``
 # ``TRACK_DEPENDS``
 # ``http_proxy``, ``https_proxy``, ``no_proxy``
13dc5ccd
 
7f9aa71b
 
27e32699
 # Save trace setting
 XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
7f9aa71b
 
4a43b7bd
 # Exit 0 if address is in network or 1 if address is not in
 # network or netaddr library is not installed.
 # address_in_net ip-address ip-range
c9ad14bd
 function address_in_net() {
     python -c "
 import netaddr
 import sys
 sys.exit(netaddr.IPAddress('$1') not in netaddr.IPNetwork('$2'))
 "
 }
 
 
4a43b7bd
 # Wrapper for ``apt-get`` to set cache and proxy environment variables
 # Uses globals ``OFFLINE``, ``*_proxy`
13dc5ccd
 # apt_get operation package [package ...]
7f9aa71b
 function apt_get() {
d0b21e2d
     [[ "$OFFLINE" = "True" || -z "$@" ]] && return
7f9aa71b
     local sudo="sudo"
     [[ "$(id -u)" = "0" ]] && sudo="env"
     $sudo DEBIAN_FRONTEND=noninteractive \
         http_proxy=$http_proxy https_proxy=$https_proxy \
7abe4f24
         no_proxy=$no_proxy \
7f9aa71b
         apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
 }
 
 
 # Gracefully cp only if source file/dir exists
 # cp_it source destination
 function cp_it {
     if [ -e $1 ] || [ -d $1 ]; then
         cp -pRL $1 $2
     fi
 }
 
 
27e32699
 # Prints "message" and exits
 # die "message"
 function die() {
489bd2a6
     local exitcode=$?
27e32699
     set +o xtrace
     echo $@
     exit $exitcode
489bd2a6
 }
 
 
 # Checks an environment variable is not set or has length 0 OR if the
 # exit code is non-zero and prints "message" and exits
 # NOTE: env-var is the variable name without a '$'
 # die_if_not_set env-var "message"
 function die_if_not_set() {
27e32699
     (
         local exitcode=$?
         set +o xtrace
         local evar=$1; shift
         if ! is_set $evar || [ $exitcode != 0 ]; then
             set +o xtrace
             echo $@
             exit -1
         fi
     )
489bd2a6
 }
 
 
 # Grab a numbered field from python prettytable output
 # Fields are numbered starting with 1
 # Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
 # get_field field-number
 function get_field() {
     while read data; do
         if [ "$1" -lt 0 ]; then
             field="(\$(NF$1))"
         else
             field="\$$(($1 + 1))"
         fi
         echo "$data" | awk -F'[ \t]*\\|[ \t]*' "{print $field}"
     done
 }
 
 
7e27051c
 # get_packages() collects a list of package names of any type from the
4a43b7bd
 # prerequisite files in ``files/{apts|rpms}``.  The list is intended
 # to be passed to a package installer such as apt or yum.
7e27051c
 #
4a43b7bd
 # Only packages required for the services in ``ENABLED_SERVICES`` will be
7e27051c
 # included.  Two bits of metadata are recognized in the prerequisite files:
 # - ``# NOPRIME`` defers installation to be performed later in stack.sh
 # - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection
 #   of the package to the distros listed.  The distro names are case insensitive.
 #
855c5875
 # Uses globals ``ENABLED_SERVICES``
7e27051c
 # get_packages dir
 function get_packages() {
     local package_dir=$1
     local file_to_parse
     local service
 
     if [[ -z "$package_dir" ]]; then
         echo "No package directory supplied"
         return 1
     fi
     if [[ -z "$DISTRO" ]]; then
855c5875
         GetDistro
7e27051c
     fi
     for service in general ${ENABLED_SERVICES//,/ }; do
         # Allow individual services to specify dependencies
         if [[ -e ${package_dir}/${service} ]]; then
             file_to_parse="${file_to_parse} $service"
         fi
         # NOTE(sdague) n-api needs glance for now because that's where
         # glance client is
         if [[ $service == n-api ]]; then
             if [[ ! $file_to_parse =~ nova ]]; then
                 file_to_parse="${file_to_parse} nova"
             fi
             if [[ ! $file_to_parse =~ glance ]]; then
                 file_to_parse="${file_to_parse} glance"
             fi
         elif [[ $service == c-* ]]; then
             if [[ ! $file_to_parse =~ cinder ]]; then
                 file_to_parse="${file_to_parse} cinder"
             fi
93361643
         elif [[ $service == ceilometer-* ]]; then
             if [[ ! $file_to_parse =~ ceilometer ]]; then
                 file_to_parse="${file_to_parse} ceilometer"
             fi
7e27051c
         elif [[ $service == n-* ]]; then
             if [[ ! $file_to_parse =~ nova ]]; then
                 file_to_parse="${file_to_parse} nova"
             fi
         elif [[ $service == g-* ]]; then
             if [[ ! $file_to_parse =~ glance ]]; then
                 file_to_parse="${file_to_parse} glance"
             fi
         elif [[ $service == key* ]]; then
             if [[ ! $file_to_parse =~ keystone ]]; then
                 file_to_parse="${file_to_parse} keystone"
             fi
         fi
     done
 
     for file in ${file_to_parse}; do
         local fname=${package_dir}/${file}
         local OIFS line package distros distro
         [[ -e $fname ]] || continue
 
         OIFS=$IFS
         IFS=$'\n'
         for line in $(<${fname}); do
             if [[ $line =~ "NOPRIME" ]]; then
                 continue
             fi
 
             if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then
                 # We are using BASH regexp matching feature.
                 package=${BASH_REMATCH[1]}
                 distros=${BASH_REMATCH[2]}
                 # In bash ${VAR,,} will lowecase VAR
                 [[ ${distros,,} =~ ${DISTRO,,} ]] && echo $package
                 continue
             fi
 
             echo ${line%#*}
         done
         IFS=$OIFS
     done
 }
 
 
13dc5ccd
 # Determine OS Vendor, Release and Update
 # Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora
 # Returns results in global variables:
 # os_VENDOR - vendor name
 # os_RELEASE - release
 # os_UPDATE - update
 # os_PACKAGE - package type
 # os_CODENAME - vendor's codename for release
 # GetOSVersion
 GetOSVersion() {
     # Figure out which vendor we are
     if [[ -n "`which sw_vers 2>/dev/null`" ]]; then
         # OS/X
         os_VENDOR=`sw_vers -productName`
         os_RELEASE=`sw_vers -productVersion`
         os_UPDATE=${os_RELEASE##*.}
         os_RELEASE=${os_RELEASE%.*}
         os_PACKAGE=""
         if [[ "$os_RELEASE" =~ "10.7" ]]; then
             os_CODENAME="lion"
         elif [[ "$os_RELEASE" =~ "10.6" ]]; then
             os_CODENAME="snow leopard"
         elif [[ "$os_RELEASE" =~ "10.5" ]]; then
             os_CODENAME="leopard"
         elif [[ "$os_RELEASE" =~ "10.4" ]]; then
             os_CODENAME="tiger"
         elif [[ "$os_RELEASE" =~ "10.3" ]]; then
             os_CODENAME="panther"
         else
             os_CODENAME=""
         fi
     elif [[ -x $(which lsb_release 2>/dev/null) ]]; then
         os_VENDOR=$(lsb_release -i -s)
         os_RELEASE=$(lsb_release -r -s)
         os_UPDATE=""
         if [[ "Debian,Ubuntu" =~ $os_VENDOR ]]; then
             os_PACKAGE="deb"
         else
             os_PACKAGE="rpm"
         fi
         os_CODENAME=$(lsb_release -c -s)
     elif [[ -r /etc/redhat-release ]]; then
         # Red Hat Enterprise Linux Server release 5.5 (Tikanga)
         # CentOS release 5.5 (Final)
         # CentOS Linux release 6.0 (Final)
         # Fedora release 16 (Verne)
         os_CODENAME=""
         for r in "Red Hat" CentOS Fedora; do
             os_VENDOR=$r
             if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then
                 ver=`sed -e 's/^.* \(.*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release`
                 os_CODENAME=${ver#*|}
                 os_RELEASE=${ver%|*}
                 os_UPDATE=${os_RELEASE##*.}
                 os_RELEASE=${os_RELEASE%.*}
                 break
             fi
             os_VENDOR=""
         done
         os_PACKAGE="rpm"
     fi
     export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
 }
 
6a3912de
 # git update using reference as a branch.
4a43b7bd
 # git_update_branch ref
6a3912de
 function git_update_branch() {
 
     GIT_BRANCH=$1
 
     git checkout -f origin/$GIT_BRANCH
     # a local branch might not exist
     git branch -D $GIT_BRANCH || true
     git checkout -b $GIT_BRANCH
 }
 
 
 # git update using reference as a tag. Be careful editing source at that repo
 # as working copy will be in a detached mode
4a43b7bd
 # git_update_tag ref
6a3912de
 function git_update_tag() {
 
     GIT_TAG=$1
 
     git tag -d $GIT_TAG
     # fetching given tag only
     git fetch origin tag $GIT_TAG
     git checkout -f $GIT_TAG
 }
 
13dc5ccd
 
f900bd79
 # git update using reference as a branch.
 # git_update_remote_branch ref
 function git_update_remote_branch() {
 
     GIT_BRANCH=$1
 
     git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH
 }
 
 
a9e0a488
 # Translate the OS version values into common nomenclature
 # Sets ``DISTRO`` from the ``os_*`` values
 function GetDistro() {
     GetOSVersion
     if [[ "$os_VENDOR" =~ (Ubuntu) ]]; then
         # 'Everyone' refers to Ubuntu releases by the code name adjective
         DISTRO=$os_CODENAME
     elif [[ "$os_VENDOR" =~ (Fedora) ]]; then
         # For Fedora, just use 'f' and the release
         DISTRO="f$os_RELEASE"
     else
         # Catch-all for now is Vendor + Release + Update
         DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
     fi
     export DISTRO
 }
 
 
7f9aa71b
 # 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.
 # Set global RECLONE=yes to simulate a clone when dest-dir exists
94cb9600
 # Set global ERROR_ON_CLONE=True to abort execution with an error if the git repo
 # does not exist (default is False, meaning the repo will be cloned).
4a43b7bd
 # Uses global ``OFFLINE``
7f9aa71b
 # git_clone remote dest-dir branch
 function git_clone {
     [[ "$OFFLINE" = "True" ]] && return
 
     GIT_REMOTE=$1
     GIT_DEST=$2
6a3912de
     GIT_REF=$3
7f9aa71b
 
6a3912de
     if echo $GIT_REF | egrep -q "^refs"; then
7f9aa71b
         # If our branch name is a gerrit style refs/changes/...
         if [[ ! -d $GIT_DEST ]]; then
94cb9600
             [[ "$ERROR_ON_CLONE" = "True" ]] && exit 1
7f9aa71b
             git clone $GIT_REMOTE $GIT_DEST
         fi
         cd $GIT_DEST
6a3912de
         git fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
7f9aa71b
     else
         # do a full clone only if the directory doesn't exist
         if [[ ! -d $GIT_DEST ]]; then
94cb9600
             [[ "$ERROR_ON_CLONE" = "True" ]] && exit 1
7f9aa71b
             git clone $GIT_REMOTE $GIT_DEST
             cd $GIT_DEST
             # This checkout syntax works for both branches and tags
6a3912de
             git checkout $GIT_REF
7f9aa71b
         elif [[ "$RECLONE" == "yes" ]]; then
             # if it does exist then simulate what clone does if asked to RECLONE
             cd $GIT_DEST
             # set the url to pull from and fetch
             git remote set-url origin $GIT_REMOTE
             git fetch origin
             # 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)
             find $GIT_DEST -name '*.pyc' -delete
6a3912de
 
             # handle GIT_REF accordingly to type (tag, branch)
             if [[ -n "`git show-ref refs/tags/$GIT_REF`" ]]; then
                 git_update_tag $GIT_REF
             elif [[ -n "`git show-ref refs/heads/$GIT_REF`" ]]; then
                 git_update_branch $GIT_REF
f900bd79
             elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then
                 git_update_remote_branch $GIT_REF
6a3912de
             else
                 echo $GIT_REF is neither branch nor tag
                 exit 1
             fi
 
7f9aa71b
         fi
     fi
 }
 
 
13dc5ccd
 # Comment an option in an INI file
c7214e83
 # inicomment config-file section option
13dc5ccd
 function inicomment() {
     local file=$1
     local section=$2
     local option=$3
     sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" $file
 }
 
c7214e83
 # Uncomment an option in an INI file
 # iniuncomment config-file section option
 function iniuncomment() {
     local file=$1
     local section=$2
     local option=$3
     sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" $file
 }
 
13dc5ccd
 
 # Get an option from an INI file
09e636e4
 # iniget config-file section option
13dc5ccd
 function iniget() {
     local file=$1
     local section=$2
     local option=$3
     local line
     line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" $file)
     echo ${line#*=}
 }
 
 
 # Set an option in an INI file
09e636e4
 # iniset config-file section option value
13dc5ccd
 function iniset() {
     local file=$1
     local section=$2
     local option=$3
     local value=$4
09e636e4
     if ! grep -q "^\[$section\]" $file; then
         # Add section at the end
         echo -e "\n[$section]" >>$file
     fi
     if [[ -z "$(iniget $file $section $option)" ]]; then
         # Add it
         sed -i -e "/^\[$section\]/ a\\
 $option = $value
 " $file
     else
         # Replace it
         sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=[ \t]*\).*$|\1$value|" $file
     fi
13dc5ccd
 }
 
 
408b009c
 # is_service_enabled() checks if the service(s) specified as arguments are
4a43b7bd
 # enabled by the user in ``ENABLED_SERVICES``.
408b009c
 #
4a43b7bd
 # Multiple services specified as arguments are ``OR``'ed together; the test
 # is a short-circuit boolean, i.e it returns on the first match.
408b009c
 #
4a43b7bd
 # There are special cases for some 'catch-all' services::
408b009c
 #   **nova** returns true if any service enabled start with **n-**
4a43b7bd
 #   **cinder** returns true if any service enabled start with **c-**
 #   **ceilometer** returns true if any service enabled start with **ceilometer**
408b009c
 #   **glance** returns true if any service enabled start with **g-**
 #   **quantum** returns true if any service enabled start with **q-**
4a43b7bd
 #
 # Uses global ``ENABLED_SERVICES``
 # is_service_enabled service [service ...]
408b009c
 function is_service_enabled() {
     services=$@
     for service in ${services}; do
         [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
         [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && return 0
67787e6b
         [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && return 0
93361643
         [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && return 0
408b009c
         [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && return 0
         [[ ${service} == "quantum" && ${ENABLED_SERVICES} =~ "q-" ]] && return 0
     done
     return 1
 }
 
4a43b7bd
 
 # remove extra commas from the input string (i.e. ``ENABLED_SERVICES``)
 # _cleanup_service_list service-list
f04178fd
 function _cleanup_service_list () {
ca0e3d02
     echo "$1" | sed -e '
f04178fd
         s/,,/,/g;
         s/^,//;
         s/,$//
     '
 }
 
4a43b7bd
 
f04178fd
 # enable_service() adds the services passed as argument to the
4a43b7bd
 # ``ENABLED_SERVICES`` list, if they are not already present.
f04178fd
 #
 # For example:
 #   enable_service n-vol
 #
 # This function does not know about the special cases
 # for nova, glance, and quantum built into is_service_enabled().
4a43b7bd
 # Uses global ``ENABLED_SERVICES``
 # enable_service service [service ...]
f04178fd
 function enable_service() {
     local tmpsvcs="${ENABLED_SERVICES}"
     for service in $@; do
         if ! is_service_enabled $service; then
             tmpsvcs+=",$service"
         fi
     done
     ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
     disable_negated_services
 }
 
4a43b7bd
 
f04178fd
 # disable_service() removes the services passed as argument to the
4a43b7bd
 # ``ENABLED_SERVICES`` list, if they are present.
f04178fd
 #
 # For example:
 #   disable_service n-vol
 #
 # This function does not know about the special cases
 # for nova, glance, and quantum built into is_service_enabled().
4a43b7bd
 # Uses global ``ENABLED_SERVICES``
 # disable_service service [service ...]
f04178fd
 function disable_service() {
     local tmpsvcs=",${ENABLED_SERVICES},"
     local service
     for service in $@; do
         if is_service_enabled $service; then
             tmpsvcs=${tmpsvcs//,$service,/,}
         fi
     done
     ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
 }
 
4a43b7bd
 
f04178fd
 # disable_all_services() removes all current services
4a43b7bd
 # from ``ENABLED_SERVICES`` to reset the configuration
f04178fd
 # before a minimal installation
4a43b7bd
 # Uses global ``ENABLED_SERVICES``
 # disable_all_services
f04178fd
 function disable_all_services() {
     ENABLED_SERVICES=""
 }
 
4a43b7bd
 
 # Remove all services starting with '-'.  For example, to install all default
 # services except nova-volume (n-vol) set in ``localrc``:
f04178fd
 # ENABLED_SERVICES+=",-n-vol"
4a43b7bd
 # Uses global ``ENABLED_SERVICES``
 # disable_negated_services
f04178fd
 function disable_negated_services() {
     local tmpsvcs="${ENABLED_SERVICES}"
     local service
     for service in ${tmpsvcs//,/ }; do
         if [[ ${service} == -* ]]; then
             tmpsvcs=$(echo ${tmpsvcs}|sed -r "s/(,)?(-)?${service#-}(,)?/,/g")
         fi
     done
     ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
 }
489bd2a6
 
4a43b7bd
 
13dc5ccd
 # Distro-agnostic package installer
 # install_package package [package ...]
 function install_package() {
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
c0482e6e
 
13dc5ccd
     if [[ "$os_PACKAGE" = "deb" ]]; then
c0482e6e
         [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
         NO_UPDATE_REPOS=True
 
13dc5ccd
         apt_get install "$@"
     else
         yum_install "$@"
     fi
 }
 
 
71ebc6ff
 # Distro-agnostic function to tell if a package is installed
 # is_package_installed package [package ...]
 function is_package_installed() {
     if [[ -z "$@" ]]; then
         return 1
     fi
 
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
     if [[ "$os_PACKAGE" = "deb" ]]; then
         dpkg -l "$@" > /dev/null
         return $?
     else
         rpm --quiet -q "$@"
         return $?
     fi
 }
 
 
489bd2a6
 # Test if the named environment variable is set and not zero length
 # is_set env-var
 function is_set() {
     local var=\$"$1"
     if eval "[ -z $var ]"; then
         return 1
     fi
     return 0
 }
 
 
4a43b7bd
 # Wrapper for ``pip install`` to set cache and proxy environment variables
 # Uses globals ``OFFLINE``, ``PIP_DOWNLOAD_CACHE``, ``TRACK_DEPENDES``, ``*_proxy`
7f9aa71b
 # pip_install package [package ...]
 function pip_install {
d0b21e2d
     [[ "$OFFLINE" = "True" || -z "$@" ]] && return
13dc5ccd
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
47f02060
     if [[ $TRACK_DEPENDS = True ]] ; then
         source $DEST/.venv/bin/activate
         CMD_PIP=$DEST/.venv/bin/pip
         SUDO_PIP="env"
13dc5ccd
     else
47f02060
         SUDO_PIP="sudo"
         if [[ "$os_PACKAGE" = "deb" ]]; then
             CMD_PIP=/usr/bin/pip
         else
             CMD_PIP=/usr/bin/pip-python
         fi
13dc5ccd
     fi
47f02060
     $SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \
7f9aa71b
         HTTP_PROXY=$http_proxy \
         HTTPS_PROXY=$https_proxy \
7abe4f24
         NO_PROXY=$no_proxy \
13dc5ccd
         $CMD_PIP install --use-mirrors $@
 }
 
 
 # Service wrapper to restart services
 # restart_service service-name
 function restart_service() {
5218d451
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
     if [[ "$os_PACKAGE" = "deb" ]]; then
         sudo /usr/sbin/service $1 restart
     else
         sudo /sbin/service $1 restart
     fi
13dc5ccd
 }
 
 
15733351
 # Helper to launch a service in a named screen
 # screen_it service "command-line"
 function screen_it {
     NL=`echo -ne '\015'`
     SCREEN_NAME=${SCREEN_NAME:-stack}
     if is_service_enabled $1; then
         # Append the service to the screen rc file
         screen_rc "$1" "$2"
 
         screen -S $SCREEN_NAME -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.5
 
         if [[ -n ${SCREEN_LOGDIR} ]]; then
             screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log
             screen -S $SCREEN_NAME -p $1 -X log on
             ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
         fi
         screen -S $SCREEN_NAME -p $1 -X stuff "$2$NL"
     fi
 }
 
 
 # Screen rc file builder
 # screen_rc service "command-line"
 function screen_rc {
     SCREEN_NAME=${SCREEN_NAME:-stack}
     SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc
     if [[ ! -e $SCREENRC ]]; then
         # Name the screen session
         echo "sessionname $SCREEN_NAME" > $SCREENRC
         # Set a reasonable statusbar
         echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC
         echo "screen -t shell bash" >> $SCREENRC
     fi
     # If this service doesn't already exist in the screenrc file
     if ! grep $1 $SCREENRC 2>&1 > /dev/null; then
         NL=`echo -ne '\015'`
         echo "screen -t $1 bash" >> $SCREENRC
         echo "stuff \"$2$NL\"" >> $SCREENRC
     fi
 }
 
 
4a43b7bd
 # ``pip install`` the dependencies of the package before ``setup.py develop``
 # so pip and not distutils processes the dependency chain
 # Uses globals ``TRACK_DEPENDES``, ``*_proxy`
bbafb1b5
 # setup_develop directory
 function setup_develop() {
47f02060
     if [[ $TRACK_DEPENDS = True ]] ; then
         SUDO_CMD="env"
     else
         SUDO_CMD="sudo"
     fi
bbafb1b5
     (cd $1; \
         python setup.py egg_info; \
         raw_links=$(awk '/^.+/ {print "-f " $1}' *.egg-info/dependency_links.txt); \
         depend_links=$(echo $raw_links | xargs); \
1a3c9fe4
         require_file=$([ ! -r *-info/requires.txt ] || echo "-r *-info/requires.txt"); \
         pip_install $require_file $depend_links; \
47f02060
         $SUDO_CMD \
bbafb1b5
             HTTP_PROXY=$http_proxy \
             HTTPS_PROXY=$https_proxy \
7abe4f24
             NO_PROXY=$no_proxy \
bbafb1b5
             python setup.py develop \
     )
 }
 
 
13dc5ccd
 # Service wrapper to start services
 # start_service service-name
 function start_service() {
5218d451
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
     if [[ "$os_PACKAGE" = "deb" ]]; then
         sudo /usr/sbin/service $1 start
     else
         sudo /sbin/service $1 start
     fi
13dc5ccd
 }
 
 
 # Service wrapper to stop services
 # stop_service service-name
 function stop_service() {
5218d451
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
     if [[ "$os_PACKAGE" = "deb" ]]; then
         sudo /usr/sbin/service $1 stop
     else
         sudo /sbin/service $1 stop
     fi
7f9aa71b
 }
 
 
 # Normalize config values to True or False
4a43b7bd
 # Accepts as False: 0 no false False FALSE
 # Accepts as True: 1 yes true True TRUE
 # VAR=$(trueorfalse default-value test-value)
7f9aa71b
 function trueorfalse() {
     local default=$1
     local testval=$2
 
     [[ -z "$testval" ]] && { echo "$default"; return; }
     [[ "0 no false False FALSE" =~ "$testval" ]] && { echo "False"; return; }
     [[ "1 yes true True TRUE" =~ "$testval" ]] && { echo "True"; return; }
     echo "$default"
 }
27e32699
 
13dc5ccd
 
ca0e3d02
 # Retrieve an image from a URL and upload into Glance
 # Uses the following variables:
4a43b7bd
 #   ``FILES`` must be set to the cache dir
 #   ``GLANCE_HOSTPORT``
ca0e3d02
 # upload_image image-url glance-token
 function upload_image() {
     local image_url=$1
     local token=$2
 
     # Create a directory for the downloaded image tarballs.
     mkdir -p $FILES/images
 
     # Downloads the image (uec ami+aki style), then extracts it.
     IMAGE_FNAME=`basename "$image_url"`
     if [[ ! -f $FILES/$IMAGE_FNAME || "$(stat -c "%s" $FILES/$IMAGE_FNAME)" = "0" ]]; then
         wget -c $image_url -O $FILES/$IMAGE_FNAME
         if [[ $? -ne 0 ]]; then
             echo "Not found: $image_url"
             return
         fi
     fi
 
     # OpenVZ-format images are provided as .tar.gz, but not decompressed prior to loading
     if [[ "$image_url" =~ 'openvz' ]]; then
         IMAGE="$FILES/${IMAGE_FNAME}"
         IMAGE_NAME="${IMAGE_FNAME%.tar.gz}"
         glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --is-public=True --container-format ami --disk-format ami < "${IMAGE}"
         return
     fi
 
     KERNEL=""
     RAMDISK=""
     DISK_FORMAT=""
     CONTAINER_FORMAT=""
     UNPACK=""
     case "$IMAGE_FNAME" in
         *.tar.gz|*.tgz)
             # Extract ami and aki files
             [ "${IMAGE_FNAME%.tar.gz}" != "$IMAGE_FNAME" ] &&
                 IMAGE_NAME="${IMAGE_FNAME%.tar.gz}" ||
                 IMAGE_NAME="${IMAGE_FNAME%.tgz}"
             xdir="$FILES/images/$IMAGE_NAME"
             rm -Rf "$xdir";
             mkdir "$xdir"
             tar -zxf $FILES/$IMAGE_FNAME -C "$xdir"
             KERNEL=$(for f in "$xdir/"*-vmlinuz* "$xdir/"aki-*/image; do
                      [ -f "$f" ] && echo "$f" && break; done; true)
             RAMDISK=$(for f in "$xdir/"*-initrd* "$xdir/"ari-*/image; do
                      [ -f "$f" ] && echo "$f" && break; done; true)
             IMAGE=$(for f in "$xdir/"*.img "$xdir/"ami-*/image; do
                      [ -f "$f" ] && echo "$f" && break; done; true)
             if [[ -z "$IMAGE_NAME" ]]; then
                 IMAGE_NAME=$(basename "$IMAGE" ".img")
             fi
             ;;
         *.img)
             IMAGE="$FILES/$IMAGE_FNAME";
             IMAGE_NAME=$(basename "$IMAGE" ".img")
636a3ff4
             format=$(qemu-img info ${IMAGE} | awk '/^file format/ { print $3; exit }')
             if [[ ",qcow2,raw,vdi,vmdk,vpc," =~ ",$format," ]]; then
                 DISK_FORMAT=$format
             else
                 DISK_FORMAT=raw
             fi
ca0e3d02
             CONTAINER_FORMAT=bare
             ;;
         *.img.gz)
             IMAGE="$FILES/${IMAGE_FNAME}"
             IMAGE_NAME=$(basename "$IMAGE" ".img.gz")
             DISK_FORMAT=raw
             CONTAINER_FORMAT=bare
             UNPACK=zcat
             ;;
         *.qcow2)
             IMAGE="$FILES/${IMAGE_FNAME}"
             IMAGE_NAME=$(basename "$IMAGE" ".qcow2")
             DISK_FORMAT=qcow2
             CONTAINER_FORMAT=bare
             ;;
         *) echo "Do not know what to do with $IMAGE_FNAME"; false;;
     esac
 
     if [ "$CONTAINER_FORMAT" = "bare" ]; then
         if [ "$UNPACK" = "zcat" ]; then
             glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --public --container-format=$CONTAINER_FORMAT --disk-format $DISK_FORMAT < <(zcat --force "${IMAGE}")
         else
             glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --public --container-format=$CONTAINER_FORMAT --disk-format $DISK_FORMAT < "${IMAGE}"
         fi
     else
         # 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.
         KERNEL_ID=""; RAMDISK_ID="";
         if [ -n "$KERNEL" ]; then
             KERNEL_ID=$(glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME-kernel" --public --container-format aki --disk-format aki < "$KERNEL" | grep ' id ' | get_field 2)
         fi
         if [ -n "$RAMDISK" ]; then
             RAMDISK_ID=$(glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME-ramdisk" --public --container-format ari --disk-format ari < "$RAMDISK" | grep ' id ' | get_field 2)
         fi
         glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "${IMAGE_NAME%.img}" --public --container-format ami --disk-format ami ${KERNEL_ID:+--property kernel_id=$KERNEL_ID} ${RAMDISK_ID:+--property ramdisk_id=$RAMDISK_ID} < "${IMAGE}"
     fi
 }
 
 
4a43b7bd
 # Wrapper for ``yum`` to set proxy environment variables
 # Uses globals ``OFFLINE``, ``*_proxy`
13dc5ccd
 # yum_install package [package ...]
 function yum_install() {
     [[ "$OFFLINE" = "True" ]] && return
     local sudo="sudo"
     [[ "$(id -u)" = "0" ]] && sudo="env"
     $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
7abe4f24
         no_proxy=$no_proxy \
13dc5ccd
         yum install -y "$@"
 }
 
 
27e32699
 # Restore xtrace
408b009c
 $XTRACE
4a43b7bd
 
 
 # Local variables:
 # -*- mode: Shell-script -*-
f900bd79
 # End: