functions

functions - Common functions used by DevStack components

The following variables are assumed to be defined by certain functions: ENABLED_SERVICES EROR_ON_CLONE FILES GLANCE_HOSTPORT OFFLINE PIP_DOWNLOAD_CACHE PIP_USE_MIRRORS RECLONE TRACK_DEPENDS http_proxy, https_proxy, no_proxy



Save trace setting

XTRACE=$(set +o | grep xtrace)
set +o xtrace


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

function address_in_net() {
    python -c "
import netaddr
import sys
sys.exit(netaddr.IPAddress('$1') not in netaddr.IPNetwork('$2'))
"
}


Wrapper for apt-get to set cache and proxy environment variables Uses globals OFFLINE, ``*_proxy` apt_get operation package [package ...]

System Message: WARNING/2 (<stdin>, line 27); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<stdin>, line 27); backlink

Inline emphasis start-string without end-string.
function apt_get() {
    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
    local sudo="sudo"
    [[ "$(id -u)" = "0" ]] && sudo="env"
    $sudo DEBIAN_FRONTEND=noninteractive \
        http_proxy=$http_proxy https_proxy=$https_proxy \
        no_proxy=$no_proxy \
        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
}


Prints "message" and exits die "message"

function die() {
    local exitcode=$?
    set +o xtrace
    echo $@
    exit $exitcode
}


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() {
    (
        local exitcode=$?
        set +o xtrace
        local evar=$1; shift
        if ! is_set $evar || [ $exitcode != 0 ]; then
            echo $@
            exit -1
        fi
    )
}


HTTP and HTTPS proxy servers are supported via the usual environment variables [1] http_proxy, https_proxy and no_proxy. They can be set in localrc or on the command line if necessary:

[1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh

function export_proxy_variables() {
    if [[ -n "$http_proxy" ]]; then
        export http_proxy=$http_proxy
    fi
    if [[ -n "$https_proxy" ]]; then
        export https_proxy=$https_proxy
    fi
    if [[ -n "$no_proxy" ]]; then
        export no_proxy=$no_proxy
    fi
}


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
}


get_packages() collects a list of package names of any type from the prerequisite files in files/{apts|rpms}. The list is intended to be passed to a package installer such as apt or yum.

Only packages required for the services in ENABLED_SERVICES will be 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

System Message: ERROR/3 (<stdin>, line 75)

Unexpected indentation.
of the package to the distros listed. The distro names are case insensitive.

Uses globals ENABLED_SERVICES 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
        GetDistro
    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
        elif [[ $service == ceilometer-* ]]; then
            if [[ ! $file_to_parse =~ ceilometer ]]; then
                file_to_parse="${file_to_parse} ceilometer"
            fi
        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
        elif [[ $service == q-* ]]; then
            if [[ ! $file_to_parse =~ quantum ]]; then
                file_to_parse="${file_to_parse} quantum"
            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
}


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=""
        os_PACKAGE="rpm"
        if [[ "Debian,Ubuntu" =~ $os_VENDOR ]]; then
            os_PACKAGE="deb"
        elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then
            lsb_release -d -s | grep -q openSUSE
            if [[ $? -eq 0 ]]; then
                os_VENDOR="openSUSE"
            fi
        elif [[ $os_VENDOR =~ Red.*Hat ]]; then
            os_VENDOR="Red Hat"
        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"
    elif [[ -r /etc/SuSE-release ]]; then
        for r in openSUSE "SUSE Linux"; do
            if [[ "$r" = "SUSE Linux" ]]; then
                os_VENDOR="SUSE LINUX"
            else
                os_VENDOR=$r
            fi

            if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then
                os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'`
                os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'`
                os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'`
                break
            fi
            os_VENDOR=""
        done
        os_PACKAGE="rpm"
    fi
    export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
}

git update using reference as a branch. git_update_branch ref

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 git_update_tag ref

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
}


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
}


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"
    elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then
        DISTRO="opensuse-$os_RELEASE"
    elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then

For SLE, also use the service pack

        if [[ -z "$os_UPDATE" ]]; then
            DISTRO="sle${os_RELEASE}"
        else
            DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
        fi
    else

