860 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			860 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| # 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``
 | |
| # ``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 ...]
 | |
| 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
 | |
|             set +o xtrace
 | |
|             echo $@
 | |
|             exit -1
 | |
|         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
 | |
| #   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
 | |
|         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=""
 | |
|         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
 | |
| }
 | |
| 
 | |
| # 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"
 | |
|     else
 | |
|         # Catch-all for now is Vendor + Release + Update
 | |
|         DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
 | |
|     fi
 | |
|     export DISTRO
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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#*=}
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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 [[ -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
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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 n-vol
 | |
| #
 | |
| # 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 n-vol
 | |
| #
 | |
| # 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 nova-volume (n-vol) set in ``localrc``:
 | |
| # ENABLED_SERVICES+=",-n-vol"
 | |
| # 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 [[ -z "$os_PACKAGE" ]]; then
 | |
|         GetOSVersion
 | |
|     fi
 | |
| 
 | |
|     if [[ "$os_PACKAGE" = "deb" ]]; then
 | |
|         [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
 | |
|         NO_UPDATE_REPOS=True
 | |
| 
 | |
|         apt_get install "$@"
 | |
|     else
 | |
|         yum_install "$@"
 | |
|     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
 | |
|         return $?
 | |
|     else
 | |
|         rpm --quiet -q "$@"
 | |
|         return $?
 | |
|     fi
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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
 | |
| }
 | |
| 
 | |
| 
 | |
| # Wrapper for ``pip install`` to set cache and proxy environment variables
 | |
| # Uses globals ``OFFLINE``, ``PIP_DOWNLOAD_CACHE``, ``TRACK_DEPENDES``, ``*_proxy`
 | |
| # 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"
 | |
|         if [[ "$os_PACKAGE" = "deb" ]]; then
 | |
|             CMD_PIP=/usr/bin/pip
 | |
|         else
 | |
|             CMD_PIP=/usr/bin/pip-python
 | |
|         fi
 | |
|     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 --use-mirrors $@
 | |
| }
 | |
| 
 | |
| 
 | |
| # Service wrapper to restart services
 | |
| # restart_service service-name
 | |
| function restart_service() {
 | |
|     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
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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
 | |
| }
 | |
| 
 | |
| 
 | |
| # ``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
 | |
| 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 [[ -z "$os_PACKAGE" ]]; then
 | |
|         GetOSVersion
 | |
|     fi
 | |
|     if [[ "$os_PACKAGE" = "deb" ]]; 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 [[ -z "$os_PACKAGE" ]]; then
 | |
|         GetOSVersion
 | |
|     fi
 | |
|     if [[ "$os_PACKAGE" = "deb" ]]; 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:
 | |
| #   ``FILES`` must be set to the cache dir
 | |
| #   ``GLANCE_HOSTPORT``
 | |
| # 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
 | |
| }
 | |
| 
 | |
| 
 | |
| # Wrapper for ``yum`` to set proxy environment variables
 | |
| # Uses globals ``OFFLINE``, ``*_proxy`
 | |
| # 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 \
 | |
|         no_proxy=$no_proxy \
 | |
|         yum install -y "$@"
 | |
| }
 | |
| 
 | |
| 
 | |
| # Restore xtrace
 | |
| $XTRACE
 | |
| 
 | |
| 
 | |
| # Local variables:
 | |
| # -*- mode: Shell-script -*-
 | |
| # End:
 | 
