functions
e263c82e
 #!/bin/bash
 #
dff49a24
 # functions - DevStack-specific functions
13dc5ccd
 #
4a43b7bd
 # The following variables are assumed to be defined by certain functions:
6a5aa7c6
 #
d8864fea
 # - ``DATABASE_BACKENDS``
6a5aa7c6
 # - ``ENABLED_SERVICES``
 # - ``FILES``
 # - ``GLANCE_HOSTPORT``
d8864fea
 #
13dc5ccd
 
4ffb4541
 # ensure we don't re-source this in the same environment
 [[ -z "$_DEVSTACK_FUNCTIONS" ]] || return 0
 declare -r _DEVSTACK_FUNCTIONS=1
 
dff49a24
 # Include the common functions
 FUNC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd)
 source ${FUNC_DIR}/functions-common
bf2ad701
 source ${FUNC_DIR}/inc/ini-config
490430db
 source ${FUNC_DIR}/inc/python
32d6bc6a
 source ${FUNC_DIR}/inc/rootwrap
7f9aa71b
 
27e32699
 # Save trace setting
 XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
54e3910f
 # Check if a function already exists
 function function_exists {
     declare -f -F $1 > /dev/null
 }
7f9aa71b
 
cb961597
 # Retrieve an image from a URL and upload into Glance.
ca0e3d02
 # Uses the following variables:
cb961597
 #
 # - ``FILES`` must be set to the cache dir
 # - ``GLANCE_HOSTPORT``
 #
5aeea6ae
 # upload_image image-url
aee18c74
 function upload_image {
ca0e3d02
     local image_url=$1
 
e9f76670
     local image image_fname image_name
 
ca0e3d02
     # Create a directory for the downloaded image tarballs.
     mkdir -p $FILES/images
e9f76670
     image_fname=`basename "$image_url"`
3e439448
     if [[ $image_url != file* ]]; then
314af0a7
         # Downloads the image (uec ami+akistyle), then extracts it.
e9f76670
         if [[ ! -f $FILES/$image_fname || "$(stat -c "%s" $FILES/$image_fname)" = "0" ]]; then
057d6ae2
             wget --progress=dot:giga -c $image_url -O $FILES/$image_fname
6681a4fa
             if [[ $? -ne 0 ]]; then
                 echo "Not found: $image_url"
                 return
             fi
3e439448
         fi
e9f76670
         image="$FILES/${image_fname}"
3e439448
     else
3324f19f
         # File based URL (RFC 1738): ``file://host/path``
3e439448
         # Remote files are not considered here.
3324f19f
         # unix: ``file:///home/user/path/file``
         # windows: ``file:///C:/Documents%20and%20Settings/user/path/file``
e9f76670
         image=$(echo $image_url | sed "s/^file:\/\///g")
         if [[ ! -f $image || "$(stat -c "%s" $image)" == "0" ]]; then
ca0e3d02
             echo "Not found: $image_url"
             return
         fi
     fi
 
     # OpenVZ-format images are provided as .tar.gz, but not decompressed prior to loading
     if [[ "$image_url" =~ 'openvz' ]]; then
e9f76670
         image_name="${image_fname%.tar.gz}"
31c313d3
         openstack --os-cloud=devstack-admin image create "$image_name" --public --container-format ami --disk-format ami < "${image}"
ca0e3d02
         return
     fi
 
cbaff86b
     # vmdk format images
     if [[ "$image_url" =~ '.vmdk' ]]; then
e9f76670
         image_name="${image_fname%.vmdk}"
a6273b93
 
         # Before we can upload vmdk type images to glance, we need to know it's
         # disk type, storage adapter, and networking adapter. These values are
bfb3e5ec
         # passed to glance as custom properties.
5ea53ee5
         # We take these values from the vmdk file if populated. Otherwise, we use
a6273b93
         # vmdk filename, which is expected in the following format:
         #
bfb3e5ec
         #     <name>-<disk type>;<storage adapter>;<network adapter>
a6273b93
         #
         # If the filename does not follow the above format then the vsphere
         # driver will supply default values.
5ea53ee5
 
e9f76670
         local vmdk_disktype=""
88cde0b3
         local vmdk_net_adapter="e1000"
e9f76670
         local path_len
bfb3e5ec
 
5ea53ee5
         # vmdk adapter type
e9f76670
         local vmdk_adapter_type="$(head -25 $image | { grep -a -F -m 1 'ddb.adapterType =' $image || true; })"
5ea53ee5
         vmdk_adapter_type="${vmdk_adapter_type#*\"}"
         vmdk_adapter_type="${vmdk_adapter_type%?}"
 
         # vmdk disk type
e9f76670
         local vmdk_create_type="$(head -25 $image | { grep -a -F -m 1 'createType=' $image || true; })"
5ea53ee5
         vmdk_create_type="${vmdk_create_type#*\"}"
8dad4bde
         vmdk_create_type="${vmdk_create_type%\"*}"
90bcd2ff
 
         descriptor_data_pair_msg="Monolithic flat and VMFS disks "`
6681a4fa
                                     `"should use a descriptor-data pair."
5ea53ee5
         if [[ "$vmdk_create_type" = "monolithicSparse" ]]; then
             vmdk_disktype="sparse"
e9f76670
         elif [[ "$vmdk_create_type" = "monolithicFlat" || "$vmdk_create_type" = "vmfs" ]]; then
3324f19f
             # Attempt to retrieve the ``*-flat.vmdk``
e9f76670
             local flat_fname="$(head -25 $image | { grep -G 'RW\|RDONLY [0-9]+ FLAT\|VMFS' $image || true; })"
90bcd2ff
             flat_fname="${flat_fname#*\"}"
             flat_fname="${flat_fname%?}"
9c6d2840
             if [[ -z "$flat_fname" ]]; then
e9f76670
                 flat_fname="$image_name-flat.vmdk"
90bcd2ff
             fi
e9f76670
             path_len=`expr ${#image_url} - ${#image_fname}`
             local flat_url="${image_url:0:$path_len}$flat_fname"
90bcd2ff
             warn $LINENO "$descriptor_data_pair_msg"`
6681a4fa
                             `" Attempt to retrieve the *-flat.vmdk: $flat_url"
90bcd2ff
             if [[ $flat_url != file* ]]; then
                 if [[ ! -f $FILES/$flat_fname || \
                 "$(stat -c "%s" $FILES/$flat_fname)" = "0" ]]; then
057d6ae2
                     wget --progress=dot:giga -c $flat_url -O $FILES/$flat_fname
90bcd2ff
                 fi
e9f76670
                 image="$FILES/${flat_fname}"
90bcd2ff
             else
e9f76670
                 image=$(echo $flat_url | sed "s/^file:\/\///g")
                 if [[ ! -f $image || "$(stat -c "%s" $image)" == "0" ]]; then
90bcd2ff
                     echo "Flat disk not found: $flat_url"
9c6d2840
                     return 1
90bcd2ff
                 fi
             fi
e9f76670
             image_name="${flat_fname}"
90bcd2ff
             vmdk_disktype="preallocated"
8dad4bde
         elif [[ "$vmdk_create_type" = "streamOptimized" ]]; then
             vmdk_disktype="streamOptimized"
90bcd2ff
         elif [[ -z "$vmdk_create_type" ]]; then
             # *-flat.vmdk provided: attempt to retrieve the descriptor (*.vmdk)
             # to retrieve appropriate metadata
e9f76670
             if [[ ${image_name: -5} != "-flat" ]]; then
90bcd2ff
                 warn $LINENO "Expected filename suffix: '-flat'."`
e9f76670
                             `" Filename provided: ${image_name}"
99b622a9
             else
e9f76670
                 descriptor_fname="${image_name:0:${#image_name} - 5}.vmdk"
                 path_len=`expr ${#image_url} - ${#image_fname}`
                 local flat_path="${image_url:0:$path_len}"
                 local descriptor_url=$flat_path$descriptor_fname
9c6d2840
                 warn $LINENO "$descriptor_data_pair_msg"`
                                 `" Attempt to retrieve the descriptor *.vmdk: $descriptor_url"
                 if [[ $flat_path != file* ]]; then
                     if [[ ! -f $FILES/$descriptor_fname || \
                     "$(stat -c "%s" $FILES/$descriptor_fname)" = "0" ]]; then
                         wget -c $descriptor_url -O $FILES/$descriptor_fname
                     fi
                     descriptor_url="$FILES/$descriptor_fname"
                 else
                     descriptor_url=$(echo $descriptor_url | sed "s/^file:\/\///g")
                     if [[ ! -f $descriptor_url || \
                     "$(stat -c "%s" $descriptor_url)" == "0" ]]; then
                         echo "Descriptor not found: $descriptor_url"
                         return 1
                     fi
6681a4fa
                 fi
99b622a9
                 vmdk_adapter_type="$(head -25 $descriptor_url | { grep -a -F -m 1 'ddb.adapterType =' $descriptor_url || true; })"
                 vmdk_adapter_type="${vmdk_adapter_type#*\"}"
                 vmdk_adapter_type="${vmdk_adapter_type%?}"
             fi
6681a4fa
             vmdk_disktype="preallocated"
5ea53ee5
         else
             vmdk_disktype="preallocated"
         fi
bfb3e5ec
 
         # NOTE: For backwards compatibility reasons, colons may be used in place
         # of semi-colons for property delimiters but they are not permitted
         # characters in NTFS filesystems.
e9f76670
         property_string=`echo "$image_name" | { grep -oP '(?<=-)(?!.*-).*[:;].*[:;].*$' || true; }`
bfb3e5ec
         IFS=':;' read -a props <<< "$property_string"
         vmdk_disktype="${props[0]:-$vmdk_disktype}"
         vmdk_adapter_type="${props[1]:-$vmdk_adapter_type}"
         vmdk_net_adapter="${props[2]:-$vmdk_net_adapter}"
a6273b93
 
31c313d3
         openstack --os-cloud=devstack-admin image create "$image_name" --public --container-format bare --disk-format vmdk --property vmware_disktype="$vmdk_disktype" --property vmware_adaptertype="$vmdk_adapter_type" --property hw_vif_model="$vmdk_net_adapter" < "${image}"
cbaff86b
         return
     fi
 
bc2ef929
     # XenServer-vhd-ovf-format images are provided as .vhd.tgz
316ed6cc
     # and should not be decompressed prior to loading
     if [[ "$image_url" =~ '.vhd.tgz' ]]; then
e9f76670
         image_name="${image_fname%.vhd.tgz}"
         local force_vm_mode=""
         if [[ "$image_name" =~ 'cirros' ]]; then
f1a2dbff
             # Cirros VHD image currently only boots in PV mode.
             # Nova defaults to PV for all VHD images, but
             # the glance setting is needed for booting
             # directly from volume.
e9f76670
             force_vm_mode="--property vm_mode=xen"
f1a2dbff
         fi
8d3ac2df
         openstack \
31c313d3
             --os-cloud=devstack-admin \
8d3ac2df
             image create \
             "$image_name" --public \
f1a2dbff
             --container-format=ovf --disk-format=vhd \
e9f76670
             $force_vm_mode < "${image}"
316ed6cc
         return
     fi
 
bc2ef929
     # .xen-raw.tgz suggests a Xen capable raw image inside a tgz.
     # and should not be decompressed prior to loading.
     # Setting metadata, so PV mode is used.
     if [[ "$image_url" =~ '.xen-raw.tgz' ]]; then
e9f76670
         image_name="${image_fname%.xen-raw.tgz}"
8d3ac2df
         openstack \
31c313d3
             --os-cloud=devstack-admin \
8d3ac2df
             image create \
             "$image_name" --public \
bc2ef929
             --container-format=tgz --disk-format=raw \
e9f76670
             --property vm_mode=xen < "${image}"
bc2ef929
         return
     fi
 
54ee8a82
     if [[ "$image_url" =~ '.hds' ]]; then
         image_name="${image_fname%.hds}"
         vm_mode=${image_name##*-}
         if [[ $vm_mode != 'exe' && $vm_mode != 'hvm' ]]; then
             die $LINENO "Unknown vm_mode=${vm_mode} for Virtuozzo image"
         fi
 
         openstack \
31c313d3
             --os-cloud=devstack-admin \
54ee8a82
             image create \
             "$image_name" --public \
             --container-format=bare --disk-format=ploop \
             --property vm_mode=$vm_mode < "${image}"
         return
     fi
 
e9f76670
     local kernel=""
     local ramdisk=""
     local disk_format=""
     local container_format=""
     local unpack=""
     local img_property=""
     case "$image_fname" in
ca0e3d02
         *.tar.gz|*.tgz)
             # Extract ami and aki files
e9f76670
             [ "${image_fname%.tar.gz}" != "$image_fname" ] &&
                 image_name="${image_fname%.tar.gz}" ||
                 image_name="${image_fname%.tgz}"
             local xdir="$FILES/images/$image_name"
ca0e3d02
             rm -Rf "$xdir";
             mkdir "$xdir"
e9f76670
             tar -zxf $image -C "$xdir"
             kernel=$(for f in "$xdir/"*-vmlinuz* "$xdir/"aki-*/image; do
537d4025
                 [ -f "$f" ] && echo "$f" && break; done; true)
e9f76670
             ramdisk=$(for f in "$xdir/"*-initrd* "$xdir/"ari-*/image; do
537d4025
                 [ -f "$f" ] && echo "$f" && break; done; true)
e9f76670
             image=$(for f in "$xdir/"*.img "$xdir/"ami-*/image; do
537d4025
                 [ -f "$f" ] && echo "$f" && break; done; true)
e9f76670
             if [[ -z "$image_name" ]]; then
                 image_name=$(basename "$image" ".img")
ca0e3d02
             fi
             ;;
         *.img)