Catch-all for now is Vendor + Release + Update

        DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
    fi
    export DISTRO
}


Determine if current distribution is an Ubuntu-based distribution. It will also detect non-Ubuntu but Debian-based distros; this is not an issue since Debian and Ubuntu should be compatible. is_ubuntu

function is_ubuntu {
    if [[ -z "$os_PACKAGE" ]]; then
        GetOSVersion
    fi

    [ "$os_PACKAGE" = "deb" ]
}


Determine if current distribution is a Fedora-based distribution (Fedora, RHEL, CentOS). is_fedora

function is_fedora {
    if [[ -z "$os_VENDOR" ]]; then
        GetOSVersion
    fi

    [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
}


Determine if current distribution is a SUSE-based distribution (openSUSE, SLE). is_suse

function is_suse {
    if [[ -z "$os_VENDOR" ]]; then
        GetOSVersion
    fi

    [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ]
}


Exit after outputting a message about the distribution not being supported. exit_distro_not_supported [optional-string-telling-what-is-missing]

function exit_distro_not_supported {
    if [[ -z "$DISTRO" ]]; then
        GetDistro
    fi

    if [ $# -gt 0 ]; then
        echo "Support for $DISTRO is incomplete: no support for $@"
    else
        echo "Support for $DISTRO is incomplete."
    fi

    exit 1
}


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 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). Uses global OFFLINE git_clone remote dest-dir branch

function git_clone {
    [[ "$OFFLINE" = "True" ]] && return

    GIT_REMOTE=$1
    GIT_DEST=$2
    GIT_REF=$3

    if echo $GIT_REF | egrep -q "^refs"; then

If our branch name is a gerrit style refs/changes/...

        if [[ ! -d $GIT_DEST ]]; then
            [[ "$ERROR_ON_CLONE" = "True" ]] && exit 1
            git clone $GIT_REMOTE $GIT_DEST
        fi
        cd $GIT_DEST
        git fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
    else

do a full clone only if the directory doesn't exist

        if [[ ! -d $GIT_DEST ]]; then
            [[ "$ERROR_ON_CLONE" = "True" ]] && exit 1
            git clone $GIT_REMOTE $GIT_DEST
            cd $GIT_DEST

This checkout syntax works for both branches and tags

            git checkout $GIT_REF
        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

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
            elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then
                git_update_remote_branch $GIT_REF
            else
                echo $GIT_REF is neither branch nor tag
                exit 1
            fi

        fi
    fi
}


Comment an option in an INI file inicomment config-file section option

function inicomment() {
    local file=$1
    local section=$2
    local option=$3
    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file"
}

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"
}


Get an option from an INI file iniget config-file section option

