blob: dcc7fdacca7d8aab5d450df75ae1402ed66b44a5 [file] [log] [blame]
Joey Armstrong96158a92022-11-25 10:36:06 -05001#!/usr/bin/env groovy
Joey Armstrong3d444c62022-11-26 21:42:20 -05002// -----------------------------------------------------------------------
Joey Armstrongaf679da2023-01-31 14:22:41 -05003// Copyright 2021-2023 Open Networking Foundation (ONF) and the ONF Contributors
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
Joey Armstrong3d444c62022-11-26 21:42:20 -050016// -----------------------------------------------------------------------
Joey Armstrong96158a92022-11-25 10:36:06 -050017
Joey Armstrong3d444c62022-11-26 21:42:20 -050018// -----------------------------------------------------------------------
19// -----------------------------------------------------------------------
20def getIam(String func)
21{
Joey Armstrong7987c112022-12-05 12:42:43 -050022 // Cannot rely on a stack trace due to jenkins manipulation
Joey Armstrong3d444c62022-11-26 21:42:20 -050023 String src = 'vars/waitForAdapters.groovy'
24 String iam = [src, func].join('::')
Joey Armstrongf0c76902022-11-28 17:14:45 -050025 return iam
Joey Armstrong3d444c62022-11-26 21:42:20 -050026}
Andrea Campanella45b8eb72021-09-28 10:50:01 +020027
Joey Armstrong3d444c62022-11-26 21:42:20 -050028// -----------------------------------------------------------------------
29// -----------------------------------------------------------------------
30def getAdapters()
31{
32 String iam = getIam('getAdapters')
33
34 def adapters = ""
35 try
36 {
37 adapters = sh (
38 script: 'voltctl adapter list --format "{{gosince .LastCommunication}}"',
39 returnStdout: true,
40 ).trim()
41 }
42 catch (err)
43 {
44 // in some older versions of voltctl the command results in
45 // ERROR: Unexpected error while attempting to format results
46 // as table : template: output:1: function "gosince" not defined
47 // if that's the case we won't be able to check the timestamp so
48 // it's useless to wait
49 println("voltctl can't parse LastCommunication, skip waiting")
Joey Armstrong14a67a12022-11-28 12:28:23 -050050 adapters = 'SKIP' // why not just retry a few times (?)
Joey Armstrong3d444c62022-11-26 21:42:20 -050051 }
52
53 print("** ${iam}: returned $adapters")
54 return adapters
55}
56
57// -----------------------------------------------------------------------
Joey Armstrong14a67a12022-11-28 12:28:23 -050058// Intent: Interrogate adapter states to determine if we should continue
59// looping waiting for adapter to start. Passed values must all be
60// Integral, Valid and within range to assert we are done waiting.
61// Function will return incomplete at the first sign of an invalid value.
62// -----------------------------------------------------------------------
63// NOTE: list.find{} was replaced with a for loop to simplify
64// early loop termination and return.
65// -----------------------------------------------------------------------
66// RETURN: scalar
67// 'DOUBLE-DIGIT' - value exceeds 0-5sec response window.
68// 'NON-NUMERIC' - garbage in the stream (letter, symbol, ctrl)
69// 'NULL' - empty or null string detected
70// 'VALID' - succes, all adapters are functional
71// 'SIX-NINE' - detected a single numeric digit between 6 and 9.
72// -----------------------------------------------------------------------
73def getAdaptersState(String adapters0)
74{
75 String iam = getIam('getAdaptersState')
76 Boolean debug = true // for now
77
78 def adapters = adapters0.split('\n')
79
80 String ans = null
81 def found = []
82 for(i=0; i<adapters.size(); i++)
83 {
Joey Armstrong3d56fee2022-11-28 16:02:41 -050084 String elapsed = adapters[i]
Joey Armstrong14a67a12022-11-28 12:28:23 -050085 if (debug)
Joey Armstrong7987c112022-12-05 12:42:43 -050086 {
Joey Armstrong14a67a12022-11-28 12:28:23 -050087 println("** ${iam} Checking elapsed[$i]: $elapsed")
Joey Armstrong7987c112022-12-05 12:42:43 -050088 }
Joey Armstrong14a67a12022-11-28 12:28:23 -050089
90 if (! elapsed) // empty string or null
91 {
92 ans = 'NULL'
93 break
94 }
95
96 Integer size = elapsed.length()
97 if (size > 2) // 463765h58m52(s)
98 {
99 // higlander: there can be only one
100 ans = 'DOUBLE-DIGIT'
101 break
102 }
103
104 if (elapsed.endsWith('s'))
105 {
106 // safer than replaceAll('s'): ssss1s => 1
107 elapsed = elapsed.substring(0, size-1)
108 }
109
110 // Line noise guard: 'a', 'f', '#', '!'
111 if (! elapsed.isInteger())
112 {
113 ans = 'NON-NUMERIC'
114 break
115 }
116
117 // Is value in range:
118 // discard negative integers as just plain wonky.
119 // HMMM(?): zero/no latency response is kinda odd to include imho.
120 Integer val = elapsed.toInteger()
121 if (5 >= val && val >= 0)
122 {
123 found.add(elapsed)
124 }
125 else
126 {
127 ans = 'SIX-NINE'
128 break
129 }
130 } // for()
131
132 // Declare success IFF all values are:
133 // o integral
134 // o valid
135 // o within range
136 if (ans == null)
137 {
138 Integer got = found.size()
139 Integer exp = adapters.size()
140 ans = (! exp) ? 'NO-ADAPTERS'
141 : (got == exp) ? 'VALID'
142 : 'CONTINUE'
143 }
144
Joey Armstrong3d56fee2022-11-28 16:02:41 -0500145 if (debug)
Joey Armstrong7987c112022-12-05 12:42:43 -0500146 {
Joey Armstrong3d56fee2022-11-28 16:02:41 -0500147 println("** ${iam} return: [$ans]")
Joey Armstrong7987c112022-12-05 12:42:43 -0500148 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500149 return ans
150} // getAdaptersState
151
152// -----------------------------------------------------------------------
Joey Armstrong3d444c62022-11-26 21:42:20 -0500153// -----------------------------------------------------------------------
154def process(Map config)
155{
156 String iam = getIam('process')
Joey Armstrong96158a92022-11-25 10:36:06 -0500157 println("** ${iam}: ENTER")
158
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200159 def defaultConfig = [
160 volthaNamespace: "voltha",
Matteo Scandolo721d08b2021-09-30 17:42:40 -0700161 stackName: "voltha",
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200162 adaptersToWait: 2,
163 ]
164
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200165 def cfg = defaultConfig + config
166
Andrea Campanella365ea1e2021-09-28 10:50:01 +0200167 if (cfg.adaptersToWait == 0){
168 //no need to wait
169 println "No need to wait for adapters to be registered"
170 return
171 }
172
Joey Armstrong3d444c62022-11-26 21:42:20 -0500173 println("** ${iam}: Wait for adapters to be registered")
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200174
175 // guarantee that at least the specified number of adapters are registered with VOLTHA before proceeding
176 sh """
177 set +x
Matteo Scandolo721d08b2021-09-30 17:42:40 -0700178 _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 +0200179 """
180
181 sh """
182 set +x
183 adapters=\$(voltctl adapter list -q | wc -l)
184 while [[ \$adapters -lt ${cfg.adaptersToWait} ]]; do
185 sleep 5
186 adapters=\$(voltctl adapter list -q | wc -l)
187 done
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200188 """
189
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700190 // NOTE that we need to wait for LastCommunication to be equal or shorter that 5s
191 // as that means the core can talk to the adapters
192 // if voltctl can't read LastCommunication we skip this check
Joey Armstrong3d444c62022-11-26 21:42:20 -0500193
194 println("** ${iam}: Wait for adapter LastCommunication")
Joey Armstrong14a67a12022-11-28 12:28:23 -0500195 Integer countdown = 60 * 10
196 while (true)
Joey Armstrong3d444c62022-11-26 21:42:20 -0500197 {
198 sleep 1
199 def adapters = getAdapters()
Joey Armstrong14a67a12022-11-28 12:28:23 -0500200 // Why are we not failing hard on this condition ?
201 // Adapters in an unknown state == testing: roll the dice
Joey Armstrong3d444c62022-11-26 21:42:20 -0500202 if (adapters == 'SKIP') { break }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200203
Joey Armstrong14a67a12022-11-28 12:28:23 -0500204 def state = getAdaptersState(adapters)
205 if (state == 'VALID') { break } // IFF
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200206
Joey Armstrong14a67a12022-11-28 12:28:23 -0500207 // ----------------------------------------------------------
208 // Excessive timeout but unsure where startup time boundry is
209 // [TODO] profile for a baseline
210 // [TODO] groovy.transform.TimedInterrupt
211 // ----------------------------------------------------------
212 countdown -= 1
213 if (1 > countdown)
Joey Armstrong7987c112022-12-05 12:42:43 -0500214 {
Joey Armstrong14a67a12022-11-28 12:28:23 -0500215 throw new Exception("ERROR: Timed out waiting on adapter startup")
Joey Armstrong7987c112022-12-05 12:42:43 -0500216 }
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700217 }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200218
Joey Armstrongf0c76902022-11-28 17:14:45 -0500219 println("** ${iam}: Tearing down port forwarding")
Joey Armstrong3d444c62022-11-26 21:42:20 -0500220 sh("""
Joey Armstrong3d444c62022-11-26 21:42:20 -0500221 ps aux \
222 | grep port-forw \
223 | grep -v grep \
224 | awk '{print \$2}' \
225 | xargs --no-run-if-empty kill -9 || true
226 """)
Joey Armstrong96158a92022-11-25 10:36:06 -0500227
228 println("** ${iam}: LEAVE")
Joey Armstrong3d444c62022-11-26 21:42:20 -0500229 return
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200230}
Joey Armstrong3d444c62022-11-26 21:42:20 -0500231
232// -----------------------------------------------------------------------
233// -----------------------------------------------------------------------
234def call(Map config)
235{
Joey Armstrong7987c112022-12-05 12:42:43 -0500236 String iam = getIam('main')
Joey Armstrong3d444c62022-11-26 21:42:20 -0500237 println("** ${iam}: ENTER")
238
239 if (!config) {
240 config = [:]
241 }
242
243 try
244 {
245 process(config)
246 }
247 catch (Exception err)
248 {
249 println("** ${iam}: EXCEPTION ${err}")
250 throw err
251 }
252 finally
253 {
254 println("** ${iam}: LEAVE")
255 }
256 return
257}
258
Joey Armstrongaf679da2023-01-31 14:22:41 -0500259// [EOF]