From 1cb551435365c7e06cb605ff11417f0a43881f37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Andr=C3=A9?= <martin.andre@kvhasia.com>
Date: Thu, 19 Mar 2015 14:42:45 +0900
Subject: [PATCH] Fix `wait_for` function in kolla-common.sh

Add `wait_for_output` and `wait_for_output_unless` helper functions that
only succeed when the command output contains the expected string, with
a possibility to exit early with a failure for `wait_for_output_unless`.

Change-Id: Ie20e7c72fb84f626f1a3fe9c4d2f22c9d6863dbe
---
 docker/base/kolla-common.sh | 73 +++++++++++++++++++++++++++++++------
 docs/wait-for.md            | 18 ---------
 2 files changed, 61 insertions(+), 30 deletions(-)
 delete mode 100644 docs/wait-for.md

diff --git a/docker/base/kolla-common.sh b/docker/base/kolla-common.sh
index 75058e521e..bc932a31d5 100644
--- a/docker/base/kolla-common.sh
+++ b/docker/base/kolla-common.sh
@@ -19,16 +19,37 @@ check_required_vars() {
     done
 }
 
+# The usage of the wait_for function looks like the following
+#     wait_for LOOPS_NUMBER SLEEP_TIME ARGS
+#
+# The ARGS are read and concatenated together into a single command and the
+# command is executed in a loop until it succeeds or reaches the max number of
+# attempts (LOOPS_NUMBER).
+#
+# Optional variables SUCCESSFUL_MATCH_OUTPUT and FAIL_MATCH_OUTPUT variable may
+# also be set to control if the loop exits early if the commands stdout/stderr
+# matches the supplied regex string. Consider using the `wait_for_output` and
+# `wait_for_output_unless` functions in case there is a need to check for the
+# command output.
+#
+# The script exits on failure, either when output contains string identified as
+# failure, or when it reaches a timeout.
+#
+# Examples:
+#     wait_for 30 10 ping -c 1 192.0.2.2
+#     wait_for 10 1 ls file_we_are_waiting_for
+#     wait_for 10 3 date \| grep 8
 wait_for() {
     local loops=${1:-""}
     local sleeptime=${2:-""}
-    local fail_match_output=${fail_match_output:-""}
-    local successful_match_output=${successful_match_output:-""}
+    FAIL_MATCH_OUTPUT=${FAIL_MATCH_OUTPUT:-""}
+    SUCCESSFUL_MATCH_OUTPUT=${SUCCESSFUL_MATCH_OUTPUT:-""}
     shift 2 || true
     local command="$@"
 
     if [ -z "$loops" -o -z "$sleeptime" -o -z "$command" ]; then
-        echo "Incorrect call of wait_for. Refer to docs/wait-for.md for help"
+        echo "wait_for is missing a required parameter"
+        return 1
     fi
 
     local i=0
@@ -36,15 +57,15 @@ wait_for() {
         i=$((i + 1))
         local status=0
         local output=$(eval $command 2>&1) || status=$?
-        if [[ -n "$successful_match_output" ]] \
-            && [[ $output =~ $successful_match_output ]]; then
-            break
-        elif [[ -n "$fail_match_output" ]] \
-            && [[ $output =~ $fail_match_output ]]; then
-            echo "Command output matched '$fail_match_output'."
-            continue
-        elif [[ -z "$successful_match_output" ]] && [[ $status -eq 0 ]]; then
-            break
+        if [[ -n "$SUCCESSFUL_MATCH_OUTPUT" ]] \
+            && [[ $output =~ $SUCCESSFUL_MATCH_OUTPUT ]]; then
+            return 0
+        elif [[ -n "$FAIL_MATCH_OUTPUT" ]] \
+            && [[ $output =~ $FAIL_MATCH_OUTPUT ]]; then
+            echo "Command output matched '$FAIL_MATCH_OUTPUT'."
+            exit 1
+        elif [[ -z "$SUCCESSFUL_MATCH_OUTPUT" ]] && [[ $status -eq 0 ]]; then
+            return 0
         fi
         sleep $sleeptime
     done
@@ -54,6 +75,34 @@ wait_for() {
     exit 1
 }
 
+# Helper function to `wait_for` that only succeeds when the given regex is
+# matching the command's output. Exit early with a failure when the second
+# supplied regexp is matching the output.
+#
+# Example:
+#     wait_for_output_unless CREATE_COMPLETE CREATE_FAIL 30 10 heat stack-show undercloud
+wait_for_output_unless() {
+    SUCCESSFUL_MATCH_OUTPUT=$1
+    FAIL_MATCH_OUTPUT=$2
+    shift 2
+    wait_for $@
+    local status=$?
+    unset SUCCESSFUL_MATCH_OUTPUT
+    unset FAIL_MATCH_OUTPUT
+    return $status
+}
+
+# Helper function to `wait_for` that only succeeds when the given regex is
+# matching the command's output.
+#
+# Example:
+#     wait_for_output CREATE_COMPLETE 30 10 heat stack-show undercloud
+wait_for_output() {
+    local expected_output=$1
+    shift
+    wait_for_output_unless $expected_output '' $@
+}
+
 # Exit unless we receive a successful response from corresponding OpenStack
 # service.
 check_for_os_service() {
diff --git a/docs/wait-for.md b/docs/wait-for.md
deleted file mode 100644
index 3317c315f5..0000000000
--- a/docs/wait-for.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Wait-for function
-
-The usage of the wait_for function looks like the following
-    $ SCRIPT_NAME LOOPS_NUMBER SLEEP_TIME ARGS
-
-The ARGS are read and concatenated together into a single command
-and the command is executed in a loop until it succeeds or reaches
-the max number of attempts (LOOPS_NUMBER).
-
-An optional FAIL_MATCH_OUTPUT variable may also be set to control
-if the loop exits early if the commands stdout/stderr matches the
-supplied regex string.
-Examples:
-    $ wait_for 30 10 ping -c 1 192.0.2.2
-    $ wait_for 10 1 ls file_we_are_waiting_for
-    $ wait_for 10 3 date \| grep 8
-    $ FAIL_MATCH_OUTPUT=CREATE_FAILED wait_for 30 10 heat stack-show undercloud
-    $ SUCCESSFUL_MATCH_OUTPUT=CREATE_COMPLETE wait_for 30 10 heat stack-show undercloud