function iniget() {
    local file=$1
    local section=$2
    local option=$3
    local line
    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
    echo ${line#*=}
}

Determinate is the given option present in the INI file ini_has_option config-file section option

function ini_has_option() {
    local file=$1
    local section=$2
    local option=$3
    local line
    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
    [ -n "$line" ]
}

Set an option in an INI file iniset config-file section option value

function iniset() {
    local file=$1
    local section=$2
    local option=$3
    local value=$4
    if ! grep -q "^\[$section\]" "$file"; then

Add section at the end

        echo -e "\n[$section]" >>"$file"
    fi
    if ! ini_has_option "$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
}


is_service_enabled() checks if the service(s) specified as arguments are enabled by the user in ENABLED_SERVICES.

Multiple services specified as arguments are OR'ed together; the test is a short-circuit boolean, i.e it returns on the first match.

There are special cases for some 'catch-all' services::
nova returns true if any service enabled start with n- cinder returns true if any service enabled start with c- ceilometer returns true if any service enabled start with ceilometer glance returns true if any service enabled start with g- quantum returns true if any service enabled start with q-

Uses global ENABLED_SERVICES is_service_enabled service [service ...]

function is_service_enabled() {
    services=$@
    for service in ${services}; do
        [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
        [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && return 0
        [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && return 0
        [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && return 0
        [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && return 0
        [[ ${service} == "quantum" && ${ENABLED_SERVICES} =~ "q-" ]] && return 0
    done
    return 1
}


remove extra commas from the input string (i.e. ENABLED_SERVICES) _cleanup_service_list service-list

function _cleanup_service_list () {
    echo "$1" | sed -e '
        s/,,/,/g;
        s/^,//;
        s/,$//
    '
}


enable_service() adds the services passed as argument to the ENABLED_SERVICES list, if they are not already present.

For example:
enable_service qpid

This function does not know about the special cases for nova, glance, and quantum built into is_service_enabled(). Uses global ENABLED_SERVICES enable_service service [service ...]

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
}


disable_service() removes the services passed as argument to the ENABLED_SERVICES list, if they are present.

For example:
disable_service rabbit

This function does not know about the special cases for nova, glance, and quantum built into is_service_enabled(). Uses global ENABLED_SERVICES disable_service service [service ...]

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")
}


disable_all_services() removes all current services from ENABLED_SERVICES to reset the configuration before a minimal installation Uses global ENABLED_SERVICES disable_all_services

function disable_all_services() {
    ENABLED_SERVICES=""
}


Remove all services starting with '-'. For example, to install all default services except rabbit (rabbit) set in localrc: ENABLED_SERVICES+=",-rabbit" Uses global ENABLED_SERVICES disable_negated_services

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")
}


Distro-agnostic package installer install_package package [package ...]

function install_package() {
    if is_ubuntu; then
        [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
        NO_UPDATE_REPOS=True

        apt_get install "$@"
    elif is_fedora; then
        yum_install "$@"
    elif is_suse; then
        zypper_install "$@"
    else
        exit_distro_not_supported "installing packages"
    fi
}


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
    elif [[ "$os_PACKAGE" = "rpm" ]]; then
        rpm --quiet -q "$@"
    else
        exit_distro_not_supported "finding if a package is installed"
    fi
}


Test if the named environment variable is set and not zero length is_set env-var

function is_set() {
    local var=\$"$1"
    eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
}


Wrapper for pip install to set cache and proxy environment variables Uses globals OFFLINE, PIP_DOWNLOAD_CACHE, PIP_USE_MIRRORS,

System Message: ERROR/3 (<stdin>, line 355)

Unexpected indentation.

TRACK_DEPENDS, ``*_proxy`

System Message: WARNING/2 (<stdin>, line 355); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<stdin>, line 355); backlink

Inline emphasis start-string without end-string.

System Message: WARNING/2 (<stdin>, line 356)

Block quote ends without a blank line; unexpected unindent.

pip_install package [package ...]

function pip_install {
    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
    if [[ -z "$os_PACKAGE" ]]; then
        GetOSVersion
    fi
    if [[ $TRACK_DEPENDS = True ]] ; then
        source $DEST/.venv/bin/activate
        CMD_PIP=$DEST/.venv/bin/pip
        SUDO_PIP="env"
    else
        SUDO_PIP="sudo"
        CMD_PIP=$(get_pip_command)
    fi
    if [[ "$PIP_USE_MIRRORS" != "False" ]]; then
        PIP_MIRROR_OPT="--use-mirrors"
    fi
    $SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \
        HTTP_PROXY=$http_proxy \
        HTTPS_PROXY=$https_proxy \
        NO_PROXY=$no_proxy \
        $CMD_PIP install $PIP_MIRROR_OPT $@
}


Service wrapper to restart services restart_service service-name

function restart_service() {
    if is_ubuntu; then
        sudo /usr/sbin/service $1 restart
    else
        sudo /sbin/service $1 restart
    fi
}


Helper to launch a service in a named screen screen_it service "command-line"

function screen_it {
    SCREEN_NAME=${SCREEN_NAME:-stack}
    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
    SCREEN_DEV=`trueorfalse True $SCREEN_DEV`

    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

        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

        if [[ "$SCREEN_DEV" = "True" ]]; then

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

            NL=`echo -ne '\015'`
            screen -S $SCREEN_NAME -p $1 -X stuff "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
        else
            screen -S $SCREEN_NAME -p $1 -X exec /bin/bash -c "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\""
        fi
    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
}

Helper to remove the *.failure files under $SERVICE_DIR/$SCREEN_NAME This is used for service_check when all the screen_it are called finished init_service_check

System Message: WARNING/2 (<stdin>, line 397); backlink

Inline emphasis start-string without end-string.
function init_service_check() {
    SCREEN_NAME=${SCREEN_NAME:-stack}
    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}

    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
        mkdir -p "$SERVICE_DIR/$SCREEN_NAME"
    fi

    rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure
}

Helper to get the status of each running service service_check

function service_check() {
    local service
    local failures
    SCREEN_NAME=${SCREEN_NAME:-stack}
    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}


    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
        echo "No service status directory found"
        return
    fi

Check if there is any falure flag file under $SERVICE_DIR/$SCREEN_NAME

    failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null`

    for service in $failures; do
        service=`basename $service`
        service=${service::-8}
        echo "Error: Service $service is not running"
    done

    if [ -n "$failures" ]; then
        echo "More details about the above errors can be found with screen, with ./rejoin-stack.sh"
    fi
}

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` setup_develop directory

System Message: WARNING/2 (<stdin>, line 412); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<stdin>, line 412); backlink

Inline emphasis start-string without end-string.
function setup_develop() {
    if [[ $TRACK_DEPENDS = True ]] ; then
        SUDO_CMD="env"
    else
        SUDO_CMD="sudo"
    fi
    (cd $1; \
        python setup.py egg_info; \
        raw_links=$(awk '/^.+/ {print "-f " $1}' *.egg-info/dependency_links.txt); \
        depend_links=$(echo $raw_links | xargs); \
        require_file=$([ ! -r *-info/requires.txt ] || echo "-r *-info/requires.txt"); \
        pip_install $require_file $depend_links; \
        $SUDO_CMD \
            HTTP_PROXY=$http_proxy \
            HTTPS_PROXY=$https_proxy \
            NO_PROXY=$no_proxy \
            python setup.py develop \
    )
}


Service wrapper to start services start_service service-name

function start_service() {
    if is_ubuntu; then
        sudo /usr/sbin/service $1 start
    else
        sudo /sbin/service $1 start
    fi
}


Service wrapper to stop services stop_service service-name

function stop_service() {
    if is_ubuntu; then
        sudo /usr/sbin/service $1 stop
    else
        sudo /sbin/service $1 stop
    fi
}


Normalize config values to True or False Accepts as False: 0 no false False FALSE Accepts as True: 1 yes true True TRUE VAR=$(trueorfalse default-value test-value)

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"
}


Retrieve an image from a URL and upload into Glance Uses the following variables:

System Message: ERROR/3 (<stdin>, line 438)

Unexpected indentation.
FILES must be set to the cache dir GLANCE_HOSTPORT

System Message: WARNING/2 (<stdin>, line 440)

Block quote ends without a blank line; unexpected unindent.

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")
            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
            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
}

Set the database backend to use When called from stackrc/localrc DATABASE_BACKENDS has not been initialized yet, just save the configuration selection and call back later to validate it.

System Message: ERROR/3 (<stdin>, line 470)

Unexpected indentation.
$1 The name of the database backend to use (mysql, postgresql, ...)
function use_database {
    if [[ -z "$DATABASE_BACKENDS" ]]; then

The backends haven't initialized yet, just save the selection for now

        DATABASE_TYPE=$1
    else
        use_exclusive_service DATABASE_BACKENDS DATABASE_TYPE $1
    fi
}

Toggle enable/disable_service for services that must run exclusive of each other
$1 The name of a variable containing a space-separated list of services $2 The name of a variable in which to store the enabled service's name $3 The name of the service to enable
function use_exclusive_service {
    local options=${!1}
    local selection=$3
    out=$2
    [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1
    for opt in $options;do
        [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt
    done
    eval "$out=$selection"
    return 0
}

Wait for an HTTP server to start answering requests wait_for_service timeout url

function wait_for_service() {
    local timeout=$1
    local url=$2
    timeout $timeout sh -c "while ! http_proxy= https_proxy= curl -s $url >/dev/null; do sleep 1; done"
}

Wrapper for yum to set proxy environment variables Uses globals OFFLINE, ``*_proxy` yum_install package [package ...]

System Message: WARNING/2 (<stdin>, line 490); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<stdin>, line 490); backlink

Inline emphasis start-string without end-string.
function yum_install() {
    [[ "$OFFLINE" = "True" ]] && return
    local sudo="sudo"
    [[ "$(id -u)" = "0" ]] && sudo="env"
    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
        no_proxy=$no_proxy \
        yum install -y "$@"
}

ping check Uses globals ENABLED_SERVICES

function ping_check() {
    if is_service_enabled quantum; then
        _ping_check_quantum  "$1" $2 $3 $4
        return
    fi
    _ping_check_novanet "$1" $2 $3 $4
}

ping check for nova Uses globals MULTI_HOST, PRIVATE_NETWORK

function _ping_check_novanet() {
    local from_net=$1
    local ip=$2
    local boot_timeout=$3
    local expected=${4:-"True"}
    local check_command=""
    MULTI_HOST=`trueorfalse False $MULTI_HOST`
    if [[ "$MULTI_HOST" = "True" && "$from_net" = "$PRIVATE_NETWORK_NAME" ]]; then
        sleep $boot_timeout
        return
    fi
    if [[ "$expected" = "True" ]]; then
        check_command="while ! ping -c1 -w1 $ip; do sleep 1; done"
    else
        check_command="while ping -c1 -w1 $ip; do sleep 1; done"
    fi
    if ! timeout $boot_timeout sh -c "$check_command"; then
        if [[ "$expected" = "True" ]]; then
            echo "[Fail] Couldn't ping server"
        else
            echo "[Fail] Could ping server"
        fi
        exit 1
    fi
}

ssh check


function ssh_check() {
    if is_service_enabled quantum; then
        _ssh_check_quantum  "$1" $2 $3 $4 $5
        return
    fi
    _ssh_check_novanet "$1" $2 $3 $4 $5
}

function _ssh_check_novanet() {
    local NET_NAME=$1
    local KEY_FILE=$2
    local FLOATING_IP=$3
    local DEFAULT_INSTANCE_USER=$4
    local ACTIVE_TIMEOUT=$5
    local probe_cmd=""
    if ! timeout $ACTIVE_TIMEOUT sh -c "while ! ssh -o StrictHostKeyChecking=no -i $KEY_FILE ${DEFAULT_INSTANCE_USER}@$FLOATING_IP echo success ; do sleep 1; done"; then
        echo "server didn't become ssh-able!"
        exit 1
    fi
}


zypper wrapper to set arguments correctly zypper_install package [package ...]

function zypper_install() {
    [[ "$OFFLINE" = "True" ]] && return
    local sudo="sudo"
    [[ "$(id -u)" = "0" ]] && sudo="env"
    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
        zypper --non-interactive install --auto-agree-with-licenses "$@"
}


Add a user to a group. add_user_to_group user group

function add_user_to_group() {
    local user=$1
    local group=$2

    if [[ -z "$os_VENDOR" ]]; then
        GetOSVersion
    fi

SLE11 and openSUSE 12.2 don't have the usual usermod

    if ! is_suse || [[ "$os_VENDOR" = "openSUSE" && "$os_RELEASE" != "12.2" ]]; then
        sudo usermod -a -G "$group" "$user"
    else
        sudo usermod -A "$group" "$user"
    fi
}


Get the path to the direcotry where python executables are installed. get_python_exec_prefix

function get_python_exec_prefix() {
    if is_fedora; then
        echo "/usr/bin"
    else
        echo "/usr/local/bin"
    fi
}

Get the location of the $module-rootwrap executables, where module is cinder or nova. get_rootwrap_location module

function get_rootwrap_location() {
    local module=$1

    echo "$(get_python_exec_prefix)/$module-rootwrap"
}

Get the path to the pip command. get_pip_command

function get_pip_command() {
    if is_fedora; then
        which pip-python
    else
        which pip
    fi
}

Restore xtrace

$XTRACE


Local variables: -- mode: Shell-script -- End: