diff --git a/openshift/libs/utilities.groovy b/openshift/libs/utilities.groovy new file mode 100644 index 0000000..9e8a2da --- /dev/null +++ b/openshift/libs/utilities.groovy @@ -0,0 +1,226 @@ +def defineAuth() { + def api = "https://ocpcluster-a.arbetsformedlingen.se:443" + env.API = sh(script:"set +x; echo ${ api }", returnStdout: true).replaceAll(/https?/, 'insecure') + def encodedToken = openshift.selector('secret/imagepromote-token-ocp-a').object().data.tokenbase64 + env.TOKEN = sh(script:"set +x; echo ${ encodedToken } | base64 --decode", returnStdout: true) +} + +def generateTag() { + echo '### Generating build tag... ###' + def hash = getVersionHash() + def tag = "${ hash }" + echo "### build tag: \"${ tag }\" ###" + return tag +} + +def getVersionHash() { + return sh(returnStdout: true, script: "git tag --points-at HEAD").trim() +} +def getShortCommitHash() { + return sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim() +} + +def pushToExternalRegistry( String appName, + String tag, + String imageProject, + String internalRegistry, + String externalRegistry) { + withCredentials([usernamePassword(credentialsId: "${ openshift.project() }-nexus-secret", usernameVariable: "REG_USER", passwordVariable: "REG_PWD")]) { + echo "Copying image..." + echo "from docker://${ internalRegistry }/${ imageProject }/${ appName }:${ tag }" + echo "to docker://${ externalRegistry }/app-af-nexus/${ appName }:latest" + sh "skopeo copy docker://${ internalRegistry }/${ imageProject }/${ appName }:${ tag } docker://${ externalRegistry }/app-af-nexus/${ appName }:latest --src-creds jenkins:\$(oc whoami -t) --dest-creds \"$REG_USER:$REG_PWD\" --src-tls-verify=false --dest-tls-verify=false --format v2s2" + // todo: annotate the image with a label + } +} + +def rollout(String appName, + String imageStreamName, + String imageTag, + String label, + String imageProject, + String registry, + boolean useConfigMap, + String configMapKey, + String configMapPath) { + if (useConfigMap) { + echo "useConfigMap was set to true" + def configMap = openshift.selector("configmap", configMapKey) + if (configMap.exists()) { + echo "Found existing config map. Removing..." + openshift.selector("configmap", configMapKey).delete(); + } + echo "Applying configmap from path: ${configMapPath} ..." + openshift.apply(readFile(configMapPath)) + } + + echo "Setting image for Deployment Config: ${ appName } to ${ registry }/${ imageProject }/${ imageStreamName }:${ imageTag } ..." + openshift.raw("set image dc/${ appName } ${ appName }=${registry}/${ imageProject }/${ imageStreamName }:${ imageTag } --record=true") + + echo "Labeling Deployment Config with build: ${ label } ..." + openshift.raw("patch dc ${ appName } -p \"{\\\"spec\\\":{\\\"template\\\":{\\\"metadata\\\":{\\\"labels\\\":{\\\"build\\\":\\\"${ label }\\\"}}}}}}\"") + + echo "Rolling out..." + openshift.selector("dc", "${ appName }").rollout().status(); + + def latestDeploymentVersion = openshift.selector('dc',"${ appName }").object().status.latestVersion + echo "Labeling Replication Controller ${ appName }-${ latestDeploymentVersion } with build: ${ label } ..." + openshift.raw("patch rc ${ appName }-${ latestDeploymentVersion } -p \"{\\\"metadata\\\":{\\\"labels\\\":{\\\"build\\\":\\\"${ label }\\\"}}}\"") +} + +def selectTag(String applicationName, + Integer timeoutTime = 10, + String timeoutUnit = 'MINUTES') { + def tagToPromote = "" + def imageStreamsSelector = openshift.selector('is') + def cancelled = false + + imageStreamsSelector.withEach { is -> + def streamName = is.name() + if (streamName == "imagestream/" + applicationName) { + def tags = sortTags(is.object().spec.tags) + try { + timeout(time: timeoutTime, unit: timeoutUnit) { + tagToPromote = input message: "We need some input from you:", + ok: "Proceed", + parameters: [ + choice(name: 'Tag', choices: tags, description: 'What tag do you want to promote?') + ] + } + } catch(err) { + def user = err.getCauses()[0].getUser() + if('SYSTEM' == user.toString()) { // SYSTEM means timeout. + echo "Pipeline timed out waiting for user input" + currentBuild.result = 'NOT_BUILT' + } else { + echo "Aborted by ${user}" + currentBuild.result = 'ABORTED' + } + error('Pipeline timed out or was aborted') + } + } + } + + return tagToPromote +} + +@NonCPS +def sortTags(tags) { + def sorted = tags.sort { a, b -> a.generation <=> b.generation }.reverse() + def arr = [] + sorted.each { tag -> + arr.add("$tag.name") + } + return arr +} + +def selectTarget(ArrayList targets, Integer timeoutTime = 10, String timeoutUnit = 'MINUTES') { + def target = "" + try { + timeout(time: timeoutTime, unit: timeoutUnit) { + target = input message: "We need some input from you!", + ok: "Proceed", + parameters: [ + choice(name: 'Target', choices: targets, description: 'Select target for promotion: ') + ] + } + } catch(err) { + def user = err.getCauses()[0].getUser() + if('SYSTEM' == user.toString()) { // SYSTEM means timeout. + echo "Pipeline timed out waiting for user input" + currentBuild.result = 'NOT_BUILT' + } else { + echo "Aborted by ${user}" + currentBuild.result = 'ABORTED' + } + error('Pipeline timed out or was aborted') + } + return target +} + +return this + +def createVulnerabilityScan(String projectName, String projectVersion, String apiKey) { + echo "### Generating vulnerability scan for \"${ projectVersion }\" of \"${ projectName }\"" + sh """ + cyclonedx-bom -o bom.xml -d + set +x + REPORT=\$(cat bom.xml|base64 -w 0) + cat > payload.json <