blob: 92edf0d9b5cf032ec99ab1229a7d8c8b4d203f30 [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// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -040020String getIam(String func) {
Joey Armstrong7987c112022-12-05 12:42:43 -050021 // Cannot rely on a stack trace due to jenkins manipulation
Joey Armstrong3d444c62022-11-26 21:42:20 -050022 String src = 'vars/waitForAdapters.groovy'
23 String iam = [src, func].join('::')
Joey Armstrongf0c76902022-11-28 17:14:45 -050024 return iam
Joey Armstrong3d444c62022-11-26 21:42:20 -050025}
Andrea Campanella45b8eb72021-09-28 10:50:01 +020026
Joey Armstrong3d444c62022-11-26 21:42:20 -050027// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -040028// Intent: Log progress message
Joey Armstrong3d444c62022-11-26 21:42:20 -050029// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -040030void enter(String name) {
31 // Announce ourselves for log usability
32 String iam = getIam(name)
33 println("${iam}: ENTER")
34 return
35}
Joey Armstrong3d444c62022-11-26 21:42:20 -050036
Joey Armstrong74ec08c2023-08-31 11:25:57 -040037// -----------------------------------------------------------------------
38// Intent: Log progress message
39// -----------------------------------------------------------------------
40void leave(String name) {
41 // Announce ourselves for log usability
42 String iam = getIam(name)
43 println("${iam}: LEAVE")
44 return
45}
46
47// -----------------------------------------------------------------------
48// -----------------------------------------------------------------------
49def getAdapters() {
50 String iam = getIam('getAdapters')
51 String adapters = ''
52
53 try {
54 adapters = sh(
Joey Armstrong3d444c62022-11-26 21:42:20 -050055 script: 'voltctl adapter list --format "{{gosince .LastCommunication}}"',
56 returnStdout: true,
57 ).trim()
58 }
Joey Armstrong74ec08c2023-08-31 11:25:57 -040059 catch (err) {
Joey Armstrong3d444c62022-11-26 21:42:20 -050060 // in some older versions of voltctl the command results in
61 // ERROR: Unexpected error while attempting to format results
62 // as table : template: output:1: function "gosince" not defined
63 // if that's the case we won't be able to check the timestamp so
64 // it's useless to wait
65 println("voltctl can't parse LastCommunication, skip waiting")
Joey Armstrong74ec08c2023-08-31 11:25:57 -040066 adapters = 'SKIP' // why not just retry a few times (?)
Joey Armstrong3d444c62022-11-26 21:42:20 -050067 }
68
69 print("** ${iam}: returned $adapters")
70 return adapters
71}
72
73// -----------------------------------------------------------------------
Joey Armstrong14a67a12022-11-28 12:28:23 -050074// Intent: Interrogate adapter states to determine if we should continue
75// looping waiting for adapter to start. Passed values must all be
76// Integral, Valid and within range to assert we are done waiting.
77// Function will return incomplete at the first sign of an invalid value.
78// -----------------------------------------------------------------------
79// NOTE: list.find{} was replaced with a for loop to simplify
80// early loop termination and return.
81// -----------------------------------------------------------------------
82// RETURN: scalar
83// 'DOUBLE-DIGIT' - value exceeds 0-5sec response window.
84// 'NON-NUMERIC' - garbage in the stream (letter, symbol, ctrl)
85// 'NULL' - empty or null string detected
86// 'VALID' - succes, all adapters are functional
87// 'SIX-NINE' - detected a single numeric digit between 6 and 9.
88// -----------------------------------------------------------------------
89def getAdaptersState(String adapters0)
90{
91 String iam = getIam('getAdaptersState')
92 Boolean debug = true // for now
93
94 def adapters = adapters0.split('\n')
95
96 String ans = null
97 def found = []
Joey Armstrong74ec08c2023-08-31 11:25:57 -040098 for(i=0; i<adapters.size(); i++) {
99 String elapsed = adapters[i]
100 if (debug) {
101 println("** ${iam} Checking elapsed[$i]: $elapsed")
102 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500103
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400104 if (! elapsed) { // empty string or null
105 ans = 'NULL'
106 break
107 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500108
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400109 Integer size = elapsed.length()
110 if (size > 2) { // 463765h58m52(s)
111 // higlander: there can be only one
112 ans = 'DOUBLE-DIGIT'
113 break
114 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500115
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400116 if (elapsed.endsWith('s')) {
117 // safer than replaceAll('s'): ssss1s => 1
118 elapsed = elapsed.substring(0, size-1)
119 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500120
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400121 // Line noise guard: 'a', 'f', '#', '!'
122 if (! elapsed.isInteger()) {
123 ans = 'NON-NUMERIC'
124 break
125 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500126
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400127 // Is value in range:
128 // discard negative integers as just plain wonky.
129 // HMMM(?): zero/no latency response is kinda odd to include imho.
130 Integer val = elapsed.toInteger()
131 if (5 >= val && val >= 0) {
132 found.add(elapsed)
133 }
134 else {
135 ans = 'SIX-NINE'
136 break
137 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500138 } // for()
139
140 // Declare success IFF all values are:
141 // o integral
142 // o valid
143 // o within range
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400144 if (ans == null) {
145 Integer got = found.size()
146 Integer exp = adapters.size()
147 ans = (! exp) ? 'NO-ADAPTERS'
Joey Armstrong14a67a12022-11-28 12:28:23 -0500148 : (got == exp) ? 'VALID'
149 : 'CONTINUE'
150 }
151
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400152 if (debug) {
153 println("** ${iam} return: [$ans]")
Joey Armstrong7987c112022-12-05 12:42:43 -0500154 }
Joey Armstrong14a67a12022-11-28 12:28:23 -0500155 return ans
156} // getAdaptersState
157
158// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400159// Intent: Poll until adapter status is known.
Joey Armstrong3d444c62022-11-26 21:42:20 -0500160// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400161def process(Map config) {
Joey Armstrong3d444c62022-11-26 21:42:20 -0500162 String iam = getIam('process')
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400163 enter('process')
Joey Armstrong96158a92022-11-25 10:36:06 -0500164
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200165 def defaultConfig = [
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400166 volthaNamespace : 'voltha',
167 stackName : 'voltha',
168 adaptersToWait : 2,
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200169 ]
170
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200171 def cfg = defaultConfig + config
172
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400173 if (cfg.adaptersToWait == 0) {
174 //no need to wait
175 println "No need to wait for adapters to be registered"
176 return
Andrea Campanella365ea1e2021-09-28 10:50:01 +0200177 }
178
Joey Armstrong3d444c62022-11-26 21:42:20 -0500179 println("** ${iam}: Wait for adapters to be registered")
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200180
181 // guarantee that at least the specified number of adapters are registered with VOLTHA before proceeding
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400182 sh(label : 'waitForAdapters: Initiate port forwarding',
183 script : """
184 _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" &
185 """)
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200186
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400187 sh(label : 'waitForAdapters: loop until adapter list',
188 script : """
189# set +x
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200190 adapters=\$(voltctl adapter list -q | wc -l)
191 while [[ \$adapters -lt ${cfg.adaptersToWait} ]]; do
192 sleep 5
193 adapters=\$(voltctl adapter list -q | wc -l)
194 done
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400195
196 cat << EOM
197** -----------------------------------------------------------------------
198** ${iam}: Available adapters:
199** -----------------------------------------------------------------------
200EOM
201 voltctl adapter list -q
202 """)
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200203
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700204 // NOTE that we need to wait for LastCommunication to be equal or shorter that 5s
205 // as that means the core can talk to the adapters
206 // if voltctl can't read LastCommunication we skip this check
Joey Armstrong3d444c62022-11-26 21:42:20 -0500207
208 println("** ${iam}: Wait for adapter LastCommunication")
Joey Armstrong14a67a12022-11-28 12:28:23 -0500209 Integer countdown = 60 * 10
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400210 while (true) {
211 sleep 1
212 def adapters = getAdapters()
213 // Why are we not failing hard on this condition ?
214 // Adapters in an unknown state == testing: roll the dice
215 if (adapters == 'SKIP') { break }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200216
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400217 def state = getAdaptersState(adapters)
218 if (state == 'VALID') { break } // IFF
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200219
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400220 // ----------------------------------------------------------
221 // Excessive timeout but unsure where startup time boundry is
222 // [TODO] profile for a baseline
223 // [TODO] groovy.transform.TimedInterrupt
224 // ----------------------------------------------------------
225 countdown -= 1
226 if (1 > countdown) {
227 throw new Exception('ERROR: Timed out waiting on adapter startup')
228 }
Matteo Scandolo28722ea2021-10-01 15:48:42 -0700229 }
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200230
Joey Armstrongf0c76902022-11-28 17:14:45 -0500231 println("** ${iam}: Tearing down port forwarding")
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400232 // pgrep_port_forward-212
Joey Armstrong96158a92022-11-25 10:36:06 -0500233
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400234 sh(label : 'waitForAdapters: Tear down port forwarding',
235 script : """
236if [[ \$(pgrep --count 'port-forw') -gt 0 ]]; then
237 pkill --uid "\$(id -u)" --echo --full 'port-forw'
238fi
239""")
240
241 leave('process')
Joey Armstrong3d444c62022-11-26 21:42:20 -0500242 return
Andrea Campanella45b8eb72021-09-28 10:50:01 +0200243}
Joey Armstrong3d444c62022-11-26 21:42:20 -0500244
245// -----------------------------------------------------------------------
246// -----------------------------------------------------------------------
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400247def call(Map config=[:])
Joey Armstrong3d444c62022-11-26 21:42:20 -0500248{
Joey Armstrong7987c112022-12-05 12:42:43 -0500249 String iam = getIam('main')
Joey Armstrong3d444c62022-11-26 21:42:20 -0500250
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400251 try {
252 enter('main')
253 process(config)
Joey Armstrong3d444c62022-11-26 21:42:20 -0500254 }
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400255 catch (Exception err) { // groovylint-disable-line CatchException
256 println("** ${iam}: EXCEPTION ${err}")
257 throw err
Joey Armstrong3d444c62022-11-26 21:42:20 -0500258 }
Joey Armstrong74ec08c2023-08-31 11:25:57 -0400259 finally {
260 leave('main')
Joey Armstrong3d444c62022-11-26 21:42:20 -0500261 }
262 return
263}
264
Joey Armstrongaf679da2023-01-31 14:22:41 -0500265// [EOF]