diff --git a/HACKING.md b/HACKING.md index f5a3c40d2..99e1a0057 100644 --- a/HACKING.md +++ b/HACKING.md @@ -163,7 +163,7 @@ If you're planning to test changes, it would be best to fork this repo so that you do your work there. The workflow requires a remote repo to which to push changes. -### Creating AWS credentials configs +### [OPTIONAL] Creating AWS credentials configs If you are in production where we upload builds to S3 OR you want to test uploading to S3 as part of your pipeline development, you need to @@ -217,6 +217,19 @@ $ aws s3 mb my-fcos-bucket And provide it to `--bucket` below. +### [OPTIONAL] Slack integration + +If you want to be able to have build status messages appear in Slack, +create a `slack-api-token` secret: + +``` +$ echo -n "$TOKEN" > slack-token +$ oc create secret generic slack-api-token --from-file=token=slack-token +``` + +You can obtain a token when creating a new instance of the Jenkins CI +app in your Slack workspace. + ### Create a Jenkins instance with a persistent volume backing store ``` diff --git a/Jenkinsfile b/Jenkinsfile index a97002eca..2e4d4dbe4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -133,6 +133,11 @@ echo "Final podspec: ${pod}" podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod) { node('coreos-assembler') { container('coreos-assembler') { + // declare this early so we can use it in Slack + def newBuildID + + try { + // this is defined IFF we *should* and we *can* upload to S3 def s3_stream_dir @@ -227,12 +232,13 @@ podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod) { """) } - def newBuildID = utils.shwrap_capture("readlink builds/latest") - if (prevBuildID == newBuildID) { + def buildID = utils.shwrap_capture("readlink builds/latest") + if (prevBuildID == buildID) { currentBuild.result = 'SUCCESS' currentBuild.description = "[${params.STREAM}] 💤 (no new build)" return } else { + newBuildID = buildID currentBuild.description = "[${params.STREAM}] ⚡ ${newBuildID}" // and insert the parent info into meta.json so we can display it in @@ -439,5 +445,40 @@ podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod) { } } } + + currentBuild.result = 'SUCCESS' + + // main try {} finishes here + } catch (e) { + currentBuild.result = 'FAILURE' + throw e + } finally { + def color + def message = "[${params.STREAM}] <${env.BUILD_URL}|${env.BUILD_NUMBER}>" + + if (currentBuild.result == 'SUCCESS') { + if (!newBuildID) { + // SUCCESS, but no new builds? Must've been a no-op + return + } + message = ":fcos: :sparkles: ${message} - SUCCESS" + color = 'good'; + } else { + message = ":fcos: :trashfire: ${message} - FAILURE" + color = 'danger'; + } + + if (newBuildID) { + message = "${message} (${newBuildID})" + } + + try { + if (official) { + slackSend(color: color, message: message) + } + } finally { + echo message + } + } }} } diff --git a/jenkins/master/plugins.txt b/jenkins/master/plugins.txt index 034c9afc0..527dd7789 100644 --- a/jenkins/master/plugins.txt +++ b/jenkins/master/plugins.txt @@ -1 +1,3 @@ github-oauth:0.33 +configuration-as-code:1.33 +slack:2.34 diff --git a/manifests/jenkins.yaml b/manifests/jenkins.yaml index 4f0d1a51f..844842ae2 100644 --- a/manifests/jenkins.yaml +++ b/manifests/jenkins.yaml @@ -74,6 +74,9 @@ objects: value: "true" - name: JNLP_SERVICE_NAME value: ${JNLP_SERVICE_NAME} + # DELTA: point c-as-c plugin to config map files; see below + - name: CASC_JENKINS_CONFIG + value: /var/lib/jenkins/configuration-as-code image: ' ' imagePullPolicy: IfNotPresent livenessProbe: @@ -100,6 +103,14 @@ objects: volumeMounts: - mountPath: /var/lib/jenkins name: ${JENKINS_SERVICE_NAME}-data + # DELTA: mount c-as-c config map + - name: ${JENKINS_SERVICE_NAME}-casc-cfg + mountPath: /var/lib/jenkins/configuration-as-code + readOnly: true + # DELTA: mount Slack token; see below + - name: slack-token + mountPath: /var/run/secrets/slack-api-token + readOnly: true dnsPolicy: ClusterFirst restartPolicy: Always serviceAccountName: ${JENKINS_SERVICE_NAME} @@ -107,6 +118,15 @@ objects: - name: ${JENKINS_SERVICE_NAME}-data persistentVolumeClaim: claimName: ${JENKINS_SERVICE_NAME} + # DELTA: add a configmap -- it's defined in pipeline.yaml + - name: ${JENKINS_SERVICE_NAME}-casc-cfg + configMap: + name: jenkins-casc-cfg + # DELTA: add the Slack token + - name: slack-token + secret: + secretName: slack-api-token + optional: true triggers: - imageChangeParams: automatic: true diff --git a/manifests/pipeline.yaml b/manifests/pipeline.yaml index 8882f3191..cbb06e362 100644 --- a/manifests/pipeline.yaml +++ b/manifests/pipeline.yaml @@ -44,6 +44,12 @@ parameters: - description: Whether to use KVM device plugin or legacy OCI KVM hook name: KVM_SELECTOR value: kvm-device-plugin + - description: Slack domain on which to post build status updates + name: SLACK_DOMAIN + value: coreos + - description: Slack channel on which to post build status updates + name: SLACK_CHANNEL + value: jenkins-coreos objects: @@ -123,6 +129,33 @@ objects: importPolicy: scheduled: true + ### JENKINS CONFIGURATION ### + + # this uses the configuration-as-code plugin: + # https://github.com/jenkinsci/configuration-as-code-plugin + - apiVersion: v1 + kind: ConfigMap + metadata: + name: jenkins-casc-cfg + annotations: + coreos.com/deploy-default: "true" + data: + jenkins.yaml: | + credentials: + system: + domainCredentials: + - credentials: + - string: + scope: GLOBAL + id: slack-token + secret: ${slack-api-token/token} + description: Slack API token + unclassified: + slackNotifier: + teamDomain: ${SLACK_DOMAIN} + tokenCredentialId: slack-token + room: "#${SLACK_CHANNEL}" + ### COREOS-ASSEMBLER ### # keep a local copy of coreos-assembler so we're not constantly pulling it