Put cronjobs to run at the same time
[infra/cicd.git] / jjb / nsm / e2e.Jenkinsfile
1 /*
2 Copyright (c) 2022 Nordix Foundation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
17
18 node('nordix-nsm-build-ubuntu2204') {
19     build_number = env.BUILD_NUMBER
20     workspace = env.WORKSPACE
21     ws("${workspace}/${build_number}") {
22         def git_project = params.GIT_PROJECT
23         def current_branch = params.CURRENT_BRANCH
24         def default_branch = params.DEFAULT_BRANCH
25         def next = params.NEXT
26
27         def meridio_version = params.MERIDIO_VERSION
28         def tapa_version = params.TAPA_VERSION
29         def kubernetes_version = params.KUBERNETES_VERSION
30         def nsm_version = params.NSM_VERSION
31         def ip_family = params.IP_FAMILY
32         def number_of_workers = params.NUMBER_OF_WORKERS
33         def environment_name = params.ENVIRONMENT_NAME
34         def focus = params.FOCUS
35         def skip = params.SKIP
36         def kind_external_host_default_route = params.KIND_EXTERNAL_HOST_DEFAULT_ROUTE
37
38         def seed = params.SEED
39
40         stage('Clone/Checkout') {
41             git branch: default_branch, url: git_project
42             checkout([
43                 $class: 'GitSCM',
44                 branches: [[name: current_branch]],
45                 extensions: [],
46                 userRemoteConfigs: [[
47                     refspec: '+refs/pull/*/head:refs/remotes/origin/pr/*',
48                     url: git_project
49                 ]]
50             ])
51             sh 'git show'
52         }
53         timeout(120) {
54             stage('Environment') {
55                 currentBuild.description = "Meridio version: $meridio_version / TAPA version: $tapa_version / NSM version: $nsm_version / IP Family: $ip_family / Kubernetes version: $kubernetes_version / Current Branch: $current_branch / Seed: $seed"
56
57                 def command = "make -s -C test/e2e/environment/$environment_name/ KUBERNETES_VERSION=$kubernetes_version NSM_VERSION=$nsm_version IP_FAMILY=$ip_family KUBERNETES_WORKERS=$number_of_workers MERIDIO_VERSION=$meridio_version TAPA_VERSION=$tapa_version KIND_EXTERNAL_HOST_DEFAULT_ROUTE=$kind_external_host_default_route"
58                 try {
59                     ExecSh(command).call()
60                 } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
61                     currentBuild.result = 'ABORTED'
62                 } catch (Exception e) {
63                     unstable 'Environment setup failed'
64                     currentBuild.result = 'FAILURE'
65                 }
66             }
67             stage('E2E') {
68                 if (currentBuild.result != 'FAILURE' && currentBuild.result != 'ABORTED') {
69                     def command = "make e2e E2E_PARAMETERS=\"\$(cat ./test/e2e/environment/$environment_name/$ip_family/config.txt | tr '\\n' ' ')\" E2E_SEED=$seed E2E_FOCUS=\"$focus\" E2E_SKIP=\"$skip\""
70                     try {
71                         ExecSh(command).call()
72                         currentBuild.result = 'SUCCESS'
73                     } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
74                         currentBuild.result = 'ABORTED'
75                     } catch (Exception e) {
76                         unstable 'E2E Tests failed'
77                         currentBuild.result = 'FAILURE'
78                     }
79                 } else {
80                     Utils.markStageSkippedForConditional('E2E')
81                 }
82             }
83         }
84         stage('Report') {
85             try {
86                 Report(build_number).call()
87             } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
88                 currentBuild.result = 'ABORTED'
89             } catch (Exception e) {
90                 unstable 'Failed to create the report'
91             }
92         }
93         stage('Next') {
94             if (next == true && currentBuild.result != 'ABORTED') {
95                 Next(next, number_of_workers, environment_name, focus, skip, current_branch).call()
96             } else {
97                 Utils.markStageSkippedForConditional('Next')
98             }
99         }
100         stage('Cleanup') {
101             Cleanup()
102         }
103     }
104 }
105
106 def Next(next, number_of_workers, environment_name, focus, skip, current_branch) {
107     return {
108         def meridio_version = GetMeridioVersion(environment_name)
109         def tapa_version = GetTAPAVersion(environment_name)
110         def nsm_version = GetNSMVersion(environment_name)
111         def kubernetes_version = GetKubernetesVersion(environment_name)
112         def ip_family = GetIPFamily(environment_name)
113         def seed = GetSeed()
114         echo "Meridio version: $meridio_version / TAPA version: $tapa_version / NSM version: $nsm_version / IP Family: $ip_family / Kubernetes version: $kubernetes_version / Seed: $seed"
115         build job: 'meridio-e2e-test-kind', parameters: [
116                 string(name: 'NEXT', value: 'true'),
117                 string(name: 'MERIDIO_VERSION', value: "$meridio_version"),
118                 string(name: 'TAPA_VERSION', value: "$tapa_version"),
119                 string(name: 'KUBERNETES_VERSION', value: "$kubernetes_version"),
120                 string(name: 'NSM_VERSION', value: "$nsm_version"),
121                 string(name: 'IP_FAMILY', value: "$ip_family"),
122                 string(name: 'NUMBER_OF_WORKERS', value: "$number_of_workers"),
123                 string(name: 'ENVIRONMENT_NAME', value: "$environment_name"),
124                 string(name: 'SEED', value: "$seed"),
125                 string(name: 'FOCUS', value: "$focus"),
126                 string(name: 'SKIP', value: "$skip"),
127                 string(name: 'CURRENT_BRANCH', value: "$current_branch"),
128                 string(name: 'DRY_RUN', value: env.DRY_RUN)
129             ], wait: false
130     }
131 }
132
133 def GetMeridioVersion(environment_name) {
134     def number_of_versions = sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.Meridio[]' | wc -l", returnStdout: true).trim()
135     def index_of_version_temp = sh(script: "shuf -i 1-$number_of_versions -n1", returnStdout: true).trim()
136     def index_of_version = sh(script: "expr $index_of_version_temp - 1 || true", returnStdout: true).trim()
137     return sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.Meridio[$index_of_version]'", returnStdout: true).trim()
138 }
139
140 def GetTAPAVersion(environment_name) {
141     def number_of_versions = sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.TAPA[]' | wc -l", returnStdout: true).trim()
142     def index_of_version_temp = sh(script: "shuf -i 1-$number_of_versions -n1", returnStdout: true).trim()
143     def index_of_version = sh(script: "expr $index_of_version_temp - 1 || true", returnStdout: true).trim()
144     return sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.TAPA[$index_of_version]'", returnStdout: true).trim()
145 }
146
147 def GetNSMVersion(environment_name) {
148     def number_of_versions = sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.NSM[]' | wc -l", returnStdout: true).trim()
149     def index_of_version_temp = sh(script: "shuf -i 1-$number_of_versions -n1", returnStdout: true).trim()
150     def index_of_version = sh(script: "expr $index_of_version_temp - 1 || true", returnStdout: true).trim()
151     return sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.NSM[$index_of_version]'", returnStdout: true).trim()
152 }
153
154 def GetKubernetesVersion(environment_name) {
155     def number_of_versions = sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.Kubernetes[]' | wc -l", returnStdout: true).trim()
156     def index_of_version_temp = sh(script: "shuf -i 1-$number_of_versions -n1", returnStdout: true).trim()
157     def index_of_version = sh(script: "expr $index_of_version_temp - 1 || true", returnStdout: true).trim()
158     return sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.Kubernetes[$index_of_version]'", returnStdout: true).trim()
159 }
160
161 def GetIPFamily(environment_name) {
162     def number_of_ip_family = sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.IP-Family[]' | wc -l", returnStdout: true).trim()
163     def index_of_ip_family_temp = sh(script: "shuf -i 1-$number_of_ip_family -n1", returnStdout: true).trim()
164     def index_of_ip_family = sh(script: "expr $index_of_ip_family_temp - 1 || true", returnStdout: true).trim()
165     return sh(script: "cat test/e2e/environment/$environment_name/test-scope.yaml | yq '.IP-Family[$index_of_ip_family]'", returnStdout: true).trim()
166 }
167
168 def GetSeed() {
169     return sh(script: 'shuf -i 1-2147483647 -n1', returnStdout: true).trim()
170 }
171
172 // http://JENKINS_URL/job/meridio-e2e-test-kind/api/json?tree=allBuilds[status,timestamp,id,result,description]{0,9}&pretty=true
173 def Report(id) {
174     return {
175         def jenkins_url = 'jenkins.nordix.org'
176
177         def success = ''
178         try {
179             success = sh(script: """
180             data=\$(curl -s -L "http://$jenkins_url/job/meridio-e2e-test-kind/api/json?tree=allBuilds\\[status,timestamp,id,result,description\\]\\{0,1000\\}&pretty=true")
181             success=\$(echo \"\$data\" | jq -r '.allBuilds[] | select(.result == \"SUCCESS\") | [.description] | @tsv' | grep -v \"^\$\")
182             echo \$success
183             """, returnStdout: true).trim()
184         } catch (Exception e) {
185         }
186
187         def failure = ''
188         try {
189             failure = sh(script: """
190             data=\$(curl -s -L "http://$jenkins_url/job/meridio-e2e-test-kind/api/json?tree=allBuilds\\[status,timestamp,id,result,description\\]\\{0,1000\\}&pretty=true")
191             failure=\$(echo \"\$data\" | jq -r '.allBuilds[] | select(.result == \"FAILURE\") | [.description] | @tsv' | grep -v \"^\$\")
192             echo \$failure
193             """, returnStdout: true).trim()
194         } catch (Exception e) {
195         }
196
197         ReportMeridio(success, failure).call()
198         ReportTAPA(success, failure).call()
199         ReportNSM(success, failure).call()
200         ReportIPFamily(success, failure).call()
201         ReportKubernetes(success, failure).call()
202
203         sh 'printenv > _output/parameters.txt'
204         sh "echo 'RESULT=$currentBuild.result' >> _output/parameters.txt"
205
206         try {
207             archiveArtifacts artifacts: '_output/**/*.*', followSymlinks: false
208             sh "tar -czvf ${id}.tar.gz -C _output ."
209             withCredentials([string(credentialsId: 'nsm-nordix-artifactory-api-key', variable: 'API_KEY')]) {
210                 sh "curl -H 'X-JFrog-Art-Api:${API_KEY}' -T ${id}.tar.gz 'https://artifactory.nordix.org/artifactory/cloud-native/meridio/e2e-test-reports/${id}.tar.gz'"
211             }
212         } catch (Exception e) {
213         }
214     }
215 }
216
217 def ReportMeridio(success, failure) {
218     return {
219         def meridio_success = sh(script: "echo \"$success\" | grep -oP '(?<=Meridio version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s %s 0\\n\", \$2, \$1 }'", returnStdout: true).trim()
220         def meridio_failure = sh(script: "echo \"$failure\" | grep -oP '(?<=Meridio version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s 0 %s\\n\", \$2, \$1 }'", returnStdout: true).trim()
221         def meridio = sh(script: "echo \"$meridio_success\\n$meridio_failure\" | grep -v '^\$' | awk '{ success[\$1] += \$2 ; failure[\$1] += \$3 } END { for(elem in success) print elem, success[elem], failure[elem] }' | sort -k1", returnStdout: true).trim()
222         def formatted = sh(script: "echo \"$meridio\" | awk '{ printf \"%s (✅ %s / ❌ %s)\\n\", \$1, \$2, \$3  }' | sed ':a;N;\$!ba;s/\\n/ | /g'", returnStdout: true).trim()
223         echo "Meridio: $formatted"
224         badge('meridio-e2e-kind-meridio', 'Meridio', formatted)
225     }
226 }
227
228 def ReportTAPA(success, failure) {
229     return {
230         def tapa_success = sh(script: "echo \"$success\" | grep -oP '(?<=TAPA version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s %s 0\\n\", \$2, \$1 }'", returnStdout: true).trim()
231         def tapa_failure = sh(script: "echo \"$failure\" | grep -oP '(?<=TAPA version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s 0 %s\\n\", \$2, \$1 }'", returnStdout: true).trim()
232         def tapa = sh(script: "echo \"$tapa_success\\n$tapa_failure\" | grep -v '^\$' | awk '{ success[\$1] += \$2 ; failure[\$1] += \$3 } END { for(elem in success) print elem, success[elem], failure[elem] }' | sort -k1", returnStdout: true).trim()
233         def formatted = sh(script: "echo \"$tapa\" | awk '{ printf \"%s (✅ %s / ❌ %s)\\n\", \$1, \$2, \$3  }' | sed ':a;N;\$!ba;s/\\n/ | /g'", returnStdout: true).trim()
234         echo "TAPA: $formatted"
235         badge('meridio-e2e-kind-tapa', 'TAPA', formatted)
236     }
237 }
238
239 def ReportNSM(success, failure) {
240     return {
241         def nsm_success = sh(script: "echo \"$success\" | grep -oP '(?<=NSM version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s %s 0\\n\", \$2, \$1 }'", returnStdout: true).trim()
242         def nsm_failure = sh(script: "echo \"$failure\" | grep -oP '(?<=NSM version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s 0 %s\\n\", \$2, \$1 }'", returnStdout: true).trim()
243         def nsm = sh(script: "echo \"$nsm_success\\n$nsm_failure\" | grep -v '^\$' | awk '{ success[\$1] += \$2 ; failure[\$1] += \$3 } END { for(elem in success) print elem, success[elem], failure[elem] }' | sort -k1", returnStdout: true).trim()
244         def formatted = sh(script: "echo \"$nsm\" | awk '{ printf \"%s (✅ %s / ❌ %s)\\n\", \$1, \$2, \$3  }' | sed ':a;N;\$!ba;s/\\n/ | /g'", returnStdout: true).trim()
245         echo "NSM: $formatted"
246         badge('meridio-e2e-kind-nsm', 'NSM', formatted)
247     }
248 }
249
250 def ReportIPFamily(success, failure) {
251     return {
252         def ip_family_success = sh(script: "echo \"$success\" | grep -oP '(?<=IP Family: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s %s 0\\n\", \$2, \$1 }'", returnStdout: true).trim()
253         def ip_family_failure = sh(script: "echo \"$failure\" | grep -oP '(?<=IP Family: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s 0 %s\\n\", \$2, \$1 }'", returnStdout: true).trim()
254         def ip_family = sh(script: "echo \"$ip_family_success\\n$ip_family_failure\" | grep -v '^\$' | awk '{ success[\$1] += \$2 ; failure[\$1] += \$3 } END { for(elem in success) print elem, success[elem], failure[elem] }' | sort -k1", returnStdout: true).trim()
255         def formatted = sh(script: "echo \"$ip_family\" | awk '{ printf \"%s (✅ %s / ❌ %s)\\n\", \$1, \$2, \$3  }' | sed ':a;N;\$!ba;s/\\n/ | /g'", returnStdout: true).trim()
256         echo "IP Family: $formatted"
257         badge('meridio-e2e-kind-ip-family', 'IP Family', formatted)
258     }
259 }
260
261 def ReportKubernetes(success, failure) {
262     return {
263         def kubernetes_success = sh(script: "echo \"$success\" | grep -oP '(?<=Kubernetes version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s %s 0\\n\", \$2, \$1 }'", returnStdout: true).trim()
264         def kubernetes_failure = sh(script: "echo \"$failure\" | grep -oP '(?<=Kubernetes version: ).*?(?=\\/)' | sort | uniq -c | awk '{ printf \"%s 0 %s\\n\", \$2, \$1 }'", returnStdout: true).trim()
265         def kubernetes = sh(script: "echo \"$kubernetes_success\\n$kubernetes_failure\" | grep -v '^\$' | awk '{ success[\$1] += \$2 ; failure[\$1] += \$3 } END { for(elem in success) print elem, success[elem], failure[elem] }' | sort -k1", returnStdout: true).trim()
266         def formatted = sh(script: "echo \"$kubernetes\" | awk '{ printf \"%s (✅ %s / ❌ %s)\\n\", \$1, \$2, \$3  }' | sed ':a;N;\$!ba;s/\\n/ | /g'", returnStdout: true).trim()
267         echo "Kubernetes: $formatted"
268         badge('meridio-e2e-kind-kubernetes', 'Kubernetes', formatted)
269     }
270 }
271
272 def badge(id, subject, message) {
273     addEmbeddableBadgeConfiguration(id: "${id}", subject: "${subject}", color: '#0B1F67', status: "$message")
274     sh """
275     mkdir -p _output
276     echo '{' >> _output/${id}.json
277     echo '"schemaVersion": 1,' >> _output/${id}.json
278     echo '"label": "${subject}",' >> _output/${id}.json
279     echo '"message": "${message}",' >> _output/${id}.json
280     echo '"color": "#0B1F67"' >> _output/${id}.json
281     echo '}' >> _output/${id}.json
282     """
283 }
284
285 // Raise error in Jenkins job
286 def Error(e) {
287     return {
288         Cleanup()
289         error e
290     }
291 }
292
293 // Cleanup directory and kind cluster
294 def Cleanup() {
295     def command = 'make -s -C docs/demo/scripts/kind/ clean'
296     ExecSh(command).call()
297     cleanWs()
298 }
299
300 // Execute command
301 def ExecSh(command) {
302     return {
303         if (env.DRY_RUN != 'true') {
304             sh """
305                 . \${HOME}/.profile
306                 ${command}
307             """
308         } else {
309             echo "${command}"
310         }
311     }
312 }