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
afef8bf0
 declare -r -g _DEVSTACK_FUNCTIONS=1
4ffb4541
 
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
2468ceaa
 source ${FUNC_DIR}/inc/meta-config
490430db
 source ${FUNC_DIR}/inc/python
32d6bc6a
 source ${FUNC_DIR}/inc/rootwrap
7f9aa71b
 
27e32699
 # Save trace setting
523f4880
 _XTRACE_FUNCTIONS=$(set +o | grep xtrace)
27e32699
 set +o xtrace
 
54e3910f
 # Check if a function already exists
 function function_exists {
     declare -f -F $1 > /dev/null
 }
7f9aa71b
 
646085d7
 # short_source prints out the current location of the caller in a way
 # that strips redundant directories. This is useful for PS4 usage.
 function short_source {
     saveIFS=$IFS
     IFS=" "
     called=($(caller 0))
     IFS=$saveIFS
     file=${called[2]}
     file=${file#$RC_DIR/}
     printf "%-40s " "$file:${called[1]}:${called[0]}"
 }
daa7a41e
 # PS4 is exported to child shells and uses the 'short_source' function, so
 # export it so child shells have access to the 'short_source' function also.
 export -f short_source
646085d7
 
d8bb2206
 # Download a file from a URL
 #
 # Will check cache (in $FILES) or download given URL.
 #
 # Argument is the URL to the remote file
 #
 # Will echo the local path to the file as the output.  Will die on
 # failure to download.
 #
 # Files can be pre-cached for CI environments, see EXTRA_CACHE_URLS
 # and tools/image_list.sh
 function get_extra_file {
     local file_url=$1
 
     file_name=$(basename "$file_url")
     if [[ $file_url != file* ]]; then
         # If the file isn't cache, download it
         if [[ ! -f $FILES/$file_name ]]; then
c652a498
             wget --progress=dot:giga -t 2 -c $file_url -O $FILES/$file_name
d8bb2206
             if [[ $? -ne 0 ]]; then
                 die "$file_url could not be downloaded"
             fi
         fi
         echo "$FILES/$file_name"
         return
     else
         # just strip the file:// bit and that's the path to the file
         echo $file_url | sed 's/$file:\/\///g'
     fi
 }
 
2614c1bb
 # Generate image property arguments for OSC
 #
 # Arguments: properties, one per, like propname=value
 #
 # Result is --property propname1=value1 --property propname2=value2
 function _image_properties_to_arg {
     local result=""
     for property in $*; do
         result+=" --property $property"
     done
     echo $result
 }
 
73ad9760
 # Upload an image to glance using the configured mechanism
 #
 # Arguments:
 #  image name
 #  container format
 #  disk format
 #  path to image file
 #  optional properties (format of propname=value)
 #
 function _upload_image {
     local image_name="$1"
     shift
     local container="$1"
     shift
     local disk="$1"
     shift
     local image="$1"
     shift
     local properties
     local useimport
 
2614c1bb
     properties=$(_image_properties_to_arg $*)
73ad9760
 
     if [[ "$GLANCE_USE_IMPORT_WORKFLOW" == "True" ]]; then
33f8f6e6
         useimport="--import"
73ad9760
     fi
 
     openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" --public --container-format "$container" --disk-format "$disk" $useimport $properties < "${image}"
 }
646085d7
 
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}"
73ad9760
         _upload_image "$image_name" ami 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
7ae97298
         local vmdk_adapter_type
         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
7ae97298
         local vmdk_create_type
         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``
7ae97298
             local flat_fname
             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
 
73ad9760
         _upload_image "$image_name" bare vmdk "$image" vmware_disktype="$vmdk_disktype" vmware_adaptertype="$vmdk_adapter_type" hw_vif_model="$vmdk_net_adapter"
 
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.
73ad9760
             force_vm_mode="vm_mode=xen"
f1a2dbff
         fi
73ad9760
         _upload_image "$image_name" ovf vhd "$image" $force_vm_mode
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}"
73ad9760
         _upload_image "$image_name" tgz raw "$image" vm_mode=xen
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
 
73ad9760
         _upload_image "$image_name" bare ploop "$image" vm_mode=$vm_mode
54ee8a82
         return
     fi
 
e9f76670
     local kernel=""
     local ramdisk=""
     local disk_format=""
     local container_format=""
     local unpack=""
49ad4850
     local img_property=""
 
     # NOTE(danms): If we're on libvirt/qemu or libvirt/kvm, set the hw_rng_model
     # to libvirt in the image properties.
     if [[ "$VIRT_DRIVER" == "libvirt" ]]; then
         if [[ "$LIBVIRT_TYPE" == "qemu" || "$LIBVIRT_TYPE" == "kvm" ]]; then
             img_property="hw_rng_model=virtio"
         fi
     fi
 
e9f76670
     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")
ada886dd
             local format
             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
             ;;
3feceb0e
         *.img.bz2)
             image_name=$(basename "$image" ".img.bz2")
             disk_format=qcow2
             container_format=bare
             unpack=bunzip2
             ;;
ca0e3d02
         *.qcow2)
e9f76670
             image_name=$(basename "$image" ".qcow2")
             disk_format=qcow2
             container_format=bare
f24e2992
             ;;
f70cb70a
         *.qcow2.xz)
             image_name=$(basename "$image" ".qcow2.xz")
             disk_format=qcow2
             container_format=bare
             unpack=unxz
             ;;
f24e2992
         *.raw)
             image_name=$(basename "$image" ".raw")
             disk_format=raw
             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")
2715fd0b
             disk_format=$(echo $image_fname | grep -oP '(?<=\.)vhdx?(?=\.|$)')
ca823944
             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
 
72f530fd
     if is_arch "ppc64le" || is_arch "ppc64" || is_arch "ppc"; then
73ad9760
         img_property="$img_property hw_cdrom_bus=scsi os_command_line=console=hvc0"
ab77587a
     fi
 
fcc3f6ee
     if is_arch "aarch64"; then
73ad9760
         img_property="$img_property hw_machine_type=virt hw_cdrom_bus=scsi hw_scsi_model=virtio-scsi os_command_line='console=ttyAMA0'"
fcc3f6ee
     fi
 
e9f76670
     if [ "$container_format" = "bare" ]; then
         if [ "$unpack" = "zcat" ]; then
73ad9760
             _upload_image "$image_name" $container_format $disk_format <(zcat --force "$image") $img_property
3feceb0e
         elif [ "$unpack" = "bunzip2" ]; then
73ad9760
             _upload_image "$image_name" $container_format $disk_format <(bunzip2 -cdk "$image") $img_property
f70cb70a
         elif [ "$unpack" = "unxz" ]; then
             # NOTE(brtknr): unxz the file first and cleanup afterwards to
             # prevent timeout while Glance tries to upload image (e.g. to Swift).
             local tmp_dir
             local image_path
             tmp_dir=$(mktemp -d)
             image_path="$tmp_dir/$image_name"
             unxz -cv "${image}" > "$image_path"
73ad9760
             _upload_image "$image_name" $container_format $disk_format "$image_path" $img_property
f70cb70a
             rm -rf $tmp_dir
ca0e3d02
         else
