From eaf97c8ee745ebe660957ab3aaa2a5bf77b324e3 Mon Sep 17 00:00:00 2001 From: Michal Kovarik Date: Mar 25 2020 12:49:31 +0000 Subject: Add verification jenkins job Deploy and test verification job which should be triggered by fedmsg for c3i-library to verify changes. 1) deploy new Jenkins master to new namespace 2) apply test role to new jenkins master 3) trigger jobs a) postmerge b) trigger-on-latest-tag c) greenwave-promote-to-stage 4) report results to pagure PR --- diff --git a/c3iaas/Makefile b/c3iaas/Makefile index 7d0cbfc..92d945b 100644 --- a/c3iaas/Makefile +++ b/c3iaas/Makefile @@ -25,24 +25,6 @@ install: echo "[PIPELINE] Pipeline job \"$${job}\" updated" ; \ done -create-jenkins-is: - $(OC_CMD) import-image jenkins:2 --confirm --scheduled=true \ - --from=registry.access.redhat.com/openshift3/jenkins-2-rhel7:v3.11 - -get-jenkins-plugins: - $(shell ./get-all-jenkins-plugins.sh) - -install-jenkins: create-jenkins-is get-jenkins-plugins - $(OC_CMD) new-app --template=jenkins-persistent \ - -p MEMORY_LIMIT=2Gi \ - -p VOLUME_CAPACITY=2Gi \ - -p NAMESPACE=$(shell $(OC_CMD) project -q) \ - -e INSTALL_PLUGINS=$(shell cat default-jenkins-plugins.txt) \ - -e JENKINS_JAVA_OVERRIDES="-Dpermissive-script-security.enabled=no_security" - -remove-jenkins: - $(OC_CMD) delete -l app=jenkins-persistent all,sa,rolebindings,pvc - uninstall: @for job in $(JOBS); do \ echo "[PIPELINE] Deleting pipeline job \"$${job}\"..." ; \ @@ -51,4 +33,4 @@ uninstall: --param-file ./$(JOBS_DIR)/$${job}.env | $(OC_CMD) delete -f -; \ echo "[PIPELINE] Pipeline job \"$${job}\" deleted" ; \ done -.PHONY: help install install-jenkins remove-jenkins uninstall +.PHONY: help install uninstall diff --git a/c3iaas/get-all-jenkins-plugins.sh b/c3iaas/get-all-jenkins-plugins.sh deleted file mode 100755 index f87a29f..0000000 --- a/c3iaas/get-all-jenkins-plugins.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -curl https://raw.githubusercontent.com/openshift/jenkins/master/2/contrib/openshift/base-plugins.txt | grep -v "#" |grep -v '^$' | sed 's/:.*/:latest/'| tr '\n' ',' > default-jenkins-plugins.txt - -cat jenkins-plugins.txt | tr '\n' ',' >> default-jenkins-plugins.txt diff --git a/c3iaas/jenkins-plugins.txt b/c3iaas/jenkins-plugins.txt deleted file mode 100644 index 0414409..0000000 --- a/c3iaas/jenkins-plugins.txt +++ /dev/null @@ -1,6 +0,0 @@ -script-security:latest -permissive-script-security:latest -timestamper:latest -http_request:latest -antisamy-markup-formatter:latest -update-sites-manager:latest diff --git a/roles/c3i/templates/default-agent.groovy b/roles/c3i/templates/default-agent.groovy index 00fa9a3..dcf8f7e 100644 --- a/roles/c3i/templates/default-agent.groovy +++ b/roles/c3i/templates/default-agent.groovy @@ -9,7 +9,7 @@ agent { kind: Pod metadata: labels: - app: "${env.JOB_BASE_NAME}" + app: "${env.JOB_BASE_NAME.take(62).replaceAll(/-$/,'')}" factory2-pipeline-build-number: "${env.BUILD_NUMBER}" spec: containers: diff --git a/setup/create-secret-key b/setup/create-secret-key new file mode 100755 index 0000000..37a5018 --- /dev/null +++ b/setup/create-secret-key @@ -0,0 +1,13 @@ +#!/bin/bash -e + +if [ $# -ne 2 ]; then + echo "Provide key name and value" + exit 1 +fi + +NAME=$1 +VALUE=$2 + +oc delete secret $NAME --ignore-not-found=true +oc create secret generic $NAME --from-literal=secrettext=$VALUE +oc label secret $NAME credential.sync.jenkins.openshift.io=true diff --git a/setup/install-jenkins b/setup/install-jenkins new file mode 100755 index 0000000..e4488f6 --- /dev/null +++ b/setup/install-jenkins @@ -0,0 +1,26 @@ +#!/bin/bash -e + + +while [[ "$#" -gt 0 ]]; do case $1 in + --jcasc) JCASC="$2"; shift;; + *) echo "Unknown parameter passed: $1"; exit 1;; +esac; shift; done + +oc import-image jenkins:2 --confirm --scheduled=true \ + --from=registry.access.redhat.com/openshift3/jenkins-2-rhel7:v3.11 + +# get jenkins plugins +PLUGINS=$(curl https://raw.githubusercontent.com/openshift/jenkins/master/2/contrib/openshift/base-plugins.txt | grep -v "#" |grep -v '^$' | sed 's/:.*/:latest/') +PLUGINS=$(echo -e "$PLUGINS\n$(cat jenkins-plugins.txt)" | sort -u | tr '\n' ',') + +cat jenkins-plugins.txt | tr '\n' ',' >> default-jenkins-plugins.txt + +oc create configmap openshift-jenkins-login-plugin-config --from-literal Overall-Administer=view + +oc new-app --file=jenkins-template.yaml \ + -p MEMORY_LIMIT=2Gi \ + -p VOLUME_CAPACITY=2Gi \ + -p NAMESPACE=$(oc project -q) \ + -e INSTALL_PLUGINS=$PLUGINS \ + -e JENKINS_JAVA_OVERRIDES="-Dpermissive-script-security.enabled=no_security" \ + ${JCASC:+--env CASC_JENKINS_CONFIG=$JCASC} diff --git a/setup/jcasc.yml b/setup/jcasc.yml new file mode 100644 index 0000000..e3108be --- /dev/null +++ b/setup/jcasc.yml @@ -0,0 +1,7 @@ +unclassified: + globalCIConfiguration: + configs: + - fedMsgMessagingProvider: + hubAddr: "tcp://hub.fedoraproject.org:9940" + name: "fedmsg" + pubAddr: "tcp://hub.fedoraproject.org:9940" diff --git a/setup/jenkins-plugins.txt b/setup/jenkins-plugins.txt new file mode 100644 index 0000000..0959599 --- /dev/null +++ b/setup/jenkins-plugins.txt @@ -0,0 +1,8 @@ +permissive-script-security:latest +timestamper:latest +http_request:latest +antisamy-markup-formatter:latest +update-sites-manager:latest +jms-messaging:latest +configuration-as-code:latest +rebuild:latest diff --git a/setup/jenkins-template.yaml b/setup/jenkins-template.yaml new file mode 100644 index 0000000..8745711 --- /dev/null +++ b/setup/jenkins-template.yaml @@ -0,0 +1,219 @@ +apiVersion: template.openshift.io/v1 +kind: Template +labels: + app: jenkins-persistent + template: jenkins-persistent-template +message: A Jenkins service has been created in your project. Log into Jenkins with + your OpenShift account. The tutorial at https://github.com/openshift/origin/blob/master/examples/jenkins/README.md + contains more information about using this template. +metadata: + annotations: + description: |- + Jenkins service, with persistent storage. + + NOTE: You must have persistent volumes available in your cluster to use this template. + iconClass: icon-jenkins + openshift.io/display-name: Jenkins + openshift.io/documentation-url: https://docs.openshift.org/latest/using_images/other_images/jenkins.html + openshift.io/long-description: This template deploys a Jenkins server capable + of managing OpenShift Pipeline builds and supporting OpenShift-based oauth login. + openshift.io/provider-display-name: Red Hat, Inc. + openshift.io/support-url: https://access.redhat.com + tags: instant-app,jenkins + name: jenkins-persistent +objects: +- apiVersion: v1 + kind: Route + metadata: + annotations: + haproxy.router.openshift.io/timeout: 4m + template.openshift.io/expose-uri: http://{.spec.host}{.spec.path} + name: ${JENKINS_SERVICE_NAME} + spec: + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: ${JENKINS_SERVICE_NAME} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${VOLUME_CAPACITY} +- apiVersion: v1 + kind: DeploymentConfig + metadata: + annotations: + template.alpha.openshift.io/wait-for-ready: "true" + name: ${JENKINS_SERVICE_NAME} + spec: + replicas: 1 + selector: + name: ${JENKINS_SERVICE_NAME} + strategy: + type: Recreate + template: + metadata: + labels: + name: ${JENKINS_SERVICE_NAME} + spec: + containers: + - capabilities: {} + env: + - name: OPENSHIFT_ENABLE_OAUTH + value: ${ENABLE_OAUTH} + - name: OPENSHIFT_ENABLE_REDIRECT_PROMPT + value: "true" + - name: DISABLE_ADMINISTRATIVE_MONITORS + value: ${DISABLE_ADMINISTRATIVE_MONITORS} + - name: KUBERNETES_MASTER + value: https://kubernetes.default:443 + - name: KUBERNETES_TRUST_CERTIFICATES + value: "true" + - name: JENKINS_SERVICE_NAME + value: ${JENKINS_SERVICE_NAME} + - name: JNLP_SERVICE_NAME + value: ${JNLP_SERVICE_NAME} + - name: ENABLE_FATAL_ERROR_LOG_FILE + value: ${ENABLE_FATAL_ERROR_LOG_FILE} + image: ' ' + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 2 + httpGet: + path: /login + port: 8080 + initialDelaySeconds: 420 + periodSeconds: 360 + timeoutSeconds: 240 + name: jenkins + readinessProbe: + httpGet: + path: /login + port: 8080 + initialDelaySeconds: 3 + timeoutSeconds: 240 + resources: + limits: + memory: ${MEMORY_LIMIT} + cpu: 2 + volumeMounts: + - mountPath: /var/lib/jenkins + name: ${JENKINS_SERVICE_NAME}-data + dnsPolicy: ClusterFirst + restartPolicy: Always + serviceAccountName: ${JENKINS_SERVICE_NAME} + volumes: + - name: ${JENKINS_SERVICE_NAME}-data + persistentVolumeClaim: + claimName: ${JENKINS_SERVICE_NAME} + triggers: + - imageChangeParams: + automatic: true + containerNames: + - jenkins + from: + kind: ImageStreamTag + name: ${JENKINS_IMAGE_STREAM_TAG} + namespace: ${NAMESPACE} + lastTriggeredImage: "" + type: ImageChange + - type: ConfigChange +- apiVersion: v1 + kind: ServiceAccount + metadata: + annotations: + serviceaccounts.openshift.io/oauth-redirectreference.jenkins: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"${JENKINS_SERVICE_NAME}"}}' + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + groupNames: null + kind: RoleBinding + metadata: + name: ${JENKINS_SERVICE_NAME}_edit + roleRef: + name: edit + subjects: + - kind: ServiceAccount + name: ${JENKINS_SERVICE_NAME} +- apiVersion: v1 + kind: Service + metadata: + name: ${JNLP_SERVICE_NAME} + spec: + ports: + - name: agent + nodePort: 0 + port: 50000 + protocol: TCP + targetPort: 50000 + selector: + name: ${JENKINS_SERVICE_NAME} + sessionAffinity: None + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + annotations: + service.alpha.openshift.io/dependencies: '[{"name": "${JNLP_SERVICE_NAME}", + "namespace": "", "kind": "Service"}]' + service.openshift.io/infrastructure: "true" + name: ${JENKINS_SERVICE_NAME} + spec: + ports: + - name: web + nodePort: 0 + port: 80 + protocol: TCP + targetPort: 8080 + selector: + name: ${JENKINS_SERVICE_NAME} + sessionAffinity: None + type: ClusterIP +parameters: +- description: The name of the OpenShift Service exposed for the Jenkins container. + displayName: Jenkins Service Name + name: JENKINS_SERVICE_NAME + value: jenkins +- description: The name of the service used for master/slave communication. + displayName: Jenkins JNLP Service Name + name: JNLP_SERVICE_NAME + value: jenkins-jnlp +- description: Whether to enable OAuth OpenShift integration. If false, the static + account 'admin' will be initialized with the password 'password'. + displayName: Enable OAuth in Jenkins + name: ENABLE_OAUTH + value: "true" +- description: Maximum amount of memory the container can use. + displayName: Memory Limit + name: MEMORY_LIMIT + value: 512Mi +- description: Volume space available for data, e.g. 512Mi, 2Gi. + displayName: Volume Capacity + name: VOLUME_CAPACITY + required: true + value: 1Gi +- description: The OpenShift Namespace where the Jenkins ImageStream resides. + displayName: Jenkins ImageStream Namespace + name: NAMESPACE + value: openshift +- description: Whether to perform memory intensive, possibly slow, synchronization + with the Jenkins Update Center on start. If true, the Jenkins core update monitor + and site warnings monitor are disabled. + displayName: Disable memory intensive administrative monitors + name: DISABLE_ADMINISTRATIVE_MONITORS + value: "false" +- description: Name of the ImageStreamTag to be used for the Jenkins image. + displayName: Jenkins ImageStreamTag + name: JENKINS_IMAGE_STREAM_TAG + value: jenkins:2 +- description: When a fatal error occurs, an error log is created with information + and the state obtained at the time of the fatal error. + displayName: Fatal Error Log File + name: ENABLE_FATAL_ERROR_LOG_FILE + value: "false" diff --git a/verification/c3i-role-verification.Jenkinsfile b/verification/c3i-role-verification.Jenkinsfile new file mode 100644 index 0000000..cf89019 --- /dev/null +++ b/verification/c3i-role-verification.Jenkinsfile @@ -0,0 +1,252 @@ +import static org.apache.commons.lang.StringEscapeUtils.escapeHtml; + +library identifier: "c3i@master", changelog: false, + retriever: modernSCM([$class: 'GitSCMSource', remote: "https://pagure.io/c3i-library.git"]) +pipeline { + + {% include 'default-agent.groovy' %} + + options { + timestamps() + timeout(time: 30, unit: 'MINUTES') + } + environment { + SERVICE_ACCOUNT_TOKEN = readFile(file: '/run/secrets/kubernetes.io/serviceaccount/token').trim() + // needed by c3i pagure client + TRIGGER_NAMESPACE = readFile('/run/secrets/kubernetes.io/serviceaccount/namespace').trim() + PAGURE_REPO_NAME = env.GIT_REPO.split('/')[3..-1].join('/').replace('forks/', '').replaceAll(/.git$/, '') + PAGURE_URL = env.GIT_REPO.split('/')[0..2].join('/') + PAGURE_API = "${env.PAGURE_URL}/api/0" + PAGURE_REPO_IS_FORK = "${env.GIT_REPO.contains('/forks/') ? 'true': 'false'}" + } + triggers { + ciBuildTrigger( + noSquash: true, + providerList: [ + fedmsgSubscriber( + name: params.MESSAGING_FEDMSG_PROVIDER, + overrides: [topic: "io.pagure.prod.pagure.pull-request.new"], + checks: [ + [field: '$.pullrequest.project.url_path', expectedValue: params.GIT_REPO.split('/')[3..-1].join('/').replace('forks/', 'fork/').replaceAll(/.git$/, '')], + [field: '$.pullrequest.branch', expectedValue: params.GIT_MAIN_BRANCH], + ] + ), + fedmsgSubscriber( + name: params.MESSAGING_FEDMSG_PROVIDER, + overrides: [topic: "io.pagure.prod.pagure.pull-request.update"], + checks: [ + [field: '$.pullrequest.project.url_path', expectedValue: params.GIT_REPO.split('/')[3..-1].join('/').replace('forks/', 'fork/').replaceAll(/.git$/, '')], + [field: '$.pullrequest.branch', expectedValue: params.GIT_MAIN_BRANCH], + ] + ), + fedmsgSubscriber( + name: params.MESSAGING_FEDMSG_PROVIDER, + overrides: [topic: "io.pagure.prod.pagure.pull-request.reopened"], + checks: [ + [field: '$.pullrequest.project.url_path', expectedValue: params.GIT_REPO.split('/')[3..-1].join('/').replace('forks/', 'fork/').replaceAll(/.git$/, '')], + [field: '$.pullrequest.branch', expectedValue: params.GIT_MAIN_BRANCH], + ] + ), + fedmsgSubscriber( + name: params.MESSAGING_FEDMSG_PROVIDER, + overrides: [topic: "io.pagure.prod.pagure.pull-request.rebased"], + checks: [ + [field: '$.pullrequest.project.url_path', expectedValue: params.GIT_REPO.split('/')[3..-1].join('/').replace('forks/', 'fork/').replaceAll(/.git$/, '')], + [field: '$.pullrequest.branch', expectedValue: params.GIT_MAIN_BRANCH], + ] + ), + ] + ) + } + stages { + stage('Proceeding CI_MESSAGE') { + when { + expression { env.CI_MESSAGE } + } + steps { + script { + def message = readJSON text: params.CI_MESSAGE + env.GIT_REPO_REF = "pull/${message.pullrequest.id}/head" + } + } + } + stage('Update Build Info') { + steps { + script { + if (!env.GIT_REPO_REF) { + error("This build is not started by a CI message and GIT_REPO_REF is empty. Only configurations were done.") + } + + c3i.clone(repo: params.GIT_REPO, + branch: env.GIT_REPO_REF) + env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim() + echo "Build ${env.GIT_REPO_REF}, commit=${env.GIT_COMMIT}" + + // Set friendly display name and description + def pagure_repo_home = env.GIT_REPO.replace('/forks/', '/fork/').replaceAll(/.git$/,'') + // Is the current branch a pull-request? If no, env.PR_NO will be empty. + env.PR_NO = env.GIT_REPO_REF.split('/')[1] // return X from pull/X/head + env.PR_URL = "${pagure_repo_home}/pull-request/${env.PR_NO}" + echo "Building PR #${env.PR_NO}: ${env.PR_URL}" + // NOTE: Old versions of OpenShift Client Jenkins plugin are buggy to handle arguments + // with special bash characters (like whitespaces, #, etc). + // https://bugzilla.redhat.com/show_bug.cgi?id=1625518 + currentBuild.displayName = "PR#${env.PR_NO}" + // To enable HTML syntax in build description, go to `Jenkins/Global Security/Markup Formatter` and select 'Safe HTML'. + def pagureLink = """${currentBuild.displayName}""" + try { + def prInfo = pagure.getPR(env.PR_NO) + pagureLink = """PR#${env.PR_NO}: ${escapeHtml(prInfo.title)}""" + // set PR status to Pending + if (params.PAGURE_API_KEY_SECRET_NAME) + pagure.setBuildStatusOnPR(null, 'Building...') + } catch (Exception e) { + echo "Error using pagure API: ${e}" + } + currentBuild.description = pagureLink + def prInfo = pagure.getPR(env.PR_NO) + env.PAGURE_REQUEST_BRANCH = prInfo.branch_from + env.PAGURE_REQUEST_REPO = "${env.PAGURE_URL}/${prInfo.repo_from.fullname}" + } + } + } + stage('Allocate C3IaaS project') { + steps { + script { + env.PIPELINE_ID = "c3i-verification-pr-${env.PR_NO}-git${env.GIT_COMMIT.take(8)}-${currentBuild.id}" + echo "Requesting new OpenShift project ${env.PIPELINE_ID}..." + openshift.withCluster() { + openshift.withProject(params.C3IAAS_NAMESPACE) { + c3i.buildAndWait(script: this, objs: "bc/${params.C3IAAS_JOB_NAME}", + '-e', "PROJECT_NAME=${env.PIPELINE_ID}", + '-e', "ADMIN_GROUPS=system:serviceaccounts:${env.TRIGGER_NAMESPACE},system:serviceaccounts:${env.C3IAAS_NAMESPACE}", + '-e', "LIFETIME_IN_MINUTES=60" + ) + } + } + } + } + post { + success { + echo "Allocated project ${env.PIPELINE_ID}" + } + failure { + echo "Failed to allocate ${env.PIPELINE_ID} project" + } + } + } + stage('Copy Secrets') { + steps { + script { + openshift.withCluster() { + factorySecret = openshift.selector('secret', 'factory2-c3i-verification-secret').object(exportable:true) + openshift.withProject(env.PIPELINE_ID) { + openshift.create(factorySecret) + } + } + } + } + } + stage('Install Jenkins master') { + steps { + script { + sh "oc project ${env.PIPELINE_ID}" + dir('setup') { + sh "./install-jenkins --jcasc ${env.PAGURE_REQUEST_REPO.replace('/forks/', '/fork/')}/raw/${env.PAGURE_REQUEST_BRANCH}/f/setup/jcasc.yml" + } + openshift.withCluster() { + openshift.withProject(env.PIPELINE_ID) { + c3i.waitForPods(script: this, objs: [name: "jenkins"], num: 1) + } + } + } + } + } + stage('Setup test project') { + steps { + script { + dir('verification/test-project') { + sh 'ln -s ../../roles roles' + sh "ansible-playbook deploy.yml -e c3i_ocp_namespace=${env.PIPELINE_ID} -e c3i_lib_branch=${env.PAGURE_REQUEST_BRANCH} -e c3i_lib_url=${env.PAGURE_REQUEST_REPO} -e c3i_git_repo=${env.PAGURE_REQUEST_REPO} -e c3i_git_main_branch=${env.PAGURE_REQUEST_BRANCH}" + } + } + } + } + stage('postmerge') { + steps { + script { + openshift.withCluster() { + openshift.withProject(env.PIPELINE_ID) { + c3i.buildAndWait(script: this, objs: "bc/c3i-library-test-postmerge", + '-e', "IMAGE=registry.access.redhat.com/rhscl/postgresql-95-rhel7:latest", + '-e', "IMAGE_TAG=latest-PR${env.PR_NO}-${env.BUILD_NUMBER}", + '-e', "PAGURE_API_KEY_SECRET_NAME=", // disable for pagure communication + '-e', "GIT_REPO_REF=${env.PAGURE_REQUEST_BRANCH}", + '-e', "LIFETIME_IN_MINUTES=30" + ) + } + } + } + } + } + stage('Parallel trigger') { + steps { + script { + openshift.withCluster() { + openshift.withProject(env.PIPELINE_ID) { + parallel( + "trigger-on-latest-tag": { + c3i.buildAndWait(script: this, objs: "bc/c3i-library-test-trigger-on-latest-tag", + '-e', "IMAGE=quay.io/factory2/c3i-library-test:latest-PR${env.PR_NO}-${env.BUILD_NUMBER}", + '-e', "TARGET_TAG=stage-PR${env.PR_NO}-${env.BUILD_NUMBER}" + ) + }, + "greenwave-promote-to-stage": { + c3i.buildAndWait(script: this, objs: "bc/c3i-library-test-greenwave-promote-to-stage", + '-e', "IMAGE=quay.io/factory2/c3i-library-test:latest-PR${env.PR_NO}-${env.BUILD_NUMBER}", + '-e', "TARGET_TAG=stage-PR${env.PR_NO}-${env.BUILD_NUMBER}" + ) + } + ) + } + } + } + } + } + } + post { + success { + script { + if (env.PAGURE_API_KEY_SECRET_NAME && env.PR_NO) { + try { + pagure.setBuildStatusOnPR(100, 'Build passed.') + echo "Updated PR #${env.PR_NO} status to PASS." + } catch (e) { + echo "Error updating PR #${env.PR_NO} status to PASS: ${e}" + } + } + } + } + failure { + script { + if (params.PAGURE_API_KEY_SECRET_NAME && env.PR_NO) { + try { + pagure.setBuildStatusOnPR(0, 'Build failed.') + echo "Updated PR #${env.PR_NO} status to FAILURE." + } catch (e) { + echo "Error updating PR #${env.PR_NO} status to FAILURE: ${e}" + } + try { + pagure.commentOnPR(""" + Build ${env.GIT_COMMIT} [FAILED](${env.BUILD_URL})! + Rebase or make new commits to rebuild. + """.stripIndent(), env.PR_NO) + echo "Comment made." + } catch (e) { + echo "Error making a comment on PR #${env.PR_NO}: ${e}" + } + } + } + } + } +} diff --git a/verification/c3i-role-verification.yml b/verification/c3i-role-verification.yml new file mode 100644 index 0000000..adc1f41 --- /dev/null +++ b/verification/c3i-role-verification.yml @@ -0,0 +1,38 @@ +kind: "BuildConfig" +apiVersion: "v1" +metadata: + name: c3i-role-verification + labels: + app: c3i-role-verification +spec: + runPolicy: "Serial" + completionDeadlineSeconds: 1800 + strategy: + type: JenkinsPipeline + jenkinsPipelineStrategy: + env: + - name: GIT_REPO + value: https://pagure.io/c3i-library.git + - name: GIT_REPO_REF + value: + - name: GIT_MAIN_BRANCH + value: master + - name: OPENSHIFT_CLOUD_NAME + value: openshift + - name: JENKINS_AGENT_IMAGE + value: docker-registry.upshift.redhat.com/factory2/pipeline-jenkins-agent:latest + - name: MESSAGING_FEDMSG_PROVIDER + value: fedmsg + - name: PAGURE_API_KEY_SECRET_NAME + value: pagure-api-key-c3i-library + - name: C3IAAS_NAMESPACE + value: c3i + - name: C3IAAS_JOB_NAME + value: c3iaas-request-project + - name: PAAS_DOMAIN + value: cloud.paas.psi.redhat.com + - name: CI_MESSAGE + - name: JENKINS_AGENT_SERVICE_ACCOUNT + value: jenkins + jenkinsfile: | + {% filter indent(width=10) %}{% include "c3i-role-verification.Jenkinsfile" %}{% endfilter %} diff --git a/verification/default-agent.groovy b/verification/default-agent.groovy new file mode 100644 index 0000000..dcf8f7e --- /dev/null +++ b/verification/default-agent.groovy @@ -0,0 +1,29 @@ +agent { + kubernetes { + cloud "${params.OPENSHIFT_CLOUD_NAME}" + label "jenkins-slave-${UUID.randomUUID().toString()}" + serviceAccount "${params.JENKINS_AGENT_SERVICE_ACCOUNT}" + defaultContainer 'jnlp' + yaml """ + apiVersion: v1 + kind: Pod + metadata: + labels: + app: "${env.JOB_BASE_NAME.take(62).replaceAll(/-$/,'')}" + factory2-pipeline-build-number: "${env.BUILD_NUMBER}" + spec: + containers: + - name: jnlp + image: "${params.JENKINS_AGENT_IMAGE}" + imagePullPolicy: Always + tty: true + resources: + requests: + memory: 512Mi + cpu: 200m + limits: + memory: 768Mi + cpu: 300m + """ + } +} diff --git a/verification/test-project/Dockerfile b/verification/test-project/Dockerfile new file mode 100644 index 0000000..6ef00f5 --- /dev/null +++ b/verification/test-project/Dockerfile @@ -0,0 +1,3 @@ +FROM registry.access.redhat.com/rhscl/postgresql-95-rhel7:latest + +LABEL quay.expires-after=2h diff --git a/verification/test-project/c3i-role-vars.yml b/verification/test-project/c3i-role-vars.yml new file mode 100644 index 0000000..88db584 --- /dev/null +++ b/verification/test-project/c3i-role-vars.yml @@ -0,0 +1,18 @@ +c3i_component: c3i-library-test +c3i_build_and_test_snippet: snippets/build-and-test.groovy +c3i_integration_test_snippet: snippets/full-integration-test.groovy + +c3i_mail_address: + +c3i_lib_url: +c3i_lib_branch: + +c3i_git_repo: +c3i_git_main_branch: + +c3i_jenkins_agent_image: "{{ c3i_workflow_jenkins_image }}" + +# disable build of jenkins agent +c3i_jenkins_agent_buildconfig_dockerfile: + +c3i_container_registry_credentials: factory2-c3i-verification-secret diff --git a/verification/test-project/container-template.yaml b/verification/test-project/container-template.yaml new file mode 100644 index 0000000..deb6579 --- /dev/null +++ b/verification/test-project/container-template.yaml @@ -0,0 +1,74 @@ +apiVersion: v1 +kind: Template +metadata: + name: container-template +labels: + template: "container-template" +parameters: +- name: NAME + displayName: Short unique identifier for the templated instances. + required: true + value: "container" +- name: GIT_REPO + displayName: Git repo URL + description: Default Git repo URL in which to run dev tests against + required: true + value: https://pagure.io/c3i-library.git +- name: GIT_REF + displayName: Git repo ref + description: Default Git repo ref in which to run dev tests against + required: true + value: master +- name: IMAGESTREAM_NAME + displayName: ImageStream name of the resulting image + required: true + value: test +- name: IMAGE_TAG + displayName: Tag of resulting image + required: true + value: latest +- name: IMAGESTREAM_NAMESPACE + displayName: Namespace of ImageStream for container images + required: false +objects: +- apiVersion: v1 + kind: ImageStream + metadata: + name: "${IMAGESTREAM_NAME}" + labels: + app: "${NAME}" +- apiVersion: v1 + kind: ImageStream + metadata: + name: "${IMAGESTREAM_NAME}" + labels: + app: "${NAME}" +- kind: "BuildConfig" + apiVersion: "v1" + metadata: + name: "${NAME}" + labels: + app: "${NAME}" + spec: + runPolicy: "Parallel" + completionDeadlineSeconds: 1800 + strategy: + dockerStrategy: + forcePull: true + dockerfilePath: verification/test-project/Dockerfile + resources: + requests: + memory: "768Mi" + cpu: "300m" + limits: + memory: "1Gi" + cpu: "500m" + source: + git: + uri: "${GIT_REPO}" + ref: "${GIT_REF}" + output: + to: + kind: "ImageStreamTag" + name: "${IMAGESTREAM_NAME}:${IMAGE_TAG}" + namespace: "${IMAGESTREAM_NAMESPACE}" diff --git a/verification/test-project/deploy.yml b/verification/test-project/deploy.yml new file mode 100644 index 0000000..6d014d8 --- /dev/null +++ b/verification/test-project/deploy.yml @@ -0,0 +1,9 @@ +- name: Deplomyent playbook + hosts: localhost + vars_files: + - c3i-role-vars.yml + tasks: + - include_role: + name: c3i + tags: + - validate diff --git a/verification/test-project/snippets/build-and-test.groovy b/verification/test-project/snippets/build-and-test.groovy new file mode 100644 index 0000000..0756e22 --- /dev/null +++ b/verification/test-project/snippets/build-and-test.groovy @@ -0,0 +1,37 @@ +stage('Build container') { + environment { + BUILDCONFIG_INSTANCE_ID = "verification-${currentBuild.id}-${UUID.randomUUID().toString().substring(0,7)}" + TEMP_TAG = "verification-${currentBuild.id}" + } + steps { + script { + openshift.withCluster() { + openshift.withProject(env.PIPELINE_ID) { + def template = readYaml file: 'verification/test-project/container-template.yaml' + def processed = openshift.process(template, + "-p", "NAME=${env.BUILDCONFIG_INSTANCE_ID}", + '-p', "GIT_REPO=${params.GIT_REPO}", + // A pull-request branch, like pull/123/head, cannot be built with commit ID + // because refspec cannot be customized in an OpenShift build . + '-p', "GIT_REF=${env.PR_NO ? env.GIT_REPO_REF : env.GIT_COMMIT}", + '-p', "IMAGE_TAG=${env.TEMP_TAG}", + '-p', "IMAGESTREAM_NAME=c3i-library-test", + '-p', "IMAGESTREAM_NAMESPACE=${env.PIPELINE_ID}", + ) + def build = c3i.buildAndWait(script: this, objs: processed) + echo 'Container build succeeds.' + def imagestream = openshift.selector('is', ['app': env.BUILDCONFIG_INSTANCE_ID]).object() + env.RESULTING_IMAGE_REPOS = imagestream.status.dockerImageRepository + env.RESULTING_TAG = env.TEMP_TAG + } + } + } + } +} +stage('Tests') { + steps { + script { + echo "Passed" + } + } +} diff --git a/verification/test-project/snippets/full-integration-test.groovy b/verification/test-project/snippets/full-integration-test.groovy new file mode 100644 index 0000000..a47caea --- /dev/null +++ b/verification/test-project/snippets/full-integration-test.groovy @@ -0,0 +1,8 @@ +stage('Tests') { + steps { + script { + sh "skopeo inspect docker://${env.IMAGE}" + echo "Passed" + } + } +}