e9f76670
             image_name=$(basename "$image" ".img")
             local format=$(qemu-img info ${image} | awk '/^file format/ { print $3; exit }')
636a3ff4
             if [[ ",qcow2,raw,vdi,vmdk,vpc," =~ ",$format," ]]; then
e9f76670
                 disk_format=$format
636a3ff4
             else
e9f76670
                 disk_format=raw
636a3ff4
             fi
e9f76670
             container_format=bare
ca0e3d02
             ;;
         *.img.gz)
e9f76670
             image_name=$(basename "$image" ".img.gz")
             disk_format=raw
             container_format=bare
             unpack=zcat
ca0e3d02
             ;;
         *.qcow2)
e9f76670
             image_name=$(basename "$image" ".qcow2")
             disk_format=qcow2
             container_format=bare
ca0e3d02
             ;;
0680204b
         *.iso)
e9f76670
             image_name=$(basename "$image" ".iso")
             disk_format=iso
             container_format=bare
0680204b
             ;;
ca823944
         *.vhd|*.vhdx|*.vhd.gz|*.vhdx.gz)
             local extension="${image_fname#*.}"
             image_name=$(basename "$image" ".$extension")
             disk_format=vhd
             container_format=bare
             if [ "${image_fname##*.}" == "gz" ]; then
                 unpack=zcat
             fi
             ;;
e9f76670
         *) echo "Do not know what to do with $image_fname"; false;;
ca0e3d02
     esac
 
7c4d678b
     if is_arch "ppc64le" || is_arch "ppc64" || is_arch "ppc"; then
         img_property="--property hw_disk_bus=scsi --property hw_scsi_model=virtio-scsi --property hw_cdrom_bus=scsi --property os_command_line=console=hvc0"
ab77587a
     fi
 
fcc3f6ee
     if is_arch "aarch64"; then
         img_property="--property hw_machine_type=virt --property hw_cdrom_bus=virtio --property os_command_line='console=ttyAMA0'"
     fi
 
e9f76670
     if [ "$container_format" = "bare" ]; then
         if [ "$unpack" = "zcat" ]; then
31c313d3
             openstack --os-cloud=devstack-admin image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < <(zcat --force "${image}")
ca0e3d02
         else
31c313d3
             openstack --os-cloud=devstack-admin image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < "${image}"
ca0e3d02
         fi
     else
         # Use glance client to add the kernel the root filesystem.
         # We parse the results of the first upload to get the glance ID of the
         # kernel for use when uploading the root filesystem.
e9f76670
         local kernel_id="" ramdisk_id="";
         if [ -n "$kernel" ]; then
31c313d3
             kernel_id=$(openstack --os-cloud=devstack-admin image create "$image_name-kernel" $img_property --public --container-format aki --disk-format aki < "$kernel" | grep ' id ' | get_field 2)
ca0e3d02
         fi
e9f76670
         if [ -n "$ramdisk" ]; then
31c313d3
             ramdisk_id=$(openstack --os-cloud=devstack-admin image create "$image_name-ramdisk" $img_property --public --container-format ari --disk-format ari < "$ramdisk" | grep ' id ' | get_field 2)
ca0e3d02
         fi
31c313d3
         openstack --os-cloud=devstack-admin image create "${image_name%.img}" $img_property --public --container-format ami --disk-format ami ${kernel_id:+--property kernel_id=$kernel_id} ${ramdisk_id:+--property ramdisk_id=$ramdisk_id} < "${image}"
ca0e3d02
     fi
 }
 
1a6d4492
 
c1b486a5
 # Set the database backend to use
 # When called from stackrc/localrc DATABASE_BACKENDS has not been
 # initialized yet, just save the configuration selection and call back later
 # to validate it.
cb961597
 #
 # ``$1`` - the name of the database backend to use (mysql, postgresql, ...)
c1b486a5
 function use_database {
     if [[ -z "$DATABASE_BACKENDS" ]]; then
afc29fe5
         # No backends registered means this is likely called from ``localrc``
         # This is now deprecated usage
c1b486a5
         DATABASE_TYPE=$1
3aa88871
         DEPRECATED_TEXT="$DEPRECATED_TEXT\nThe database backend needs to be properly set in ENABLED_SERVICES; use_database is deprecated localrc\n"
251d3b5f
     else
afc29fe5
         # This should no longer get called...here for posterity
251d3b5f
         use_exclusive_service DATABASE_BACKENDS DATABASE_TYPE $1
c1b486a5
     fi
 }
 
b5ab6468
 #Macro for curl statements. curl requires -g option for literal IPv6 addresses.
 CURL_GET="${CURL_GET:-curl -g}"
1a6d4492
 
3a3a2bac
 # Wait for an HTTP server to start answering requests
 # wait_for_service timeout url
aee18c74
 function wait_for_service {
3a3a2bac
     local timeout=$1
     local url=$2
b5ab6468
     timeout $timeout sh -c "while ! $CURL_GET -k --noproxy '*' -s $url >/dev/null; do sleep 1; done"
3a3a2bac
 }
 
1a6d4492
 
fda946e3
 # ping check
af9bf866
 # Uses globals ``ENABLED_SERVICES``, ``TOP_DIR``, ``MULTI_HOST``, ``PRIVATE_NETWORK``
 # ping_check <ip> [boot-timeout] [from_net] [expected]
aee18c74
 function ping_check {
af9bf866
     local ip=$1
     local timeout=${2:-30}
     local from_net=${3:-""}
     local expected=${4:-True}
     local op="!"
     local failmsg="[Fail] Couldn't ping server"
     local ping_cmd="ping"
fda946e3
 
af9bf866
     # if we don't specify a from_net we're expecting things to work
     # fine from our local box.
     if [[ -n "$from_net" ]]; then
         if is_service_enabled neutron; then
             ping_cmd="$TOP_DIR/tools/ping_neutron.sh $from_net"
         elif [[ "$MULTI_HOST" = "True" && "$from_net" = "$PRIVATE_NETWORK_NAME" ]]; then
             # there is no way to address the multihost / private case, bail here for compatibility.
             # TODO: remove this cruft and redo code to handle this at the caller level.
             return
         fi
fda946e3
     fi
af9bf866
 
     # inverse the logic if we're testing no connectivity
     if [[ "$expected" != "True" ]]; then
         op=""
         failmsg="[Fail] Could ping server"
5db5bfa2
     fi
af9bf866
 
     # Because we've transformed this command so many times, print it
     # out at the end.
     local check_command="while $op $ping_cmd -c1 -w1 $ip; do sleep 1; done"
     echo "Checking connectivity with $check_command"
 
     if ! timeout $timeout sh -c "$check_command"; then
         die $LINENO $failmsg
fda946e3
     fi
 }
 
6769b166
 # Get ip of instance
aee18c74
 function get_instance_ip {
6769b166
     local vm_id=$1
     local network_name=$2
     local nova_result="$(nova show $vm_id)"
     local ip=$(echo "$nova_result" | grep "$network_name" | get_field 2)
     if [[ $ip = "" ]];then
         echo "$nova_result"
         die $LINENO "[Fail] Coudn't get ipaddress of VM"
     fi
     echo $ip
 }
1a6d4492
 
fda946e3
 # ssh check
5db5bfa2
 
1a6d4492
 # ssh_check net-name key-file floating-ip default-user active-timeout
aee18c74
 function ssh_check {
b05c8769
     if is_service_enabled neutron; then
         _ssh_check_neutron  "$1" $2 $3 $4 $5
5db5bfa2
         return
     fi
     _ssh_check_novanet "$1" $2 $3 $4 $5
 }
 
aee18c74
 function _ssh_check_novanet {
fda946e3
     local NET_NAME=$1
     local KEY_FILE=$2
     local FLOATING_IP=$3
     local DEFAULT_INSTANCE_USER=$4
     local ACTIVE_TIMEOUT=$5
6931c137
     local probe_cmd=""
cc6b4435
     if ! timeout $ACTIVE_TIMEOUT sh -c "while ! ssh -o StrictHostKeyChecking=no -i $KEY_FILE ${DEFAULT_INSTANCE_USER}@$FLOATING_IP echo success; do sleep 1; done"; then
07115eb5
         die $LINENO "server didn't become ssh-able!"
fda946e3
     fi
 }
13dc5ccd
 
856a11e0
 
 # Get the location of the $module-rootwrap executables, where module is cinder
 # or nova.
 # get_rootwrap_location module
aee18c74
 function get_rootwrap_location {
856a11e0
     local module=$1
 
4196d556
     echo "$(get_python_exec_prefix)/$module-rootwrap"
856a11e0
 }
 
1a6d4492
 
0488edda
 # Path permissions sanity check
 # check_path_perm_sanity path
aee18c74
 function check_path_perm_sanity {
0488edda
     # Ensure no element of the path has 0700 permissions, which is very
     # likely to cause issues for daemons.  Inspired by default 0700
     # homedir permissions on RHEL and common practice of making DEST in
     # the stack user's homedir.
 
     local real_path=$(readlink -f $1)
     local rebuilt_path=""
     for i in $(echo ${real_path} | tr "/" " "); do
         rebuilt_path=$rebuilt_path"/"$i
 
         if [[ $(stat -c '%a' ${rebuilt_path}) = 700 ]]; then
             echo "*** DEST path element"
             echo "***    ${rebuilt_path}"
             echo "*** appears to have 0700 permissions."
dc97cb71
             echo "*** This is very likely to cause fatal issues for DevStack daemons."
0488edda
 
             if [[ -n "$SKIP_PATH_SANITY" ]]; then
                 return
             else
                 echo "*** Set SKIP_PATH_SANITY to skip this check"
                 die $LINENO "Invalid path permissions"
             fi
         fi
     done
 }
 
1a6d4492
 
51a3f1f6
 # This function recursively compares versions, and is not meant to be
 # called by anything other than vercmp_numbers below. This function does
 # not work with alphabetic versions.
 #
 # _vercmp_r sep ver1 ver2
 function _vercmp_r {
537d4025
     typeset sep
     typeset -a ver1=() ver2=()
     sep=$1; shift
     ver1=("${@:1:sep}")
     ver2=("${@:sep+1}")
51a3f1f6
 
537d4025
     if ((ver1 > ver2)); then
         echo 1; return 0
     elif ((ver2 > ver1)); then
         echo -1; return 0
     fi
51a3f1f6
 
537d4025
     if ((sep <= 1)); then
         echo 0; return 0
     fi
51a3f1f6
 
537d4025
     _vercmp_r $((sep-1)) "${ver1[@]:1}" "${ver2[@]:1}"
51a3f1f6
 }
 
 
 # This function compares two versions and is meant to be called by
 # external callers. Please note the function assumes non-alphabetic
 # versions. For example, this will work:
 #
 #   vercmp_numbers 1.10 1.4
 #
 # The above will return "1", as 1.10 is greater than 1.4.
 #
 #   vercmp_numbers 5.2 6.4
 #
 # The above will return "-1", as 5.2 is less than 6.4.
 #
 #   vercmp_numbers 4.0 4.0
 #
 # The above will return "0", as the versions are equal.
 #
 # vercmp_numbers ver1 ver2
aee18c74
 function vercmp_numbers {
537d4025
     typeset v1=$1 v2=$2 sep
     typeset -a ver1 ver2
51a3f1f6
 
2a866dd2
     deprecated "vercmp_numbers is deprecated for more generic vercmp"
 
537d4025
     IFS=. read -ra ver1 <<< "$v1"
     IFS=. read -ra ver2 <<< "$v2"
51a3f1f6
 
537d4025
     _vercmp_r "${#ver1[@]}" "${ver1[@]}" "${ver2[@]}"
51a3f1f6
 }
 