73ad9760
             _upload_image "$image_name" $container_format $disk_format "$image" $img_property
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
2614c1bb
             kernel_id=$(openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name-kernel" $(_image_properties_to_arg $img_property) --public --container-format aki --disk-format aki < "$kernel" | grep ' id ' | get_field 2)
ca0e3d02
         fi
e9f76670
         if [ -n "$ramdisk" ]; then
2614c1bb
             ramdisk_id=$(openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name-ramdisk" $(_image_properties_to_arg $img_property) --public --container-format ari --disk-format ari < "$ramdisk" | grep ' id ' | get_field 2)
ca0e3d02
         fi
73ad9760
         _upload_image "${image_name%.img}" ami ami "$image" ${kernel_id:+ kernel_id=$kernel_id} ${ramdisk_id:+ ramdisk_id=$ramdisk_id} $img_property
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
 #
b14665f0
 # ``$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
72ad9427
         deprecated "The database backend needs to be properly set in ENABLED_SERVICES; use_database is deprecated localrc"
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
21e3d1e5
 #
 # If the service we want is behind a proxy, the proxy may be available
 # before the service. Compliant proxies will return a 503 in this case
 # Loop until we get something else.
 # Also check for the case where there is no proxy and the service just
 # hasn't started yet. curl returns 7 for Failed to connect to host.
aee18c74
 function wait_for_service {
3a3a2bac
     local timeout=$1
     local url=$2
21e3d1e5
     local rval=0
2ca8af45
     time_start "wait_for_service"
21e3d1e5
     timeout $timeout bash -x <<EOF || rval=$?
         while [[ \$( ${CURL_GET} -k --noproxy '*' -s -o /dev/null -w '%{http_code}' ${url} ) == 503 || \$? -eq 7 ]]; do
             sleep 1
         done
 EOF
2ca8af45
     time_stop "wait_for_service"
21e3d1e5
     return $rval
3a3a2bac
 }
 
c2fe916f
 function wait_for_compute {
     local timeout=$1
     local rval=0
6f38cf4a
     local compute_hostname
c2fe916f
     time_start "wait_for_service"
6f38cf4a
     compute_hostname=$(iniget $NOVA_CONF DEFAULT host)
     if [[ -z $compute_hostname ]]; then
         compute_hostname=$(hostname)
     fi
c2fe916f
     timeout $timeout bash -x <<EOF || rval=$?
         ID=""
         while [[ "\$ID" == "" ]]; do
             sleep 1
ac475bbb
             if [[ "$VIRT_DRIVER" = 'fake' ]]; then
                 # When using the fake driver the compute hostnames have a suffix of 1 to NUMBER_FAKE_NOVA_COMPUTE
                 ID=\$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" compute service list --host `hostname`1 --service nova-compute -c ID -f value)
             else
6f38cf4a
                 ID=\$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" compute service list --host "$compute_hostname" --service nova-compute -c ID -f value)
ac475bbb
             fi
c2fe916f
         done
 EOF
     time_stop "wait_for_service"
     # Figure out what's happening on platforms where this doesn't work
     if [[ "$rval" != 0 ]]; then
         echo "Didn't find service registered by hostname after $timeout seconds"
         openstack --os-cloud devstack-admin --os-region "$REGION_NAME" compute service list
     fi
     return $rval
 }
 
1a6d4492
 
fda946e3
 # ping check
4b8cba77
 # Uses globals ``ENABLED_SERVICES``, ``TOP_DIR``, ``PRIVATE_NETWORK``
af9bf866
 # 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
4b8cba77
         # TODO(stephenfin): Is there any way neutron could be disabled now?
af9bf866
         if is_service_enabled neutron; then
             ping_cmd="$TOP_DIR/tools/ping_neutron.sh $from_net"
         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
842d54a2
     local addresses
ada886dd
     local ip
7ae97298
 
842d54a2
     addresses=$(openstack server show -c addresses -f value "$vm_id")
     ip=$(echo $addresses | sed -n "s/^.*$network_name=\([0-9\.]*\).*$/\1/p")
6769b166
     if [[ $ip = "" ]];then
842d54a2
         echo "addresses of server $vm_id : $addresses"
33c9a67e
         die $LINENO "[Fail] Couldn't get ipaddress of VM"
6769b166
     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.
 
ada886dd
     local real_path
     real_path=$(readlink -f $1)
0488edda
     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
 
2ba36cda
 # 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
 
9751be66
 # This sets up defaults we like in devstack for logging for tracking
 # down issues, and makes sure everything is done the same between
 # projects.
6808a346
 # NOTE(jh): Historically this function switched between three different
 # functions: setup_systemd_logging, setup_colorized_logging and
 # setup_standard_logging_identity. Since we always run with systemd now,
 # this could be cleaned up, but the other functions may still be in use
 # by plugins. Since deprecations haven't worked in the past, we'll just
 # leave them in place.
9751be66
 function setup_logging {
6808a346
     setup_systemd_logging $1
9751be66
 }
 
05ae833b
 # This function sets log formatting options for colorizing log
 # output to stdout. It is meant to be called by lib modules.
aee18c74
 function setup_colorized_logging {
05ae833b
     local conf_file=$1
     # Add color to logging output
6808a346
     iniset $conf_file DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(project_name)s %(user_name)s%(color)s] %(instance)s%(color)s%(message)s"
     iniset $conf_file DEFAULT 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 DEFAULT logging_debug_format_suffix "from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d"
     iniset $conf_file DEFAULT logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s"
05ae833b
 }
 
5edae548
 function setup_systemd_logging {
     local conf_file=$1
b2bfe561
     # NOTE(sdague): this is a nice to have, and means we're using the
     # native systemd path, which provides for things like search on
     # request-id. However, there may be an eventlet interaction here,
     # so going off for now.
c0644f39
     USE_JOURNAL=$(trueorfalse False USE_JOURNAL)
8cd310d7
     local pidstr=""
b2bfe561
     if [[ "$USE_JOURNAL" == "True" ]]; then
6808a346
         iniset $conf_file DEFAULT use_journal "True"
b2bfe561
         # if we are using the journal directly, our process id is already correct
     else
8cd310d7
         pidstr="(pid=%(process)d) "
b2bfe561
     fi
6808a346
     iniset $conf_file DEFAULT logging_debug_format_suffix "{{${pidstr}%(funcName)s %(pathname)s:%(lineno)d}}"
b2bfe561
 
6808a346
     iniset $conf_file DEFAULT logging_context_format_string "%(color)s%(levelname)s %(name)s [%(global_request_id)s %(request_id)s %(project_name)s %(user_name)s%(color)s] %(instance)s%(color)s%(message)s"
     iniset $conf_file DEFAULT logging_default_format_string "%(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
     iniset $conf_file DEFAULT logging_exception_prefix "ERROR %(name)s %(instance)s"
5edae548
 }
 
9751be66
 function setup_standard_logging_identity {
     local conf_file=$1
     iniset $conf_file DEFAULT logging_user_identity_format "%(project_name)s %(user_name)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
38a23d90
             sudo umount ${storage_data_dir}
36f2f024
             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
5d7d8913
         sudo mount -t xfs -o loop,noatime,nodiratime,logbufs=8  \
36f2f024
             ${disk_image} ${storage_data_dir}
     fi
 }
 
7b5c7dce
 
 # set_mtu - Set MTU on a device
 function set_mtu {
     local dev=$1
     local mtu=$2
     sudo ip link set mtu $mtu dev $dev
 }
 
 
0bf75a47
 # running_in_container - Returns true otherwise false
 function running_in_container {
d18d7c86
     [[ $(systemd-detect-virt --container) != 'none' ]]
0bf75a47
 }
 
 
b3a210f6
 # enable_kernel_bridge_firewall - Enable kernel support for bridge firewalling
 function enable_kernel_bridge_firewall {
     # Load bridge module. This module provides access to firewall for bridged
     # frames; and also on older kernels (pre-3.18) it provides sysctl knobs to
     # enable/disable bridge firewalling
     sudo modprobe bridge
     # For newer kernels (3.18+), those sysctl settings are split into a separate
     # kernel module (br_netfilter). Load it too, if present.
     sudo modprobe br_netfilter 2>> /dev/null || :
     # Enable bridge firewalling in case it's disabled in kernel (upstream
     # default is enabled, but some distributions may decide to change it).
     # This is at least needed for RHEL 7.2 and earlier releases.
3f771b7b
     for proto in ip ip6; do
b3a210f6
         sudo sysctl -w net.bridge.bridge-nf-call-${proto}tables=1
     done
 }
 
 
1f55d389
 # Set a systemd system override
 #
 # This sets a system-side override in system.conf. A per-service
 # override would be /etc/systemd/system/${service}.service/override.conf
 function set_systemd_override {
     local key="$1"
     local value="$2"
 
     local sysconf="/etc/systemd/system.conf"
     iniset -sudo "${sysconf}" "Manager" "$key" "$value"
     echo "Set systemd system override for ${key}=${value}"
 
     sudo systemctl daemon-reload
 }
 
309b99eb
 # Get a random port from the local port range
 #
 # This function returns an available port in the local port range. The search
 # order is not truly random, but should be considered a random value by the
 # user because it depends on the state of your local system.
 function get_random_port {
     read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
     while true; do
         for (( port = upper_port ; port >= lower_port ; port-- )); do
             sudo lsof -i ":$port" &> /dev/null
             if [[ $? > 0 ]] ; then
                 break 2
             fi
         done
     done
     echo $port
 }
 
07cbc449
 # Save some state information
 #
 # Write out various useful state information to /etc/devstack-version
2c0faca0
 function write_devstack_version {
6bab8321
     cat - <<EOF | sudo tee /etc/devstack-version >/dev/null
07cbc449
 DevStack Version: ${DEVSTACK_SERIES}
 Change: $(git log --format="%H %s %ci" -1)
 OS Version: ${os_VENDOR} ${os_RELEASE} ${os_CODENAME}
2c0faca0
 EOF
 }
 
27e32699
 # Restore xtrace
523f4880
 $_XTRACE_FUNCTIONS
4a43b7bd
 
 # Local variables:
584d90ec
 # mode: shell-script
f900bd79
 # End: