github.com/verrazzano/verrazzano@v1.7.1/ci/a-la-carte/JenkensfileALaCarteTriggered (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 pipeline { 5 options { 6 skipDefaultCheckout true 7 timestamps () 8 } 9 10 agent { 11 docker { 12 image "${RUNNER_DOCKER_IMAGE}" 13 args "${RUNNER_DOCKER_ARGS}" 14 registryUrl "${RUNNER_DOCKER_REGISTRY_URL}" 15 registryCredentialsId 'ocir-pull-and-push-account' 16 label "pipeline-job-large" 17 } 18 } 19 20 parameters { 21 choice (name: 'KUBERNETES_CLUSTER_VERSION', 22 description: 'Kubernetes Version for KinD Cluster', 23 // 1st choice is the default value 24 choices: [ "1.27", "1.26", "1.25", "1.24" ]) 25 string (name: 'GIT_COMMIT_TO_USE', 26 defaultValue: 'NONE', 27 description: 'This is the full git commit hash from the source build to be used for all jobs', 28 trim: true) 29 string (name: 'VERRAZZANO_OPERATOR_IMAGE', 30 defaultValue: 'NONE', 31 description: 'Verrazzano platform operator image name (in ghcr.io repo). If not specified, the operator.yaml from Verrazzano repo will be used to create Verrazzano platform operator', 32 trim: true) 33 booleanParam (description: 'Whether to capture full cluster snapshot on test failure', name: 'CAPTURE_FULL_CLUSTER', defaultValue: false) 34 } 35 36 environment { 37 CLEAN_BRANCH_NAME = "${env.BRANCH_NAME.replace("/", "%2F")}" 38 GOPATH = '/home/opc/go' 39 GO_REPO_PATH = "${GOPATH}/src/github.com/verrazzano" 40 SERVICE_KEY = credentials('PAGERDUTY_SERVICE_KEY') 41 42 OCI_CLI_AUTH="instance_principal" 43 OCI_OS_NAMESPACE = credentials('oci-os-namespace') 44 } 45 46 stages { 47 stage('Clean workspace and checkout') { 48 steps { 49 script { 50 if (params.GIT_COMMIT_TO_USE == "NONE") { 51 echo "Specific GIT commit was not specified, use current head" 52 def scmInfo = checkout([ 53 $class: 'GitSCM', 54 branches: [[name: env.BRANCH_NAME]], 55 doGenerateSubmoduleConfigurations: false, 56 extensions: [], 57 submoduleCfg: [], 58 userRemoteConfigs: [[url: env.SCM_VERRAZZANO_GIT_URL]]]) 59 env.GIT_COMMIT = scmInfo.GIT_COMMIT 60 env.GIT_BRANCH = scmInfo.GIT_BRANCH 61 } else { 62 echo "SCM checkout of ${params.GIT_COMMIT_TO_USE}" 63 def scmInfo = checkout([ 64 $class: 'GitSCM', 65 branches: [[name: params.GIT_COMMIT_TO_USE]], 66 doGenerateSubmoduleConfigurations: false, 67 extensions: [], 68 submoduleCfg: [], 69 userRemoteConfigs: [[url: env.SCM_VERRAZZANO_GIT_URL]]]) 70 env.GIT_COMMIT = scmInfo.GIT_COMMIT 71 env.GIT_BRANCH = scmInfo.GIT_BRANCH 72 // If the commit we were handed is not what the SCM says we are using, fail 73 if (!env.GIT_COMMIT.equals(params.GIT_COMMIT_TO_USE)) { 74 echo "SCM didn't checkout the commit we expected. Expected: ${params.GIT_COMMIT_TO_USE}, Found: ${scmInfo.GIT_COMMIT}" 75 exit 1 76 } 77 } 78 echo "SCM checkout of ${env.GIT_BRANCH} at ${env.GIT_COMMIT}" 79 } 80 81 script { 82 def props = readProperties file: '.verrazzano-development-version' 83 VERRAZZANO_DEV_VERSION = props['verrazzano-development-version'] 84 TIMESTAMP = sh(returnStdout: true, script: "date +%Y%m%d%H%M%S").trim() 85 SHORT_COMMIT_HASH = sh(returnStdout: true, script: "git rev-parse --short=8 HEAD").trim() 86 87 // update the description with some meaningful info 88 currentBuild.description = SHORT_COMMIT_HASH + " : " + env.GIT_COMMIT + " : " + params.GIT_COMMIT_TO_USE 89 def currentCommitHash = env.GIT_COMMIT 90 def commitList = getCommitList() 91 withCredentials([file(credentialsId: 'jenkins-to-slack-users', variable: 'JENKINS_TO_SLACK_JSON')]) { 92 def userMappings = readJSON file: JENKINS_TO_SLACK_JSON 93 SUSPECT_LIST = getSuspectList(commitList, userMappings) 94 echo "Suspect list: ${SUSPECT_LIST}" 95 } 96 } 97 } 98 } 99 100 stage ('Kick off a-la-carte tests') { 101 parallel { 102 stage('Wildcard DNS, Default CA, Cert-Manager default clusterResourceNamespace') { 103 steps { 104 retry(count: JOB_PROMOTION_RETRIES) { 105 script { 106 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 107 parameters: [ 108 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 109 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 110 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 111 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 112 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cert-manager"), 113 string(name: 'DNS_TYPE', value: "wildcard"), 114 string(name: 'CERTIFICATE_TYPE', value: "default"), 115 ], wait: true 116 } 117 } 118 } 119 } 120 stage('OCIDNS, Default CA, Cert-Manager default clusterResourceNamespace') { 121 steps { 122 retry(count: JOB_PROMOTION_RETRIES) { 123 script { 124 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 125 parameters: [ 126 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 127 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 128 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 129 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 130 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cert-manager"), 131 string(name: 'DNS_TYPE', value: "ocidns"), 132 string(name: 'CERTIFICATE_TYPE', value: "default"), 133 ], wait: true 134 } 135 } 136 } 137 } 138 stage('OCIDNS, LetEncypt staging, Cert-Manager default clusterResourceNamespace') { 139 steps { 140 retry(count: JOB_PROMOTION_RETRIES) { 141 script { 142 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 143 parameters: [ 144 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 145 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 146 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 147 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 148 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cert-manager"), 149 string(name: 'DNS_TYPE', value: "ocidns"), 150 string(name: 'CERTIFICATE_TYPE', value: "letsEncrypt"), 151 ], wait: true 152 } 153 } 154 } 155 } 156 stage('Wildcard DNS, Default CA, Cert-Manager custom clusterResourceNamespace') { 157 steps { 158 retry(count: JOB_PROMOTION_RETRIES) { 159 script { 160 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 161 parameters: [ 162 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 163 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 164 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 165 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 166 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cluster-resource"), 167 string(name: 'DNS_TYPE', value: "wildcard"), 168 string(name: 'CERTIFICATE_TYPE', value: "default"), 169 ], wait: true 170 } 171 } 172 } 173 } 174 stage('OCIDNS, Default CA, Cert-Manager custom clusterResourceNamespace') { 175 steps { 176 retry(count: JOB_PROMOTION_RETRIES) { 177 script { 178 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 179 parameters: [ 180 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 181 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 182 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 183 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 184 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cluster-resource"), 185 string(name: 'DNS_TYPE', value: "ocidns"), 186 string(name: 'CERTIFICATE_TYPE', value: "default"), 187 ], wait: true 188 } 189 } 190 } 191 } 192 stage('OCIDNS, LetEncypt staging, Cert-Manager custom clusterResourceNamespace') { 193 steps { 194 retry(count: JOB_PROMOTION_RETRIES) { 195 script { 196 build job: "/verrazzano-a-la-carte/${CLEAN_BRANCH_NAME}", 197 parameters: [ 198 string(name: 'KUBERNETES_CLUSTER_VERSION', value: params.KUBERNETES_CLUSTER_VERSION), 199 string(name: 'GIT_COMMIT_TO_USE', value: params.GIT_COMMIT_TO_USE), 200 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 201 booleanParam(name: 'CAPTURE_FULL_CLUSTER', value: params.CAPTURE_FULL_CLUSTER), 202 string(name: 'CLUSTER_RESOURCE_NAMESPACE', value: "my-cluster-resource"), 203 string(name: 'DNS_TYPE', value: "ocidns"), 204 string(name: 'CERTIFICATE_TYPE', value: "letsEncrypt"), 205 ], wait: true 206 } 207 } 208 } 209 } 210 } 211 } 212 } 213 post { 214 failure { 215 script { 216 if (env.JOB_NAME == "verrazzano-a-la-carte-triggered/master" || env.JOB_NAME ==~ "errazzano-a-la-carte-triggered/release-1.*") { 217 if (isPagerDutyEnabled()) { 218 pagerduty(resolve: false, serviceKey: "$SERVICE_KEY", incDescription: "Verrazzano: ${env.JOB_NAME} - Failed", incDetails: "Job Failed - \"${env.JOB_NAME}\" build: ${env.BUILD_NUMBER}\n\nView the log at:\n ${env.BUILD_URL}\n\nBlue Ocean:\n${env.RUN_DISPLAY_URL}") 219 } 220 slackSend ( channel: "$SLACK_ALERT_CHANNEL", message: "Job Failed - \"${env.JOB_NAME}\" build: ${env.BUILD_NUMBER}\n\nView the log at:\n ${env.BUILD_URL}\n\nBlue Ocean:\n${env.RUN_DISPLAY_URL}\n\nSuspects:\n${SUSPECT_LIST}" ) 221 } 222 } 223 } 224 } 225 } 226 227 def isPagerDutyEnabled() { 228 // this controls whether PD alerts are enabled 229 if (NOTIFY_PAGERDUTY_TRIGGERED_FAILURES.equals("true")) { 230 echo "Pager-Duty notifications enabled via global override setting" 231 return true 232 } 233 return false 234 } 235 236 237 // Called in Stage Clean workspace and checkout steps 238 @NonCPS 239 def getCommitList() { 240 echo "Checking for change sets" 241 def commitList = [] 242 def changeSets = currentBuild.changeSets 243 for (int i = 0; i < changeSets.size(); i++) { 244 echo "get commits from change set" 245 def commits = changeSets[i].items 246 for (int j = 0; j < commits.length; j++) { 247 def commit = commits[j] 248 def id = commit.commitId 249 echo "Add commit id: ${id}" 250 commitList.add(id) 251 } 252 } 253 return commitList 254 } 255 256 def trimIfGithubNoreplyUser(userIn) { 257 if (userIn == null) { 258 echo "Not a github noreply user, not trimming: ${userIn}" 259 return userIn 260 } 261 if (userIn.matches(".*\\+.*@users.noreply.github.com.*")) { 262 def userOut = userIn.substring(userIn.indexOf("+") + 1, userIn.indexOf("@")) 263 return userOut; 264 } 265 if (userIn.matches(".*<.*@users.noreply.github.com.*")) { 266 def userOut = userIn.substring(userIn.indexOf("<") + 1, userIn.indexOf("@")) 267 return userOut; 268 } 269 if (userIn.matches(".*@users.noreply.github.com")) { 270 def userOut = userIn.substring(0, userIn.indexOf("@")) 271 return userOut; 272 } 273 echo "Not a github noreply user, not trimming: ${userIn}" 274 return userIn 275 } 276 277 def getSuspectList(commitList, userMappings) { 278 def retValue = "" 279 def suspectList = [] 280 if (commitList == null || commitList.size() == 0) { 281 echo "No commits to form suspect list" 282 } else { 283 for (int i = 0; i < commitList.size(); i++) { 284 def id = commitList[i] 285 try { 286 def gitAuthor = sh( 287 script: "git log --format='%ae' '$id^!'", 288 returnStdout: true 289 ).trim() 290 if (gitAuthor != null) { 291 def author = trimIfGithubNoreplyUser(gitAuthor) 292 echo "DEBUG: author: ${gitAuthor}, ${author}, id: ${id}" 293 if (userMappings.containsKey(author)) { 294 def slackUser = userMappings.get(author) 295 if (!suspectList.contains(slackUser)) { 296 echo "Added ${slackUser} as suspect" 297 retValue += " ${slackUser}" 298 suspectList.add(slackUser) 299 } 300 } else { 301 // If we don't have a name mapping use the commit.author, at least we can easily tell if the mapping gets dated 302 if (!suspectList.contains(author)) { 303 echo "Added ${author} as suspect" 304 retValue += " ${author}" 305 suspectList.add(author) 306 } 307 } 308 } else { 309 echo "No author returned from git" 310 } 311 } catch (Exception e) { 312 echo "INFO: Problem processing commit ${id}, skipping commit: " + e.toString() 313 } 314 } 315 } 316 def startedByUser = ""; 317 def causes = currentBuild.getBuildCauses() 318 echo "causes: " + causes.toString() 319 for (cause in causes) { 320 def causeString = cause.toString() 321 echo "current cause: " + causeString 322 def causeInfo = readJSON text: causeString 323 if (causeInfo.userId != null) { 324 startedByUser = causeInfo.userId 325 } 326 } 327 328 if (startedByUser.length() > 0) { 329 echo "Build was started by a user, adding them to the suspect notification list: ${startedByUser}" 330 def author = trimIfGithubNoreplyUser(startedByUser) 331 echo "DEBUG: author: ${startedByUser}, ${author}" 332 if (userMappings.containsKey(author)) { 333 def slackUser = userMappings.get(author) 334 if (!suspectList.contains(slackUser)) { 335 echo "Added ${slackUser} as suspect" 336 retValue += " ${slackUser}" 337 suspectList.add(slackUser) 338 } 339 } else { 340 // If we don't have a name mapping use the commit.author, at least we can easily tell if the mapping gets dated 341 if (!suspectList.contains(author)) { 342 echo "Added ${author} as suspect" 343 retValue += " ${author}" 344 suspectList.add(author) 345 } 346 } 347 } else { 348 echo "Build not started by a user, not adding to notification list" 349 } 350 echo "returning suspect list: ${retValue}" 351 return retValue 352 } 353 354 def getCronSchedule() { 355 if (env.BRANCH_NAME.equals("master")) { 356 return "H */2 * * *" 357 } else if (env.BRANCH_NAME.startsWith("release-1")) { 358 return "@daily" 359 } 360 return "" 361 }