2a866dd2
 # vercmp ver1 op ver2
 #  Compare VER1 to VER2
 #   - op is one of < <= == >= >
 #   - returns true if satisified
 #  e.g.
 #  if vercmp 1.0 "<" 2.0; then
 #    ...
 #  fi
 function vercmp {
     local v1=$1
     local op=$2
     local v2=$3
     local result
 
     # sort the two numbers with sort's "-V" argument.  Based on if v2
     # swapped places with v1, we can determine ordering.
     result=$(echo -e "$v1\n$v2" | sort -V | head -1)
 
     case $op in
         "==")
             [ "$v1" = "$v2" ]
             return
             ;;
         ">")
             [ "$v1" != "$v2" ] && [ "$result" = "$v2" ]
             return
             ;;
         "<")
             [ "$v1" != "$v2" ] && [ "$result" = "$v1" ]
             return
             ;;
         ">=")
             [ "$result" = "$v2" ]
             return
             ;;
         "<=")
             [ "$result" = "$v1" ]
             return
             ;;
         *)
             die $LINENO "unrecognised op: $op"
             ;;
     esac
 }
51a3f1f6
 
05ae833b
 # This function sets log formatting options for colorizing log
 # output to stdout. It is meant to be called by lib modules.
 # The last two parameters are optional and can be used to specify
 # non-default value for project and user format variables.
 # Defaults are respectively 'project_name' and 'user_name'
 #
 # setup_colorized_logging something.conf SOMESECTION
aee18c74
 function setup_colorized_logging {
05ae833b
     local conf_file=$1
     local conf_section=$2
     local project_var=${3:-"project_name"}
     local user_var=${4:-"user_name"}
     # Add color to logging output
     iniset $conf_file $conf_section logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %("$user_var")s %("$project_var")s%(color)s] %(instance)s%(color)s%(message)s"
     iniset $conf_file $conf_section logging_default_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
     iniset $conf_file $conf_section logging_debug_format_suffix "from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d"
     iniset $conf_file $conf_section logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s"
 }
 
54e3910f
 # These functions are provided for basic fall-back functionality for
dc97cb71
 # projects that include parts of DevStack (Grenade).  stack.sh will
 # override these with more specific versions for DevStack (with fancy
54e3910f
 # spinners, etc).  We never override an existing version
 if ! function_exists echo_summary; then
     function echo_summary {
         echo $@
     }
 fi
 if ! function_exists echo_nolog; then
     function echo_nolog {
         echo $@
     }
 fi
dff49a24
 
36f2f024
 
 # create_disk - Create backing disk
 function create_disk {
     local node_number
     local disk_image=${1}
     local storage_data_dir=${2}
     local loopback_disk_size=${3}
 
     # Create a loopback disk and format it to XFS.
     if [[ -e ${disk_image} ]]; then
         if egrep -q ${storage_data_dir} /proc/mounts; then
             sudo umount ${storage_data_dir}/drives/sdb1
             sudo rm -f ${disk_image}
         fi
     fi
 
     sudo mkdir -p ${storage_data_dir}/drives/images
 
     sudo truncate -s ${loopback_disk_size} ${disk_image}
 
     # Make a fresh XFS filesystem. Use bigger inodes so xattr can fit in
     # a single inode. Keeping the default inode size (256) will result in multiple
     # inodes being used to store xattr. Retrieving the xattr will be slower
     # since we have to read multiple inodes. This statement is true for both
     # Swift and Ceph.
     sudo mkfs.xfs -f -i size=1024 ${disk_image}
 
     # Mount the disk with mount options to make it as efficient as possible
     if ! egrep -q ${storage_data_dir} /proc/mounts; then
         sudo mount -t xfs -o loop,noatime,nodiratime,nobarrier,logbufs=8  \
             ${disk_image} ${storage_data_dir}
     fi
 }
 
e4e088e5
 
 # set_mtu - Set MTU on a device
 function set_mtu {
     local dev=$1
     local mtu=$2
     sudo ip link set mtu $mtu dev $dev
 }
 
 
27e32699
 # Restore xtrace
408b009c
 $XTRACE
4a43b7bd
 
 # Local variables:
584d90ec
 # mode: shell-script
f900bd79
 # End: