diff --git a/HACKING.md b/HACKING.md index b1c999325..5f422bfda 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,16 @@ $ 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 +``` + ### Create a Jenkins instance with a persistent volume backing store ``` diff --git a/Jenkinsfile b/Jenkinsfile index cc17ab949..f161e8ac9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -125,6 +125,11 @@ node { podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod, defaultContainer: 'jnlp') { 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 @@ -219,12 +224,13 @@ podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod, defaultCon """) } - 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 @@ -423,5 +429,37 @@ podTemplate(cloud: 'openshift', label: 'coreos-assembler', yaml: pod, defaultCon } } } + + } 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..ed28f5d31 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/jcasc 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}-cfg + mountPath: /var/lib/jenkins/jcasc + 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}-cfg + configMap: + name: jenkins-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..a1e80be45 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,34 @@ 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-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