blob: c8f551de3c4890840659a9e288e98dfb71d72591 [file] [log] [blame]
Sean Daguee263c822014-12-05 14:25:28 -05001#!/bin/bash
2#
Dean Troyerdff49a22014-01-30 15:37:40 -06003# functions-common - Common functions used by DevStack components
4#
5# The canonical copy of this file is maintained in the DevStack repo.
6# All modifications should be made there and then sync'ed to other repos
7# as required.
8#
9# This file is sorted alphabetically within the function groups.
10#
11# - Config Functions
12# - Control Functions
13# - Distro Functions
14# - Git Functions
15# - OpenStack Functions
16# - Package Functions
17# - Process Functions
Dean Troyerdff49a22014-01-30 15:37:40 -060018# - Service Functions
Masayuki Igawaf6368d32014-02-20 13:31:26 +090019# - System Functions
Dean Troyerdff49a22014-01-30 15:37:40 -060020#
21# The following variables are assumed to be defined by certain functions:
22#
23# - ``ENABLED_SERVICES``
24# - ``ERROR_ON_CLONE``
25# - ``FILES``
26# - ``OFFLINE``
Dean Troyerdff49a22014-01-30 15:37:40 -060027# - ``RECLONE``
Masayuki Igawad20f6322014-02-28 09:22:37 +090028# - ``REQUIREMENTS_DIR``
29# - ``STACK_USER``
Dean Troyerdff49a22014-01-30 15:37:40 -060030# - ``TRACK_DEPENDS``
31# - ``http_proxy``, ``https_proxy``, ``no_proxy``
Dean Troyer3324f192014-09-18 09:26:39 -050032#
Dean Troyerdff49a22014-01-30 15:37:40 -060033
34# Save trace setting
35XTRACE=$(set +o | grep xtrace)
36set +o xtrace
37
Ian Wienand4ffb4542015-06-30 11:00:32 +100038# ensure we don't re-source this in the same environment
39[[ -z "$_DEVSTACK_FUNCTIONS_COMMON" ]] || return 0
40declare -r _DEVSTACK_FUNCTIONS_COMMON=1
41
Sean Daguecc524062014-10-01 09:06:43 -040042# Global Config Variables
43declare -A GITREPO
44declare -A GITBRANCH
45declare -A GITDIR
46
Sean Dague53753292014-12-04 19:38:15 -050047TRACK_DEPENDS=${TRACK_DEPENDS:-False}
48
Dean Troyer68162342015-05-13 15:41:03 -050049# Save these variables to .stackenv
50STACK_ENV_VARS="BASE_SQL_CONN DATA_DIR DEST ENABLED_SERVICES HOST_IP \
51 KEYSTONE_AUTH_PROTOCOL KEYSTONE_AUTH_URI KEYSTONE_SERVICE_URI \
Brian Haley180f5eb2015-06-16 13:14:31 -040052 LOGFILE OS_CACERT SERVICE_HOST SERVICE_PROTOCOL STACK_USER TLS_IP \
Brian Haley5d04db22015-06-16 13:14:31 -040053 HOST_IPV6 SERVICE_IP_VERSION"
Dean Troyer68162342015-05-13 15:41:03 -050054
55
56# Saves significant environment variables to .stackenv for later use
57# Refers to a lot of globals, only TOP_DIR and STACK_ENV_VARS are required to
58# function, the rest are simply saved and do not cause problems if they are undefined.
59# save_stackenv [tag]
60function save_stackenv {
61 local tag=${1:-""}
62 # Save some values we generated for later use
63 time_stamp=$(date "+$TIMESTAMP_FORMAT")
64 echo "# $time_stamp $tag" >$TOP_DIR/.stackenv
65 for i in $STACK_ENV_VARS; do
66 echo $i=${!i} >>$TOP_DIR/.stackenv
67 done
68}
Dean Troyerdff49a22014-01-30 15:37:40 -060069
Monty Taylor7224eec2015-09-19 11:26:18 -040070# Update/create user clouds.yaml file.
71# clouds.yaml will have
72# - A `devstack` entry for the `demo` user for the `demo` project.
73# - A `devstack-admin` entry for the `admin` user for the `admin` project.
74# write_clouds_yaml
75function write_clouds_yaml {
76 # The location is a variable to allow for easier refactoring later to make it
77 # overridable. There is currently no usecase where doing so makes sense, so
78 # it's not currently configurable.
79 CLOUDS_YAML=~/.config/openstack/clouds.yaml
80
81 mkdir -p $(dirname $CLOUDS_YAML)
82
83 CA_CERT_ARG=''
84 if [ -f "$SSL_BUNDLE_FILE" ]; then
85 CA_CERT_ARG="--os-cacert $SSL_BUNDLE_FILE"
86 fi
87 $TOP_DIR/tools/update_clouds_yaml.py \
88 --file $CLOUDS_YAML \
89 --os-cloud devstack \
90 --os-region-name $REGION_NAME \
Steve Martinelli050a0d52015-09-06 22:03:54 +000091 --os-identity-api-version 3 \
Monty Taylor7224eec2015-09-19 11:26:18 -040092 $CA_CERT_ARG \
Steve Martinelli050a0d52015-09-06 22:03:54 +000093 --os-auth-url $KEYSTONE_AUTH_URI \
Monty Taylor7224eec2015-09-19 11:26:18 -040094 --os-username demo \
95 --os-password $ADMIN_PASSWORD \
96 --os-project-name demo
97 $TOP_DIR/tools/update_clouds_yaml.py \
98 --file $CLOUDS_YAML \
99 --os-cloud devstack-admin \
100 --os-region-name $REGION_NAME \
Steve Martinelli050a0d52015-09-06 22:03:54 +0000101 --os-identity-api-version 3 \
Monty Taylor7224eec2015-09-19 11:26:18 -0400102 $CA_CERT_ARG \
Steve Martinelli050a0d52015-09-06 22:03:54 +0000103 --os-auth-url $KEYSTONE_AUTH_URI \
Monty Taylor7224eec2015-09-19 11:26:18 -0400104 --os-username admin \
105 --os-password $ADMIN_PASSWORD \
106 --os-project-name admin
107}
108
Dean Troyerdff49a22014-01-30 15:37:40 -0600109# Normalize config values to True or False
110# Accepts as False: 0 no No NO false False FALSE
111# Accepts as True: 1 yes Yes YES true True TRUE
112# VAR=$(trueorfalse default-value test-value)
Ian Wienandaee18c72014-02-21 15:35:08 +1100113function trueorfalse {
Ian Wienand433a9b12015-10-07 13:29:31 +1100114 local xtrace
115 xtrace=$(set +o | grep xtrace)
Sean Dague45917cc2014-02-24 16:09:14 -0500116 set +o xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600117
Mahito OGURA98f59aa2015-05-11 18:02:34 +0900118 local default=$1
119 local testval=${!2:-}
120
121 case "$testval" in
122 "1" | [yY]es | "YES" | [tT]rue | "TRUE" ) echo "True" ;;
123 "0" | [nN]o | "NO" | [fF]alse | "FALSE" ) echo "False" ;;
124 * ) echo "$default" ;;
125 esac
126
Sean Dague45917cc2014-02-24 16:09:14 -0500127 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600128}
129
Attila Fazekas1bd79592015-02-24 14:06:56 +0100130function isset {
131 [[ -v "$1" ]]
132}
Dean Troyerdff49a22014-01-30 15:37:40 -0600133
Dean Troyer68162342015-05-13 15:41:03 -0500134
Dean Troyerdff49a22014-01-30 15:37:40 -0600135# Control Functions
136# =================
137
138# Prints backtrace info
139# filename:lineno:function
140# backtrace level
141function backtrace {
142 local level=$1
Ian Wienandada886d2015-10-07 14:06:26 +1100143 local deep
144 deep=$((${#BASH_SOURCE[@]} - 1))
Dean Troyerdff49a22014-01-30 15:37:40 -0600145 echo "[Call Trace]"
146 while [ $level -le $deep ]; do
147 echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
148 deep=$((deep - 1))
149 done
150}
151
152# Prints line number and "message" then exits
153# die $LINENO "message"
Ian Wienandaee18c72014-02-21 15:35:08 +1100154function die {
Dean Troyerdff49a22014-01-30 15:37:40 -0600155 local exitcode=$?
156 set +o xtrace
157 local line=$1; shift
158 if [ $exitcode == 0 ]; then
159 exitcode=1
160 fi
161 backtrace 2
162 err $line "$*"
Dean Troyera25a6f62014-02-24 16:03:41 -0600163 # Give buffers a second to flush
164 sleep 1
Dean Troyerdff49a22014-01-30 15:37:40 -0600165 exit $exitcode
166}
167
168# Checks an environment variable is not set or has length 0 OR if the
169# exit code is non-zero and prints "message" and exits
170# NOTE: env-var is the variable name without a '$'
171# die_if_not_set $LINENO env-var "message"
Ian Wienandaee18c72014-02-21 15:35:08 +1100172function die_if_not_set {
Dean Troyerdff49a22014-01-30 15:37:40 -0600173 local exitcode=$?
Ian Wienand433a9b12015-10-07 13:29:31 +1100174 local xtrace
175 xtrace=$(set +o | grep xtrace)
Dean Troyerdff49a22014-01-30 15:37:40 -0600176 set +o xtrace
177 local line=$1; shift
178 local evar=$1; shift
179 if ! is_set $evar || [ $exitcode != 0 ]; then
180 die $line "$*"
181 fi
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500182 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600183}
184
Sean Dague1de9e332015-10-07 08:46:13 -0400185function deprecated {
186 local text=$1
187 DEPRECATED_TEXT+="\n$text"
188 echo "WARNING: $text"
189}
190
Dean Troyerdff49a22014-01-30 15:37:40 -0600191# Prints line number and "message" in error format
192# err $LINENO "message"
Ian Wienandaee18c72014-02-21 15:35:08 +1100193function err {
Dean Troyerdff49a22014-01-30 15:37:40 -0600194 local exitcode=$?
Ian Wienand433a9b12015-10-07 13:29:31 +1100195 local xtrace
196 xtrace=$(set +o | grep xtrace)
Dean Troyerdff49a22014-01-30 15:37:40 -0600197 set +o xtrace
198 local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
199 echo $msg 1>&2;
Dean Troyerdde41d02014-12-09 17:47:57 -0600200 if [[ -n ${LOGDIR} ]]; then
201 echo $msg >> "${LOGDIR}/error.log"
Dean Troyerdff49a22014-01-30 15:37:40 -0600202 fi
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500203 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600204 return $exitcode
205}
206
207# Checks an environment variable is not set or has length 0 OR if the
208# exit code is non-zero and prints "message"
209# NOTE: env-var is the variable name without a '$'
210# err_if_not_set $LINENO env-var "message"
Ian Wienandaee18c72014-02-21 15:35:08 +1100211function err_if_not_set {
Dean Troyerdff49a22014-01-30 15:37:40 -0600212 local exitcode=$?
Ian Wienand433a9b12015-10-07 13:29:31 +1100213 local xtrace
214 xtrace=$(set +o | grep xtrace)
Dean Troyerdff49a22014-01-30 15:37:40 -0600215 set +o xtrace
216 local line=$1; shift
217 local evar=$1; shift
218 if ! is_set $evar || [ $exitcode != 0 ]; then
219 err $line "$*"
220 fi
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500221 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600222 return $exitcode
223}
224
225# Exit after outputting a message about the distribution not being supported.
226# exit_distro_not_supported [optional-string-telling-what-is-missing]
227function exit_distro_not_supported {
228 if [[ -z "$DISTRO" ]]; then
229 GetDistro
230 fi
231
232 if [ $# -gt 0 ]; then
233 die $LINENO "Support for $DISTRO is incomplete: no support for $@"
234 else
235 die $LINENO "Support for $DISTRO is incomplete."
236 fi
237}
238
239# Test if the named environment variable is set and not zero length
240# is_set env-var
Ian Wienandaee18c72014-02-21 15:35:08 +1100241function is_set {
Dean Troyerdff49a22014-01-30 15:37:40 -0600242 local var=\$"$1"
243 eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
244}
245
246# Prints line number and "message" in warning format
247# warn $LINENO "message"
Ian Wienandaee18c72014-02-21 15:35:08 +1100248function warn {
Dean Troyerdff49a22014-01-30 15:37:40 -0600249 local exitcode=$?
Ian Wienand433a9b12015-10-07 13:29:31 +1100250 local xtrace
251 xtrace=$(set +o | grep xtrace)
Dean Troyerdff49a22014-01-30 15:37:40 -0600252 set +o xtrace
253 local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
Sean Daguee4af9292015-04-28 08:57:57 -0400254 echo $msg
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500255 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -0600256 return $exitcode
257}
258
259
260# Distro Functions
261# ================
262
263# Determine OS Vendor, Release and Update
264# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora
265# Returns results in global variables:
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500266# ``os_VENDOR`` - vendor name: ``Ubuntu``, ``Fedora``, etc
267# ``os_RELEASE`` - major release: ``14.04`` (Ubuntu), ``20`` (Fedora)
268# ``os_UPDATE`` - update: ex. the ``5`` in ``RHEL6.5``
269# ``os_PACKAGE`` - package type: ``deb`` or ``rpm``
270# ``os_CODENAME`` - vendor's codename for release: ``snow leopard``, ``trusty``
Sean Dague53753292014-12-04 19:38:15 -0500271os_VENDOR=""
272os_RELEASE=""
273os_UPDATE=""
274os_PACKAGE=""
275os_CODENAME=""
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500276
Dean Troyerdff49a22014-01-30 15:37:40 -0600277# GetOSVersion
Ian Wienandaee18c72014-02-21 15:35:08 +1100278function GetOSVersion {
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500279
Dean Troyerdff49a22014-01-30 15:37:40 -0600280 # Figure out which vendor we are
281 if [[ -x "`which sw_vers 2>/dev/null`" ]]; then
282 # OS/X
283 os_VENDOR=`sw_vers -productName`
284 os_RELEASE=`sw_vers -productVersion`
285 os_UPDATE=${os_RELEASE##*.}
286 os_RELEASE=${os_RELEASE%.*}
287 os_PACKAGE=""
288 if [[ "$os_RELEASE" =~ "10.7" ]]; then
289 os_CODENAME="lion"
290 elif [[ "$os_RELEASE" =~ "10.6" ]]; then
291 os_CODENAME="snow leopard"
292 elif [[ "$os_RELEASE" =~ "10.5" ]]; then
293 os_CODENAME="leopard"
294 elif [[ "$os_RELEASE" =~ "10.4" ]]; then
295 os_CODENAME="tiger"
296 elif [[ "$os_RELEASE" =~ "10.3" ]]; then
297 os_CODENAME="panther"
298 else
299 os_CODENAME=""
300 fi
301 elif [[ -x $(which lsb_release 2>/dev/null) ]]; then
302 os_VENDOR=$(lsb_release -i -s)
303 os_RELEASE=$(lsb_release -r -s)
304 os_UPDATE=""
305 os_PACKAGE="rpm"
306 if [[ "Debian,Ubuntu,LinuxMint" =~ $os_VENDOR ]]; then
307 os_PACKAGE="deb"
308 elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then
309 lsb_release -d -s | grep -q openSUSE
310 if [[ $? -eq 0 ]]; then
311 os_VENDOR="openSUSE"
312 fi
313 elif [[ $os_VENDOR == "openSUSE project" ]]; then
314 os_VENDOR="openSUSE"
315 elif [[ $os_VENDOR =~ Red.*Hat ]]; then
316 os_VENDOR="Red Hat"
317 fi
318 os_CODENAME=$(lsb_release -c -s)
319 elif [[ -r /etc/redhat-release ]]; then
320 # Red Hat Enterprise Linux Server release 5.5 (Tikanga)
321 # Red Hat Enterprise Linux Server release 7.0 Beta (Maipo)
322 # CentOS release 5.5 (Final)
323 # CentOS Linux release 6.0 (Final)
324 # Fedora release 16 (Verne)
325 # XenServer release 6.2.0-70446c (xenenterprise)
Wiekus Beukesec47bc12015-03-19 08:20:38 -0700326 # Oracle Linux release 7
Maxim Nestratove6f37b92015-06-30 14:54:12 +0300327 # CloudLinux release 7.1
Dean Troyerdff49a22014-01-30 15:37:40 -0600328 os_CODENAME=""
Maxim Nestratove6f37b92015-06-30 14:54:12 +0300329 for r in "Red Hat" CentOS Fedora XenServer CloudLinux; do
Dean Troyerdff49a22014-01-30 15:37:40 -0600330 os_VENDOR=$r
331 if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then
332 ver=`sed -e 's/^.* \([0-9].*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release`
333 os_CODENAME=${ver#*|}
334 os_RELEASE=${ver%|*}
335 os_UPDATE=${os_RELEASE##*.}
336 os_RELEASE=${os_RELEASE%.*}
337 break
338 fi
339 os_VENDOR=""
340 done
Wiekus Beukesec47bc12015-03-19 08:20:38 -0700341 if [ "$os_VENDOR" = "Red Hat" ] && [[ -r /etc/oracle-release ]]; then
342 os_VENDOR=OracleLinux
343 fi
Dean Troyerdff49a22014-01-30 15:37:40 -0600344 os_PACKAGE="rpm"
345 elif [[ -r /etc/SuSE-release ]]; then
346 for r in openSUSE "SUSE Linux"; do
347 if [[ "$r" = "SUSE Linux" ]]; then
348 os_VENDOR="SUSE LINUX"
349 else
350 os_VENDOR=$r
351 fi
352
353 if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then
354 os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'`
355 os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'`
356 os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'`
357 break
358 fi
359 os_VENDOR=""
360 done
361 os_PACKAGE="rpm"
362 # If lsb_release is not installed, we should be able to detect Debian OS
363 elif [[ -f /etc/debian_version ]] && [[ $(cat /proc/version) =~ "Debian" ]]; then
364 os_VENDOR="Debian"
365 os_PACKAGE="deb"
366 os_CODENAME=$(awk '/VERSION=/' /etc/os-release | sed 's/VERSION=//' | sed -r 's/\"|\(|\)//g' | awk '{print $2}')
367 os_RELEASE=$(awk '/VERSION_ID=/' /etc/os-release | sed 's/VERSION_ID=//' | sed 's/\"//g')
368 fi
369 export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
370}
371
372# Translate the OS version values into common nomenclature
373# Sets global ``DISTRO`` from the ``os_*`` values
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500374declare DISTRO
375
Ian Wienandaee18c72014-02-21 15:35:08 +1100376function GetDistro {
Dean Troyerdff49a22014-01-30 15:37:40 -0600377 GetOSVersion
378 if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then
379 # 'Everyone' refers to Ubuntu / Debian releases by the code name adjective
380 DISTRO=$os_CODENAME
381 elif [[ "$os_VENDOR" =~ (Fedora) ]]; then
382 # For Fedora, just use 'f' and the release
383 DISTRO="f$os_RELEASE"
384 elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then
385 DISTRO="opensuse-$os_RELEASE"
386 elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then
387 # For SLE, also use the service pack
388 if [[ -z "$os_UPDATE" ]]; then
389 DISTRO="sle${os_RELEASE}"
390 else
391 DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
392 fi
anju Tiwari6c639c92014-07-15 18:11:54 +0530393 elif [[ "$os_VENDOR" =~ (Red Hat) || \
394 "$os_VENDOR" =~ (CentOS) || \
Wiekus Beukesec47bc12015-03-19 08:20:38 -0700395 "$os_VENDOR" =~ (OracleLinux) ]]; then
Dean Troyerdff49a22014-01-30 15:37:40 -0600396 # Drop the . release as we assume it's compatible
397 DISTRO="rhel${os_RELEASE::1}"
398 elif [[ "$os_VENDOR" =~ (XenServer) ]]; then
399 DISTRO="xs$os_RELEASE"
400 else
401 # Catch-all for now is Vendor + Release + Update
402 DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
403 fi
404 export DISTRO
405}
406
407# Utility function for checking machine architecture
408# is_arch arch-type
409function is_arch {
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500410 [[ "$(uname -m)" == "$1" ]]
Dean Troyerdff49a22014-01-30 15:37:40 -0600411}
412
Wiekus Beukesec47bc12015-03-19 08:20:38 -0700413# Determine if current distribution is an Oracle distribution
414# is_oraclelinux
415function is_oraclelinux {
416 if [[ -z "$os_VENDOR" ]]; then
417 GetOSVersion
418 fi
419
420 [ "$os_VENDOR" = "OracleLinux" ]
421}
422
423
Dean Troyerdff49a22014-01-30 15:37:40 -0600424# Determine if current distribution is a Fedora-based distribution
425# (Fedora, RHEL, CentOS, etc).
426# is_fedora
427function is_fedora {
428 if [[ -z "$os_VENDOR" ]]; then
429 GetOSVersion
430 fi
431
anju Tiwari6c639c92014-07-15 18:11:54 +0530432 [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || \
Maxim Nestratove6f37b92015-06-30 14:54:12 +0300433 [ "$os_VENDOR" = "CentOS" ] || [ "$os_VENDOR" = "OracleLinux" ] || \
434 [ "$os_VENDOR" = "CloudLinux" ]
Dean Troyerdff49a22014-01-30 15:37:40 -0600435}
436
437
438# Determine if current distribution is a SUSE-based distribution
439# (openSUSE, SLE).
440# is_suse
441function is_suse {
442 if [[ -z "$os_VENDOR" ]]; then
443 GetOSVersion
444 fi
445
446 [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ]
447}
448
449
450# Determine if current distribution is an Ubuntu-based distribution
451# It will also detect non-Ubuntu but Debian-based distros
452# is_ubuntu
453function is_ubuntu {
454 if [[ -z "$os_PACKAGE" ]]; then
455 GetOSVersion
456 fi
457 [ "$os_PACKAGE" = "deb" ]
458}
459
460
461# Git Functions
462# =============
463
Dean Troyerabc7b1d2014-02-12 12:09:22 -0600464# Returns openstack release name for a given branch name
465# ``get_release_name_from_branch branch-name``
Ian Wienandaee18c72014-02-21 15:35:08 +1100466function get_release_name_from_branch {
Dean Troyerabc7b1d2014-02-12 12:09:22 -0600467 local branch=$1
Adam Gandelman8f385722014-10-14 15:50:18 -0700468 if [[ $branch =~ "stable/" || $branch =~ "proposed/" ]]; then
Dean Troyerabc7b1d2014-02-12 12:09:22 -0600469 echo ${branch#*/}
470 else
471 echo "master"
472 fi
473}
474
Dean Troyerdff49a22014-01-30 15:37:40 -0600475# git clone only if directory doesn't exist already. Since ``DEST`` might not
476# be owned by the installation user, we create the directory and change the
477# ownership to the proper user.
Dean Troyer50cda692014-07-25 11:57:20 -0500478# Set global ``RECLONE=yes`` to simulate a clone when dest-dir exists
479# Set global ``ERROR_ON_CLONE=True`` to abort execution with an error if the git repo
Dean Troyerdff49a22014-01-30 15:37:40 -0600480# does not exist (default is False, meaning the repo will be cloned).
Sean Dague53753292014-12-04 19:38:15 -0500481# Uses globals ``ERROR_ON_CLONE``, ``OFFLINE``, ``RECLONE``
Dean Troyerdff49a22014-01-30 15:37:40 -0600482# git_clone remote dest-dir branch
483function git_clone {
Dean Troyer50cda692014-07-25 11:57:20 -0500484 local git_remote=$1
485 local git_dest=$2
486 local git_ref=$3
Ian Wienandada886d2015-10-07 14:06:26 +1100487 local orig_dir
488 orig_dir=$(pwd)
Jamie Lennox51f0de52014-10-20 16:32:34 +0200489 local git_clone_flags=""
Dean Troyer50cda692014-07-25 11:57:20 -0500490
Sean Dague53753292014-12-04 19:38:15 -0500491 RECLONE=$(trueorfalse False RECLONE)
Kevin Benton59d52f32015-01-17 11:29:12 -0800492 if [[ "${GIT_DEPTH}" -gt 0 ]]; then
Jamie Lennox51f0de52014-10-20 16:32:34 +0200493 git_clone_flags="$git_clone_flags --depth $GIT_DEPTH"
494 fi
495
Dean Troyerdff49a22014-01-30 15:37:40 -0600496 if [[ "$OFFLINE" = "True" ]]; then
497 echo "Running in offline mode, clones already exist"
498 # print out the results so we know what change was used in the logs
Dean Troyer50cda692014-07-25 11:57:20 -0500499 cd $git_dest
Dean Troyerdff49a22014-01-30 15:37:40 -0600500 git show --oneline | head -1
Sean Dague64bd0162014-03-12 13:04:22 -0400501 cd $orig_dir
Dean Troyerdff49a22014-01-30 15:37:40 -0600502 return
503 fi
504
Dean Troyer50cda692014-07-25 11:57:20 -0500505 if echo $git_ref | egrep -q "^refs"; then
Dean Troyerdff49a22014-01-30 15:37:40 -0600506 # If our branch name is a gerrit style refs/changes/...
Dean Troyer50cda692014-07-25 11:57:20 -0500507 if [[ ! -d $git_dest ]]; then
James E. Blairebe63d82015-09-24 07:43:50 -0700508 if [[ "$ERROR_ON_CLONE" = "True" ]]; then
509 echo "The $git_dest project was not found; if this is a gate job, add"
510 echo "the project to the \$PROJECTS variable in the job definition."
Dean Troyerdff49a22014-01-30 15:37:40 -0600511 die $LINENO "Cloning not allowed in this configuration"
James E. Blairebe63d82015-09-24 07:43:50 -0700512 fi
Jamie Lennox51f0de52014-10-20 16:32:34 +0200513 git_timed clone $git_clone_flags $git_remote $git_dest
Dean Troyerdff49a22014-01-30 15:37:40 -0600514 fi
Dean Troyer50cda692014-07-25 11:57:20 -0500515 cd $git_dest
516 git_timed fetch $git_remote $git_ref && git checkout FETCH_HEAD
Dean Troyerdff49a22014-01-30 15:37:40 -0600517 else
518 # do a full clone only if the directory doesn't exist
Dean Troyer50cda692014-07-25 11:57:20 -0500519 if [[ ! -d $git_dest ]]; then
James E. Blairebe63d82015-09-24 07:43:50 -0700520 if [[ "$ERROR_ON_CLONE" = "True" ]]; then
521 echo "The $git_dest project was not found; if this is a gate job, add"
522 echo "the project to the \$PROJECTS variable in the job definition."
Dean Troyerdff49a22014-01-30 15:37:40 -0600523 die $LINENO "Cloning not allowed in this configuration"
James E. Blairebe63d82015-09-24 07:43:50 -0700524 fi
Jamie Lennox51f0de52014-10-20 16:32:34 +0200525 git_timed clone $git_clone_flags $git_remote $git_dest
Dean Troyer50cda692014-07-25 11:57:20 -0500526 cd $git_dest
Dean Troyerdff49a22014-01-30 15:37:40 -0600527 # This checkout syntax works for both branches and tags
Dean Troyer50cda692014-07-25 11:57:20 -0500528 git checkout $git_ref
Dean Troyerdff49a22014-01-30 15:37:40 -0600529 elif [[ "$RECLONE" = "True" ]]; then
530 # if it does exist then simulate what clone does if asked to RECLONE
Dean Troyer50cda692014-07-25 11:57:20 -0500531 cd $git_dest
Dean Troyerdff49a22014-01-30 15:37:40 -0600532 # set the url to pull from and fetch
Dean Troyer50cda692014-07-25 11:57:20 -0500533 git remote set-url origin $git_remote
Ian Wienandd53ad0b2014-02-20 13:55:13 +1100534 git_timed fetch origin
Dean Troyerdff49a22014-01-30 15:37:40 -0600535 # remove the existing ignored files (like pyc) as they cause breakage
536 # (due to the py files having older timestamps than our pyc, so python
537 # thinks the pyc files are correct using them)
Dean Troyer50cda692014-07-25 11:57:20 -0500538 find $git_dest -name '*.pyc' -delete
Dean Troyerdff49a22014-01-30 15:37:40 -0600539
Dean Troyer50cda692014-07-25 11:57:20 -0500540 # handle git_ref accordingly to type (tag, branch)
541 if [[ -n "`git show-ref refs/tags/$git_ref`" ]]; then
542 git_update_tag $git_ref
543 elif [[ -n "`git show-ref refs/heads/$git_ref`" ]]; then
544 git_update_branch $git_ref
545 elif [[ -n "`git show-ref refs/remotes/origin/$git_ref`" ]]; then
546 git_update_remote_branch $git_ref
Dean Troyerdff49a22014-01-30 15:37:40 -0600547 else
Dean Troyer50cda692014-07-25 11:57:20 -0500548 die $LINENO "$git_ref is neither branch nor tag"
Dean Troyerdff49a22014-01-30 15:37:40 -0600549 fi
550
551 fi
552 fi
553
554 # print out the results so we know what change was used in the logs
Dean Troyer50cda692014-07-25 11:57:20 -0500555 cd $git_dest
Dean Troyerdff49a22014-01-30 15:37:40 -0600556 git show --oneline | head -1
Sean Dague64bd0162014-03-12 13:04:22 -0400557 cd $orig_dir
Dean Troyerdff49a22014-01-30 15:37:40 -0600558}
559
Sean Daguecc524062014-10-01 09:06:43 -0400560# A variation on git clone that lets us specify a project by it's
561# actual name, like oslo.config. This is exceptionally useful in the
562# library installation case
563function git_clone_by_name {
564 local name=$1
565 local repo=${GITREPO[$name]}
566 local dir=${GITDIR[$name]}
567 local branch=${GITBRANCH[$name]}
568 git_clone $repo $dir $branch
569}
570
571
Ian Wienandd53ad0b2014-02-20 13:55:13 +1100572# git can sometimes get itself infinitely stuck with transient network
573# errors or other issues with the remote end. This wraps git in a
574# timeout/retry loop and is intended to watch over non-local git
575# processes that might hang. GIT_TIMEOUT, if set, is passed directly
576# to timeout(1); otherwise the default value of 0 maintains the status
577# quo of waiting forever.
578# usage: git_timed <git-command>
Ian Wienandaee18c72014-02-21 15:35:08 +1100579function git_timed {
Ian Wienandd53ad0b2014-02-20 13:55:13 +1100580 local count=0
581 local timeout=0
582
583 if [[ -n "${GIT_TIMEOUT}" ]]; then
584 timeout=${GIT_TIMEOUT}
585 fi
586
587 until timeout -s SIGINT ${timeout} git "$@"; do
588 # 124 is timeout(1)'s special return code when it reached the
589 # timeout; otherwise assume fatal failure
590 if [[ $? -ne 124 ]]; then
591 die $LINENO "git call failed: [git $@]"
592 fi
593
594 count=$(($count + 1))
Sean Daguee4af9292015-04-28 08:57:57 -0400595 warn $LINENO "timeout ${count} for git call: [git $@]"
Ian Wienandd53ad0b2014-02-20 13:55:13 +1100596 if [ $count -eq 3 ]; then
597 die $LINENO "Maximum of 3 git retries reached"
598 fi
599 sleep 5
600 done
601}
602
Dean Troyerdff49a22014-01-30 15:37:40 -0600603# git update using reference as a branch.
604# git_update_branch ref
Ian Wienandaee18c72014-02-21 15:35:08 +1100605function git_update_branch {
Dean Troyer50cda692014-07-25 11:57:20 -0500606 local git_branch=$1
Dean Troyerdff49a22014-01-30 15:37:40 -0600607
Dean Troyer50cda692014-07-25 11:57:20 -0500608 git checkout -f origin/$git_branch
Dean Troyerdff49a22014-01-30 15:37:40 -0600609 # a local branch might not exist
Dean Troyer50cda692014-07-25 11:57:20 -0500610 git branch -D $git_branch || true
611 git checkout -b $git_branch
Dean Troyerdff49a22014-01-30 15:37:40 -0600612}
613
614# git update using reference as a branch.
615# git_update_remote_branch ref
Ian Wienandaee18c72014-02-21 15:35:08 +1100616function git_update_remote_branch {
Dean Troyer50cda692014-07-25 11:57:20 -0500617 local git_branch=$1
Dean Troyerdff49a22014-01-30 15:37:40 -0600618
Dean Troyer50cda692014-07-25 11:57:20 -0500619 git checkout -b $git_branch -t origin/$git_branch
Dean Troyerdff49a22014-01-30 15:37:40 -0600620}
621
622# git update using reference as a tag. Be careful editing source at that repo
623# as working copy will be in a detached mode
624# git_update_tag ref
Ian Wienandaee18c72014-02-21 15:35:08 +1100625function git_update_tag {
Dean Troyer50cda692014-07-25 11:57:20 -0500626 local git_tag=$1
Dean Troyerdff49a22014-01-30 15:37:40 -0600627
Dean Troyer50cda692014-07-25 11:57:20 -0500628 git tag -d $git_tag
Dean Troyerdff49a22014-01-30 15:37:40 -0600629 # fetching given tag only
Dean Troyer50cda692014-07-25 11:57:20 -0500630 git_timed fetch origin tag $git_tag
631 git checkout -f $git_tag
Dean Troyerdff49a22014-01-30 15:37:40 -0600632}
633
634
635# OpenStack Functions
636# ===================
637
638# Get the default value for HOST_IP
639# get_default_host_ip fixed_range floating_range host_ip_iface host_ip
Ian Wienandaee18c72014-02-21 15:35:08 +1100640function get_default_host_ip {
Dean Troyerdff49a22014-01-30 15:37:40 -0600641 local fixed_range=$1
642 local floating_range=$2
643 local host_ip_iface=$3
644 local host_ip=$4
Brian Haley180f5eb2015-06-16 13:14:31 -0400645 local af=$5
Dean Troyerdff49a22014-01-30 15:37:40 -0600646
Dean Troyerdff49a22014-01-30 15:37:40 -0600647 # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable
648 if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then
649 host_ip=""
Andreas Scheuringa3430272015-03-09 16:55:32 +0100650 # Find the interface used for the default route
Brian Haley180f5eb2015-06-16 13:14:31 -0400651 host_ip_iface=${host_ip_iface:-$(ip -f $af route | awk '/default/ {print $5}' | head -1)}
Ian Wienandada886d2015-10-07 14:06:26 +1100652 local host_ips
653 host_ips=$(LC_ALL=C ip -f $af addr show ${host_ip_iface} | sed /temporary/d |awk /$af'/ {split($2,parts,"/"); print parts[1]}')
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500654 local ip
655 for ip in $host_ips; do
Dean Troyerdff49a22014-01-30 15:37:40 -0600656 # Attempt to filter out IP addresses that are part of the fixed and
657 # floating range. Note that this method only works if the ``netaddr``
658 # python library is installed. If it is not installed, an error
659 # will be printed and the first IP from the interface will be used.
660 # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct
661 # address.
Brian Haley180f5eb2015-06-16 13:14:31 -0400662 if [[ "$af" == "inet6" ]]; then
663 host_ip=$ip
664 break;
665 fi
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500666 if ! (address_in_net $ip $fixed_range || address_in_net $ip $floating_range); then
667 host_ip=$ip
Dean Troyerdff49a22014-01-30 15:37:40 -0600668 break;
669 fi
670 done
671 fi
672 echo $host_ip
673}
674
Attila Fazekasf71b5002014-05-28 09:52:22 +0200675# Generates hex string from ``size`` byte of pseudo random data
676# generate_hex_string size
677function generate_hex_string {
678 local size=$1
679 hexdump -n "$size" -v -e '/1 "%02x"' /dev/urandom
680}
681
Dean Troyerdff49a22014-01-30 15:37:40 -0600682# Grab a numbered field from python prettytable output
683# Fields are numbered starting with 1
684# Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
685# get_field field-number
Ian Wienandaee18c72014-02-21 15:35:08 +1100686function get_field {
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500687 local data field
Dean Troyerdff49a22014-01-30 15:37:40 -0600688 while read data; do
689 if [ "$1" -lt 0 ]; then
690 field="(\$(NF$1))"
691 else
692 field="\$$(($1 + 1))"
693 fi
694 echo "$data" | awk -F'[ \t]*\\|[ \t]*' "{print $field}"
695 done
696}
697
yuntongjinf26deea2015-02-28 10:50:34 +0800698# install default policy
699# copy over a default policy.json and policy.d for projects
700function install_default_policy {
701 local project=$1
Ian Wienandada886d2015-10-07 14:06:26 +1100702 local project_uc
703 project_uc=$(echo $1|tr a-z A-Z)
yuntongjinf26deea2015-02-28 10:50:34 +0800704 local conf_dir="${project_uc}_CONF_DIR"
705 # eval conf dir to get the variable
706 conf_dir="${!conf_dir}"
707 local project_dir="${project_uc}_DIR"
708 # eval project dir to get the variable
709 project_dir="${!project_dir}"
710 local sample_conf_dir="${project_dir}/etc/${project}"
711 local sample_policy_dir="${project_dir}/etc/${project}/policy.d"
712
713 # first copy any policy.json
714 cp -p $sample_conf_dir/policy.json $conf_dir
715 # then optionally copy over policy.d
716 if [[ -d $sample_policy_dir ]]; then
717 cp -r $sample_policy_dir $conf_dir/policy.d
718 fi
719}
720
Dean Troyerdff49a22014-01-30 15:37:40 -0600721# Add a policy to a policy.json file
722# Do nothing if the policy already exists
723# ``policy_add policy_file policy_name policy_permissions``
Ian Wienandaee18c72014-02-21 15:35:08 +1100724function policy_add {
Dean Troyerdff49a22014-01-30 15:37:40 -0600725 local policy_file=$1
726 local policy_name=$2
727 local policy_perm=$3
728
729 if grep -q ${policy_name} ${policy_file}; then
730 echo "Policy ${policy_name} already exists in ${policy_file}"
731 return
732 fi
733
734 # Add a terminating comma to policy lines without one
735 # Remove the closing '}' and all lines following to the end-of-file
Ian Wienandada886d2015-10-07 14:06:26 +1100736 local tmpfile
737 tmpfile=$(mktemp)
Dean Troyerdff49a22014-01-30 15:37:40 -0600738 uniq ${policy_file} | sed -e '
739 s/]$/],/
740 /^[}]/,$d
741 ' > ${tmpfile}
742
743 # Append policy and closing brace
744 echo " \"${policy_name}\": ${policy_perm}" >>${tmpfile}
745 echo "}" >>${tmpfile}
746
747 mv ${tmpfile} ${policy_file}
748}
749
Alistair Coles24779f62014-10-15 18:57:59 +0100750# Gets or creates a domain
751# Usage: get_or_create_domain <name> <description>
752function get_or_create_domain {
Ian Wienand11d276c2015-07-02 09:34:34 +1000753 local domain_id
Alistair Coles24779f62014-10-15 18:57:59 +0100754 # Gets domain id
Ian Wienand11d276c2015-07-02 09:34:34 +1000755 domain_id=$(
Alistair Coles24779f62014-10-15 18:57:59 +0100756 # Gets domain id
Steve Martinelli050a0d52015-09-06 22:03:54 +0000757 openstack domain show $1 \
Alistair Coles24779f62014-10-15 18:57:59 +0100758 -f value -c id 2>/dev/null ||
759 # Creates new domain
Steve Martinelli050a0d52015-09-06 22:03:54 +0000760 openstack domain create $1 \
Alistair Coles24779f62014-10-15 18:57:59 +0100761 --description "$2" \
762 -f value -c id
763 )
764 echo $domain_id
765}
766
Steve Martinellib74e01c2014-12-18 01:35:35 -0500767# Gets or creates group
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000768# Usage: get_or_create_group <groupname> <domain> [<description>]
Steve Martinellib74e01c2014-12-18 01:35:35 -0500769function get_or_create_group {
Steve Martinellib74e01c2014-12-18 01:35:35 -0500770 local desc="${3:-}"
Ian Wienand11d276c2015-07-02 09:34:34 +1000771 local group_id
Steve Martinellib74e01c2014-12-18 01:35:35 -0500772 # Gets group id
Ian Wienand11d276c2015-07-02 09:34:34 +1000773 group_id=$(
Steve Martinellib74e01c2014-12-18 01:35:35 -0500774 # Creates new group with --or-show
Steve Martinelli050a0d52015-09-06 22:03:54 +0000775 openstack group create $1 \
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000776 --domain $2 --description "$desc" --or-show \
Steve Martinellib74e01c2014-12-18 01:35:35 -0500777 -f value -c id
778 )
779 echo $group_id
780}
781
Bartosz Górski0abde392014-02-28 14:15:19 +0100782# Gets or creates user
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000783# Usage: get_or_create_user <username> <password> <domain> [<email>]
Bartosz Górski0abde392014-02-28 14:15:19 +0100784function get_or_create_user {
Ian Wienand11d276c2015-07-02 09:34:34 +1000785 local user_id
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000786 if [[ ! -z "$4" ]]; then
787 local email="--email=$4"
Gael Chamoulaud6dd8a8b2014-07-22 01:12:12 +0200788 else
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500789 local email=""
Gael Chamoulaud6dd8a8b2014-07-22 01:12:12 +0200790 fi
Bartosz Górski0abde392014-02-28 14:15:19 +0100791 # Gets user id
Ian Wienand11d276c2015-07-02 09:34:34 +1000792 user_id=$(
Steve Martinelli245daa22014-11-14 02:17:22 -0500793 # Creates new user with --or-show
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000794 openstack user create \
Bartosz Górski0abde392014-02-28 14:15:19 +0100795 $1 \
796 --password "$2" \
Jamie Lennox9d7e7762015-05-29 01:08:53 +0000797 --domain=$3 \
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500798 $email \
Steve Martinelli245daa22014-11-14 02:17:22 -0500799 --or-show \
Bartosz Górski0abde392014-02-28 14:15:19 +0100800 -f value -c id
801 )
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500802 echo $user_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100803}
804
805# Gets or creates project
Jamie Lennoxb632c9e2015-05-28 23:36:15 +0000806# Usage: get_or_create_project <name> <domain>
Bartosz Górski0abde392014-02-28 14:15:19 +0100807function get_or_create_project {
Ian Wienand11d276c2015-07-02 09:34:34 +1000808 local project_id
809 project_id=$(
Steve Martinelli245daa22014-11-14 02:17:22 -0500810 # Creates new project with --or-show
Steve Martinelli050a0d52015-09-06 22:03:54 +0000811 openstack project create $1 \
Jamie Lennoxb632c9e2015-05-28 23:36:15 +0000812 --domain=$2 \
813 --or-show -f value -c id
Bartosz Górski0abde392014-02-28 14:15:19 +0100814 )
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500815 echo $project_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100816}
817
818# Gets or creates role
819# Usage: get_or_create_role <name>
820function get_or_create_role {
Ian Wienand11d276c2015-07-02 09:34:34 +1000821 local role_id
822 role_id=$(
Steve Martinelli245daa22014-11-14 02:17:22 -0500823 # Creates role with --or-show
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000824 openstack role create $1 \
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000825 --or-show -f value -c id
Bartosz Górski0abde392014-02-28 14:15:19 +0100826 )
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500827 echo $role_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100828}
829
Jamie Lennox9b215db2015-02-10 18:19:57 +1100830# Gets or adds user role to project
831# Usage: get_or_add_user_project_role <role> <user> <project>
832function get_or_add_user_project_role {
Ian Wienand11d276c2015-07-02 09:34:34 +1000833 local user_role_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100834 # Gets user role id
Ian Wienand11d276c2015-07-02 09:34:34 +1000835 user_role_id=$(openstack role list \
Steve Martinelli5541a612015-01-19 15:58:49 -0500836 --user $2 \
Bartosz Górski0abde392014-02-28 14:15:19 +0100837 --column "ID" \
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000838 --project $3 \
Bartosz Górski0abde392014-02-28 14:15:19 +0100839 --column "Name" \
840 | grep " $1 " | get_field 1)
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500841 if [[ -z "$user_role_id" ]]; then
Roxana Gherle50821be2015-09-22 10:52:46 -0700842 # Adds role to user and get it
843 openstack role add $1 \
Bartosz Górski0abde392014-02-28 14:15:19 +0100844 --user $2 \
Steve Martinelli050a0d52015-09-06 22:03:54 +0000845 --project $3
Roxana Gherle50821be2015-09-22 10:52:46 -0700846 user_role_id=$(openstack role list \
847 --user $2 \
Roxana Gherle50821be2015-09-22 10:52:46 -0700848 --column "ID" \
849 --project $3 \
850 --column "Name" \
851 | grep " $1 " | get_field 1)
Bartosz Górski0abde392014-02-28 14:15:19 +0100852 fi
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500853 echo $user_role_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100854}
855
Steve Martinelli4599fd12015-03-12 21:30:58 -0400856# Gets or adds group role to project
857# Usage: get_or_add_group_project_role <role> <group> <project>
858function get_or_add_group_project_role {
Ian Wienand11d276c2015-07-02 09:34:34 +1000859 local group_role_id
Steve Martinelli4599fd12015-03-12 21:30:58 -0400860 # Gets group role id
Ian Wienand11d276c2015-07-02 09:34:34 +1000861 group_role_id=$(openstack role list \
Steve Martinelli4599fd12015-03-12 21:30:58 -0400862 --group $2 \
863 --project $3 \
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000864 -c "ID" -f value)
Steve Martinelli4599fd12015-03-12 21:30:58 -0400865 if [[ -z "$group_role_id" ]]; then
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000866 # Adds role to group and get it
867 openstack role add $1 \
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000868 --group $2 \
869 --project $3
870 group_role_id=$(openstack role list \
Steve Martinelli4599fd12015-03-12 21:30:58 -0400871 --group $2 \
872 --project $3 \
Jamie Lennox72ce6ac2015-07-02 09:19:01 +1000873 -c "ID" -f value)
Steve Martinelli4599fd12015-03-12 21:30:58 -0400874 fi
875 echo $group_role_id
876}
877
Bartosz Górski0abde392014-02-28 14:15:19 +0100878# Gets or creates service
879# Usage: get_or_create_service <name> <type> <description>
880function get_or_create_service {
Ian Wienand11d276c2015-07-02 09:34:34 +1000881 local service_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100882 # Gets service id
Ian Wienand11d276c2015-07-02 09:34:34 +1000883 service_id=$(
Bartosz Górski0abde392014-02-28 14:15:19 +0100884 # Gets service id
Jamie Lennoxaedb8b92015-07-02 17:39:07 +1000885 openstack service show $2 -f value -c id 2>/dev/null ||
Bartosz Górski0abde392014-02-28 14:15:19 +0100886 # Creates new service if not exists
887 openstack service create \
Steve Martinelli789af5c2015-01-19 16:11:44 -0500888 $2 \
889 --name $1 \
Bartosz Górski0abde392014-02-28 14:15:19 +0100890 --description="$3" \
891 -f value -c id
892 )
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500893 echo $service_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100894}
895
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000896# Create an endpoint with a specific interface
897# Usage: _get_or_create_endpoint_with_interface <service> <interface> <url> <region>
898function _get_or_create_endpoint_with_interface {
Ian Wienand11d276c2015-07-02 09:34:34 +1000899 local endpoint_id
Daniel Gonzalez1991e752015-08-11 19:34:22 +0200900 # TODO(dgonzalez): The check of the region name, as done in the grep
901 # statement below, exists only because keystone does currently
902 # not allow filtering the region name when listing endpoints. If keystone
903 # gets support for this, the check for the region name can be removed.
904 # Related bug in keystone: https://bugs.launchpad.net/keystone/+bug/1482772
Ian Wienand11d276c2015-07-02 09:34:34 +1000905 endpoint_id=$(openstack endpoint list \
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000906 --service $1 \
907 --interface $2 \
908 --region $4 \
Daniel Gonzalez1991e752015-08-11 19:34:22 +0200909 -c ID -c Region -f value | grep $4 | cut -f 1 -d " ")
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500910 if [[ -z "$endpoint_id" ]]; then
Bartosz Górski0abde392014-02-28 14:15:19 +0100911 # Creates new endpoint
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500912 endpoint_id=$(openstack endpoint create \
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000913 $1 $2 $3 --region $4 -f value -c id)
Bartosz Górski0abde392014-02-28 14:15:19 +0100914 fi
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000915
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500916 echo $endpoint_id
Bartosz Górski0abde392014-02-28 14:15:19 +0100917}
Dean Troyerdff49a22014-01-30 15:37:40 -0600918
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000919# Gets or creates endpoint
920# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
921function get_or_create_endpoint {
922 # NOTE(jamielennnox): when converting to v3 endpoint creation we go from
923 # creating one endpoint with multiple urls to multiple endpoints each with
924 # a different interface. To maintain the existing function interface we
925 # create 3 endpoints and return the id of the public one. In reality
926 # returning the public id will not make a lot of difference as there are no
927 # scenarios currently that use the returned id. Ideally this behaviour
928 # should be pushed out to the service setups and let them create the
929 # endpoints they need.
Ian Wienandada886d2015-10-07 14:06:26 +1100930 local public_id
931 public_id=$(_get_or_create_endpoint_with_interface $1 public $3 $2)
Jamie Lennoxb17ad752015-05-29 06:04:47 +0000932 _get_or_create_endpoint_with_interface $1 admin $4 $2
933 _get_or_create_endpoint_with_interface $1 internal $5 $2
934
935 # return the public id to indicate success, and this is the endpoint most likely wanted
936 echo $public_id
937}
938
939# Get a URL from the identity service
940# Usage: get_endpoint_url <service> <interface>
941function get_endpoint_url {
942 echo $(openstack endpoint list \
943 --service $1 --interface $2 \
944 --os-url $KEYSTONE_SERVICE_URI_V3 \
945 --os-identity-api-version=3 \
946 -c URL -f value)
947}
948
Dean Troyerd5dfa4c2014-07-25 11:13:11 -0500949
Dean Troyerdff49a22014-01-30 15:37:40 -0600950# Package Functions
951# =================
952
953# _get_package_dir
Ian Wienandaee18c72014-02-21 15:35:08 +1100954function _get_package_dir {
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800955 local base_dir=$1
Dean Troyerdff49a22014-01-30 15:37:40 -0600956 local pkg_dir
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800957
958 if [[ -z "$base_dir" ]]; then
959 base_dir=$FILES
960 fi
Dean Troyerdff49a22014-01-30 15:37:40 -0600961 if is_ubuntu; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800962 pkg_dir=$base_dir/debs
Dean Troyerdff49a22014-01-30 15:37:40 -0600963 elif is_fedora; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800964 pkg_dir=$base_dir/rpms
Dean Troyerdff49a22014-01-30 15:37:40 -0600965 elif is_suse; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800966 pkg_dir=$base_dir/rpms-suse
Dean Troyerdff49a22014-01-30 15:37:40 -0600967 else
968 exit_distro_not_supported "list of packages"
969 fi
970 echo "$pkg_dir"
971}
972
973# Wrapper for ``apt-get`` to set cache and proxy environment variables
974# Uses globals ``OFFLINE``, ``*_proxy``
975# apt_get operation package [package ...]
Ian Wienandaee18c72014-02-21 15:35:08 +1100976function apt_get {
Ian Wienand433a9b12015-10-07 13:29:31 +1100977 local xtrace
978 xtrace=$(set +o | grep xtrace)
Sean Dague45917cc2014-02-24 16:09:14 -0500979 set +o xtrace
980
Dean Troyerdff49a22014-01-30 15:37:40 -0600981 [[ "$OFFLINE" = "True" || -z "$@" ]] && return
982 local sudo="sudo"
983 [[ "$(id -u)" = "0" ]] && sudo="env"
Sean Dague45917cc2014-02-24 16:09:14 -0500984
Sean Dague95c33d52015-10-07 11:05:59 -0400985 # time all the apt operations
986 time_start "apt-get"
987
Sean Dague45917cc2014-02-24 16:09:14 -0500988 $xtrace
Sean Dague53753292014-12-04 19:38:15 -0500989
Dean Troyerdff49a22014-01-30 15:37:40 -0600990 $sudo DEBIAN_FRONTEND=noninteractive \
Sean Dague53753292014-12-04 19:38:15 -0500991 http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} \
992 no_proxy=${no_proxy:-} \
Dean Troyerdff49a22014-01-30 15:37:40 -0600993 apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
Sean Dague95c33d52015-10-07 11:05:59 -0400994
995 # stop the clock
996 time_stop "apt-get"
Dean Troyerdff49a22014-01-30 15:37:40 -0600997}
998
Adam Gandelman7ca90cd2015-03-04 17:25:07 -0800999function _parse_package_files {
1000 local files_to_parse=$@
Dean Troyerdff49a22014-01-30 15:37:40 -06001001
Dean Troyerdff49a22014-01-30 15:37:40 -06001002 if [[ -z "$DISTRO" ]]; then
1003 GetDistro
1004 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001005
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001006 for fname in ${files_to_parse}; do
Dean Troyerdff49a22014-01-30 15:37:40 -06001007 local OIFS line package distros distro
1008 [[ -e $fname ]] || continue
1009
1010 OIFS=$IFS
1011 IFS=$'\n'
1012 for line in $(<${fname}); do
1013 if [[ $line =~ "NOPRIME" ]]; then
1014 continue
1015 fi
1016
1017 # Assume we want this package
1018 package=${line%#*}
1019 inst_pkg=1
1020
1021 # Look for # dist:xxx in comment
1022 if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then
1023 # We are using BASH regexp matching feature.
1024 package=${BASH_REMATCH[1]}
1025 distros=${BASH_REMATCH[2]}
1026 # In bash ${VAR,,} will lowecase VAR
1027 # Look for a match in the distro list
1028 if [[ ! ${distros,,} =~ ${DISTRO,,} ]]; then
1029 # If no match then skip this package
1030 inst_pkg=0
1031 fi
1032 fi
1033
Dean Troyerdff49a22014-01-30 15:37:40 -06001034 if [[ $inst_pkg = 1 ]]; then
1035 echo $package
1036 fi
1037 done
1038 IFS=$OIFS
1039 done
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001040}
1041
1042# get_packages() collects a list of package names of any type from the
1043# prerequisite files in ``files/{debs|rpms}``. The list is intended
1044# to be passed to a package installer such as apt or yum.
1045#
1046# Only packages required for the services in 1st argument will be
1047# included. Two bits of metadata are recognized in the prerequisite files:
1048#
1049# - ``# NOPRIME`` defers installation to be performed later in `stack.sh`
1050# - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection
1051# of the package to the distros listed. The distro names are case insensitive.
1052function get_packages {
Ian Wienand433a9b12015-10-07 13:29:31 +11001053 local xtrace
1054 xtrace=$(set +o | grep xtrace)
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001055 set +o xtrace
1056 local services=$@
Ian Wienandada886d2015-10-07 14:06:26 +11001057 local package_dir
1058 package_dir=$(_get_package_dir)
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001059 local file_to_parse=""
1060 local service=""
1061
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001062 if [[ -z "$package_dir" ]]; then
1063 echo "No package directory supplied"
1064 return 1
1065 fi
1066 for service in ${services//,/ }; do
1067 # Allow individual services to specify dependencies
1068 if [[ -e ${package_dir}/${service} ]]; then
1069 file_to_parse="${file_to_parse} ${package_dir}/${service}"
1070 fi
1071 # NOTE(sdague) n-api needs glance for now because that's where
1072 # glance client is
1073 if [[ $service == n-api ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001074 if [[ ! $file_to_parse =~ $package_dir/nova ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001075 file_to_parse="${file_to_parse} ${package_dir}/nova"
1076 fi
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001077 if [[ ! $file_to_parse =~ $package_dir/glance ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001078 file_to_parse="${file_to_parse} ${package_dir}/glance"
1079 fi
1080 elif [[ $service == c-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001081 if [[ ! $file_to_parse =~ $package_dir/cinder ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001082 file_to_parse="${file_to_parse} ${package_dir}/cinder"
1083 fi
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001084 elif [[ $service == s-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001085 if [[ ! $file_to_parse =~ $package_dir/swift ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001086 file_to_parse="${file_to_parse} ${package_dir}/swift"
1087 fi
1088 elif [[ $service == n-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001089 if [[ ! $file_to_parse =~ $package_dir/nova ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001090 file_to_parse="${file_to_parse} ${package_dir}/nova"
1091 fi
1092 elif [[ $service == g-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001093 if [[ ! $file_to_parse =~ $package_dir/glance ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001094 file_to_parse="${file_to_parse} ${package_dir}/glance"
1095 fi
1096 elif [[ $service == key* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001097 if [[ ! $file_to_parse =~ $package_dir/keystone ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001098 file_to_parse="${file_to_parse} ${package_dir}/keystone"
1099 fi
1100 elif [[ $service == q-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001101 if [[ ! $file_to_parse =~ $package_dir/neutron ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001102 file_to_parse="${file_to_parse} ${package_dir}/neutron"
1103 fi
1104 elif [[ $service == ir-* ]]; then
Ryan Hsu6f3f3102015-03-19 16:26:45 -07001105 if [[ ! $file_to_parse =~ $package_dir/ironic ]]; then
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001106 file_to_parse="${file_to_parse} ${package_dir}/ironic"
1107 fi
1108 fi
1109 done
1110 echo "$(_parse_package_files $file_to_parse)"
1111 $xtrace
1112}
1113
1114# get_plugin_packages() collects a list of package names of any type from a
1115# plugin's prerequisite files in ``$PLUGIN/devstack/files/{debs|rpms}``. The
1116# list is intended to be passed to a package installer such as apt or yum.
1117#
1118# Only packages required for enabled and collected plugins will included.
1119#
Dean Troyerdc97cb72015-03-28 08:20:50 -05001120# The same metadata used in the main DevStack prerequisite files may be used
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001121# in these prerequisite files, see get_packages() for more info.
1122function get_plugin_packages {
Ian Wienand433a9b12015-10-07 13:29:31 +11001123 local xtrace
1124 xtrace=$(set +o | grep xtrace)
Adam Gandelman7ca90cd2015-03-04 17:25:07 -08001125 set +o xtrace
1126 local files_to_parse=""
1127 local package_dir=""
1128 for plugin in ${DEVSTACK_PLUGINS//,/ }; do
1129 local package_dir="$(_get_package_dir ${GITDIR[$plugin]}/devstack/files)"
1130 files_to_parse+="$package_dir/$plugin"
1131 done
1132 echo "$(_parse_package_files $files_to_parse)"
Sean Dague45917cc2014-02-24 16:09:14 -05001133 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06001134}
1135
1136# Distro-agnostic package installer
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001137# Uses globals ``NO_UPDATE_REPOS``, ``REPOS_UPDATED``, ``RETRY_UPDATE``
Dean Troyerdff49a22014-01-30 15:37:40 -06001138# install_package package [package ...]
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001139function update_package_repo {
Sean Dague53753292014-12-04 19:38:15 -05001140 NO_UPDATE_REPOS=${NO_UPDATE_REPOS:-False}
1141 REPOS_UPDATED=${REPOS_UPDATED:-False}
1142 RETRY_UPDATE=${RETRY_UPDATE:-False}
1143
Paul Linchpiner9e179742014-07-13 22:23:00 -07001144 if [[ "$NO_UPDATE_REPOS" = "True" ]]; then
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001145 return 0
1146 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001147
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001148 if is_ubuntu; then
Ian Wienand433a9b12015-10-07 13:29:31 +11001149 local xtrace
Ian Wienand8043bfa2015-10-14 14:53:18 +11001150 xtrace=$(set +o | grep xtrace)
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001151 set +o xtrace
1152 if [[ "$REPOS_UPDATED" != "True" || "$RETRY_UPDATE" = "True" ]]; then
1153 # if there are transient errors pulling the updates, that's fine.
1154 # It may be secondary repositories that we don't really care about.
1155 apt_get update || /bin/true
1156 REPOS_UPDATED=True
1157 fi
Sean Dague45917cc2014-02-24 16:09:14 -05001158 $xtrace
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001159 fi
1160}
1161
1162function real_install_package {
1163 if is_ubuntu; then
Dean Troyerdff49a22014-01-30 15:37:40 -06001164 apt_get install "$@"
1165 elif is_fedora; then
1166 yum_install "$@"
1167 elif is_suse; then
1168 zypper_install "$@"
1169 else
1170 exit_distro_not_supported "installing packages"
1171 fi
1172}
1173
Monty Taylor5cc6d2c2014-06-06 08:45:16 -04001174# Distro-agnostic package installer
1175# install_package package [package ...]
1176function install_package {
1177 update_package_repo
1178 real_install_package $@ || RETRY_UPDATE=True update_package_repo && real_install_package $@
1179}
1180
Dean Troyerdff49a22014-01-30 15:37:40 -06001181# Distro-agnostic function to tell if a package is installed
1182# is_package_installed package [package ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001183function is_package_installed {
Dean Troyerdff49a22014-01-30 15:37:40 -06001184 if [[ -z "$@" ]]; then
1185 return 1
1186 fi
1187
1188 if [[ -z "$os_PACKAGE" ]]; then
1189 GetOSVersion
1190 fi
1191
1192 if [[ "$os_PACKAGE" = "deb" ]]; then
1193 dpkg -s "$@" > /dev/null 2> /dev/null
1194 elif [[ "$os_PACKAGE" = "rpm" ]]; then
1195 rpm --quiet -q "$@"
1196 else
1197 exit_distro_not_supported "finding if a package is installed"
1198 fi
1199}
1200
1201# Distro-agnostic package uninstaller
1202# uninstall_package package [package ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001203function uninstall_package {
Dean Troyerdff49a22014-01-30 15:37:40 -06001204 if is_ubuntu; then
1205 apt_get purge "$@"
1206 elif is_fedora; then
Ian Wienand36298ee2015-02-04 10:29:31 +11001207 sudo ${YUM:-yum} remove -y "$@" ||:
Dean Troyerdff49a22014-01-30 15:37:40 -06001208 elif is_suse; then
1209 sudo zypper rm "$@"
1210 else
1211 exit_distro_not_supported "uninstalling packages"
1212 fi
1213}
1214
1215# Wrapper for ``yum`` to set proxy environment variables
Daniel P. Berrange63d25d92014-12-09 15:21:22 +00001216# Uses globals ``OFFLINE``, ``*_proxy``, ``YUM``
Dean Troyerdff49a22014-01-30 15:37:40 -06001217# yum_install package [package ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001218function yum_install {
Dean Troyerdff49a22014-01-30 15:37:40 -06001219 [[ "$OFFLINE" = "True" ]] && return
1220 local sudo="sudo"
1221 [[ "$(id -u)" = "0" ]] && sudo="env"
Ian Wienandb27f16d2014-02-28 14:29:02 +11001222
1223 # The manual check for missing packages is because yum -y assumes
1224 # missing packages are OK. See
1225 # https://bugzilla.redhat.com/show_bug.cgi?id=965567
Ian Wienandfdf00f22015-03-13 11:50:02 +11001226 $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}" \
1227 no_proxy="${no_proxy:-}" \
Ian Wienand36298ee2015-02-04 10:29:31 +11001228 ${YUM:-yum} install -y "$@" 2>&1 | \
Ian Wienandb27f16d2014-02-28 14:29:02 +11001229 awk '
1230 BEGIN { fail=0 }
1231 /No package/ { fail=1 }
1232 { print }
1233 END { exit fail }' || \
1234 die $LINENO "Missing packages detected"
1235
1236 # also ensure we catch a yum failure
1237 if [[ ${PIPESTATUS[0]} != 0 ]]; then
Ian Wienand36298ee2015-02-04 10:29:31 +11001238 die $LINENO "${YUM:-yum} install failure"
Ian Wienandb27f16d2014-02-28 14:29:02 +11001239 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001240}
1241
1242# zypper wrapper to set arguments correctly
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001243# Uses globals ``OFFLINE``, ``*_proxy``
Dean Troyerdff49a22014-01-30 15:37:40 -06001244# zypper_install package [package ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001245function zypper_install {
Dean Troyerdff49a22014-01-30 15:37:40 -06001246 [[ "$OFFLINE" = "True" ]] && return
1247 local sudo="sudo"
1248 [[ "$(id -u)" = "0" ]] && sudo="env"
Ian Wienandfdf00f22015-03-13 11:50:02 +11001249 $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}" \
1250 no_proxy="${no_proxy:-}" \
Dean Troyerdff49a22014-01-30 15:37:40 -06001251 zypper --non-interactive install --auto-agree-with-licenses "$@"
1252}
1253
1254
1255# Process Functions
1256# =================
1257
1258# _run_process() is designed to be backgrounded by run_process() to simulate a
1259# fork. It includes the dirty work of closing extra filehandles and preparing log
1260# files to produce the same logs as screen_it(). The log filename is derived
Dean Troyerdde41d02014-12-09 17:47:57 -06001261# from the service name.
1262# Uses globals ``CURRENT_LOG_TIME``, ``LOGDIR``, ``SCREEN_LOGDIR``, ``SCREEN_NAME``, ``SERVICE_DIR``
Chris Dent2f27a0e2014-09-09 13:46:02 +01001263# If an optional group is provided sg will be used to set the group of
1264# the command.
1265# _run_process service "command-line" [group]
Ian Wienandaee18c72014-02-21 15:35:08 +11001266function _run_process {
Sean Dague6e137ab2015-04-29 08:22:24 -04001267 # disable tracing through the exec redirects, it's just confusing in the logs.
1268 xtrace=$(set +o | grep xtrace)
1269 set +o xtrace
1270
Dean Troyerdff49a22014-01-30 15:37:40 -06001271 local service=$1
1272 local command="$2"
Chris Dent2f27a0e2014-09-09 13:46:02 +01001273 local group=$3
Dean Troyerdff49a22014-01-30 15:37:40 -06001274
1275 # Undo logging redirections and close the extra descriptors
1276 exec 1>&3
1277 exec 2>&3
1278 exec 3>&-
1279 exec 6>&-
1280
Dean Troyerdde41d02014-12-09 17:47:57 -06001281 local real_logfile="${LOGDIR}/${service}.log.${CURRENT_LOG_TIME}"
1282 if [[ -n ${LOGDIR} ]]; then
1283 exec 1>&"$real_logfile" 2>&1
1284 ln -sf "$real_logfile" ${LOGDIR}/${service}.log
1285 if [[ -n ${SCREEN_LOGDIR} ]]; then
1286 # Drop the backward-compat symlink
1287 ln -sf "$real_logfile" ${SCREEN_LOGDIR}/screen-${service}.log
1288 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001289
1290 # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs.
1291 export PYTHONUNBUFFERED=1
1292 fi
1293
Sean Dague6e137ab2015-04-29 08:22:24 -04001294 # reenable xtrace before we do *real* work
1295 $xtrace
1296
Dean Troyer3159a822014-08-27 14:13:58 -05001297 # Run under ``setsid`` to force the process to become a session and group leader.
1298 # The pid saved can be used with pkill -g to get the entire process group.
Chris Dent2f27a0e2014-09-09 13:46:02 +01001299 if [[ -n "$group" ]]; then
1300 setsid sg $group "$command" & echo $! >$SERVICE_DIR/$SCREEN_NAME/$service.pid
1301 else
1302 setsid $command & echo $! >$SERVICE_DIR/$SCREEN_NAME/$service.pid
1303 fi
Dean Troyer3159a822014-08-27 14:13:58 -05001304
1305 # Just silently exit this process
1306 exit 0
Dean Troyerdff49a22014-01-30 15:37:40 -06001307}
1308
1309# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``.
1310# This is used for ``service_check`` when all the ``screen_it`` are called finished
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001311# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``
Dean Troyerdff49a22014-01-30 15:37:40 -06001312# init_service_check
Ian Wienandaee18c72014-02-21 15:35:08 +11001313function init_service_check {
Dean Troyerdff49a22014-01-30 15:37:40 -06001314 SCREEN_NAME=${SCREEN_NAME:-stack}
1315 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1316
1317 if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
1318 mkdir -p "$SERVICE_DIR/$SCREEN_NAME"
1319 fi
1320
1321 rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure
1322}
1323
1324# Find out if a process exists by partial name.
1325# is_running name
Ian Wienandaee18c72014-02-21 15:35:08 +11001326function is_running {
Dean Troyerdff49a22014-01-30 15:37:40 -06001327 local name=$1
1328 ps auxw | grep -v grep | grep ${name} > /dev/null
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001329 local exitcode=$?
Dean Troyerdff49a22014-01-30 15:37:40 -06001330 # some times I really hate bash reverse binary logic
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001331 return $exitcode
Dean Troyerdff49a22014-01-30 15:37:40 -06001332}
1333
Dean Troyer3159a822014-08-27 14:13:58 -05001334# Run a single service under screen or directly
1335# If the command includes shell metachatacters (;<>*) it must be run using a shell
Chris Dent2f27a0e2014-09-09 13:46:02 +01001336# If an optional group is provided sg will be used to run the
1337# command as that group.
1338# run_process service "command-line" [group]
Ian Wienandaee18c72014-02-21 15:35:08 +11001339function run_process {
Dean Troyerdff49a22014-01-30 15:37:40 -06001340 local service=$1
1341 local command="$2"
Chris Dent2f27a0e2014-09-09 13:46:02 +01001342 local group=$3
Dean Troyerdff49a22014-01-30 15:37:40 -06001343
Dean Troyer3159a822014-08-27 14:13:58 -05001344 if is_service_enabled $service; then
1345 if [[ "$USE_SCREEN" = "True" ]]; then
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001346 screen_process "$service" "$command" "$group"
Dean Troyer3159a822014-08-27 14:13:58 -05001347 else
1348 # Spawn directly without screen
Chris Dent2f27a0e2014-09-09 13:46:02 +01001349 _run_process "$service" "$command" "$group" &
Dean Troyer3159a822014-08-27 14:13:58 -05001350 fi
1351 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001352}
1353
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001354# Helper to launch a process in a named screen
Dean Troyerdde41d02014-12-09 17:47:57 -06001355# Uses globals ``CURRENT_LOG_TIME``, ```LOGDIR``, ``SCREEN_LOGDIR``, `SCREEN_NAME``,
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001356# ``SERVICE_DIR``, ``USE_SCREEN``
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001357# screen_process name "command-line" [group]
Chris Dent2f27a0e2014-09-09 13:46:02 +01001358# Run a command in a shell in a screen window, if an optional group
1359# is provided, use sg to set the group of the command.
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001360function screen_process {
1361 local name=$1
Dean Troyer3159a822014-08-27 14:13:58 -05001362 local command="$2"
Chris Dent2f27a0e2014-09-09 13:46:02 +01001363 local group=$3
Dean Troyer3159a822014-08-27 14:13:58 -05001364
Sean Dagueea22a4f2014-06-27 15:21:41 -04001365 SCREEN_NAME=${SCREEN_NAME:-stack}
1366 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
Sean Dague53753292014-12-04 19:38:15 -05001367 USE_SCREEN=$(trueorfalse True USE_SCREEN)
Dean Troyerdff49a22014-01-30 15:37:40 -06001368
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001369 screen -S $SCREEN_NAME -X screen -t $name
Dean Troyerdff49a22014-01-30 15:37:40 -06001370
Dean Troyerdde41d02014-12-09 17:47:57 -06001371 local real_logfile="${LOGDIR}/${name}.log.${CURRENT_LOG_TIME}"
1372 echo "LOGDIR: $LOGDIR"
1373 echo "SCREEN_LOGDIR: $SCREEN_LOGDIR"
1374 echo "log: $real_logfile"
1375 if [[ -n ${LOGDIR} ]]; then
1376 screen -S $SCREEN_NAME -p $name -X logfile "$real_logfile"
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001377 screen -S $SCREEN_NAME -p $name -X log on
Dean Troyerdde41d02014-12-09 17:47:57 -06001378 ln -sf "$real_logfile" ${LOGDIR}/${name}.log
1379 if [[ -n ${SCREEN_LOGDIR} ]]; then
1380 # Drop the backward-compat symlink
1381 ln -sf "$real_logfile" ${SCREEN_LOGDIR}/screen-${1}.log
1382 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001383 fi
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001384
1385 # sleep to allow bash to be ready to be send the command - we are
1386 # creating a new window in screen and then sends characters, so if
Sean Dague4d7ee092015-04-07 10:40:49 -04001387 # bash isn't running by the time we send the command, nothing
1388 # happens. This sleep was added originally to handle gate runs
1389 # where we needed this to be at least 3 seconds to pass
1390 # consistently on slow clouds. Now this is configurable so that we
1391 # can determine a reasonable value for the local case which should
1392 # be much smaller.
1393 sleep ${SCREEN_SLEEP:-3}
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001394
1395 NL=`echo -ne '\015'`
1396 # This fun command does the following:
1397 # - the passed server command is backgrounded
1398 # - the pid of the background process is saved in the usual place
1399 # - the server process is brought back to the foreground
1400 # - if the server process exits prematurely the fg command errors
1401 # and a message is written to stdout and the process failure file
1402 #
1403 # The pid saved can be used in stop_process() as a process group
1404 # id to kill off all child processes
1405 if [[ -n "$group" ]]; then
1406 command="sg $group '$command'"
1407 fi
Ian Wienandb28b2702015-04-16 08:43:43 +10001408
1409 # Append the process to the screen rc file
1410 screen_rc "$name" "$command"
1411
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001412 screen -S $SCREEN_NAME -p $name -X stuff "$command & echo \$! >$SERVICE_DIR/$SCREEN_NAME/${name}.pid; fg || echo \"$name failed to start\" | tee \"$SERVICE_DIR/$SCREEN_NAME/${name}.failure\"$NL"
Dean Troyerdff49a22014-01-30 15:37:40 -06001413}
1414
1415# Screen rc file builder
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001416# Uses globals ``SCREEN_NAME``, ``SCREENRC``
Dean Troyerdff49a22014-01-30 15:37:40 -06001417# screen_rc service "command-line"
1418function screen_rc {
1419 SCREEN_NAME=${SCREEN_NAME:-stack}
1420 SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc
1421 if [[ ! -e $SCREENRC ]]; then
1422 # Name the screen session
1423 echo "sessionname $SCREEN_NAME" > $SCREENRC
1424 # Set a reasonable statusbar
1425 echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC
1426 # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off
1427 echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC
1428 echo "screen -t shell bash" >> $SCREENRC
1429 fi
1430 # If this service doesn't already exist in the screenrc file
1431 if ! grep $1 $SCREENRC 2>&1 > /dev/null; then
1432 NL=`echo -ne '\015'`
1433 echo "screen -t $1 bash" >> $SCREENRC
1434 echo "stuff \"$2$NL\"" >> $SCREENRC
1435
Dean Troyerdde41d02014-12-09 17:47:57 -06001436 if [[ -n ${LOGDIR} ]]; then
1437 echo "logfile ${LOGDIR}/${1}.log.${CURRENT_LOG_TIME}" >>$SCREENRC
Dean Troyerdff49a22014-01-30 15:37:40 -06001438 echo "log on" >>$SCREENRC
1439 fi
1440 fi
1441}
1442
1443# Stop a service in screen
1444# If a PID is available use it, kill the whole process group via TERM
1445# If screen is being used kill the screen window; this will catch processes
1446# that did not leave a PID behind
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001447# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``, ``USE_SCREEN``
Chris Dent2f27a0e2014-09-09 13:46:02 +01001448# screen_stop_service service
Dean Troyer3159a822014-08-27 14:13:58 -05001449function screen_stop_service {
1450 local service=$1
1451
Dean Troyerdff49a22014-01-30 15:37:40 -06001452 SCREEN_NAME=${SCREEN_NAME:-stack}
1453 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
Sean Dague53753292014-12-04 19:38:15 -05001454 USE_SCREEN=$(trueorfalse True USE_SCREEN)
Dean Troyerdff49a22014-01-30 15:37:40 -06001455
Dean Troyer3159a822014-08-27 14:13:58 -05001456 if is_service_enabled $service; then
1457 # Clean up the screen window
Attila Fazekasf750a6f2015-07-01 12:17:35 +02001458 screen -S $SCREEN_NAME -p $service -X kill || true
Dean Troyer3159a822014-08-27 14:13:58 -05001459 fi
1460}
1461
1462# Stop a service process
1463# If a PID is available use it, kill the whole process group via TERM
1464# If screen is being used kill the screen window; this will catch processes
1465# that did not leave a PID behind
1466# Uses globals ``SERVICE_DIR``, ``USE_SCREEN``
1467# stop_process service
1468function stop_process {
1469 local service=$1
1470
1471 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
Sean Dague53753292014-12-04 19:38:15 -05001472 USE_SCREEN=$(trueorfalse True USE_SCREEN)
Dean Troyer3159a822014-08-27 14:13:58 -05001473
1474 if is_service_enabled $service; then
Dean Troyerdff49a22014-01-30 15:37:40 -06001475 # Kill via pid if we have one available
Dean Troyer3159a822014-08-27 14:13:58 -05001476 if [[ -r $SERVICE_DIR/$SCREEN_NAME/$service.pid ]]; then
1477 pkill -g $(cat $SERVICE_DIR/$SCREEN_NAME/$service.pid)
Dan Smithce7246a2015-04-23 09:41:06 -07001478 # oslo.service tends to stop actually shutting down
1479 # reliably in between releases because someone believes it
1480 # is dying too early due to some inflight work they
1481 # have. This is a tension. It happens often enough we're
1482 # going to just account for it in devstack and assume it
1483 # doesn't work.
1484 #
1485 # Set OSLO_SERVICE_WORKS=True to skip this block
1486 if [[ -z "$OSLO_SERVICE_WORKS" ]]; then
1487 # TODO(danms): Remove this double-kill when we have
1488 # this fixed in all services:
1489 # https://bugs.launchpad.net/oslo-incubator/+bug/1446583
1490 sleep 1
1491 # /bin/true becakse pkill on a non existant process returns an error
1492 pkill -g $(cat $SERVICE_DIR/$SCREEN_NAME/$service.pid) || /bin/true
1493 fi
Dean Troyer3159a822014-08-27 14:13:58 -05001494 rm $SERVICE_DIR/$SCREEN_NAME/$service.pid
Dean Troyerdff49a22014-01-30 15:37:40 -06001495 fi
1496 if [[ "$USE_SCREEN" = "True" ]]; then
1497 # Clean up the screen window
Dean Troyer3159a822014-08-27 14:13:58 -05001498 screen_stop_service $service
Dean Troyerdff49a22014-01-30 15:37:40 -06001499 fi
1500 fi
1501}
1502
1503# Helper to get the status of each running service
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001504# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``
Dean Troyerdff49a22014-01-30 15:37:40 -06001505# service_check
Ian Wienandaee18c72014-02-21 15:35:08 +11001506function service_check {
Dean Troyerdff49a22014-01-30 15:37:40 -06001507 local service
1508 local failures
1509 SCREEN_NAME=${SCREEN_NAME:-stack}
1510 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1511
1512
1513 if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
1514 echo "No service status directory found"
1515 return
1516 fi
1517
Wei Jiangange3340f12015-09-21 17:52:14 +08001518 # Check if there is any failure flag file under $SERVICE_DIR/$SCREEN_NAME
Sean Dague09bd7c82014-02-03 08:35:26 +09001519 # make this -o errexit safe
1520 failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null || /bin/true`
Dean Troyerdff49a22014-01-30 15:37:40 -06001521
1522 for service in $failures; do
1523 service=`basename $service`
1524 service=${service%.failure}
1525 echo "Error: Service $service is not running"
1526 done
1527
1528 if [ -n "$failures" ]; then
Sean Dague12379222014-02-27 17:16:46 -05001529 die $LINENO "More details about the above errors can be found with screen, with ./rejoin-stack.sh"
Dean Troyerdff49a22014-01-30 15:37:40 -06001530 fi
1531}
1532
Chris Dent2f27a0e2014-09-09 13:46:02 +01001533# Tail a log file in a screen if USE_SCREEN is true.
1534function tail_log {
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001535 local name=$1
Chris Dent2f27a0e2014-09-09 13:46:02 +01001536 local logfile=$2
1537
Sean Dague53753292014-12-04 19:38:15 -05001538 USE_SCREEN=$(trueorfalse True USE_SCREEN)
Chris Dent2f27a0e2014-09-09 13:46:02 +01001539 if [[ "$USE_SCREEN" = "True" ]]; then
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001540 screen_process "$name" "sudo tail -f $logfile"
Chris Dent2f27a0e2014-09-09 13:46:02 +01001541 fi
1542}
1543
Dean Troyerdff49a22014-01-30 15:37:40 -06001544
Dean Troyer3159a822014-08-27 14:13:58 -05001545# Deprecated Functions
1546# --------------------
1547
1548# _old_run_process() is designed to be backgrounded by old_run_process() to simulate a
1549# fork. It includes the dirty work of closing extra filehandles and preparing log
1550# files to produce the same logs as screen_it(). The log filename is derived
1551# from the service name and global-and-now-misnamed ``SCREEN_LOGDIR``
1552# Uses globals ``CURRENT_LOG_TIME``, ``SCREEN_LOGDIR``, ``SCREEN_NAME``, ``SERVICE_DIR``
1553# _old_run_process service "command-line"
1554function _old_run_process {
1555 local service=$1
1556 local command="$2"
1557
1558 # Undo logging redirections and close the extra descriptors
1559 exec 1>&3
1560 exec 2>&3
1561 exec 3>&-
1562 exec 6>&-
1563
1564 if [[ -n ${SCREEN_LOGDIR} ]]; then
Dean Troyerad5cc982014-12-10 16:35:32 -06001565 exec 1>&${SCREEN_LOGDIR}/screen-${1}.log.${CURRENT_LOG_TIME} 2>&1
1566 ln -sf ${SCREEN_LOGDIR}/screen-${1}.log.${CURRENT_LOG_TIME} ${SCREEN_LOGDIR}/screen-${1}.log
Dean Troyer3159a822014-08-27 14:13:58 -05001567
1568 # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs.
1569 export PYTHONUNBUFFERED=1
1570 fi
1571
1572 exec /bin/bash -c "$command"
1573 die "$service exec failure: $command"
1574}
1575
1576# old_run_process() launches a child process that closes all file descriptors and
1577# then exec's the passed in command. This is meant to duplicate the semantics
1578# of screen_it() without screen. PIDs are written to
1579# ``$SERVICE_DIR/$SCREEN_NAME/$service.pid`` by the spawned child process.
1580# old_run_process service "command-line"
1581function old_run_process {
1582 local service=$1
1583 local command="$2"
1584
1585 # Spawn the child process
1586 _old_run_process "$service" "$command" &
1587 echo $!
1588}
1589
1590# Compatibility for existing start_XXXX() functions
1591# Uses global ``USE_SCREEN``
1592# screen_it service "command-line"
1593function screen_it {
1594 if is_service_enabled $1; then
1595 # Append the service to the screen rc file
1596 screen_rc "$1" "$2"
1597
1598 if [[ "$USE_SCREEN" = "True" ]]; then
Adam Gandelman8543a0f2014-10-16 17:42:33 -07001599 screen_process "$1" "$2"
Dean Troyer3159a822014-08-27 14:13:58 -05001600 else
1601 # Spawn directly without screen
1602 old_run_process "$1" "$2" >$SERVICE_DIR/$SCREEN_NAME/$1.pid
1603 fi
1604 fi
1605}
1606
1607# Compatibility for existing stop_XXXX() functions
1608# Stop a service in screen
1609# If a PID is available use it, kill the whole process group via TERM
1610# If screen is being used kill the screen window; this will catch processes
1611# that did not leave a PID behind
1612# screen_stop service
1613function screen_stop {
1614 # Clean up the screen window
1615 stop_process $1
1616}
1617
1618
Sean Dague2c65e712014-12-18 09:44:56 -05001619# Plugin Functions
1620# =================
1621
1622DEVSTACK_PLUGINS=${DEVSTACK_PLUGINS:-""}
1623
1624# enable_plugin <name> <url> [branch]
1625#
1626# ``name`` is an arbitrary name - (aka: glusterfs, nova-docker, zaqar)
1627# ``url`` is a git url
1628# ``branch`` is a gitref. If it's not set, defaults to master
1629function enable_plugin {
1630 local name=$1
1631 local url=$2
1632 local branch=${3:-master}
1633 DEVSTACK_PLUGINS+=",$name"
1634 GITREPO[$name]=$url
1635 GITDIR[$name]=$DEST/$name
1636 GITBRANCH[$name]=$branch
1637}
1638
1639# fetch_plugins
1640#
1641# clones all plugins
1642function fetch_plugins {
1643 local plugins="${DEVSTACK_PLUGINS}"
1644 local plugin
1645
1646 # short circuit if nothing to do
1647 if [[ -z $plugins ]]; then
1648 return
1649 fi
1650
Dean Troyerdc97cb72015-03-28 08:20:50 -05001651 echo "Fetching DevStack plugins"
Sean Dague2c65e712014-12-18 09:44:56 -05001652 for plugin in ${plugins//,/ }; do
1653 git_clone_by_name $plugin
1654 done
1655}
1656
1657# load_plugin_settings
1658#
1659# Load settings from plugins in the order that they were registered
1660function load_plugin_settings {
1661 local plugins="${DEVSTACK_PLUGINS}"
1662 local plugin
1663
1664 # short circuit if nothing to do
1665 if [[ -z $plugins ]]; then
1666 return
1667 fi
1668
1669 echo "Loading plugin settings"
1670 for plugin in ${plugins//,/ }; do
1671 local dir=${GITDIR[$plugin]}
1672 # source any known settings
1673 if [[ -f $dir/devstack/settings ]]; then
1674 source $dir/devstack/settings
1675 fi
1676 done
1677}
1678
Sean Dague6e275e12015-03-26 05:54:28 -04001679# plugin_override_defaults
1680#
1681# Run an extremely early setting phase for plugins that allows default
1682# overriding of services.
1683function plugin_override_defaults {
1684 local plugins="${DEVSTACK_PLUGINS}"
1685 local plugin
1686
1687 # short circuit if nothing to do
1688 if [[ -z $plugins ]]; then
1689 return
1690 fi
1691
1692 echo "Overriding Configuration Defaults"
1693 for plugin in ${plugins//,/ }; do
1694 local dir=${GITDIR[$plugin]}
1695 # source any overrides
1696 if [[ -f $dir/devstack/override-defaults ]]; then
1697 # be really verbose that an override is happening, as it
1698 # may not be obvious if things fail later.
1699 echo "$plugin has overriden the following defaults"
1700 cat $dir/devstack/override-defaults
1701 source $dir/devstack/override-defaults
1702 fi
1703 done
1704}
1705
Sean Dague2c65e712014-12-18 09:44:56 -05001706# run_plugins
1707#
1708# Run the devstack/plugin.sh in all the plugin directories. These are
1709# run in registration order.
1710function run_plugins {
1711 local mode=$1
1712 local phase=$2
Bharat Kumar Kobagana441ff072015-01-08 12:26:26 +05301713
1714 local plugins="${DEVSTACK_PLUGINS}"
1715 local plugin
Sean Dague2c65e712014-12-18 09:44:56 -05001716 for plugin in ${plugins//,/ }; do
1717 local dir=${GITDIR[$plugin]}
1718 if [[ -f $dir/devstack/plugin.sh ]]; then
1719 source $dir/devstack/plugin.sh $mode $phase
1720 fi
1721 done
1722}
1723
1724function run_phase {
1725 local mode=$1
1726 local phase=$2
1727 if [[ -d $TOP_DIR/extras.d ]]; then
Dmitry Tantsur64be3212015-10-12 13:10:24 +02001728 local extra_plugin_file_name
1729 for extra_plugin_file_name in $TOP_DIR/extras.d/*.sh; do
1730 [[ -r $extra_plugin_file_name ]] && source $extra_plugin_file_name $mode $phase
Sean Dague1de9e332015-10-07 08:46:13 -04001731 # NOTE(sdague): generate a big warning about using
1732 # extras.d in an unsupported way which will let us track
1733 # unsupported usage in the gate.
1734 local exceptions="50-ironic.sh 60-ceph.sh 80-tempest.sh"
Dmitry Tantsur64be3212015-10-12 13:10:24 +02001735 local extra=$(basename $extra_plugin_file_name)
Sean Dague1de9e332015-10-07 08:46:13 -04001736 if [[ ! ( $exceptions =~ "$extra" ) ]]; then
1737 deprecated "extras.d support is being removed in Mitaka-1"
1738 deprecated "jobs for project $extra will break after that point"
1739 deprecated "please move project to a supported devstack plugin model"
1740 fi
Sean Dague2c65e712014-12-18 09:44:56 -05001741 done
1742 fi
1743 # the source phase corresponds to settings loading in plugins
1744 if [[ "$mode" == "source" ]]; then
1745 load_plugin_settings
Chris Dentc6d47012015-10-09 14:57:05 +00001746 verify_disabled_services
Sean Dague6e275e12015-03-26 05:54:28 -04001747 elif [[ "$mode" == "override_defaults" ]]; then
1748 plugin_override_defaults
Sean Dague2c65e712014-12-18 09:44:56 -05001749 else
1750 run_plugins $mode $phase
1751 fi
1752}
1753
Dean Troyerdff49a22014-01-30 15:37:40 -06001754
1755# Service Functions
1756# =================
1757
1758# remove extra commas from the input string (i.e. ``ENABLED_SERVICES``)
1759# _cleanup_service_list service-list
Ian Wienandaee18c72014-02-21 15:35:08 +11001760function _cleanup_service_list {
Ian Wienand8043bfa2015-10-14 14:53:18 +11001761 local xtrace
1762 xtrace=$(set +o | grep xtrace)
1763 set +o xtrace
1764
Dean Troyerdff49a22014-01-30 15:37:40 -06001765 echo "$1" | sed -e '
1766 s/,,/,/g;
1767 s/^,//;
1768 s/,$//
1769 '
Ian Wienand8043bfa2015-10-14 14:53:18 +11001770
1771 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06001772}
1773
1774# disable_all_services() removes all current services
1775# from ``ENABLED_SERVICES`` to reset the configuration
1776# before a minimal installation
1777# Uses global ``ENABLED_SERVICES``
1778# disable_all_services
Ian Wienandaee18c72014-02-21 15:35:08 +11001779function disable_all_services {
Dean Troyerdff49a22014-01-30 15:37:40 -06001780 ENABLED_SERVICES=""
1781}
1782
1783# Remove all services starting with '-'. For example, to install all default
1784# services except rabbit (rabbit) set in ``localrc``:
1785# ENABLED_SERVICES+=",-rabbit"
1786# Uses global ``ENABLED_SERVICES``
1787# disable_negated_services
Ian Wienandaee18c72014-02-21 15:35:08 +11001788function disable_negated_services {
Ian Wienand8043bfa2015-10-14 14:53:18 +11001789 local xtrace
1790 xtrace=$(set +o | grep xtrace)
1791 set +o xtrace
1792
Ian Wienand2796a822015-04-15 08:59:04 +10001793 local to_remove=""
1794 local remaining=""
Dean Troyerdff49a22014-01-30 15:37:40 -06001795 local service
Ian Wienand2796a822015-04-15 08:59:04 +10001796
1797 # build up list of services that should be removed; i.e. they
1798 # begin with "-"
1799 for service in ${ENABLED_SERVICES//,/ }; do
Dean Troyerdff49a22014-01-30 15:37:40 -06001800 if [[ ${service} == -* ]]; then
Ian Wienand2796a822015-04-15 08:59:04 +10001801 to_remove+=",${service#-}"
1802 else
1803 remaining+=",${service}"
Dean Troyerdff49a22014-01-30 15:37:40 -06001804 fi
1805 done
Ian Wienand2796a822015-04-15 08:59:04 +10001806
1807 # go through the service list. if this service appears in the "to
1808 # be removed" list, drop it
fumihiko kakuma8606c982015-04-13 09:55:06 +09001809 ENABLED_SERVICES=$(remove_disabled_services "$remaining" "$to_remove")
Ian Wienand8043bfa2015-10-14 14:53:18 +11001810
1811 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06001812}
1813
Chris Dentc6d47012015-10-09 14:57:05 +00001814# disable_service() prepares the services passed as argument to be
1815# removed from the ``ENABLED_SERVICES`` list, if they are present.
Dean Troyerdff49a22014-01-30 15:37:40 -06001816#
1817# For example:
1818# disable_service rabbit
1819#
Chris Dentc6d47012015-10-09 14:57:05 +00001820# Uses global ``DISABLED_SERVICES``
Dean Troyerdff49a22014-01-30 15:37:40 -06001821# disable_service service [service ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001822function disable_service {
Ian Wienand8043bfa2015-10-14 14:53:18 +11001823 local xtrace
1824 xtrace=$(set +o | grep xtrace)
1825 set +o xtrace
1826
Chris Dentc6d47012015-10-09 14:57:05 +00001827 local disabled_svcs="${DISABLED_SERVICES}"
1828 local enabled_svcs=",${ENABLED_SERVICES},"
Dean Troyerdff49a22014-01-30 15:37:40 -06001829 local service
1830 for service in $@; do
Chris Dentc6d47012015-10-09 14:57:05 +00001831 disabled_svcs+=",$service"
Dean Troyerdff49a22014-01-30 15:37:40 -06001832 if is_service_enabled $service; then
Chris Dentc6d47012015-10-09 14:57:05 +00001833 enabled_svcs=${enabled_svcs//,$service,/,}
Dean Troyerdff49a22014-01-30 15:37:40 -06001834 fi
1835 done
Chris Dentc6d47012015-10-09 14:57:05 +00001836 DISABLED_SERVICES=$(_cleanup_service_list "$disabled_svcs")
1837 ENABLED_SERVICES=$(_cleanup_service_list "$enabled_svcs")
Ian Wienand8043bfa2015-10-14 14:53:18 +11001838
1839 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06001840}
1841
1842# enable_service() adds the services passed as argument to the
1843# ``ENABLED_SERVICES`` list, if they are not already present.
1844#
1845# For example:
Sean Dague37eca482015-06-16 07:19:22 -04001846# enable_service q-svc
Dean Troyerdff49a22014-01-30 15:37:40 -06001847#
1848# This function does not know about the special cases
1849# for nova, glance, and neutron built into is_service_enabled().
1850# Uses global ``ENABLED_SERVICES``
1851# enable_service service [service ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001852function enable_service {
Ian Wienand8043bfa2015-10-14 14:53:18 +11001853 local xtrace
1854 xtrace=$(set +o | grep xtrace)
1855 set +o xtrace
1856
Dean Troyerdff49a22014-01-30 15:37:40 -06001857 local tmpsvcs="${ENABLED_SERVICES}"
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001858 local service
Dean Troyerdff49a22014-01-30 15:37:40 -06001859 for service in $@; do
Chris Dentc6d47012015-10-09 14:57:05 +00001860 if [[ ,${DISABLED_SERVICES}, =~ ,${service}, ]]; then
1861 warn $LINENO "Attempt to enable_service ${service} when it has been disabled"
1862 continue
1863 fi
Dean Troyerdff49a22014-01-30 15:37:40 -06001864 if ! is_service_enabled $service; then
1865 tmpsvcs+=",$service"
1866 fi
1867 done
1868 ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
1869 disable_negated_services
Ian Wienand8043bfa2015-10-14 14:53:18 +11001870
1871 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06001872}
1873
1874# is_service_enabled() checks if the service(s) specified as arguments are
1875# enabled by the user in ``ENABLED_SERVICES``.
1876#
1877# Multiple services specified as arguments are ``OR``'ed together; the test
1878# is a short-circuit boolean, i.e it returns on the first match.
1879#
1880# There are special cases for some 'catch-all' services::
1881# **nova** returns true if any service enabled start with **n-**
1882# **cinder** returns true if any service enabled start with **c-**
Dean Troyerdff49a22014-01-30 15:37:40 -06001883# **glance** returns true if any service enabled start with **g-**
1884# **neutron** returns true if any service enabled start with **q-**
1885# **swift** returns true if any service enabled start with **s-**
1886# **trove** returns true if any service enabled start with **tr-**
1887# For backward compatibility if we have **swift** in ENABLED_SERVICES all the
1888# **s-** services will be enabled. This will be deprecated in the future.
1889#
1890# Cells within nova is enabled if **n-cell** is in ``ENABLED_SERVICES``.
1891# We also need to make sure to treat **n-cell-region** and **n-cell-child**
1892# as enabled in this case.
1893#
1894# Uses global ``ENABLED_SERVICES``
1895# is_service_enabled service [service ...]
Ian Wienandaee18c72014-02-21 15:35:08 +11001896function is_service_enabled {
Ian Wienand433a9b12015-10-07 13:29:31 +11001897 local xtrace
1898 xtrace=$(set +o | grep xtrace)
Sean Dague45917cc2014-02-24 16:09:14 -05001899 set +o xtrace
Ian Wienand8043bfa2015-10-14 14:53:18 +11001900
Sean Dague45917cc2014-02-24 16:09:14 -05001901 local enabled=1
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001902 local services=$@
1903 local service
Dean Troyerdff49a22014-01-30 15:37:40 -06001904 for service in ${services}; do
Sean Dague45917cc2014-02-24 16:09:14 -05001905 [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && enabled=0
Dean Troyerdff49a22014-01-30 15:37:40 -06001906
1907 # Look for top-level 'enabled' function for this service
1908 if type is_${service}_enabled >/dev/null 2>&1; then
1909 # A function exists for this service, use it
Christian Schwede3db0aad2015-09-10 11:15:39 +00001910 is_${service}_enabled && enabled=0
Dean Troyerdff49a22014-01-30 15:37:40 -06001911 fi
1912
1913 # TODO(dtroyer): Remove these legacy special-cases after the is_XXX_enabled()
1914 # are implemented
1915
Sean Dague45917cc2014-02-24 16:09:14 -05001916 [[ ${service} == n-cell-* && ${ENABLED_SERVICES} =~ "n-cell" ]] && enabled=0
Chris Dent2f27a0e2014-09-09 13:46:02 +01001917 [[ ${service} == n-cpu-* && ${ENABLED_SERVICES} =~ "n-cpu" ]] && enabled=0
Sean Dague45917cc2014-02-24 16:09:14 -05001918 [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && enabled=0
Sean Dague45917cc2014-02-24 16:09:14 -05001919 [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && enabled=0
1920 [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && enabled=0
1921 [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && enabled=0
1922 [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && enabled=0
1923 [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && enabled=0
1924 [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && enabled=0
Dean Troyerdff49a22014-01-30 15:37:40 -06001925 done
Ian Wienand8043bfa2015-10-14 14:53:18 +11001926
Sean Dague45917cc2014-02-24 16:09:14 -05001927 $xtrace
1928 return $enabled
Dean Troyerdff49a22014-01-30 15:37:40 -06001929}
1930
fumihiko kakuma8606c982015-04-13 09:55:06 +09001931# remove specified list from the input string
1932# remove_disabled_services service-list remove-list
1933function remove_disabled_services {
Ian Wienand8043bfa2015-10-14 14:53:18 +11001934 local xtrace
1935 xtrace=$(set +o | grep xtrace)
1936 set +o xtrace
1937
fumihiko kakuma8606c982015-04-13 09:55:06 +09001938 local service_list=$1
1939 local remove_list=$2
1940 local service
1941 local enabled=""
1942
1943 for service in ${service_list//,/ }; do
1944 local remove
1945 local add=1
1946 for remove in ${remove_list//,/ }; do
1947 if [[ ${remove} == ${service} ]]; then
1948 add=0
1949 break
1950 fi
1951 done
1952 if [[ $add == 1 ]]; then
1953 enabled="${enabled},$service"
1954 fi
1955 done
Ian Wienand8043bfa2015-10-14 14:53:18 +11001956
1957 $xtrace
1958
fumihiko kakuma8606c982015-04-13 09:55:06 +09001959 _cleanup_service_list "$enabled"
1960}
1961
Dean Troyerdff49a22014-01-30 15:37:40 -06001962# Toggle enable/disable_service for services that must run exclusive of each other
1963# $1 The name of a variable containing a space-separated list of services
1964# $2 The name of a variable in which to store the enabled service's name
1965# $3 The name of the service to enable
1966function use_exclusive_service {
1967 local options=${!1}
1968 local selection=$3
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001969 local out=$2
Dean Troyerdff49a22014-01-30 15:37:40 -06001970 [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05001971 local opt
Dean Troyerdff49a22014-01-30 15:37:40 -06001972 for opt in $options;do
1973 [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt
1974 done
1975 eval "$out=$selection"
1976 return 0
1977}
1978
Chris Dentc6d47012015-10-09 14:57:05 +00001979# Make sure that nothing has manipulated ENABLED_SERVICES in a way
1980# that conflicts with prior calls to disable_service.
1981# Uses global ``ENABLED_SERVICES``
1982function verify_disabled_services {
1983 local service
1984 for service in ${ENABLED_SERVICES//,/ }; do
1985 if [[ ,${DISABLED_SERVICES}, =~ ,${service}, ]]; then
1986 die $LINENO "ENABLED_SERVICES directly modified to overcome 'disable_service ${service}'"
1987 fi
1988 done
1989}
1990
Dean Troyerdff49a22014-01-30 15:37:40 -06001991
Masayuki Igawaf6368d32014-02-20 13:31:26 +09001992# System Functions
1993# ================
Dean Troyerdff49a22014-01-30 15:37:40 -06001994
1995# Only run the command if the target file (the last arg) is not on an
1996# NFS filesystem.
Ian Wienandaee18c72014-02-21 15:35:08 +11001997function _safe_permission_operation {
Ian Wienand433a9b12015-10-07 13:29:31 +11001998 local xtrace
1999 xtrace=$(set +o | grep xtrace)
Sean Dague45917cc2014-02-24 16:09:14 -05002000 set +o xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06002001 local args=( $@ )
2002 local last
2003 local sudo_cmd
2004 local dir_to_check
2005
2006 let last="${#args[*]} - 1"
2007
Dean Troyerd5dfa4c2014-07-25 11:13:11 -05002008 local dir_to_check=${args[$last]}
Dean Troyerdff49a22014-01-30 15:37:40 -06002009 if [ ! -d "$dir_to_check" ]; then
2010 dir_to_check=`dirname "$dir_to_check"`
2011 fi
2012
2013 if is_nfs_directory "$dir_to_check" ; then
Sean Dague45917cc2014-02-24 16:09:14 -05002014 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06002015 return 0
2016 fi
2017
2018 if [[ $TRACK_DEPENDS = True ]]; then
2019 sudo_cmd="env"
2020 else
2021 sudo_cmd="sudo"
2022 fi
2023
Sean Dague45917cc2014-02-24 16:09:14 -05002024 $xtrace
Dean Troyerdff49a22014-01-30 15:37:40 -06002025 $sudo_cmd $@
2026}
2027
2028# Exit 0 if address is in network or 1 if address is not in network
2029# ip-range is in CIDR notation: 1.2.3.4/20
2030# address_in_net ip-address ip-range
Ian Wienandaee18c72014-02-21 15:35:08 +11002031function address_in_net {
Dean Troyerdff49a22014-01-30 15:37:40 -06002032 local ip=$1
2033 local range=$2
2034 local masklen=${range#*/}
Ian Wienandada886d2015-10-07 14:06:26 +11002035 local network
2036 network=$(maskip ${range%/*} $(cidr2netmask $masklen))
2037 local subnet
2038 subnet=$(maskip $ip $(cidr2netmask $masklen))
Dean Troyerdff49a22014-01-30 15:37:40 -06002039 [[ $network == $subnet ]]
2040}
2041
2042# Add a user to a group.
2043# add_user_to_group user group
Ian Wienandaee18c72014-02-21 15:35:08 +11002044function add_user_to_group {
Dean Troyerdff49a22014-01-30 15:37:40 -06002045 local user=$1
2046 local group=$2
2047
Thomas Bechtolda8580852015-05-31 00:04:33 +02002048 sudo usermod -a -G "$group" "$user"
Dean Troyerdff49a22014-01-30 15:37:40 -06002049}
2050
2051# Convert CIDR notation to a IPv4 netmask
2052# cidr2netmask cidr-bits
Ian Wienandaee18c72014-02-21 15:35:08 +11002053function cidr2netmask {
Dean Troyerdff49a22014-01-30 15:37:40 -06002054 local maskpat="255 255 255 255"
2055 local maskdgt="254 252 248 240 224 192 128"
2056 set -- ${maskpat:0:$(( ($1 / 8) * 4 ))}${maskdgt:$(( (7 - ($1 % 8)) * 4 )):3}
2057 echo ${1-0}.${2-0}.${3-0}.${4-0}
2058}
2059
2060# Gracefully cp only if source file/dir exists
2061# cp_it source destination
2062function cp_it {
2063 if [ -e $1 ] || [ -d $1 ]; then
2064 cp -pRL $1 $2
2065 fi
2066}
2067
2068# HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
2069# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
2070# ``localrc`` or on the command line if necessary::
2071#
2072# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
2073#
2074# http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh
2075
Ian Wienandaee18c72014-02-21 15:35:08 +11002076function export_proxy_variables {
Sean Dague53753292014-12-04 19:38:15 -05002077 if isset http_proxy ; then
Dean Troyerdff49a22014-01-30 15:37:40 -06002078 export http_proxy=$http_proxy
2079 fi
Sean Dague53753292014-12-04 19:38:15 -05002080 if isset https_proxy ; then
Dean Troyerdff49a22014-01-30 15:37:40 -06002081 export https_proxy=$https_proxy
2082 fi
Sean Dague53753292014-12-04 19:38:15 -05002083 if isset no_proxy ; then
Dean Troyerdff49a22014-01-30 15:37:40 -06002084 export no_proxy=$no_proxy
2085 fi
2086}
2087
2088# Returns true if the directory is on a filesystem mounted via NFS.
Ian Wienandaee18c72014-02-21 15:35:08 +11002089function is_nfs_directory {
Ian Wienandada886d2015-10-07 14:06:26 +11002090 local mount_type
2091 mount_type=`stat -f -L -c %T $1`
Dean Troyerdff49a22014-01-30 15:37:40 -06002092 test "$mount_type" == "nfs"
2093}
2094
2095# Return the network portion of the given IP address using netmask
2096# netmask is in the traditional dotted-quad format
2097# maskip ip-address netmask
Ian Wienandaee18c72014-02-21 15:35:08 +11002098function maskip {
Dean Troyerdff49a22014-01-30 15:37:40 -06002099 local ip=$1
2100 local mask=$2
2101 local l="${ip%.*}"; local r="${ip#*.}"; local n="${mask%.*}"; local m="${mask#*.}"
Ian Wienandada886d2015-10-07 14:06:26 +11002102 local subnet
2103 subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.}))
Dean Troyerdff49a22014-01-30 15:37:40 -06002104 echo $subnet
2105}
2106
Chris Dent3a2c86a2015-05-12 13:41:25 +00002107# Return the current python as "python<major>.<minor>"
2108function python_version {
Ian Wienandada886d2015-10-07 14:06:26 +11002109 local python_version
2110 python_version=$(python -c 'import sys; print("%s.%s" % sys.version_info[0:2])')
Chris Dent3a2c86a2015-05-12 13:41:25 +00002111 echo "python${python_version}"
2112}
2113
Dean Troyerdff49a22014-01-30 15:37:40 -06002114# Service wrapper to restart services
2115# restart_service service-name
Ian Wienandaee18c72014-02-21 15:35:08 +11002116function restart_service {
Dean Troyerdff49a22014-01-30 15:37:40 -06002117 if is_ubuntu; then
2118 sudo /usr/sbin/service $1 restart
2119 else
2120 sudo /sbin/service $1 restart
2121 fi
2122}
2123
2124# Only change permissions of a file or directory if it is not on an
2125# NFS filesystem.
Ian Wienandaee18c72014-02-21 15:35:08 +11002126function safe_chmod {
Dean Troyerdff49a22014-01-30 15:37:40 -06002127 _safe_permission_operation chmod $@
2128}
2129
2130# Only change ownership of a file or directory if it is not on an NFS
2131# filesystem.
Ian Wienandaee18c72014-02-21 15:35:08 +11002132function safe_chown {
Dean Troyerdff49a22014-01-30 15:37:40 -06002133 _safe_permission_operation chown $@
2134}
2135
2136# Service wrapper to start services
2137# start_service service-name
Ian Wienandaee18c72014-02-21 15:35:08 +11002138function start_service {
Dean Troyerdff49a22014-01-30 15:37:40 -06002139 if is_ubuntu; then
2140 sudo /usr/sbin/service $1 start
2141 else
2142 sudo /sbin/service $1 start
2143 fi
2144}
2145
2146# Service wrapper to stop services
2147# stop_service service-name
Ian Wienandaee18c72014-02-21 15:35:08 +11002148function stop_service {
Dean Troyerdff49a22014-01-30 15:37:40 -06002149 if is_ubuntu; then
2150 sudo /usr/sbin/service $1 stop
2151 else
2152 sudo /sbin/service $1 stop
2153 fi
2154}
2155
Sean Dague442e4e92015-06-24 13:24:02 -04002156# Test with a finite retry loop.
2157#
2158function test_with_retry {
2159 local testcmd=$1
2160 local failmsg=$2
2161 local until=${3:-10}
2162 local sleep=${4:-0.5}
2163
2164 if ! timeout $until sh -c "while ! $testcmd; do sleep $sleep; done"; then
2165 die $LINENO "$failmsg"
2166 fi
2167}
2168
Sean Dague95c33d52015-10-07 11:05:59 -04002169# Timing infrastructure - figure out where large blocks of time are
2170# used in DevStack
2171#
2172# The timing infrastructure for DevStack is about collecting buckets
2173# of time that are spend in some subtask. For instance, that might be
2174# 'apt', 'pip', 'osc', even database migrations. We do this by a pair
2175# of functions: time_start / time_stop.
2176#
2177# These take a single parameter: $name - which specifies the name of
2178# the bucket to be accounted against. time_totals function spits out
2179# the results.
2180#
2181# Resolution is only in whole seconds, so should be used for long
2182# running activities.
2183
2184declare -A TOTAL_TIME
2185declare -A START_TIME
2186
2187# time_start $name
2188#
2189# starts the clock for a timer by name. Errors if that clock is
2190# already started.
2191function time_start {
2192 local name=$1
2193 local start_time=${START_TIME[$name]}
2194 if [[ -n "$start_time" ]]; then
2195 die $LINENO "Trying to start the clock on $name, but it's already been started"
2196 fi
2197 START_TIME[$name]=$(date +%s)
2198}
2199
2200# time_stop $name
2201#
2202# stops the clock for a timer by name, and accumulate that time in the
2203# global counter for that name. Errors if that clock had not
2204# previously been started.
2205function time_stop {
2206 local name=$1
2207 local start_time=${START_TIME[$name]}
2208 if [[ -z "$start_time" ]]; then
2209 die $LINENO "Trying to stop the clock on $name, but it was never started"
2210 fi
2211 local end_time=$(date +%s)
2212 local elapsed_time=$(($end_time - $start_time))
2213 local total=${TOTAL_TIME[$name]:-0}
2214 # reset the clock so we can start it in the future
2215 START_TIME[$name]=""
2216 TOTAL_TIME[$name]=$(($total + $elapsed_time))
2217}
2218
2219# time_totals
2220#
2221# prints out total time
2222function time_totals {
2223 echo
2224 echo "========================"
2225 echo "DevStack Components Timed"
2226 echo "========================"
2227 echo
2228 for t in ${!TOTAL_TIME[*]}; do
2229 local v=${TOTAL_TIME[$t]}
2230 echo "$t - $v secs"
2231 done
2232}
Dean Troyerdff49a22014-01-30 15:37:40 -06002233
2234# Restore xtrace
2235$XTRACE
2236
2237# Local variables:
2238# mode: shell-script
2239# End: