Browse code

Split functions

Move shared and non-DevStack-specific functions to `functions-common`. This is
a code move only with some updated comments. The functions are now
sorted alphabetically within function groups, eg. all git-related functions
are grouped together. The groups are listed at the top of the file.

'functions' sources 'functions-common' so no additional changes are required
for backward-compatability.

All functions shared with Grenade have also been moved.

functions-common was created from commit e0ed8ea038299952826b27a16753775472f108d8

Change-Id: I73bf7134fd6a60ec1ea44a5bfab08b0569b60ded

Dean Troyer authored on 2014/01/31 06:37:40
Showing 2 changed files
... ...
@@ -1,563 +1,21 @@
1
-# functions - Common functions used by DevStack components
1
+# functions - DevStack-specific functions
2 2
 #
3 3
 # The following variables are assumed to be defined by certain functions:
4 4
 #
5 5
 # - ``ENABLED_SERVICES``
6
-# - ``ERROR_ON_CLONE``
7 6
 # - ``FILES``
8 7
 # - ``GLANCE_HOSTPORT``
9
-# - ``OFFLINE``
10
-# - ``PIP_DOWNLOAD_CACHE``
11
-# - ``PIP_USE_MIRRORS``
12
-# - ``RECLONE``
13 8
 # - ``TRACK_DEPENDS``
14
-# - ``http_proxy``, ``https_proxy``, ``no_proxy``
15 9
 
10
+# Include the common functions
11
+FUNC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd)
12
+source ${FUNC_DIR}/functions-common
16 13
 
17 14
 # Save trace setting
18 15
 XTRACE=$(set +o | grep xtrace)
19 16
 set +o xtrace
20 17
 
21 18
 
22
-# Convert CIDR notation to a IPv4 netmask
23
-# cidr2netmask cidr-bits
24
-function cidr2netmask() {
25
-    local maskpat="255 255 255 255"
26
-    local maskdgt="254 252 248 240 224 192 128"
27
-    set -- ${maskpat:0:$(( ($1 / 8) * 4 ))}${maskdgt:$(( (7 - ($1 % 8)) * 4 )):3}
28
-    echo ${1-0}.${2-0}.${3-0}.${4-0}
29
-}
30
-
31
-
32
-# Return the network portion of the given IP address using netmask
33
-# netmask is in the traditional dotted-quad format
34
-# maskip ip-address netmask
35
-function maskip() {
36
-    local ip=$1
37
-    local mask=$2
38
-    local l="${ip%.*}"; local r="${ip#*.}"; local n="${mask%.*}"; local m="${mask#*.}"
39
-    local subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.}))
40
-    echo $subnet
41
-}
42
-
43
-
44
-# Exit 0 if address is in network or 1 if address is not in network
45
-# ip-range is in CIDR notation: 1.2.3.4/20
46
-# address_in_net ip-address ip-range
47
-function address_in_net() {
48
-    local ip=$1
49
-    local range=$2
50
-    local masklen=${range#*/}
51
-    local network=$(maskip ${range%/*} $(cidr2netmask $masklen))
52
-    local subnet=$(maskip $ip $(cidr2netmask $masklen))
53
-    [[ $network == $subnet ]]
54
-}
55
-
56
-
57
-# Wrapper for ``apt-get`` to set cache and proxy environment variables
58
-# Uses globals ``OFFLINE``, ``*_proxy``
59
-# apt_get operation package [package ...]
60
-function apt_get() {
61
-    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
62
-    local sudo="sudo"
63
-    [[ "$(id -u)" = "0" ]] && sudo="env"
64
-    $sudo DEBIAN_FRONTEND=noninteractive \
65
-        http_proxy=$http_proxy https_proxy=$https_proxy \
66
-        no_proxy=$no_proxy \
67
-        apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
68
-}
69
-
70
-
71
-# Gracefully cp only if source file/dir exists
72
-# cp_it source destination
73
-function cp_it {
74
-    if [ -e $1 ] || [ -d $1 ]; then
75
-        cp -pRL $1 $2
76
-    fi
77
-}
78
-
79
-
80
-# Prints backtrace info
81
-# filename:lineno:function
82
-function backtrace {
83
-    local level=$1
84
-    local deep=$((${#BASH_SOURCE[@]} - 1))
85
-    echo "[Call Trace]"
86
-    while [ $level -le $deep ]; do
87
-        echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
88
-        deep=$((deep - 1))
89
-    done
90
-}
91
-
92
-
93
-# Prints line number and "message" then exits
94
-# die $LINENO "message"
95
-function die() {
96
-    local exitcode=$?
97
-    set +o xtrace
98
-    local line=$1; shift
99
-    if [ $exitcode == 0 ]; then
100
-        exitcode=1
101
-    fi
102
-    backtrace 2
103
-    err $line "$*"
104
-    exit $exitcode
105
-}
106
-
107
-
108
-# Checks an environment variable is not set or has length 0 OR if the
109
-# exit code is non-zero and prints "message" and exits
110
-# NOTE: env-var is the variable name without a '$'
111
-# die_if_not_set $LINENO env-var "message"
112
-function die_if_not_set() {
113
-    local exitcode=$?
114
-    FXTRACE=$(set +o | grep xtrace)
115
-    set +o xtrace
116
-    local line=$1; shift
117
-    local evar=$1; shift
118
-    if ! is_set $evar || [ $exitcode != 0 ]; then
119
-        die $line "$*"
120
-    fi
121
-    $FXTRACE
122
-}
123
-
124
-
125
-# Prints line number and "message" in error format
126
-# err $LINENO "message"
127
-function err() {
128
-    local exitcode=$?
129
-    errXTRACE=$(set +o | grep xtrace)
130
-    set +o xtrace
131
-    local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
132
-    echo $msg 1>&2;
133
-    if [[ -n ${SCREEN_LOGDIR} ]]; then
134
-        echo $msg >> "${SCREEN_LOGDIR}/error.log"
135
-    fi
136
-    $errXTRACE
137
-    return $exitcode
138
-}
139
-
140
-
141
-# Checks an environment variable is not set or has length 0 OR if the
142
-# exit code is non-zero and prints "message"
143
-# NOTE: env-var is the variable name without a '$'
144
-# err_if_not_set $LINENO env-var "message"
145
-function err_if_not_set() {
146
-    local exitcode=$?
147
-    errinsXTRACE=$(set +o | grep xtrace)
148
-    set +o xtrace
149
-    local line=$1; shift
150
-    local evar=$1; shift
151
-    if ! is_set $evar || [ $exitcode != 0 ]; then
152
-        err $line "$*"
153
-    fi
154
-    $errinsXTRACE
155
-    return $exitcode
156
-}
157
-
158
-
159
-# Prints line number and "message" in warning format
160
-# warn $LINENO "message"
161
-function warn() {
162
-    local exitcode=$?
163
-    errXTRACE=$(set +o | grep xtrace)
164
-    set +o xtrace
165
-    local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
166
-    echo $msg 1>&2;
167
-    if [[ -n ${SCREEN_LOGDIR} ]]; then
168
-        echo $msg >> "${SCREEN_LOGDIR}/error.log"
169
-    fi
170
-    $errXTRACE
171
-    return $exitcode
172
-}
173
-
174
-
175
-# HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
176
-# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
177
-# ``localrc`` or on the command line if necessary::
178
-#
179
-# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
180
-#
181
-#     http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh
182
-
183
-function export_proxy_variables() {
184
-    if [[ -n "$http_proxy" ]]; then
185
-        export http_proxy=$http_proxy
186
-    fi
187
-    if [[ -n "$https_proxy" ]]; then
188
-        export https_proxy=$https_proxy
189
-    fi
190
-    if [[ -n "$no_proxy" ]]; then
191
-        export no_proxy=$no_proxy
192
-    fi
193
-}
194
-
195
-
196
-# Grab a numbered field from python prettytable output
197
-# Fields are numbered starting with 1
198
-# Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
199
-# get_field field-number
200
-function get_field() {
201
-    while read data; do
202
-        if [ "$1" -lt 0 ]; then
203
-            field="(\$(NF$1))"
204
-        else
205
-            field="\$$(($1 + 1))"
206
-        fi
207
-        echo "$data" | awk -F'[ \t]*\\|[ \t]*' "{print $field}"
208
-    done
209
-}
210
-
211
-
212
-# Get the default value for HOST_IP
213
-# get_default_host_ip fixed_range floating_range host_ip_iface host_ip
214
-function get_default_host_ip() {
215
-    local fixed_range=$1
216
-    local floating_range=$2
217
-    local host_ip_iface=$3
218
-    local host_ip=$4
219
-
220
-    # Find the interface used for the default route
221
-    host_ip_iface=${host_ip_iface:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }' | head -1)}
222
-    # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable
223
-    if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then
224
-        host_ip=""
225
-        host_ips=`LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/");  print parts[1]}'`
226
-        for IP in $host_ips; do
227
-            # Attempt to filter out IP addresses that are part of the fixed and
228
-            # floating range. Note that this method only works if the ``netaddr``
229
-            # python library is installed. If it is not installed, an error
230
-            # will be printed and the first IP from the interface will be used.
231
-            # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct
232
-            # address.
233
-            if ! (address_in_net $IP $fixed_range || address_in_net $IP $floating_range); then
234
-                host_ip=$IP
235
-                break;
236
-            fi
237
-        done
238
-    fi
239
-    echo $host_ip
240
-}
241
-
242
-
243
-function _get_package_dir() {
244
-    local pkg_dir
245
-    if is_ubuntu; then
246
-        pkg_dir=$FILES/apts
247
-    elif is_fedora; then
248
-        pkg_dir=$FILES/rpms
249
-    elif is_suse; then
250
-        pkg_dir=$FILES/rpms-suse
251
-    else
252
-        exit_distro_not_supported "list of packages"
253
-    fi
254
-    echo "$pkg_dir"
255
-}
256
-
257
-
258
-# get_packages() collects a list of package names of any type from the
259
-# prerequisite files in ``files/{apts|rpms}``.  The list is intended
260
-# to be passed to a package installer such as apt or yum.
261
-#
262
-# Only packages required for the services in 1st argument will be
263
-# included.  Two bits of metadata are recognized in the prerequisite files:
264
-#
265
-# - ``# NOPRIME`` defers installation to be performed later in `stack.sh`
266
-# - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection
267
-#   of the package to the distros listed.  The distro names are case insensitive.
268
-function get_packages() {
269
-    local services=$@
270
-    local package_dir=$(_get_package_dir)
271
-    local file_to_parse
272
-    local service
273
-
274
-    if [[ -z "$package_dir" ]]; then
275
-        echo "No package directory supplied"
276
-        return 1
277
-    fi
278
-    if [[ -z "$DISTRO" ]]; then
279
-        GetDistro
280
-    fi
281
-    for service in ${services//,/ }; do
282
-        # Allow individual services to specify dependencies
283
-        if [[ -e ${package_dir}/${service} ]]; then
284
-            file_to_parse="${file_to_parse} $service"
285
-        fi
286
-        # NOTE(sdague) n-api needs glance for now because that's where
287
-        # glance client is
288
-        if [[ $service == n-api ]]; then
289
-            if [[ ! $file_to_parse =~ nova ]]; then
290
-                file_to_parse="${file_to_parse} nova"
291
-            fi
292
-            if [[ ! $file_to_parse =~ glance ]]; then
293
-                file_to_parse="${file_to_parse} glance"
294
-            fi
295
-        elif [[ $service == c-* ]]; then
296
-            if [[ ! $file_to_parse =~ cinder ]]; then
297
-                file_to_parse="${file_to_parse} cinder"
298
-            fi
299
-        elif [[ $service == ceilometer-* ]]; then
300
-            if [[ ! $file_to_parse =~ ceilometer ]]; then
301
-                file_to_parse="${file_to_parse} ceilometer"
302
-            fi
303
-        elif [[ $service == s-* ]]; then
304
-            if [[ ! $file_to_parse =~ swift ]]; then
305
-                file_to_parse="${file_to_parse} swift"
306
-            fi
307
-        elif [[ $service == n-* ]]; then
308
-            if [[ ! $file_to_parse =~ nova ]]; then
309
-                file_to_parse="${file_to_parse} nova"
310
-            fi
311
-        elif [[ $service == g-* ]]; then
312
-            if [[ ! $file_to_parse =~ glance ]]; then
313
-                file_to_parse="${file_to_parse} glance"
314
-            fi
315
-        elif [[ $service == key* ]]; then
316
-            if [[ ! $file_to_parse =~ keystone ]]; then
317
-                file_to_parse="${file_to_parse} keystone"
318
-            fi
319
-        elif [[ $service == q-* ]]; then
320
-            if [[ ! $file_to_parse =~ neutron ]]; then
321
-                file_to_parse="${file_to_parse} neutron"
322
-            fi
323
-        fi
324
-    done
325
-
326
-    for file in ${file_to_parse}; do
327
-        local fname=${package_dir}/${file}
328
-        local OIFS line package distros distro
329
-        [[ -e $fname ]] || continue
330
-
331
-        OIFS=$IFS
332
-        IFS=$'\n'
333
-        for line in $(<${fname}); do
334
-            if [[ $line =~ "NOPRIME" ]]; then
335
-                continue
336
-            fi
337
-
338
-            # Assume we want this package
339
-            package=${line%#*}
340
-            inst_pkg=1
341
-
342
-            # Look for # dist:xxx in comment
343
-            if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then
344
-                # We are using BASH regexp matching feature.
345
-                package=${BASH_REMATCH[1]}
346
-                distros=${BASH_REMATCH[2]}
347
-                # In bash ${VAR,,} will lowecase VAR
348
-                # Look for a match in the distro list
349
-                if [[ ! ${distros,,} =~ ${DISTRO,,} ]]; then
350
-                    # If no match then skip this package
351
-                    inst_pkg=0
352
-                fi
353
-            fi
354
-
355
-            # Look for # testonly in comment
356
-            if [[ $line =~ (.*)#.*testonly.* ]]; then
357
-                package=${BASH_REMATCH[1]}
358
-                # Are we installing test packages? (test for the default value)
359
-                if [[ $INSTALL_TESTONLY_PACKAGES = "False" ]]; then
360
-                    # If not installing test packages the skip this package
361
-                    inst_pkg=0
362
-                fi
363
-            fi
364
-
365
-            if [[ $inst_pkg = 1 ]]; then
366
-                echo $package
367
-            fi
368
-        done
369
-        IFS=$OIFS
370
-    done
371
-}
372
-
373
-
374
-# Determine OS Vendor, Release and Update
375
-# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora
376
-# Returns results in global variables:
377
-# os_VENDOR - vendor name
378
-# os_RELEASE - release
379
-# os_UPDATE - update
380
-# os_PACKAGE - package type
381
-# os_CODENAME - vendor's codename for release
382
-# GetOSVersion
383
-GetOSVersion() {
384
-    # Figure out which vendor we are
385
-    if [[ -x "`which sw_vers 2>/dev/null`" ]]; then
386
-        # OS/X
387
-        os_VENDOR=`sw_vers -productName`
388
-        os_RELEASE=`sw_vers -productVersion`
389
-        os_UPDATE=${os_RELEASE##*.}
390
-        os_RELEASE=${os_RELEASE%.*}
391
-        os_PACKAGE=""
392
-        if [[ "$os_RELEASE" =~ "10.7" ]]; then
393
-            os_CODENAME="lion"
394
-        elif [[ "$os_RELEASE" =~ "10.6" ]]; then
395
-            os_CODENAME="snow leopard"
396
-        elif [[ "$os_RELEASE" =~ "10.5" ]]; then
397
-            os_CODENAME="leopard"
398
-        elif [[ "$os_RELEASE" =~ "10.4" ]]; then
399
-            os_CODENAME="tiger"
400
-        elif [[ "$os_RELEASE" =~ "10.3" ]]; then
401
-            os_CODENAME="panther"
402
-        else
403
-            os_CODENAME=""
404
-        fi
405
-    elif [[ -x $(which lsb_release 2>/dev/null) ]]; then
406
-        os_VENDOR=$(lsb_release -i -s)
407
-        os_RELEASE=$(lsb_release -r -s)
408
-        os_UPDATE=""
409
-        os_PACKAGE="rpm"
410
-        if [[ "Debian,Ubuntu,LinuxMint" =~ $os_VENDOR ]]; then
411
-            os_PACKAGE="deb"
412
-        elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then
413
-            lsb_release -d -s | grep -q openSUSE
414
-            if [[ $? -eq 0 ]]; then
415
-                os_VENDOR="openSUSE"
416
-            fi
417
-        elif [[ $os_VENDOR == "openSUSE project" ]]; then
418
-            os_VENDOR="openSUSE"
419
-        elif [[ $os_VENDOR =~ Red.*Hat ]]; then
420
-            os_VENDOR="Red Hat"
421
-        fi
422
-        os_CODENAME=$(lsb_release -c -s)
423
-    elif [[ -r /etc/redhat-release ]]; then
424
-        # Red Hat Enterprise Linux Server release 5.5 (Tikanga)
425
-        # Red Hat Enterprise Linux Server release 7.0 Beta (Maipo)
426
-        # CentOS release 5.5 (Final)
427
-        # CentOS Linux release 6.0 (Final)
428
-        # Fedora release 16 (Verne)
429
-        # XenServer release 6.2.0-70446c (xenenterprise)
430
-        os_CODENAME=""
431
-        for r in "Red Hat" CentOS Fedora XenServer; do
432
-            os_VENDOR=$r
433
-            if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then
434
-                ver=`sed -e 's/^.* \([0-9].*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release`
435
-                os_CODENAME=${ver#*|}
436
-                os_RELEASE=${ver%|*}
437
-                os_UPDATE=${os_RELEASE##*.}
438
-                os_RELEASE=${os_RELEASE%.*}
439
-                break
440
-            fi
441
-            os_VENDOR=""
442
-        done
443
-        os_PACKAGE="rpm"
444
-    elif [[ -r /etc/SuSE-release ]]; then
445
-        for r in openSUSE "SUSE Linux"; do
446
-            if [[ "$r" = "SUSE Linux" ]]; then
447
-                os_VENDOR="SUSE LINUX"
448
-            else
449
-                os_VENDOR=$r
450
-            fi
451
-
452
-            if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then
453
-                os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'`
454
-                os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'`
455
-                os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'`
456
-                break
457
-            fi
458
-            os_VENDOR=""
459
-        done
460
-        os_PACKAGE="rpm"
461
-    # If lsb_release is not installed, we should be able to detect Debian OS
462
-    elif [[ -f /etc/debian_version ]] && [[ $(cat /proc/version) =~ "Debian" ]]; then
463
-        os_VENDOR="Debian"
464
-        os_PACKAGE="deb"
465
-        os_CODENAME=$(awk '/VERSION=/' /etc/os-release | sed 's/VERSION=//' | sed -r 's/\"|\(|\)//g' | awk '{print $2}')
466
-        os_RELEASE=$(awk '/VERSION_ID=/' /etc/os-release | sed 's/VERSION_ID=//' | sed 's/\"//g')
467
-    fi
468
-    export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
469
-}
470
-
471
-
472
-# Translate the OS version values into common nomenclature
473
-# Sets ``DISTRO`` from the ``os_*`` values
474
-function GetDistro() {
475
-    GetOSVersion
476
-    if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then
477
-        # 'Everyone' refers to Ubuntu / Debian releases by the code name adjective
478
-        DISTRO=$os_CODENAME
479
-    elif [[ "$os_VENDOR" =~ (Fedora) ]]; then
480
-        # For Fedora, just use 'f' and the release
481
-        DISTRO="f$os_RELEASE"
482
-    elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then
483
-        DISTRO="opensuse-$os_RELEASE"
484
-    elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then
485
-        # For SLE, also use the service pack
486
-        if [[ -z "$os_UPDATE" ]]; then
487
-            DISTRO="sle${os_RELEASE}"
488
-        else
489
-            DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
490
-        fi
491
-    elif [[ "$os_VENDOR" =~ (Red Hat) || "$os_VENDOR" =~ (CentOS) ]]; then
492
-        # Drop the . release as we assume it's compatible
493
-        DISTRO="rhel${os_RELEASE::1}"
494
-    elif [[ "$os_VENDOR" =~ (XenServer) ]]; then
495
-        DISTRO="xs$os_RELEASE"
496
-    else
497
-        # Catch-all for now is Vendor + Release + Update
498
-        DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
499
-    fi
500
-    export DISTRO
501
-}
502
-
503
-
504
-# Determine if current distribution is a Fedora-based distribution
505
-# (Fedora, RHEL, CentOS, etc).
506
-# is_fedora
507
-function is_fedora {
508
-    if [[ -z "$os_VENDOR" ]]; then
509
-        GetOSVersion
510
-    fi
511
-
512
-    [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
513
-}
514
-
515
-
516
-# Determine if current distribution is a SUSE-based distribution
517
-# (openSUSE, SLE).
518
-# is_suse
519
-function is_suse {
520
-    if [[ -z "$os_VENDOR" ]]; then
521
-        GetOSVersion
522
-    fi
523
-
524
-    [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ]
525
-}
526
-
527
-
528
-# Determine if current distribution is an Ubuntu-based distribution
529
-# It will also detect non-Ubuntu but Debian-based distros
530
-# is_ubuntu
531
-function is_ubuntu {
532
-    if [[ -z "$os_PACKAGE" ]]; then
533
-        GetOSVersion
534
-    fi
535
-    [ "$os_PACKAGE" = "deb" ]
536
-}
537
-
538
-
539
-# Exit after outputting a message about the distribution not being supported.
540
-# exit_distro_not_supported [optional-string-telling-what-is-missing]
541
-function exit_distro_not_supported {
542
-    if [[ -z "$DISTRO" ]]; then
543
-        GetDistro
544
-    fi
545
-
546
-    if [ $# -gt 0 ]; then
547
-        die $LINENO "Support for $DISTRO is incomplete: no support for $@"
548
-    else
549
-        die $LINENO "Support for $DISTRO is incomplete."
550
-    fi
551
-}
552
-
553
-# Utility function for checking machine architecture
554
-# is_arch arch-type
555
-function is_arch {
556
-    ARCH_TYPE=$1
557
-
558
-    [[ "$(uname -m)" == "$ARCH_TYPE" ]]
559
-}
560
-
561 19
 # Checks if installed Apache is <= given version
562 20
 # $1 = x.y.z (version string of Apache)
563 21
 function check_apache_version {
... ...
@@ -570,488 +28,6 @@ function check_apache_version {
570 570
     expr "$version" '>=' $1 > /dev/null
571 571
 }
572 572
 
573
-# git clone only if directory doesn't exist already.  Since ``DEST`` might not
574
-# be owned by the installation user, we create the directory and change the
575
-# ownership to the proper user.
576
-# Set global RECLONE=yes to simulate a clone when dest-dir exists
577
-# Set global ERROR_ON_CLONE=True to abort execution with an error if the git repo
578
-# does not exist (default is False, meaning the repo will be cloned).
579
-# Uses global ``OFFLINE``
580
-# git_clone remote dest-dir branch
581
-function git_clone {
582
-    GIT_REMOTE=$1
583
-    GIT_DEST=$2
584
-    GIT_REF=$3
585
-    RECLONE=$(trueorfalse False $RECLONE)
586
-
587
-    if [[ "$OFFLINE" = "True" ]]; then
588
-        echo "Running in offline mode, clones already exist"
589
-        # print out the results so we know what change was used in the logs
590
-        cd $GIT_DEST
591
-        git show --oneline | head -1
592
-        return
593
-    fi
594
-
595
-    if echo $GIT_REF | egrep -q "^refs"; then
596
-        # If our branch name is a gerrit style refs/changes/...
597
-        if [[ ! -d $GIT_DEST ]]; then
598
-            [[ "$ERROR_ON_CLONE" = "True" ]] && \
599
-                die $LINENO "Cloning not allowed in this configuration"
600
-            git clone $GIT_REMOTE $GIT_DEST
601
-        fi
602
-        cd $GIT_DEST
603
-        git fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
604
-    else
605
-        # do a full clone only if the directory doesn't exist
606
-        if [[ ! -d $GIT_DEST ]]; then
607
-            [[ "$ERROR_ON_CLONE" = "True" ]] && \
608
-                die $LINENO "Cloning not allowed in this configuration"
609
-            git clone $GIT_REMOTE $GIT_DEST
610
-            cd $GIT_DEST
611
-            # This checkout syntax works for both branches and tags
612
-            git checkout $GIT_REF
613
-        elif [[ "$RECLONE" = "True" ]]; then
614
-            # if it does exist then simulate what clone does if asked to RECLONE
615
-            cd $GIT_DEST
616
-            # set the url to pull from and fetch
617
-            git remote set-url origin $GIT_REMOTE
618
-            git fetch origin
619
-            # remove the existing ignored files (like pyc) as they cause breakage
620
-            # (due to the py files having older timestamps than our pyc, so python
621
-            # thinks the pyc files are correct using them)
622
-            find $GIT_DEST -name '*.pyc' -delete
623
-
624
-            # handle GIT_REF accordingly to type (tag, branch)
625
-            if [[ -n "`git show-ref refs/tags/$GIT_REF`" ]]; then
626
-                git_update_tag $GIT_REF
627
-            elif [[ -n "`git show-ref refs/heads/$GIT_REF`" ]]; then
628
-                git_update_branch $GIT_REF
629
-            elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then
630
-                git_update_remote_branch $GIT_REF
631
-            else
632
-                die $LINENO "$GIT_REF is neither branch nor tag"
633
-            fi
634
-
635
-        fi
636
-    fi
637
-
638
-    # print out the results so we know what change was used in the logs
639
-    cd $GIT_DEST
640
-    git show --oneline | head -1
641
-}
642
-
643
-
644
-# git update using reference as a branch.
645
-# git_update_branch ref
646
-function git_update_branch() {
647
-
648
-    GIT_BRANCH=$1
649
-
650
-    git checkout -f origin/$GIT_BRANCH
651
-    # a local branch might not exist
652
-    git branch -D $GIT_BRANCH || true
653
-    git checkout -b $GIT_BRANCH
654
-}
655
-
656
-
657
-# git update using reference as a branch.
658
-# git_update_remote_branch ref
659
-function git_update_remote_branch() {
660
-
661
-    GIT_BRANCH=$1
662
-
663
-    git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH
664
-}
665
-
666
-
667
-# git update using reference as a tag. Be careful editing source at that repo
668
-# as working copy will be in a detached mode
669
-# git_update_tag ref
670
-function git_update_tag() {
671
-
672
-    GIT_TAG=$1
673
-
674
-    git tag -d $GIT_TAG
675
-    # fetching given tag only
676
-    git fetch origin tag $GIT_TAG
677
-    git checkout -f $GIT_TAG
678
-}
679
-
680
-
681
-# Comment an option in an INI file
682
-# inicomment config-file section option
683
-function inicomment() {
684
-    local file=$1
685
-    local section=$2
686
-    local option=$3
687
-    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file"
688
-}
689
-
690
-
691
-# Uncomment an option in an INI file
692
-# iniuncomment config-file section option
693
-function iniuncomment() {
694
-    local file=$1
695
-    local section=$2
696
-    local option=$3
697
-    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file"
698
-}
699
-
700
-
701
-# Get an option from an INI file
702
-# iniget config-file section option
703
-function iniget() {
704
-    local file=$1
705
-    local section=$2
706
-    local option=$3
707
-    local line
708
-    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
709
-    echo ${line#*=}
710
-}
711
-
712
-
713
-# Determinate is the given option present in the INI file
714
-# ini_has_option config-file section option
715
-function ini_has_option() {
716
-    local file=$1
717
-    local section=$2
718
-    local option=$3
719
-    local line
720
-    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
721
-    [ -n "$line" ]
722
-}
723
-
724
-
725
-# Set an option in an INI file
726
-# iniset config-file section option value
727
-function iniset() {
728
-    local file=$1
729
-    local section=$2
730
-    local option=$3
731
-    local value=$4
732
-
733
-    [[ -z $section || -z $option ]] && return
734
-
735
-    if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then
736
-        # Add section at the end
737
-        echo -e "\n[$section]" >>"$file"
738
-    fi
739
-    if ! ini_has_option "$file" "$section" "$option"; then
740
-        # Add it
741
-        sed -i -e "/^\[$section\]/ a\\
742
-$option = $value
743
-" "$file"
744
-    else
745
-        local sep=$(echo -ne "\x01")
746
-        # Replace it
747
-        sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file"
748
-    fi
749
-}
750
-
751
-
752
-# Get a multiple line option from an INI file
753
-# iniget_multiline config-file section option
754
-function iniget_multiline() {
755
-    local file=$1
756
-    local section=$2
757
-    local option=$3
758
-    local values
759
-    values=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { s/^$option[ \t]*=[ \t]*//gp; }" "$file")
760
-    echo ${values}
761
-}
762
-
763
-
764
-# Set a multiple line option in an INI file
765
-# iniset_multiline config-file section option value1 value2 valu3 ...
766
-function iniset_multiline() {
767
-    local file=$1
768
-    local section=$2
769
-    local option=$3
770
-    shift 3
771
-    local values
772
-    for v in $@; do
773
-        # The later sed command inserts each new value in the line next to
774
-        # the section identifier, which causes the values to be inserted in
775
-        # the reverse order. Do a reverse here to keep the original order.
776
-        values="$v ${values}"
777
-    done
778
-    if ! grep -q "^\[$section\]" "$file"; then
779
-        # Add section at the end
780
-        echo -e "\n[$section]" >>"$file"
781
-    else
782
-        # Remove old values
783
-        sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file"
784
-    fi
785
-    # Add new ones
786
-    for v in $values; do
787
-        sed -i -e "/^\[$section\]/ a\\
788
-$option = $v
789
-" "$file"
790
-    done
791
-}
792
-
793
-
794
-# Append a new option in an ini file without replacing the old value
795
-# iniadd config-file section option value1 value2 value3 ...
796
-function iniadd() {
797
-    local file=$1
798
-    local section=$2
799
-    local option=$3
800
-    shift 3
801
-    local values="$(iniget_multiline $file $section $option) $@"
802
-    iniset_multiline $file $section $option $values
803
-}
804
-
805
-# Find out if a process exists by partial name.
806
-# is_running name
807
-function is_running() {
808
-    local name=$1
809
-    ps auxw | grep -v grep | grep ${name} > /dev/null
810
-    RC=$?
811
-    # some times I really hate bash reverse binary logic
812
-    return $RC
813
-}
814
-
815
-
816
-# is_service_enabled() checks if the service(s) specified as arguments are
817
-# enabled by the user in ``ENABLED_SERVICES``.
818
-#
819
-# Multiple services specified as arguments are ``OR``'ed together; the test
820
-# is a short-circuit boolean, i.e it returns on the first match.
821
-#
822
-# There are special cases for some 'catch-all' services::
823
-#   **nova** returns true if any service enabled start with **n-**
824
-#   **cinder** returns true if any service enabled start with **c-**
825
-#   **ceilometer** returns true if any service enabled start with **ceilometer**
826
-#   **glance** returns true if any service enabled start with **g-**
827
-#   **neutron** returns true if any service enabled start with **q-**
828
-#   **swift** returns true if any service enabled start with **s-**
829
-#   **trove** returns true if any service enabled start with **tr-**
830
-#   For backward compatibility if we have **swift** in ENABLED_SERVICES all the
831
-#   **s-** services will be enabled. This will be deprecated in the future.
832
-#
833
-# Cells within nova is enabled if **n-cell** is in ``ENABLED_SERVICES``.
834
-# We also need to make sure to treat **n-cell-region** and **n-cell-child**
835
-# as enabled in this case.
836
-#
837
-# Uses global ``ENABLED_SERVICES``
838
-# is_service_enabled service [service ...]
839
-function is_service_enabled() {
840
-    services=$@
841
-    for service in ${services}; do
842
-        [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
843
-
844
-        # Look for top-level 'enabled' function for this service
845
-        if type is_${service}_enabled >/dev/null 2>&1; then
846
-            # A function exists for this service, use it
847
-            is_${service}_enabled
848
-            return $?
849
-        fi
850
-
851
-        # TODO(dtroyer): Remove these legacy special-cases after the is_XXX_enabled()
852
-        #                are implemented
853
-        [[ ${service} == n-cell-* && ${ENABLED_SERVICES} =~ "n-cell" ]] && return 0
854
-        [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && return 0
855
-        [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && return 0
856
-        [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && return 0
857
-        [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && return 0
858
-        [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && return 0
859
-        [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && return 0
860
-        [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && return 0
861
-        [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && return 0
862
-        [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && return 0
863
-    done
864
-    return 1
865
-}
866
-
867
-
868
-# remove extra commas from the input string (i.e. ``ENABLED_SERVICES``)
869
-# _cleanup_service_list service-list
870
-function _cleanup_service_list () {
871
-    echo "$1" | sed -e '
872
-        s/,,/,/g;
873
-        s/^,//;
874
-        s/,$//
875
-    '
876
-}
877
-
878
-
879
-# enable_service() adds the services passed as argument to the
880
-# ``ENABLED_SERVICES`` list, if they are not already present.
881
-#
882
-# For example:
883
-#   enable_service qpid
884
-#
885
-# This function does not know about the special cases
886
-# for nova, glance, and neutron built into is_service_enabled().
887
-# Uses global ``ENABLED_SERVICES``
888
-# enable_service service [service ...]
889
-function enable_service() {
890
-    local tmpsvcs="${ENABLED_SERVICES}"
891
-    for service in $@; do
892
-        if ! is_service_enabled $service; then
893
-            tmpsvcs+=",$service"
894
-        fi
895
-    done
896
-    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
897
-    disable_negated_services
898
-}
899
-
900
-
901
-# disable_service() removes the services passed as argument to the
902
-# ``ENABLED_SERVICES`` list, if they are present.
903
-#
904
-# For example:
905
-#   disable_service rabbit
906
-#
907
-# This function does not know about the special cases
908
-# for nova, glance, and neutron built into is_service_enabled().
909
-# Uses global ``ENABLED_SERVICES``
910
-# disable_service service [service ...]
911
-function disable_service() {
912
-    local tmpsvcs=",${ENABLED_SERVICES},"
913
-    local service
914
-    for service in $@; do
915
-        if is_service_enabled $service; then
916
-            tmpsvcs=${tmpsvcs//,$service,/,}
917
-        fi
918
-    done
919
-    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
920
-}
921
-
922
-
923
-# disable_all_services() removes all current services
924
-# from ``ENABLED_SERVICES`` to reset the configuration
925
-# before a minimal installation
926
-# Uses global ``ENABLED_SERVICES``
927
-# disable_all_services
928
-function disable_all_services() {
929
-    ENABLED_SERVICES=""
930
-}
931
-
932
-
933
-# Remove all services starting with '-'.  For example, to install all default
934
-# services except rabbit (rabbit) set in ``localrc``:
935
-# ENABLED_SERVICES+=",-rabbit"
936
-# Uses global ``ENABLED_SERVICES``
937
-# disable_negated_services
938
-function disable_negated_services() {
939
-    local tmpsvcs="${ENABLED_SERVICES}"
940
-    local service
941
-    for service in ${tmpsvcs//,/ }; do
942
-        if [[ ${service} == -* ]]; then
943
-            tmpsvcs=$(echo ${tmpsvcs}|sed -r "s/(,)?(-)?${service#-}(,)?/,/g")
944
-        fi
945
-    done
946
-    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
947
-}
948
-
949
-
950
-# Distro-agnostic package installer
951
-# install_package package [package ...]
952
-function install_package() {
953
-    if is_ubuntu; then
954
-        [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
955
-        NO_UPDATE_REPOS=True
956
-
957
-        apt_get install "$@"
958
-    elif is_fedora; then
959
-        yum_install "$@"
960
-    elif is_suse; then
961
-        zypper_install "$@"
962
-    else
963
-        exit_distro_not_supported "installing packages"
964
-    fi
965
-}
966
-
967
-
968
-# Distro-agnostic package uninstaller
969
-# uninstall_package package [package ...]
970
-function uninstall_package() {
971
-    if is_ubuntu; then
972
-        apt_get purge "$@"
973
-    elif is_fedora; then
974
-        sudo yum remove -y "$@"
975
-    elif is_suse; then
976
-        sudo zypper rm "$@"
977
-    else
978
-        exit_distro_not_supported "uninstalling packages"
979
-    fi
980
-}
981
-
982
-
983
-# Distro-agnostic function to tell if a package is installed
984
-# is_package_installed package [package ...]
985
-function is_package_installed() {
986
-    if [[ -z "$@" ]]; then
987
-        return 1
988
-    fi
989
-
990
-    if [[ -z "$os_PACKAGE" ]]; then
991
-        GetOSVersion
992
-    fi
993
-
994
-    if [[ "$os_PACKAGE" = "deb" ]]; then
995
-        dpkg -s "$@" > /dev/null 2> /dev/null
996
-    elif [[ "$os_PACKAGE" = "rpm" ]]; then
997
-        rpm --quiet -q "$@"
998
-    else
999
-        exit_distro_not_supported "finding if a package is installed"
1000
-    fi
1001
-}
1002
-
1003
-
1004
-# Test if the named environment variable is set and not zero length
1005
-# is_set env-var
1006
-function is_set() {
1007
-    local var=\$"$1"
1008
-    eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
1009
-}
1010
-
1011
-
1012
-# Wrapper for ``pip install`` to set cache and proxy environment variables
1013
-# Uses globals ``OFFLINE``, ``PIP_DOWNLOAD_CACHE``, ``PIP_USE_MIRRORS``,
1014
-# ``TRACK_DEPENDS``, ``*_proxy``
1015
-# pip_install package [package ...]
1016
-function pip_install {
1017
-    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
1018
-    if [[ -z "$os_PACKAGE" ]]; then
1019
-        GetOSVersion
1020
-    fi
1021
-    if [[ $TRACK_DEPENDS = True ]]; then
1022
-        source $DEST/.venv/bin/activate
1023
-        CMD_PIP=$DEST/.venv/bin/pip
1024
-        SUDO_PIP="env"
1025
-    else
1026
-        SUDO_PIP="sudo"
1027
-        CMD_PIP=$(get_pip_command)
1028
-    fi
1029
-
1030
-    # Mirror option not needed anymore because pypi has CDN available,
1031
-    # but it's useful in certain circumstances
1032
-    PIP_USE_MIRRORS=${PIP_USE_MIRRORS:-False}
1033
-    if [[ "$PIP_USE_MIRRORS" != "False" ]]; then
1034
-        PIP_MIRROR_OPT="--use-mirrors"
1035
-    fi
1036
-
1037
-    # pip < 1.4 has a bug where it will use an already existing build
1038
-    # directory unconditionally.  Say an earlier component installs
1039
-    # foo v1.1; pip will have built foo's source in
1040
-    # /tmp/$USER-pip-build.  Even if a later component specifies foo <
1041
-    # 1.1, the existing extracted build will be used and cause
1042
-    # confusing errors.  By creating unique build directories we avoid
1043
-    # this problem. See https://github.com/pypa/pip/issues/709
1044
-    local pip_build_tmp=$(mktemp --tmpdir -d pip-build.XXXXX)
1045
-
1046
-    $SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \
1047
-        HTTP_PROXY=$http_proxy \
1048
-        HTTPS_PROXY=$https_proxy \
1049
-        NO_PROXY=$no_proxy \
1050
-        $CMD_PIP install --build=${pip_build_tmp} \
1051
-        $PIP_MIRROR_OPT $@ \
1052
-        && $SUDO_PIP rm -rf ${pip_build_tmp}
1053
-}
1054
-
1055 573
 
1056 574
 # Cleanup anything from /tmp on unstack
1057 575
 # clean_tmp
... ...
@@ -1062,243 +38,6 @@ function cleanup_tmp {
1062 1062
     sudo rm -rf ${tmp_dir}/pip-build.*
1063 1063
 }
1064 1064
 
1065
-# Service wrapper to restart services
1066
-# restart_service service-name
1067
-function restart_service() {
1068
-    if is_ubuntu; then
1069
-        sudo /usr/sbin/service $1 restart
1070
-    else
1071
-        sudo /sbin/service $1 restart
1072
-    fi
1073
-}
1074
-
1075
-
1076
-# _run_process() is designed to be backgrounded by run_process() to simulate a
1077
-# fork.  It includes the dirty work of closing extra filehandles and preparing log
1078
-# files to produce the same logs as screen_it().  The log filename is derived
1079
-# from the service name and global-and-now-misnamed SCREEN_LOGDIR
1080
-# _run_process service "command-line"
1081
-function _run_process() {
1082
-    local service=$1
1083
-    local command="$2"
1084
-
1085
-    # Undo logging redirections and close the extra descriptors
1086
-    exec 1>&3
1087
-    exec 2>&3
1088
-    exec 3>&-
1089
-    exec 6>&-
1090
-
1091
-    if [[ -n ${SCREEN_LOGDIR} ]]; then
1092
-        exec 1>&${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log 2>&1
1093
-        ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
1094
-
1095
-        # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs.
1096
-        export PYTHONUNBUFFERED=1
1097
-    fi
1098
-
1099
-    exec /bin/bash -c "$command"
1100
-    die "$service exec failure: $command"
1101
-}
1102
-
1103
-
1104
-# run_process() launches a child process that closes all file descriptors and
1105
-# then exec's the passed in command.  This is meant to duplicate the semantics
1106
-# of screen_it() without screen.  PIDs are written to
1107
-# $SERVICE_DIR/$SCREEN_NAME/$service.pid
1108
-# run_process service "command-line"
1109
-function run_process() {
1110
-    local service=$1
1111
-    local command="$2"
1112
-
1113
-    # Spawn the child process
1114
-    _run_process "$service" "$command" &
1115
-    echo $!
1116
-}
1117
-
1118
-
1119
-# Helper to launch a service in a named screen
1120
-# screen_it service "command-line"
1121
-function screen_it {
1122
-    SCREEN_NAME=${SCREEN_NAME:-stack}
1123
-    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1124
-    USE_SCREEN=$(trueorfalse True $USE_SCREEN)
1125
-
1126
-    if is_service_enabled $1; then
1127
-        # Append the service to the screen rc file
1128
-        screen_rc "$1" "$2"
1129
-
1130
-        if [[ "$USE_SCREEN" = "True" ]]; then
1131
-            screen -S $SCREEN_NAME -X screen -t $1
1132
-
1133
-            if [[ -n ${SCREEN_LOGDIR} ]]; then
1134
-                screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log
1135
-                screen -S $SCREEN_NAME -p $1 -X log on
1136
-                ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
1137
-            fi
1138
-
1139
-            # sleep to allow bash to be ready to be send the command - we are
1140
-            # creating a new window in screen and then sends characters, so if
1141
-            # bash isn't running by the time we send the command, nothing happens
1142
-            sleep 1.5
1143
-
1144
-            NL=`echo -ne '\015'`
1145
-            # This fun command does the following:
1146
-            # - the passed server command is backgrounded
1147
-            # - the pid of the background process is saved in the usual place
1148
-            # - the server process is brought back to the foreground
1149
-            # - if the server process exits prematurely the fg command errors
1150
-            #   and a message is written to stdout and the service failure file
1151
-            # The pid saved can be used in screen_stop() as a process group
1152
-            # id to kill off all child processes
1153
-            screen -S $SCREEN_NAME -p $1 -X stuff "$2 & echo \$! >$SERVICE_DIR/$SCREEN_NAME/$1.pid; fg || echo \"$1 failed to start\" | tee \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
1154
-        else
1155
-            # Spawn directly without screen
1156
-            run_process "$1" "$2" >$SERVICE_DIR/$SCREEN_NAME/$1.pid
1157
-        fi
1158
-    fi
1159
-}
1160
-
1161
-
1162
-# Stop a service in screen
1163
-# If a PID is available use it, kill the whole process group via TERM
1164
-# If screen is being used kill the screen window; this will catch processes
1165
-# that did not leave a PID behind
1166
-# screen_stop service
1167
-function screen_stop() {
1168
-    SCREEN_NAME=${SCREEN_NAME:-stack}
1169
-    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1170
-    USE_SCREEN=$(trueorfalse True $USE_SCREEN)
1171
-
1172
-    if is_service_enabled $1; then
1173
-        # Kill via pid if we have one available
1174
-        if [[ -r $SERVICE_DIR/$SCREEN_NAME/$1.pid ]]; then
1175
-            pkill -TERM -P -$(cat $SERVICE_DIR/$SCREEN_NAME/$1.pid)
1176
-            rm $SERVICE_DIR/$SCREEN_NAME/$1.pid
1177
-        fi
1178
-        if [[ "$USE_SCREEN" = "True" ]]; then
1179
-            # Clean up the screen window
1180
-            screen -S $SCREEN_NAME -p $1 -X kill
1181
-        fi
1182
-    fi
1183
-}
1184
-
1185
-
1186
-# Screen rc file builder
1187
-# screen_rc service "command-line"
1188
-function screen_rc {
1189
-    SCREEN_NAME=${SCREEN_NAME:-stack}
1190
-    SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc
1191
-    if [[ ! -e $SCREENRC ]]; then
1192
-        # Name the screen session
1193
-        echo "sessionname $SCREEN_NAME" > $SCREENRC
1194
-        # Set a reasonable statusbar
1195
-        echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC
1196
-        # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off
1197
-        echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC
1198
-        echo "screen -t shell bash" >> $SCREENRC
1199
-    fi
1200
-    # If this service doesn't already exist in the screenrc file
1201
-    if ! grep $1 $SCREENRC 2>&1 > /dev/null; then
1202
-        NL=`echo -ne '\015'`
1203
-        echo "screen -t $1 bash" >> $SCREENRC
1204
-        echo "stuff \"$2$NL\"" >> $SCREENRC
1205
-
1206
-        if [[ -n ${SCREEN_LOGDIR} ]]; then
1207
-            echo "logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log" >>$SCREENRC
1208
-            echo "log on" >>$SCREENRC
1209
-        fi
1210
-    fi
1211
-}
1212
-
1213
-
1214
-# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``.
1215
-# This is used for ``service_check`` when all the ``screen_it`` are called finished
1216
-# init_service_check
1217
-function init_service_check() {
1218
-    SCREEN_NAME=${SCREEN_NAME:-stack}
1219
-    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1220
-
1221
-    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
1222
-        mkdir -p "$SERVICE_DIR/$SCREEN_NAME"
1223
-    fi
1224
-
1225
-    rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure
1226
-}
1227
-
1228
-
1229
-# Helper to get the status of each running service
1230
-# service_check
1231
-function service_check() {
1232
-    local service
1233
-    local failures
1234
-    SCREEN_NAME=${SCREEN_NAME:-stack}
1235
-    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1236
-
1237
-
1238
-    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
1239
-        echo "No service status directory found"
1240
-        return
1241
-    fi
1242
-
1243
-    # Check if there is any falure flag file under $SERVICE_DIR/$SCREEN_NAME
1244
-    failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null`
1245
-
1246
-    for service in $failures; do
1247
-        service=`basename $service`
1248
-        service=${service%.failure}
1249
-        echo "Error: Service $service is not running"
1250
-    done
1251
-
1252
-    if [ -n "$failures" ]; then
1253
-        echo "More details about the above errors can be found with screen, with ./rejoin-stack.sh"
1254
-    fi
1255
-}
1256
-
1257
-# Returns true if the directory is on a filesystem mounted via NFS.
1258
-function is_nfs_directory() {
1259
-    local mount_type=`stat -f -L -c %T $1`
1260
-    test "$mount_type" == "nfs"
1261
-}
1262
-
1263
-# Only run the command if the target file (the last arg) is not on an
1264
-# NFS filesystem.
1265
-function _safe_permission_operation() {
1266
-    local args=( $@ )
1267
-    local last
1268
-    local sudo_cmd
1269
-    local dir_to_check
1270
-
1271
-    let last="${#args[*]} - 1"
1272
-
1273
-    dir_to_check=${args[$last]}
1274
-    if [ ! -d "$dir_to_check" ]; then
1275
-        dir_to_check=`dirname "$dir_to_check"`
1276
-    fi
1277
-
1278
-    if is_nfs_directory "$dir_to_check" ; then
1279
-        return 0
1280
-    fi
1281
-
1282
-    if [[ $TRACK_DEPENDS = True ]]; then
1283
-        sudo_cmd="env"
1284
-    else
1285
-        sudo_cmd="sudo"
1286
-    fi
1287
-
1288
-    $sudo_cmd $@
1289
-}
1290
-
1291
-# Only change ownership of a file or directory if it is not on an NFS
1292
-# filesystem.
1293
-function safe_chown() {
1294
-    _safe_permission_operation chown $@
1295
-}
1296
-
1297
-# Only change permissions of a file or directory if it is not on an
1298
-# NFS filesystem.
1299
-function safe_chmod() {
1300
-    _safe_permission_operation chmod $@
1301
-}
1302 1065
 
1303 1066
 # ``pip install -e`` the package, which processes the dependencies
1304 1067
 # using pip before running `setup.py develop`
... ...
@@ -1340,6 +79,7 @@ function setup_develop() {
1340 1340
     fi
1341 1341
 }
1342 1342
 
1343
+
1343 1344
 # ``pip install -e`` the package, which processes the dependencies
1344 1345
 # using pip before running `setup.py develop`
1345 1346
 # Uses globals ``STACK_USER``
... ...
@@ -1353,43 +93,6 @@ function setup_develop_no_requirements_update() {
1353 1353
 }
1354 1354
 
1355 1355
 
1356
-# Service wrapper to start services
1357
-# start_service service-name
1358
-function start_service() {
1359
-    if is_ubuntu; then
1360
-        sudo /usr/sbin/service $1 start
1361
-    else
1362
-        sudo /sbin/service $1 start
1363
-    fi
1364
-}
1365
-
1366
-
1367
-# Service wrapper to stop services
1368
-# stop_service service-name
1369
-function stop_service() {
1370
-    if is_ubuntu; then
1371
-        sudo /usr/sbin/service $1 stop
1372
-    else
1373
-        sudo /sbin/service $1 stop
1374
-    fi
1375
-}
1376
-
1377
-
1378
-# Normalize config values to True or False
1379
-# Accepts as False: 0 no No NO false False FALSE
1380
-# Accepts as True: 1 yes Yes YES true True TRUE
1381
-# VAR=$(trueorfalse default-value test-value)
1382
-function trueorfalse() {
1383
-    local default=$1
1384
-    local testval=$2
1385
-
1386
-    [[ -z "$testval" ]] && { echo "$default"; return; }
1387
-    [[ "0 no No NO false False FALSE" =~ "$testval" ]] && { echo "False"; return; }
1388
-    [[ "1 yes Yes YES true True TRUE" =~ "$testval" ]] && { echo "True"; return; }
1389
-    echo "$default"
1390
-}
1391
-
1392
-
1393 1356
 # Retrieve an image from a URL and upload into Glance.
1394 1357
 # Uses the following variables:
1395 1358
 #
... ...
@@ -1685,23 +388,6 @@ function use_database {
1685 1685
 }
1686 1686
 
1687 1687
 
1688
-# Toggle enable/disable_service for services that must run exclusive of each other
1689
-#  $1 The name of a variable containing a space-separated list of services
1690
-#  $2 The name of a variable in which to store the enabled service's name
1691
-#  $3 The name of the service to enable
1692
-function use_exclusive_service {
1693
-    local options=${!1}
1694
-    local selection=$3
1695
-    out=$2
1696
-    [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1
1697
-    for opt in $options;do
1698
-        [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt
1699
-    done
1700
-    eval "$out=$selection"
1701
-    return 0
1702
-}
1703
-
1704
-
1705 1688
 # Wait for an HTTP server to start answering requests
1706 1689
 # wait_for_service timeout url
1707 1690
 function wait_for_service() {
... ...
@@ -1711,30 +397,6 @@ function wait_for_service() {
1711 1711
 }
1712 1712
 
1713 1713
 
1714
-# Wrapper for ``yum`` to set proxy environment variables
1715
-# Uses globals ``OFFLINE``, ``*_proxy``
1716
-# yum_install package [package ...]
1717
-function yum_install() {
1718
-    [[ "$OFFLINE" = "True" ]] && return
1719
-    local sudo="sudo"
1720
-    [[ "$(id -u)" = "0" ]] && sudo="env"
1721
-    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
1722
-        no_proxy=$no_proxy \
1723
-        yum install -y "$@"
1724
-}
1725
-
1726
-
1727
-# zypper wrapper to set arguments correctly
1728
-# zypper_install package [package ...]
1729
-function zypper_install() {
1730
-    [[ "$OFFLINE" = "True" ]] && return
1731
-    local sudo="sudo"
1732
-    [[ "$(id -u)" = "0" ]] && sudo="env"
1733
-    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
1734
-        zypper --non-interactive install --auto-agree-with-licenses "$@"
1735
-}
1736
-
1737
-
1738 1714
 # ping check
1739 1715
 # Uses globals ``ENABLED_SERVICES``
1740 1716
 # ping_check from-net ip boot-timeout expected
... ...
@@ -1809,36 +471,6 @@ function _ssh_check_novanet() {
1809 1809
 }
1810 1810
 
1811 1811
 
1812
-# Add a user to a group.
1813
-# add_user_to_group user group
1814
-function add_user_to_group() {
1815
-    local user=$1
1816
-    local group=$2
1817
-
1818
-    if [[ -z "$os_VENDOR" ]]; then
1819
-        GetOSVersion
1820
-    fi
1821
-
1822
-    # SLE11 and openSUSE 12.2 don't have the usual usermod
1823
-    if ! is_suse || [[ "$os_VENDOR" = "openSUSE" && "$os_RELEASE" != "12.2" ]]; then
1824
-        sudo usermod -a -G "$group" "$user"
1825
-    else
1826
-        sudo usermod -A "$group" "$user"
1827
-    fi
1828
-}
1829
-
1830
-
1831
-# Get the path to the direcotry where python executables are installed.
1832
-# get_python_exec_prefix
1833
-function get_python_exec_prefix() {
1834
-    if is_fedora || is_suse; then
1835
-        echo "/usr/bin"
1836
-    else
1837
-        echo "/usr/local/bin"
1838
-    fi
1839
-}
1840
-
1841
-
1842 1812
 # Get the location of the $module-rootwrap executables, where module is cinder
1843 1813
 # or nova.
1844 1814
 # get_rootwrap_location module
... ...
@@ -1849,17 +481,6 @@ function get_rootwrap_location() {
1849 1849
 }
1850 1850
 
1851 1851
 
1852
-# Get the path to the pip command.
1853
-# get_pip_command
1854
-function get_pip_command() {
1855
-    which pip || which pip-python
1856
-
1857
-    if [ $? -ne 0 ]; then
1858
-        die $LINENO "Unable to find pip; cannot continue"
1859
-    fi
1860
-}
1861
-
1862
-
1863 1852
 # Path permissions sanity check
1864 1853
 # check_path_perm_sanity path
1865 1854
 function check_path_perm_sanity() {
... ...
@@ -1944,37 +565,6 @@ vercmp_numbers() {
1944 1944
 }
1945 1945
 
1946 1946
 
1947
-# ``policy_add policy_file policy_name policy_permissions``
1948
-#
1949
-# Add a policy to a policy.json file
1950
-# Do nothing if the policy already exists
1951
-
1952
-function policy_add() {
1953
-    local policy_file=$1
1954
-    local policy_name=$2
1955
-    local policy_perm=$3
1956
-
1957
-    if grep -q ${policy_name} ${policy_file}; then
1958
-        echo "Policy ${policy_name} already exists in ${policy_file}"
1959
-        return
1960
-    fi
1961
-
1962
-    # Add a terminating comma to policy lines without one
1963
-    # Remove the closing '}' and all lines following to the end-of-file
1964
-    local tmpfile=$(mktemp)
1965
-    uniq ${policy_file} | sed -e '
1966
-        s/]$/],/
1967
-        /^[}]/,$d
1968
-    ' > ${tmpfile}
1969
-
1970
-    # Append policy and closing brace
1971
-    echo "    \"${policy_name}\": ${policy_perm}" >>${tmpfile}
1972
-    echo "}" >>${tmpfile}
1973
-
1974
-    mv ${tmpfile} ${policy_file}
1975
-}
1976
-
1977
-
1978 1947
 # This function sets log formatting options for colorizing log
1979 1948
 # output to stdout. It is meant to be called by lib modules.
1980 1949
 # The last two parameters are optional and can be used to specify
... ...
@@ -1994,10 +584,10 @@ function setup_colorized_logging() {
1994 1994
     iniset $conf_file $conf_section logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s"
1995 1995
 }
1996 1996
 
1997
+
1997 1998
 # Restore xtrace
1998 1999
 $XTRACE
1999 2000
 
2000
-
2001 2001
 # Local variables:
2002 2002
 # mode: shell-script
2003 2003
 # End:
2004 2004
new file mode 100644
... ...
@@ -0,0 +1,1433 @@
0
+# functions-common - Common functions used by DevStack components
1
+#
2
+# The canonical copy of this file is maintained in the DevStack repo.
3
+# All modifications should be made there and then sync'ed to other repos
4
+# as required.
5
+#
6
+# This file is sorted alphabetically within the function groups.
7
+#
8
+# - Config Functions
9
+# - Control Functions
10
+# - Distro Functions
11
+# - Git Functions
12
+# - OpenStack Functions
13
+# - Package Functions
14
+# - Process Functions
15
+# - Python Functions
16
+# - Service Functions
17
+#
18
+# The following variables are assumed to be defined by certain functions:
19
+#
20
+# - ``ENABLED_SERVICES``
21
+# - ``ERROR_ON_CLONE``
22
+# - ``FILES``
23
+# - ``OFFLINE``
24
+# - ``PIP_DOWNLOAD_CACHE``
25
+# - ``PIP_USE_MIRRORS``
26
+# - ``RECLONE``
27
+# - ``TRACK_DEPENDS``
28
+# - ``http_proxy``, ``https_proxy``, ``no_proxy``
29
+
30
+# Save trace setting
31
+XTRACE=$(set +o | grep xtrace)
32
+set +o xtrace
33
+
34
+
35
+# Config Functions
36
+# ================
37
+
38
+# Append a new option in an ini file without replacing the old value
39
+# iniadd config-file section option value1 value2 value3 ...
40
+function iniadd() {
41
+    local file=$1
42
+    local section=$2
43
+    local option=$3
44
+    shift 3
45
+    local values="$(iniget_multiline $file $section $option) $@"
46
+    iniset_multiline $file $section $option $values
47
+}
48
+
49
+# Comment an option in an INI file
50
+# inicomment config-file section option
51
+function inicomment() {
52
+    local file=$1
53
+    local section=$2
54
+    local option=$3
55
+    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file"
56
+}
57
+
58
+# Get an option from an INI file
59
+# iniget config-file section option
60
+function iniget() {
61
+    local file=$1
62
+    local section=$2
63
+    local option=$3
64
+    local line
65
+    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
66
+    echo ${line#*=}
67
+}
68
+
69
+# Get a multiple line option from an INI file
70
+# iniget_multiline config-file section option
71
+function iniget_multiline() {
72
+    local file=$1
73
+    local section=$2
74
+    local option=$3
75
+    local values
76
+    values=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { s/^$option[ \t]*=[ \t]*//gp; }" "$file")
77
+    echo ${values}
78
+}
79
+
80
+# Determinate is the given option present in the INI file
81
+# ini_has_option config-file section option
82
+function ini_has_option() {
83
+    local file=$1
84
+    local section=$2
85
+    local option=$3
86
+    local line
87
+    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
88
+    [ -n "$line" ]
89
+}
90
+
91
+# Set an option in an INI file
92
+# iniset config-file section option value
93
+function iniset() {
94
+    local file=$1
95
+    local section=$2
96
+    local option=$3
97
+    local value=$4
98
+
99
+    [[ -z $section || -z $option ]] && return
100
+
101
+    if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then
102
+        # Add section at the end
103
+        echo -e "\n[$section]" >>"$file"
104
+    fi
105
+    if ! ini_has_option "$file" "$section" "$option"; then
106
+        # Add it
107
+        sed -i -e "/^\[$section\]/ a\\
108
+$option = $value
109
+" "$file"
110
+    else
111
+        local sep=$(echo -ne "\x01")
112
+        # Replace it
113
+        sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file"
114
+    fi
115
+}
116
+
117
+# Set a multiple line option in an INI file
118
+# iniset_multiline config-file section option value1 value2 valu3 ...
119
+function iniset_multiline() {
120
+    local file=$1
121
+    local section=$2
122
+    local option=$3
123
+    shift 3
124
+    local values
125
+    for v in $@; do
126
+        # The later sed command inserts each new value in the line next to
127
+        # the section identifier, which causes the values to be inserted in
128
+        # the reverse order. Do a reverse here to keep the original order.
129
+        values="$v ${values}"
130
+    done
131
+    if ! grep -q "^\[$section\]" "$file"; then
132
+        # Add section at the end
133
+        echo -e "\n[$section]" >>"$file"
134
+    else
135
+        # Remove old values
136
+        sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file"
137
+    fi
138
+    # Add new ones
139
+    for v in $values; do
140
+        sed -i -e "/^\[$section\]/ a\\
141
+$option = $v
142
+" "$file"
143
+    done
144
+}
145
+
146
+# Uncomment an option in an INI file
147
+# iniuncomment config-file section option
148
+function iniuncomment() {
149
+    local file=$1
150
+    local section=$2
151
+    local option=$3
152
+    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file"
153
+}
154
+
155
+# Normalize config values to True or False
156
+# Accepts as False: 0 no No NO false False FALSE
157
+# Accepts as True: 1 yes Yes YES true True TRUE
158
+# VAR=$(trueorfalse default-value test-value)
159
+function trueorfalse() {
160
+    local default=$1
161
+    local testval=$2
162
+
163
+    [[ -z "$testval" ]] && { echo "$default"; return; }
164
+    [[ "0 no No NO false False FALSE" =~ "$testval" ]] && { echo "False"; return; }
165
+    [[ "1 yes Yes YES true True TRUE" =~ "$testval" ]] && { echo "True"; return; }
166
+    echo "$default"
167
+}
168
+
169
+
170
+# Control Functions
171
+# =================
172
+
173
+# Prints backtrace info
174
+# filename:lineno:function
175
+# backtrace level
176
+function backtrace {
177
+    local level=$1
178
+    local deep=$((${#BASH_SOURCE[@]} - 1))
179
+    echo "[Call Trace]"
180
+    while [ $level -le $deep ]; do
181
+        echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
182
+        deep=$((deep - 1))
183
+    done
184
+}
185
+
186
+# Prints line number and "message" then exits
187
+# die $LINENO "message"
188
+function die() {
189
+    local exitcode=$?
190
+    set +o xtrace
191
+    local line=$1; shift
192
+    if [ $exitcode == 0 ]; then
193
+        exitcode=1
194
+    fi
195
+    backtrace 2
196
+    err $line "$*"
197
+    exit $exitcode
198
+}
199
+
200
+# Checks an environment variable is not set or has length 0 OR if the
201
+# exit code is non-zero and prints "message" and exits
202
+# NOTE: env-var is the variable name without a '$'
203
+# die_if_not_set $LINENO env-var "message"
204
+function die_if_not_set() {
205
+    local exitcode=$?
206
+    FXTRACE=$(set +o | grep xtrace)
207
+    set +o xtrace
208
+    local line=$1; shift
209
+    local evar=$1; shift
210
+    if ! is_set $evar || [ $exitcode != 0 ]; then
211
+        die $line "$*"
212
+    fi
213
+    $FXTRACE
214
+}
215
+
216
+# Prints line number and "message" in error format
217
+# err $LINENO "message"
218
+function err() {
219
+    local exitcode=$?
220
+    errXTRACE=$(set +o | grep xtrace)
221
+    set +o xtrace
222
+    local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
223
+    echo $msg 1>&2;
224
+    if [[ -n ${SCREEN_LOGDIR} ]]; then
225
+        echo $msg >> "${SCREEN_LOGDIR}/error.log"
226
+    fi
227
+    $errXTRACE
228
+    return $exitcode
229
+}
230
+
231
+# Checks an environment variable is not set or has length 0 OR if the
232
+# exit code is non-zero and prints "message"
233
+# NOTE: env-var is the variable name without a '$'
234
+# err_if_not_set $LINENO env-var "message"
235
+function err_if_not_set() {
236
+    local exitcode=$?
237
+    errinsXTRACE=$(set +o | grep xtrace)
238
+    set +o xtrace
239
+    local line=$1; shift
240
+    local evar=$1; shift
241
+    if ! is_set $evar || [ $exitcode != 0 ]; then
242
+        err $line "$*"
243
+    fi
244
+    $errinsXTRACE
245
+    return $exitcode
246
+}
247
+
248
+# Exit after outputting a message about the distribution not being supported.
249
+# exit_distro_not_supported [optional-string-telling-what-is-missing]
250
+function exit_distro_not_supported {
251
+    if [[ -z "$DISTRO" ]]; then
252
+        GetDistro
253
+    fi
254
+
255
+    if [ $# -gt 0 ]; then
256
+        die $LINENO "Support for $DISTRO is incomplete: no support for $@"
257
+    else
258
+        die $LINENO "Support for $DISTRO is incomplete."
259
+    fi
260
+}
261
+
262
+# Test if the named environment variable is set and not zero length
263
+# is_set env-var
264
+function is_set() {
265
+    local var=\$"$1"
266
+    eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
267
+}
268
+
269
+# Prints line number and "message" in warning format
270
+# warn $LINENO "message"
271
+function warn() {
272
+    local exitcode=$?
273
+    errXTRACE=$(set +o | grep xtrace)
274
+    set +o xtrace
275
+    local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
276
+    echo $msg 1>&2;
277
+    if [[ -n ${SCREEN_LOGDIR} ]]; then
278
+        echo $msg >> "${SCREEN_LOGDIR}/error.log"
279
+    fi
280
+    $errXTRACE
281
+    return $exitcode
282
+}
283
+
284
+
285
+# Distro Functions
286
+# ================
287
+
288
+# Determine OS Vendor, Release and Update
289
+# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora
290
+# Returns results in global variables:
291
+# os_VENDOR - vendor name
292
+# os_RELEASE - release
293
+# os_UPDATE - update
294
+# os_PACKAGE - package type
295
+# os_CODENAME - vendor's codename for release
296
+# GetOSVersion
297
+GetOSVersion() {
298
+    # Figure out which vendor we are
299
+    if [[ -x "`which sw_vers 2>/dev/null`" ]]; then
300
+        # OS/X
301
+        os_VENDOR=`sw_vers -productName`
302
+        os_RELEASE=`sw_vers -productVersion`
303
+        os_UPDATE=${os_RELEASE##*.}
304
+        os_RELEASE=${os_RELEASE%.*}
305
+        os_PACKAGE=""
306
+        if [[ "$os_RELEASE" =~ "10.7" ]]; then
307
+            os_CODENAME="lion"
308
+        elif [[ "$os_RELEASE" =~ "10.6" ]]; then
309
+            os_CODENAME="snow leopard"
310
+        elif [[ "$os_RELEASE" =~ "10.5" ]]; then
311
+            os_CODENAME="leopard"
312
+        elif [[ "$os_RELEASE" =~ "10.4" ]]; then
313
+            os_CODENAME="tiger"
314
+        elif [[ "$os_RELEASE" =~ "10.3" ]]; then
315
+            os_CODENAME="panther"
316
+        else
317
+            os_CODENAME=""
318
+        fi
319
+    elif [[ -x $(which lsb_release 2>/dev/null) ]]; then
320
+        os_VENDOR=$(lsb_release -i -s)
321
+        os_RELEASE=$(lsb_release -r -s)
322
+        os_UPDATE=""
323
+        os_PACKAGE="rpm"
324
+        if [[ "Debian,Ubuntu,LinuxMint" =~ $os_VENDOR ]]; then
325
+            os_PACKAGE="deb"
326
+        elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then
327
+            lsb_release -d -s | grep -q openSUSE
328
+            if [[ $? -eq 0 ]]; then
329
+                os_VENDOR="openSUSE"
330
+            fi
331
+        elif [[ $os_VENDOR == "openSUSE project" ]]; then
332
+            os_VENDOR="openSUSE"
333
+        elif [[ $os_VENDOR =~ Red.*Hat ]]; then
334
+            os_VENDOR="Red Hat"
335
+        fi
336
+        os_CODENAME=$(lsb_release -c -s)
337
+    elif [[ -r /etc/redhat-release ]]; then
338
+        # Red Hat Enterprise Linux Server release 5.5 (Tikanga)
339
+        # Red Hat Enterprise Linux Server release 7.0 Beta (Maipo)
340
+        # CentOS release 5.5 (Final)
341
+        # CentOS Linux release 6.0 (Final)
342
+        # Fedora release 16 (Verne)
343
+        # XenServer release 6.2.0-70446c (xenenterprise)
344
+        os_CODENAME=""
345
+        for r in "Red Hat" CentOS Fedora XenServer; do
346
+            os_VENDOR=$r
347
+            if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then
348
+                ver=`sed -e 's/^.* \([0-9].*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release`
349
+                os_CODENAME=${ver#*|}
350
+                os_RELEASE=${ver%|*}
351
+                os_UPDATE=${os_RELEASE##*.}
352
+                os_RELEASE=${os_RELEASE%.*}
353
+                break
354
+            fi
355
+            os_VENDOR=""
356
+        done
357
+        os_PACKAGE="rpm"
358
+    elif [[ -r /etc/SuSE-release ]]; then
359
+        for r in openSUSE "SUSE Linux"; do
360
+            if [[ "$r" = "SUSE Linux" ]]; then
361
+                os_VENDOR="SUSE LINUX"
362
+            else
363
+                os_VENDOR=$r
364
+            fi
365
+
366
+            if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then
367
+                os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'`
368
+                os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'`
369
+                os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'`
370
+                break
371
+            fi
372
+            os_VENDOR=""
373
+        done
374
+        os_PACKAGE="rpm"
375
+    # If lsb_release is not installed, we should be able to detect Debian OS
376
+    elif [[ -f /etc/debian_version ]] && [[ $(cat /proc/version) =~ "Debian" ]]; then
377
+        os_VENDOR="Debian"
378
+        os_PACKAGE="deb"
379
+        os_CODENAME=$(awk '/VERSION=/' /etc/os-release | sed 's/VERSION=//' | sed -r 's/\"|\(|\)//g' | awk '{print $2}')
380
+        os_RELEASE=$(awk '/VERSION_ID=/' /etc/os-release | sed 's/VERSION_ID=//' | sed 's/\"//g')
381
+    fi
382
+    export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
383
+}
384
+
385
+# Translate the OS version values into common nomenclature
386
+# Sets global ``DISTRO`` from the ``os_*`` values
387
+function GetDistro() {
388
+    GetOSVersion
389
+    if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then
390
+        # 'Everyone' refers to Ubuntu / Debian releases by the code name adjective
391
+        DISTRO=$os_CODENAME
392
+    elif [[ "$os_VENDOR" =~ (Fedora) ]]; then
393
+        # For Fedora, just use 'f' and the release
394
+        DISTRO="f$os_RELEASE"
395
+    elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then
396
+        DISTRO="opensuse-$os_RELEASE"
397
+    elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then
398
+        # For SLE, also use the service pack
399
+        if [[ -z "$os_UPDATE" ]]; then
400
+            DISTRO="sle${os_RELEASE}"
401
+        else
402
+            DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
403
+        fi
404
+    elif [[ "$os_VENDOR" =~ (Red Hat) || "$os_VENDOR" =~ (CentOS) ]]; then
405
+        # Drop the . release as we assume it's compatible
406
+        DISTRO="rhel${os_RELEASE::1}"
407
+    elif [[ "$os_VENDOR" =~ (XenServer) ]]; then
408
+        DISTRO="xs$os_RELEASE"
409
+    else
410
+        # Catch-all for now is Vendor + Release + Update
411
+        DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
412
+    fi
413
+    export DISTRO
414
+}
415
+
416
+# Utility function for checking machine architecture
417
+# is_arch arch-type
418
+function is_arch {
419
+    ARCH_TYPE=$1
420
+
421
+    [[ "$(uname -m)" == "$ARCH_TYPE" ]]
422
+}
423
+
424
+# Determine if current distribution is a Fedora-based distribution
425
+# (Fedora, RHEL, CentOS, etc).
426
+# is_fedora
427
+function is_fedora {
428
+    if [[ -z "$os_VENDOR" ]]; then
429
+        GetOSVersion
430
+    fi
431
+
432
+    [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
433
+}
434
+
435
+
436
+# Determine if current distribution is a SUSE-based distribution
437
+# (openSUSE, SLE).
438
+# is_suse
439
+function is_suse {
440
+    if [[ -z "$os_VENDOR" ]]; then
441
+        GetOSVersion
442
+    fi
443
+
444
+    [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ]
445
+}
446
+
447
+
448
+# Determine if current distribution is an Ubuntu-based distribution
449
+# It will also detect non-Ubuntu but Debian-based distros
450
+# is_ubuntu
451
+function is_ubuntu {
452
+    if [[ -z "$os_PACKAGE" ]]; then
453
+        GetOSVersion
454
+    fi
455
+    [ "$os_PACKAGE" = "deb" ]
456
+}
457
+
458
+
459
+# Git Functions
460
+# =============
461
+
462
+# git clone only if directory doesn't exist already.  Since ``DEST`` might not
463
+# be owned by the installation user, we create the directory and change the
464
+# ownership to the proper user.
465
+# Set global RECLONE=yes to simulate a clone when dest-dir exists
466
+# Set global ERROR_ON_CLONE=True to abort execution with an error if the git repo
467
+# does not exist (default is False, meaning the repo will be cloned).
468
+# Uses global ``OFFLINE``
469
+# git_clone remote dest-dir branch
470
+function git_clone {
471
+    GIT_REMOTE=$1
472
+    GIT_DEST=$2
473
+    GIT_REF=$3
474
+    RECLONE=$(trueorfalse False $RECLONE)
475
+
476
+    if [[ "$OFFLINE" = "True" ]]; then
477
+        echo "Running in offline mode, clones already exist"
478
+        # print out the results so we know what change was used in the logs
479
+        cd $GIT_DEST
480
+        git show --oneline | head -1
481
+        return
482
+    fi
483
+
484
+    if echo $GIT_REF | egrep -q "^refs"; then
485
+        # If our branch name is a gerrit style refs/changes/...
486
+        if [[ ! -d $GIT_DEST ]]; then
487
+            [[ "$ERROR_ON_CLONE" = "True" ]] && \
488
+                die $LINENO "Cloning not allowed in this configuration"
489
+            git clone $GIT_REMOTE $GIT_DEST
490
+        fi
491
+        cd $GIT_DEST
492
+        git fetch $GIT_REMOTE $GIT_REF && git checkout FETCH_HEAD
493
+    else
494
+        # do a full clone only if the directory doesn't exist
495
+        if [[ ! -d $GIT_DEST ]]; then
496
+            [[ "$ERROR_ON_CLONE" = "True" ]] && \
497
+                die $LINENO "Cloning not allowed in this configuration"
498
+            git clone $GIT_REMOTE $GIT_DEST
499
+            cd $GIT_DEST
500
+            # This checkout syntax works for both branches and tags
501
+            git checkout $GIT_REF
502
+        elif [[ "$RECLONE" = "True" ]]; then
503
+            # if it does exist then simulate what clone does if asked to RECLONE
504
+            cd $GIT_DEST
505
+            # set the url to pull from and fetch
506
+            git remote set-url origin $GIT_REMOTE
507
+            git fetch origin
508
+            # remove the existing ignored files (like pyc) as they cause breakage
509
+            # (due to the py files having older timestamps than our pyc, so python
510
+            # thinks the pyc files are correct using them)
511
+            find $GIT_DEST -name '*.pyc' -delete
512
+
513
+            # handle GIT_REF accordingly to type (tag, branch)
514
+            if [[ -n "`git show-ref refs/tags/$GIT_REF`" ]]; then
515
+                git_update_tag $GIT_REF
516
+            elif [[ -n "`git show-ref refs/heads/$GIT_REF`" ]]; then
517
+                git_update_branch $GIT_REF
518
+            elif [[ -n "`git show-ref refs/remotes/origin/$GIT_REF`" ]]; then
519
+                git_update_remote_branch $GIT_REF
520
+            else
521
+                die $LINENO "$GIT_REF is neither branch nor tag"
522
+            fi
523
+
524
+        fi
525
+    fi
526
+
527
+    # print out the results so we know what change was used in the logs
528
+    cd $GIT_DEST
529
+    git show --oneline | head -1
530
+}
531
+
532
+# git update using reference as a branch.
533
+# git_update_branch ref
534
+function git_update_branch() {
535
+
536
+    GIT_BRANCH=$1
537
+
538
+    git checkout -f origin/$GIT_BRANCH
539
+    # a local branch might not exist
540
+    git branch -D $GIT_BRANCH || true
541
+    git checkout -b $GIT_BRANCH
542
+}
543
+
544
+# git update using reference as a branch.
545
+# git_update_remote_branch ref
546
+function git_update_remote_branch() {
547
+
548
+    GIT_BRANCH=$1
549
+
550
+    git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH
551
+}
552
+
553
+# git update using reference as a tag. Be careful editing source at that repo
554
+# as working copy will be in a detached mode
555
+# git_update_tag ref
556
+function git_update_tag() {
557
+
558
+    GIT_TAG=$1
559
+
560
+    git tag -d $GIT_TAG
561
+    # fetching given tag only
562
+    git fetch origin tag $GIT_TAG
563
+    git checkout -f $GIT_TAG
564
+}
565
+
566
+
567
+# OpenStack Functions
568
+# ===================
569
+
570
+# Get the default value for HOST_IP
571
+# get_default_host_ip fixed_range floating_range host_ip_iface host_ip
572
+function get_default_host_ip() {
573
+    local fixed_range=$1
574
+    local floating_range=$2
575
+    local host_ip_iface=$3
576
+    local host_ip=$4
577
+
578
+    # Find the interface used for the default route
579
+    host_ip_iface=${host_ip_iface:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }' | head -1)}
580
+    # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable
581
+    if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then
582
+        host_ip=""
583
+        host_ips=`LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/");  print parts[1]}'`
584
+        for IP in $host_ips; do
585
+            # Attempt to filter out IP addresses that are part of the fixed and
586
+            # floating range. Note that this method only works if the ``netaddr``
587
+            # python library is installed. If it is not installed, an error
588
+            # will be printed and the first IP from the interface will be used.
589
+            # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct
590
+            # address.
591
+            if ! (address_in_net $IP $fixed_range || address_in_net $IP $floating_range); then
592
+                host_ip=$IP
593
+                break;
594
+            fi
595
+        done
596
+    fi
597
+    echo $host_ip
598
+}
599
+
600
+# Grab a numbered field from python prettytable output
601
+# Fields are numbered starting with 1
602
+# Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
603
+# get_field field-number
604
+function get_field() {
605
+    while read data; do
606
+        if [ "$1" -lt 0 ]; then
607
+            field="(\$(NF$1))"
608
+        else
609
+            field="\$$(($1 + 1))"
610
+        fi
611
+        echo "$data" | awk -F'[ \t]*\\|[ \t]*' "{print $field}"
612
+    done
613
+}
614
+
615
+# Add a policy to a policy.json file
616
+# Do nothing if the policy already exists
617
+# ``policy_add policy_file policy_name policy_permissions``
618
+function policy_add() {
619
+    local policy_file=$1
620
+    local policy_name=$2
621
+    local policy_perm=$3
622
+
623
+    if grep -q ${policy_name} ${policy_file}; then
624
+        echo "Policy ${policy_name} already exists in ${policy_file}"
625
+        return
626
+    fi
627
+
628
+    # Add a terminating comma to policy lines without one
629
+    # Remove the closing '}' and all lines following to the end-of-file
630
+    local tmpfile=$(mktemp)
631
+    uniq ${policy_file} | sed -e '
632
+        s/]$/],/
633
+        /^[}]/,$d
634
+    ' > ${tmpfile}
635
+
636
+    # Append policy and closing brace
637
+    echo "    \"${policy_name}\": ${policy_perm}" >>${tmpfile}
638
+    echo "}" >>${tmpfile}
639
+
640
+    mv ${tmpfile} ${policy_file}
641
+}
642
+
643
+
644
+# Package Functions
645
+# =================
646
+
647
+# _get_package_dir
648
+function _get_package_dir() {
649
+    local pkg_dir
650
+    if is_ubuntu; then
651
+        pkg_dir=$FILES/apts
652
+    elif is_fedora; then
653
+        pkg_dir=$FILES/rpms
654
+    elif is_suse; then
655
+        pkg_dir=$FILES/rpms-suse
656
+    else
657
+        exit_distro_not_supported "list of packages"
658
+    fi
659
+    echo "$pkg_dir"
660
+}
661
+
662
+# Wrapper for ``apt-get`` to set cache and proxy environment variables
663
+# Uses globals ``OFFLINE``, ``*_proxy``
664
+# apt_get operation package [package ...]
665
+function apt_get() {
666
+    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
667
+    local sudo="sudo"
668
+    [[ "$(id -u)" = "0" ]] && sudo="env"
669
+    $sudo DEBIAN_FRONTEND=noninteractive \
670
+        http_proxy=$http_proxy https_proxy=$https_proxy \
671
+        no_proxy=$no_proxy \
672
+        apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
673
+}
674
+
675
+# get_packages() collects a list of package names of any type from the
676
+# prerequisite files in ``files/{apts|rpms}``.  The list is intended
677
+# to be passed to a package installer such as apt or yum.
678
+#
679
+# Only packages required for the services in 1st argument will be
680
+# included.  Two bits of metadata are recognized in the prerequisite files:
681
+#
682
+# - ``# NOPRIME`` defers installation to be performed later in `stack.sh`
683
+# - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection
684
+#   of the package to the distros listed.  The distro names are case insensitive.
685
+function get_packages() {
686
+    local services=$@
687
+    local package_dir=$(_get_package_dir)
688
+    local file_to_parse
689
+    local service
690
+
691
+    if [[ -z "$package_dir" ]]; then
692
+        echo "No package directory supplied"
693
+        return 1
694
+    fi
695
+    if [[ -z "$DISTRO" ]]; then
696
+        GetDistro
697
+    fi
698
+    for service in ${services//,/ }; do
699
+        # Allow individual services to specify dependencies
700
+        if [[ -e ${package_dir}/${service} ]]; then
701
+            file_to_parse="${file_to_parse} $service"
702
+        fi
703
+        # NOTE(sdague) n-api needs glance for now because that's where
704
+        # glance client is
705
+        if [[ $service == n-api ]]; then
706
+            if [[ ! $file_to_parse =~ nova ]]; then
707
+                file_to_parse="${file_to_parse} nova"
708
+            fi
709
+            if [[ ! $file_to_parse =~ glance ]]; then
710
+                file_to_parse="${file_to_parse} glance"
711
+            fi
712
+        elif [[ $service == c-* ]]; then
713
+            if [[ ! $file_to_parse =~ cinder ]]; then
714
+                file_to_parse="${file_to_parse} cinder"
715
+            fi
716
+        elif [[ $service == ceilometer-* ]]; then
717
+            if [[ ! $file_to_parse =~ ceilometer ]]; then
718
+                file_to_parse="${file_to_parse} ceilometer"
719
+            fi
720
+        elif [[ $service == s-* ]]; then
721
+            if [[ ! $file_to_parse =~ swift ]]; then
722
+                file_to_parse="${file_to_parse} swift"
723
+            fi
724
+        elif [[ $service == n-* ]]; then
725
+            if [[ ! $file_to_parse =~ nova ]]; then
726
+                file_to_parse="${file_to_parse} nova"
727
+            fi
728
+        elif [[ $service == g-* ]]; then
729
+            if [[ ! $file_to_parse =~ glance ]]; then
730
+                file_to_parse="${file_to_parse} glance"
731
+            fi
732
+        elif [[ $service == key* ]]; then
733
+            if [[ ! $file_to_parse =~ keystone ]]; then
734
+                file_to_parse="${file_to_parse} keystone"
735
+            fi
736
+        elif [[ $service == q-* ]]; then
737
+            if [[ ! $file_to_parse =~ neutron ]]; then
738
+                file_to_parse="${file_to_parse} neutron"
739
+            fi
740
+        fi
741
+    done
742
+
743
+    for file in ${file_to_parse}; do
744
+        local fname=${package_dir}/${file}
745
+        local OIFS line package distros distro
746
+        [[ -e $fname ]] || continue
747
+
748
+        OIFS=$IFS
749
+        IFS=$'\n'
750
+        for line in $(<${fname}); do
751
+            if [[ $line =~ "NOPRIME" ]]; then
752
+                continue
753
+            fi
754
+
755
+            # Assume we want this package
756
+            package=${line%#*}
757
+            inst_pkg=1
758
+
759
+            # Look for # dist:xxx in comment
760
+            if [[ $line =~ (.*)#.*dist:([^ ]*) ]]; then
761
+                # We are using BASH regexp matching feature.
762
+                package=${BASH_REMATCH[1]}
763
+                distros=${BASH_REMATCH[2]}
764
+                # In bash ${VAR,,} will lowecase VAR
765
+                # Look for a match in the distro list
766
+                if [[ ! ${distros,,} =~ ${DISTRO,,} ]]; then
767
+                    # If no match then skip this package
768
+                    inst_pkg=0
769
+                fi
770
+            fi
771
+
772
+            # Look for # testonly in comment
773
+            if [[ $line =~ (.*)#.*testonly.* ]]; then
774
+                package=${BASH_REMATCH[1]}
775
+                # Are we installing test packages? (test for the default value)
776
+                if [[ $INSTALL_TESTONLY_PACKAGES = "False" ]]; then
777
+                    # If not installing test packages the skip this package
778
+                    inst_pkg=0
779
+                fi
780
+            fi
781
+
782
+            if [[ $inst_pkg = 1 ]]; then
783
+                echo $package
784
+            fi
785
+        done
786
+        IFS=$OIFS
787
+    done
788
+}
789
+
790
+# Distro-agnostic package installer
791
+# install_package package [package ...]
792
+function install_package() {
793
+    if is_ubuntu; then
794
+        [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
795
+        NO_UPDATE_REPOS=True
796
+
797
+        apt_get install "$@"
798
+    elif is_fedora; then
799
+        yum_install "$@"
800
+    elif is_suse; then
801
+        zypper_install "$@"
802
+    else
803
+        exit_distro_not_supported "installing packages"
804
+    fi
805
+}
806
+
807
+# Distro-agnostic function to tell if a package is installed
808
+# is_package_installed package [package ...]
809
+function is_package_installed() {
810
+    if [[ -z "$@" ]]; then
811
+        return 1
812
+    fi
813
+
814
+    if [[ -z "$os_PACKAGE" ]]; then
815
+        GetOSVersion
816
+    fi
817
+
818
+    if [[ "$os_PACKAGE" = "deb" ]]; then
819
+        dpkg -s "$@" > /dev/null 2> /dev/null
820
+    elif [[ "$os_PACKAGE" = "rpm" ]]; then
821
+        rpm --quiet -q "$@"
822
+    else
823
+        exit_distro_not_supported "finding if a package is installed"
824
+    fi
825
+}
826
+
827
+# Distro-agnostic package uninstaller
828
+# uninstall_package package [package ...]
829
+function uninstall_package() {
830
+    if is_ubuntu; then
831
+        apt_get purge "$@"
832
+    elif is_fedora; then
833
+        sudo yum remove -y "$@"
834
+    elif is_suse; then
835
+        sudo zypper rm "$@"
836
+    else
837
+        exit_distro_not_supported "uninstalling packages"
838
+    fi
839
+}
840
+
841
+# Wrapper for ``yum`` to set proxy environment variables
842
+# Uses globals ``OFFLINE``, ``*_proxy``
843
+# yum_install package [package ...]
844
+function yum_install() {
845
+    [[ "$OFFLINE" = "True" ]] && return
846
+    local sudo="sudo"
847
+    [[ "$(id -u)" = "0" ]] && sudo="env"
848
+    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
849
+        no_proxy=$no_proxy \
850
+        yum install -y "$@"
851
+}
852
+
853
+# zypper wrapper to set arguments correctly
854
+# zypper_install package [package ...]
855
+function zypper_install() {
856
+    [[ "$OFFLINE" = "True" ]] && return
857
+    local sudo="sudo"
858
+    [[ "$(id -u)" = "0" ]] && sudo="env"
859
+    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
860
+        zypper --non-interactive install --auto-agree-with-licenses "$@"
861
+}
862
+
863
+
864
+# Process Functions
865
+# =================
866
+
867
+# _run_process() is designed to be backgrounded by run_process() to simulate a
868
+# fork.  It includes the dirty work of closing extra filehandles and preparing log
869
+# files to produce the same logs as screen_it().  The log filename is derived
870
+# from the service name and global-and-now-misnamed SCREEN_LOGDIR
871
+# _run_process service "command-line"
872
+function _run_process() {
873
+    local service=$1
874
+    local command="$2"
875
+
876
+    # Undo logging redirections and close the extra descriptors
877
+    exec 1>&3
878
+    exec 2>&3
879
+    exec 3>&-
880
+    exec 6>&-
881
+
882
+    if [[ -n ${SCREEN_LOGDIR} ]]; then
883
+        exec 1>&${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log 2>&1
884
+        ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
885
+
886
+        # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs.
887
+        export PYTHONUNBUFFERED=1
888
+    fi
889
+
890
+    exec /bin/bash -c "$command"
891
+    die "$service exec failure: $command"
892
+}
893
+
894
+# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``.
895
+# This is used for ``service_check`` when all the ``screen_it`` are called finished
896
+# init_service_check
897
+function init_service_check() {
898
+    SCREEN_NAME=${SCREEN_NAME:-stack}
899
+    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
900
+
901
+    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
902
+        mkdir -p "$SERVICE_DIR/$SCREEN_NAME"
903
+    fi
904
+
905
+    rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure
906
+}
907
+
908
+# Find out if a process exists by partial name.
909
+# is_running name
910
+function is_running() {
911
+    local name=$1
912
+    ps auxw | grep -v grep | grep ${name} > /dev/null
913
+    RC=$?
914
+    # some times I really hate bash reverse binary logic
915
+    return $RC
916
+}
917
+
918
+# run_process() launches a child process that closes all file descriptors and
919
+# then exec's the passed in command.  This is meant to duplicate the semantics
920
+# of screen_it() without screen.  PIDs are written to
921
+# $SERVICE_DIR/$SCREEN_NAME/$service.pid
922
+# run_process service "command-line"
923
+function run_process() {
924
+    local service=$1
925
+    local command="$2"
926
+
927
+    # Spawn the child process
928
+    _run_process "$service" "$command" &
929
+    echo $!
930
+}
931
+
932
+# Helper to launch a service in a named screen
933
+# screen_it service "command-line"
934
+function screen_it {
935
+    SCREEN_NAME=${SCREEN_NAME:-stack}
936
+    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
937
+    USE_SCREEN=$(trueorfalse True $USE_SCREEN)
938
+
939
+    if is_service_enabled $1; then
940
+        # Append the service to the screen rc file
941
+        screen_rc "$1" "$2"
942
+
943
+        if [[ "$USE_SCREEN" = "True" ]]; then
944
+            screen -S $SCREEN_NAME -X screen -t $1
945
+
946
+            if [[ -n ${SCREEN_LOGDIR} ]]; then
947
+                screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log
948
+                screen -S $SCREEN_NAME -p $1 -X log on
949
+                ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
950
+            fi
951
+
952
+            # sleep to allow bash to be ready to be send the command - we are
953
+            # creating a new window in screen and then sends characters, so if
954
+            # bash isn't running by the time we send the command, nothing happens
955
+            sleep 1.5
956
+
957
+            NL=`echo -ne '\015'`
958
+            # This fun command does the following:
959
+            # - the passed server command is backgrounded
960
+            # - the pid of the background process is saved in the usual place
961
+            # - the server process is brought back to the foreground
962
+            # - if the server process exits prematurely the fg command errors
963
+            #   and a message is written to stdout and the service failure file
964
+            # The pid saved can be used in screen_stop() as a process group
965
+            # id to kill off all child processes
966
+            screen -S $SCREEN_NAME -p $1 -X stuff "$2 & echo \$! >$SERVICE_DIR/$SCREEN_NAME/$1.pid; fg || echo \"$1 failed to start\" | tee \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
967
+        else
968
+            # Spawn directly without screen
969
+            run_process "$1" "$2" >$SERVICE_DIR/$SCREEN_NAME/$1.pid
970
+        fi
971
+    fi
972
+}
973
+
974
+# Screen rc file builder
975
+# screen_rc service "command-line"
976
+function screen_rc {
977
+    SCREEN_NAME=${SCREEN_NAME:-stack}
978
+    SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc
979
+    if [[ ! -e $SCREENRC ]]; then
980
+        # Name the screen session
981
+        echo "sessionname $SCREEN_NAME" > $SCREENRC
982
+        # Set a reasonable statusbar
983
+        echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC
984
+        # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off
985
+        echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC
986
+        echo "screen -t shell bash" >> $SCREENRC
987
+    fi
988
+    # If this service doesn't already exist in the screenrc file
989
+    if ! grep $1 $SCREENRC 2>&1 > /dev/null; then
990
+        NL=`echo -ne '\015'`
991
+        echo "screen -t $1 bash" >> $SCREENRC
992
+        echo "stuff \"$2$NL\"" >> $SCREENRC
993
+
994
+        if [[ -n ${SCREEN_LOGDIR} ]]; then
995
+            echo "logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log" >>$SCREENRC
996
+            echo "log on" >>$SCREENRC
997
+        fi
998
+    fi
999
+}
1000
+
1001
+# Stop a service in screen
1002
+# If a PID is available use it, kill the whole process group via TERM
1003
+# If screen is being used kill the screen window; this will catch processes
1004
+# that did not leave a PID behind
1005
+# screen_stop service
1006
+function screen_stop() {
1007
+    SCREEN_NAME=${SCREEN_NAME:-stack}
1008
+    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1009
+    USE_SCREEN=$(trueorfalse True $USE_SCREEN)
1010
+
1011
+    if is_service_enabled $1; then
1012
+        # Kill via pid if we have one available
1013
+        if [[ -r $SERVICE_DIR/$SCREEN_NAME/$1.pid ]]; then
1014
+            pkill -TERM -P -$(cat $SERVICE_DIR/$SCREEN_NAME/$1.pid)
1015
+            rm $SERVICE_DIR/$SCREEN_NAME/$1.pid
1016
+        fi
1017
+        if [[ "$USE_SCREEN" = "True" ]]; then
1018
+            # Clean up the screen window
1019
+            screen -S $SCREEN_NAME -p $1 -X kill
1020
+        fi
1021
+    fi
1022
+}
1023
+
1024
+# Helper to get the status of each running service
1025
+# service_check
1026
+function service_check() {
1027
+    local service
1028
+    local failures
1029
+    SCREEN_NAME=${SCREEN_NAME:-stack}
1030
+    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
1031
+
1032
+
1033
+    if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then
1034
+        echo "No service status directory found"
1035
+        return
1036
+    fi
1037
+
1038
+    # Check if there is any falure flag file under $SERVICE_DIR/$SCREEN_NAME
1039
+    failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null`
1040
+
1041
+    for service in $failures; do
1042
+        service=`basename $service`
1043
+        service=${service%.failure}
1044
+        echo "Error: Service $service is not running"
1045
+    done
1046
+
1047
+    if [ -n "$failures" ]; then
1048
+        echo "More details about the above errors can be found with screen, with ./rejoin-stack.sh"
1049
+    fi
1050
+}
1051
+
1052
+
1053
+# Python Functions
1054
+# ================
1055
+
1056
+# Get the path to the pip command.
1057
+# get_pip_command
1058
+function get_pip_command() {
1059
+    which pip || which pip-python
1060
+
1061
+    if [ $? -ne 0 ]; then
1062
+        die $LINENO "Unable to find pip; cannot continue"
1063
+    fi
1064
+}
1065
+
1066
+# Get the path to the direcotry where python executables are installed.
1067
+# get_python_exec_prefix
1068
+function get_python_exec_prefix() {
1069
+    if is_fedora || is_suse; then
1070
+        echo "/usr/bin"
1071
+    else
1072
+        echo "/usr/local/bin"
1073
+    fi
1074
+}
1075
+
1076
+# Wrapper for ``pip install`` to set cache and proxy environment variables
1077
+# Uses globals ``OFFLINE``, ``PIP_DOWNLOAD_CACHE``, ``PIP_USE_MIRRORS``,
1078
+# ``TRACK_DEPENDS``, ``*_proxy``
1079
+# pip_install package [package ...]
1080
+function pip_install {
1081
+    [[ "$OFFLINE" = "True" || -z "$@" ]] && return
1082
+    if [[ -z "$os_PACKAGE" ]]; then
1083
+        GetOSVersion
1084
+    fi
1085
+    if [[ $TRACK_DEPENDS = True ]]; then
1086
+        source $DEST/.venv/bin/activate
1087
+        CMD_PIP=$DEST/.venv/bin/pip
1088
+        SUDO_PIP="env"
1089
+    else
1090
+        SUDO_PIP="sudo"
1091
+        CMD_PIP=$(get_pip_command)
1092
+    fi
1093
+
1094
+    # Mirror option not needed anymore because pypi has CDN available,
1095
+    # but it's useful in certain circumstances
1096
+    PIP_USE_MIRRORS=${PIP_USE_MIRRORS:-False}
1097
+    if [[ "$PIP_USE_MIRRORS" != "False" ]]; then
1098
+        PIP_MIRROR_OPT="--use-mirrors"
1099
+    fi
1100
+
1101
+    # pip < 1.4 has a bug where it will use an already existing build
1102
+    # directory unconditionally.  Say an earlier component installs
1103
+    # foo v1.1; pip will have built foo's source in
1104
+    # /tmp/$USER-pip-build.  Even if a later component specifies foo <
1105
+    # 1.1, the existing extracted build will be used and cause
1106
+    # confusing errors.  By creating unique build directories we avoid
1107
+    # this problem. See https://github.com/pypa/pip/issues/709
1108
+    local pip_build_tmp=$(mktemp --tmpdir -d pip-build.XXXXX)
1109
+
1110
+    $SUDO_PIP PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-/var/cache/pip} \
1111
+        HTTP_PROXY=$http_proxy \
1112
+        HTTPS_PROXY=$https_proxy \
1113
+        NO_PROXY=$no_proxy \
1114
+        $CMD_PIP install --build=${pip_build_tmp} \
1115
+        $PIP_MIRROR_OPT $@ \
1116
+        && $SUDO_PIP rm -rf ${pip_build_tmp}
1117
+}
1118
+
1119
+
1120
+# Service Functions
1121
+# =================
1122
+
1123
+# remove extra commas from the input string (i.e. ``ENABLED_SERVICES``)
1124
+# _cleanup_service_list service-list
1125
+function _cleanup_service_list () {
1126
+    echo "$1" | sed -e '
1127
+        s/,,/,/g;
1128
+        s/^,//;
1129
+        s/,$//
1130
+    '
1131
+}
1132
+
1133
+# disable_all_services() removes all current services
1134
+# from ``ENABLED_SERVICES`` to reset the configuration
1135
+# before a minimal installation
1136
+# Uses global ``ENABLED_SERVICES``
1137
+# disable_all_services
1138
+function disable_all_services() {
1139
+    ENABLED_SERVICES=""
1140
+}
1141
+
1142
+# Remove all services starting with '-'.  For example, to install all default
1143
+# services except rabbit (rabbit) set in ``localrc``:
1144
+# ENABLED_SERVICES+=",-rabbit"
1145
+# Uses global ``ENABLED_SERVICES``
1146
+# disable_negated_services
1147
+function disable_negated_services() {
1148
+    local tmpsvcs="${ENABLED_SERVICES}"
1149
+    local service
1150
+    for service in ${tmpsvcs//,/ }; do
1151
+        if [[ ${service} == -* ]]; then
1152
+            tmpsvcs=$(echo ${tmpsvcs}|sed -r "s/(,)?(-)?${service#-}(,)?/,/g")
1153
+        fi
1154
+    done
1155
+    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
1156
+}
1157
+
1158
+# disable_service() removes the services passed as argument to the
1159
+# ``ENABLED_SERVICES`` list, if they are present.
1160
+#
1161
+# For example:
1162
+#   disable_service rabbit
1163
+#
1164
+# This function does not know about the special cases
1165
+# for nova, glance, and neutron built into is_service_enabled().
1166
+# Uses global ``ENABLED_SERVICES``
1167
+# disable_service service [service ...]
1168
+function disable_service() {
1169
+    local tmpsvcs=",${ENABLED_SERVICES},"
1170
+    local service
1171
+    for service in $@; do
1172
+        if is_service_enabled $service; then
1173
+            tmpsvcs=${tmpsvcs//,$service,/,}
1174
+        fi
1175
+    done
1176
+    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
1177
+}
1178
+
1179
+# enable_service() adds the services passed as argument to the
1180
+# ``ENABLED_SERVICES`` list, if they are not already present.
1181
+#
1182
+# For example:
1183
+#   enable_service qpid
1184
+#
1185
+# This function does not know about the special cases
1186
+# for nova, glance, and neutron built into is_service_enabled().
1187
+# Uses global ``ENABLED_SERVICES``
1188
+# enable_service service [service ...]
1189
+function enable_service() {
1190
+    local tmpsvcs="${ENABLED_SERVICES}"
1191
+    for service in $@; do
1192
+        if ! is_service_enabled $service; then
1193
+            tmpsvcs+=",$service"
1194
+        fi
1195
+    done
1196
+    ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
1197
+    disable_negated_services
1198
+}
1199
+
1200
+# is_service_enabled() checks if the service(s) specified as arguments are
1201
+# enabled by the user in ``ENABLED_SERVICES``.
1202
+#
1203
+# Multiple services specified as arguments are ``OR``'ed together; the test
1204
+# is a short-circuit boolean, i.e it returns on the first match.
1205
+#
1206
+# There are special cases for some 'catch-all' services::
1207
+#   **nova** returns true if any service enabled start with **n-**
1208
+#   **cinder** returns true if any service enabled start with **c-**
1209
+#   **ceilometer** returns true if any service enabled start with **ceilometer**
1210
+#   **glance** returns true if any service enabled start with **g-**
1211
+#   **neutron** returns true if any service enabled start with **q-**
1212
+#   **swift** returns true if any service enabled start with **s-**
1213
+#   **trove** returns true if any service enabled start with **tr-**
1214
+#   For backward compatibility if we have **swift** in ENABLED_SERVICES all the
1215
+#   **s-** services will be enabled. This will be deprecated in the future.
1216
+#
1217
+# Cells within nova is enabled if **n-cell** is in ``ENABLED_SERVICES``.
1218
+# We also need to make sure to treat **n-cell-region** and **n-cell-child**
1219
+# as enabled in this case.
1220
+#
1221
+# Uses global ``ENABLED_SERVICES``
1222
+# is_service_enabled service [service ...]
1223
+function is_service_enabled() {
1224
+    services=$@
1225
+    for service in ${services}; do
1226
+        [[ ,${ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
1227
+
1228
+        # Look for top-level 'enabled' function for this service
1229
+        if type is_${service}_enabled >/dev/null 2>&1; then
1230
+            # A function exists for this service, use it
1231
+            is_${service}_enabled
1232
+            return $?
1233
+        fi
1234
+
1235
+        # TODO(dtroyer): Remove these legacy special-cases after the is_XXX_enabled()
1236
+        #                are implemented
1237
+
1238
+        [[ ${service} == n-cell-* && ${ENABLED_SERVICES} =~ "n-cell" ]] && return 0
1239
+        [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && return 0
1240
+        [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && return 0
1241
+        [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && return 0
1242
+        [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && return 0
1243
+        [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && return 0
1244
+        [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && return 0
1245
+        [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && return 0
1246
+        [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && return 0
1247
+        [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && return 0
1248
+    done
1249
+    return 1
1250
+}
1251
+
1252
+# Toggle enable/disable_service for services that must run exclusive of each other
1253
+#  $1 The name of a variable containing a space-separated list of services
1254
+#  $2 The name of a variable in which to store the enabled service's name
1255
+#  $3 The name of the service to enable
1256
+function use_exclusive_service {
1257
+    local options=${!1}
1258
+    local selection=$3
1259
+    out=$2
1260
+    [ -z $selection ] || [[ ! "$options" =~ "$selection" ]] && return 1
1261
+    for opt in $options;do
1262
+        [[ "$opt" = "$selection" ]] && enable_service $opt || disable_service $opt
1263
+    done
1264
+    eval "$out=$selection"
1265
+    return 0
1266
+}
1267
+
1268
+
1269
+# System Function
1270
+# ===============
1271
+
1272
+# Only run the command if the target file (the last arg) is not on an
1273
+# NFS filesystem.
1274
+function _safe_permission_operation() {
1275
+    local args=( $@ )
1276
+    local last
1277
+    local sudo_cmd
1278
+    local dir_to_check
1279
+
1280
+    let last="${#args[*]} - 1"
1281
+
1282
+    dir_to_check=${args[$last]}
1283
+    if [ ! -d "$dir_to_check" ]; then
1284
+        dir_to_check=`dirname "$dir_to_check"`
1285
+    fi
1286
+
1287
+    if is_nfs_directory "$dir_to_check" ; then
1288
+        return 0
1289
+    fi
1290
+
1291
+    if [[ $TRACK_DEPENDS = True ]]; then
1292
+        sudo_cmd="env"
1293
+    else
1294
+        sudo_cmd="sudo"
1295
+    fi
1296
+
1297
+    $sudo_cmd $@
1298
+}
1299
+
1300
+# Exit 0 if address is in network or 1 if address is not in network
1301
+# ip-range is in CIDR notation: 1.2.3.4/20
1302
+# address_in_net ip-address ip-range
1303
+function address_in_net() {
1304
+    local ip=$1
1305
+    local range=$2
1306
+    local masklen=${range#*/}
1307
+    local network=$(maskip ${range%/*} $(cidr2netmask $masklen))
1308
+    local subnet=$(maskip $ip $(cidr2netmask $masklen))
1309
+    [[ $network == $subnet ]]
1310
+}
1311
+
1312
+# Add a user to a group.
1313
+# add_user_to_group user group
1314
+function add_user_to_group() {
1315
+    local user=$1
1316
+    local group=$2
1317
+
1318
+    if [[ -z "$os_VENDOR" ]]; then
1319
+        GetOSVersion
1320
+    fi
1321
+
1322
+    # SLE11 and openSUSE 12.2 don't have the usual usermod
1323
+    if ! is_suse || [[ "$os_VENDOR" = "openSUSE" && "$os_RELEASE" != "12.2" ]]; then
1324
+        sudo usermod -a -G "$group" "$user"
1325
+    else
1326
+        sudo usermod -A "$group" "$user"
1327
+    fi
1328
+}
1329
+
1330
+# Convert CIDR notation to a IPv4 netmask
1331
+# cidr2netmask cidr-bits
1332
+function cidr2netmask() {
1333
+    local maskpat="255 255 255 255"
1334
+    local maskdgt="254 252 248 240 224 192 128"
1335
+    set -- ${maskpat:0:$(( ($1 / 8) * 4 ))}${maskdgt:$(( (7 - ($1 % 8)) * 4 )):3}
1336
+    echo ${1-0}.${2-0}.${3-0}.${4-0}
1337
+}
1338
+
1339
+# Gracefully cp only if source file/dir exists
1340
+# cp_it source destination
1341
+function cp_it {
1342
+    if [ -e $1 ] || [ -d $1 ]; then
1343
+        cp -pRL $1 $2
1344
+    fi
1345
+}
1346
+
1347
+# HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
1348
+# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
1349
+# ``localrc`` or on the command line if necessary::
1350
+#
1351
+# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
1352
+#
1353
+#     http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh
1354
+
1355
+function export_proxy_variables() {
1356
+    if [[ -n "$http_proxy" ]]; then
1357
+        export http_proxy=$http_proxy
1358
+    fi
1359
+    if [[ -n "$https_proxy" ]]; then
1360
+        export https_proxy=$https_proxy
1361
+    fi
1362
+    if [[ -n "$no_proxy" ]]; then
1363
+        export no_proxy=$no_proxy
1364
+    fi
1365
+}
1366
+
1367
+# Returns true if the directory is on a filesystem mounted via NFS.
1368
+function is_nfs_directory() {
1369
+    local mount_type=`stat -f -L -c %T $1`
1370
+    test "$mount_type" == "nfs"
1371
+}
1372
+
1373
+# Return the network portion of the given IP address using netmask
1374
+# netmask is in the traditional dotted-quad format
1375
+# maskip ip-address netmask
1376
+function maskip() {
1377
+    local ip=$1
1378
+    local mask=$2
1379
+    local l="${ip%.*}"; local r="${ip#*.}"; local n="${mask%.*}"; local m="${mask#*.}"
1380
+    local subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.}))
1381
+    echo $subnet
1382
+}
1383
+
1384
+# Service wrapper to restart services
1385
+# restart_service service-name
1386
+function restart_service() {
1387
+    if is_ubuntu; then
1388
+        sudo /usr/sbin/service $1 restart
1389
+    else
1390
+        sudo /sbin/service $1 restart
1391
+    fi
1392
+}
1393
+
1394
+# Only change permissions of a file or directory if it is not on an
1395
+# NFS filesystem.
1396
+function safe_chmod() {
1397
+    _safe_permission_operation chmod $@
1398
+}
1399
+
1400
+# Only change ownership of a file or directory if it is not on an NFS
1401
+# filesystem.
1402
+function safe_chown() {
1403
+    _safe_permission_operation chown $@
1404
+}
1405
+
1406
+# Service wrapper to start services
1407
+# start_service service-name
1408
+function start_service() {
1409
+    if is_ubuntu; then
1410
+        sudo /usr/sbin/service $1 start
1411
+    else
1412
+        sudo /sbin/service $1 start
1413
+    fi
1414
+}
1415
+
1416
+# Service wrapper to stop services
1417
+# stop_service service-name
1418
+function stop_service() {
1419
+    if is_ubuntu; then
1420
+        sudo /usr/sbin/service $1 stop
1421
+    else
1422
+        sudo /sbin/service $1 stop
1423
+    fi
1424
+}
1425
+
1426
+
1427
+# Restore xtrace
1428
+$XTRACE
1429
+
1430
+# Local variables:
1431
+# mode: shell-script
1432
+# End: