blob: a293fa5bf6514a94309a62b1dc67d0b143895da2 [file] [log] [blame]
Joey Armstrong96158a92022-11-25 10:36:06 -05001#!/usr/bin/env groovy
Joey Armstrong3d444c62022-11-26 21:42:20 -05002// -----------------------------------------------------------------------
3// -----------------------------------------------------------------------
Joey Armstrong96158a92022-11-25 10:36:06 -05004
Joey Armstrong3d444c62022-11-26 21:42:20 -05005// -----------------------------------------------------------------------
6// -----------------------------------------------------------------------
7def getIam(String func)
8{
9 String src = 'vars/waitForAdapters.groovy'
10 String iam = [src, func].join('::')
11 return
12}
Andrea Campanella45b8eb72021-09-28 10:50:01 +020013
Joey Armstrong3d444c62022-11-26 21:42:20 -050014// -----------------------------------------------------------------------
15// -----------------------------------------------------------------------
16def getAdapters()
17{
18 String iam = getIam('getAdapters')
19
20 def adapters = ""
21 try
22 {
23 adapters = sh (
24 script: 'voltctl adapter list --format "{{gosince .LastCommunication}}"',
25 returnStdout: true,
26 ).trim()
27 }
28 catch (err)
29 {
30 // in some older versions of voltctl the command results in
31 // ERROR: Unexpected error while attempting to format results
32 // as table : template: output:1: function "gosince" not defined
33 // if that's the case we won't be able to check the timestamp so
34 // it's useless to wait
35 println("voltctl can't parse LastCommunication, skip waiting")
Joey Armstrong14a67a12022-11-28 12:28:23 -050036 adapters = 'SKIP' // why not just retry a few times (?)
Joey Armstrong3d444c62022-11-26 21:42:20 -050037 }
38
39 print("** ${iam}: returned $adapters")
40 return adapters
41}
42
43// -----------------------------------------------------------------------
Joey Armstrong14a67a12022-11-28 12:28:23 -050044// Intent: Interrogate adapter states to determine if we should continue
45// looping waiting for adapter to start. Passed values must all be
46// Integral, Valid and within range to assert we are done waiting.
47// Function will return incomplete at the first sign of an invalid value.
48// -----------------------------------------------------------------------
49// NOTE: list.find{} was replaced with a for loop to simplify
50// early loop termination and return.
51// -----------------------------------------------------------------------
52// RETURN: scalar
53// 'DOUBLE-DIGIT' - value exceeds 0-5sec response window.
54// 'NON-NUMERIC' - garbage in the stream (letter, symbol, ctrl)
55// 'NULL' - empty or null string detected
56// 'VALID' - succes, all adapters are functional
57// 'SIX-NINE' - detected a single numeric digit between 6 and 9.
58// -----------------------------------------------------------------------
59def getAdaptersState(String adapters0)
60{
61 String iam = getIam('getAdaptersState')
62 Boolean debug = true // for now
63
64 def adapters = adapters0.split('\n')
65
66 String ans = null
67 def found = []
68 for(i=0; i<adapters.size(); i++)
69 {
Joey Armstrong3d56fee2022-11-28 16:02:41 -050070 String elapsed = adapters[i]
Joey Armstrong14a67a12022-11-28 12:28:23 -050071 if (debug)
72 println("** ${iam} Checking elapsed[$i]: $elapsed")
73
74 if (! elapsed) // empty string or null
75 {
76 ans = 'NULL'
77 break
78 }
79
80 Integer size = elapsed.length()
81 if (size > 2) // 463765h58m52(s)
82 {
83 // higlander: there can be only one
84 ans = 'DOUBLE-DIGIT'
85 break
86 }
87
88 if (elapsed.endsWith('s'))
89 {
90 // safer than replaceAll('s'): ssss1s => 1
91 elapsed = elapsed.substring(0, size-1)
92 }
93
94 // Line noise guard: 'a', 'f', '#', '!'
95 if (! elapsed.isInteger())
96 {
97 ans = 'NON-NUMERIC'
98 break
99 }
100
101 // Is value in range:
102 // discard negative integers as just plain wonky.
103 // HMMM(?): zero/no latency response is kinda odd to include imho.
104 Integer val = elapsed.toInteger()
105 if (5 >= val && val >= 0)
106 {
107 found.add(elapsed)
108 }
109 else
110 {
111 ans = 'SIX-NINE'
112 break
113 }
114 } // for()
115
116 // Declare success IFF all values are:
117 // o integral
118 // o valid
119 // o within range
120 if (ans == null)
121 {
122 Integer got = found.size()
123 Integer exp = adapters.size()
124 ans = (! exp) ? 'NO-ADAPTERS'
125 : (got == exp) ? 'VALID'
126 : 'CONTINUE'
127 }
128
Joey Armstrong3d56fee2022-11-28 16:02:41 -0500129 if (debug)
130 println("** ${iam} return: [$ans]")
Joey Armstrong14a67a12022-11-28 12:28:23 -0500131 return ans
132} // getAdaptersState
133
134// -----------------------------------------------------------------------
Joey Armstrong3d444c62022-11-26 21:42:20 -0500135// -----------------------------------------------------------------------
136def process(Map config)
137{
138 String iam = getIam('process')
Joey Armstrong96158a92022-11-25 10:36:06 -0500139 println("** ${iam}: ENTER")
140
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200141 def defaultConfig = [
142 volthaNamespace: "voltha",
Matteo Scandolo721d08b2021-09-30 17:42:40 -0700143 stackName: "voltha",
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200144 adaptersToWait: 2,
145 ]
146
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200147 def cfg = defaultConfig + config
148
Andrea Campanella365ea1e2021-09-28 10:50:01 +0200149 if (cfg.adaptersToWait == 0){
150 //no need to wait
151 println "No need to wait for adapters to be registered"
152 return
153 }
154
Joey Armstrong3d444c62022-11-26 21:42:20 -0500155 println("** ${iam}: Wait for adapters to be registered")
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200156
157 // guarantee that at least the specified number of adapters are registered with VOLTHA before proceeding
158 sh """
159 set +x
Matteo Scandolo721d08b2021-09-30 17:42:40 -0700160 _TAG="voltha-voltha-api" bash -c "while true; do kubectl port-forward --address 0.0.0.0 -n ${cfg.volthaNamespace} svc/${cfg.stackName}-voltha-api 55555:55555; done"&
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200161 """
162
163 sh """
164 set +x
165 adapters=\$(voltctl adapter list -q | wc -l)
166 while [[ \$adapters -lt ${cfg.adaptersToWait} ]]; do
167 sleep 5
168 adapters=\$(voltctl adapter list -q | wc -l)
169 done
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200170 """
171
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700172 // NOTE that we need to wait for LastCommunication to be equal or shorter that 5s
173 // as that means the core can talk to the adapters
174 // if voltctl can't read LastCommunication we skip this check
Joey Armstrong3d444c62022-11-26 21:42:20 -0500175
176 println("** ${iam}: Wait for adapter LastCommunication")
Joey Armstrong14a67a12022-11-28 12:28:23 -0500177 Integer countdown = 60 * 10
178 while (true)
Joey Armstrong3d444c62022-11-26 21:42:20 -0500179 {
180 sleep 1
181 def adapters = getAdapters()
Joey Armstrong14a67a12022-11-28 12:28:23 -0500182 // Why are we not failing hard on this condition ?
183 // Adapters in an unknown state == testing: roll the dice
Joey Armstrong3d444c62022-11-26 21:42:20 -0500184 if (adapters == 'SKIP') { break }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200185
Joey Armstrong14a67a12022-11-28 12:28:23 -0500186 def state = getAdaptersState(adapters)
187 if (state == 'VALID') { break } // IFF
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200188
Joey Armstrong14a67a12022-11-28 12:28:23 -0500189 // ----------------------------------------------------------
190 // Excessive timeout but unsure where startup time boundry is
191 // [TODO] profile for a baseline
192 // [TODO] groovy.transform.TimedInterrupt
193 // ----------------------------------------------------------
194 countdown -= 1
195 if (1 > countdown)
196 throw new Exception("ERROR: Timed out waiting on adapter startup")
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700197 }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200198
Joey Armstrong3d444c62022-11-26 21:42:20 -0500199 println("** ${iam}: Wait for adapter LastCommunication")
200 sh("""
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700201 set +x
Joey Armstronga1915cf2022-11-26 15:58:49 -0500202 pgrep --list-full port-forw
Joey Armstrong96158a92022-11-25 10:36:06 -0500203
Joey Armstrong3d444c62022-11-26 21:42:20 -0500204 ps aux \
205 | grep port-forw \
206 | grep -v grep \
207 | awk '{print \$2}' \
208 | xargs --no-run-if-empty kill -9 || true
209 """)
Joey Armstrong96158a92022-11-25 10:36:06 -0500210
211 println("** ${iam}: LEAVE")
Joey Armstrong3d444c62022-11-26 21:42:20 -0500212 return
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200213}
Joey Armstrong3d444c62022-11-26 21:42:20 -0500214
215// -----------------------------------------------------------------------
216// -----------------------------------------------------------------------
217def call(Map config)
218{
219 String iam = getIam('process')
220 println("** ${iam}: ENTER")
221
222 if (!config) {
223 config = [:]
224 }
225
226 try
227 {
228 process(config)
229 }
230 catch (Exception err)
231 {
232 println("** ${iam}: EXCEPTION ${err}")
233 throw err
234 }
235 finally
236 {
237 println("** ${iam}: LEAVE")
238 }
239 return
240}
241
242// EOF