Cleanups for elapsed detection logic.
vars/waitForAdapters.groovy
---------------------------
o Extract waitOn= logic into a named function.
o Added more data checks to consider an elapsed time as valid.
o Replace list.find{} loop with for() to simplify earliest possible
return when invalid elapsed values are detected.
o Check adapter list size passed in to avoid GIGO.
o Return a string describing state so logic is easier to follow.
o Literal string state can also be displayed inline for debugging.
o Wrap done loop with a explicit 10min (silly) timeout so no chance of going infinite.
Change-Id: I8a93d591e8f4dbf5267769792019789fb5a3e8e1
diff --git a/vars/waitForAdapters.groovy b/vars/waitForAdapters.groovy
index b8ba596..5d2f2a8 100644
--- a/vars/waitForAdapters.groovy
+++ b/vars/waitForAdapters.groovy
@@ -33,7 +33,7 @@
// if that's the case we won't be able to check the timestamp so
// it's useless to wait
println("voltctl can't parse LastCommunication, skip waiting")
- adapters = 'SKIP'
+ adapters = 'SKIP' // why not just retry a few times (?)
}
print("** ${iam}: returned $adapters")
@@ -41,6 +41,96 @@
}
// -----------------------------------------------------------------------
+// Intent: Interrogate adapter states to determine if we should continue
+// looping waiting for adapter to start. Passed values must all be
+// Integral, Valid and within range to assert we are done waiting.
+// Function will return incomplete at the first sign of an invalid value.
+// -----------------------------------------------------------------------
+// NOTE: list.find{} was replaced with a for loop to simplify
+// early loop termination and return.
+// -----------------------------------------------------------------------
+// RETURN: scalar
+// 'DOUBLE-DIGIT' - value exceeds 0-5sec response window.
+// 'NON-NUMERIC' - garbage in the stream (letter, symbol, ctrl)
+// 'NULL' - empty or null string detected
+// 'VALID' - succes, all adapters are functional
+// 'SIX-NINE' - detected a single numeric digit between 6 and 9.
+// -----------------------------------------------------------------------
+def getAdaptersState(String adapters0)
+{
+ String iam = getIam('getAdaptersState')
+ Boolean debug = true // for now
+
+ def adapters = adapters0.split('\n')
+
+ String ans = null
+ def found = []
+ for(i=0; i<adapters.size(); i++)
+ {
+ String elapsed = args[i]
+ if (debug)
+ println("** ${iam} Checking elapsed[$i]: $elapsed")
+
+ if (! elapsed) // empty string or null
+ {
+ ans = 'NULL'
+ break
+ }
+
+ Integer size = elapsed.length()
+ if (size > 2) // 463765h58m52(s)
+ {
+ // higlander: there can be only one
+ ans = 'DOUBLE-DIGIT'
+ break
+ }
+
+ if (elapsed.endsWith('s'))
+ {
+ // safer than replaceAll('s'): ssss1s => 1
+ elapsed = elapsed.substring(0, size-1)
+ }
+
+ // Line noise guard: 'a', 'f', '#', '!'
+ if (! elapsed.isInteger())
+ {
+ ans = 'NON-NUMERIC'
+ break
+ }
+
+ // Is value in range:
+ // discard negative integers as just plain wonky.
+ // HMMM(?): zero/no latency response is kinda odd to include imho.
+ Integer val = elapsed.toInteger()
+ if (5 >= val && val >= 0)
+ {
+ found.add(elapsed)
+ }
+ else
+ {
+ ans = 'SIX-NINE'
+ break
+ }
+ } // for()
+
+ // Declare success IFF all values are:
+ // o integral
+ // o valid
+ // o within range
+ if (ans == null)
+ {
+ Integer got = found.size()
+ Integer exp = adapters.size()
+ ans = (! exp) ? 'NO-ADAPTERS'
+ : (got == exp) ? 'VALID'
+ : 'CONTINUE'
+ }
+
+ println("** ${iam} return: [$ans]")
+ return ans
+} // getAdaptersState
+
+// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
def process(Map config)
{
@@ -83,28 +173,26 @@
// if voltctl can't read LastCommunication we skip this check
println("** ${iam}: Wait for adapter LastCommunication")
- def done = false;
- while (!done)
+ Integer countdown = 60 * 10
+ while (true)
{
sleep 1
def adapters = getAdapters()
+ // Why are we not failing hard on this condition ?
+ // Adapters in an unknown state == testing: roll the dice
if (adapters == 'SKIP') { break }
- def waitingOn = adapters.split( '\n' ).find{elapsed ->
- elapsed = elapsed.replaceAll('s','') // remove seconds
- print("** ${iam}: waitingOn elapsed=[${elapsed}]")
+ def state = getAdaptersState(adapters)
+ if (state == 'VALID') { break } // IFF
- // it has to be a single digit
- if (elapsed.length() > 1) { // 463765h58m52s
- return true
- }
-
- Boolean is_valid = (5 >= (elapsed as Integer))
- print("** ${iam}: waitingOn: is_valid=[$is_valid]")
- return is_valid
- }
-
- done = (waitingOn == null || waitingOn.length() == 0)
+ // ----------------------------------------------------------
+ // Excessive timeout but unsure where startup time boundry is
+ // [TODO] profile for a baseline
+ // [TODO] groovy.transform.TimedInterrupt
+ // ----------------------------------------------------------
+ countdown -= 1
+ if (1 > countdown)
+ throw new Exception("ERROR: Timed out waiting on adapter startup")
}
println("** ${iam}: Wait for adapter LastCommunication")