diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7ab079c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*/galaxy/* diff --git a/basic-tomcat/.applier/group_vars/seed-hosts.yml b/basic-tomcat/.applier/group_vars/seed-hosts.yml new file mode 100644 index 00000000..96a01455 --- /dev/null +++ b/basic-tomcat/.applier/group_vars/seed-hosts.yml @@ -0,0 +1,27 @@ +--- +openshift_cluster_content: +- object: projectrequest + content: + - name: basic-tomcat-spaces + file: "{{ inventory_dir }}/../.openshift/projects/projects.yml" + action: create +- object: deployments + content: + - name: jenkins + namespace: basic-tomcat-build + template: openshift//jenkins-ephemeral + params: "{{ inventory_dir }}/../.openshift/deployment/build/params" + - name: basic-tomcat-dev + template: "{{ inventory_dir }}/../.openshift/deployment/template.yml" + params: "{{ inventory_dir }}/../.openshift/deployment/dev/params" + - name: basic-tomcat-stage + template: "{{ inventory_dir }}/../.openshift/deployment/template.yml" + params: "{{ inventory_dir }}/../.openshift/deployment/stage/params" + - name: basic-tomcat-prod + template: "{{ inventory_dir }}/../.openshift/deployment/template.yml" + params: "{{ inventory_dir }}/../.openshift/deployment/prod/params" +- object: builds + content: + - name: jenkins + template: "{{ inventory_dir }}/../.openshift/builds/template.yml" + params: "{{ inventory_dir }}/../.openshift/builds/params" diff --git a/basic-tomcat/.applier/hosts b/basic-tomcat/.applier/hosts new file mode 100644 index 00000000..7f325c4b --- /dev/null +++ b/basic-tomcat/.applier/hosts @@ -0,0 +1,2 @@ +[seed-hosts] +localhost ansible_connection=local diff --git a/basic-tomcat/.openshift/builds/params b/basic-tomcat/.openshift/builds/params new file mode 100644 index 00000000..11fe844c --- /dev/null +++ b/basic-tomcat/.openshift/builds/params @@ -0,0 +1 @@ +NAMESPACE=basic-tomcat-build diff --git a/basic-tomcat/files/builds/template.yml b/basic-tomcat/.openshift/builds/template.yml similarity index 80% rename from basic-tomcat/files/builds/template.yml rename to basic-tomcat/.openshift/builds/template.yml index e0d086b7..86fc2594 100644 --- a/basic-tomcat/files/builds/template.yml +++ b/basic-tomcat/.openshift/builds/template.yml @@ -33,9 +33,13 @@ objects: type: "JenkinsPipeline" jenkinsPipelineStrategy: jenkinsfilePath: ${PIPELINE_SCRIPT} - env: + env: + - name: "APPLICATION_SOURCE_REPO" + value: "${APPLICATION_SOURCE_REPO}" + - name: "APPLICATION_SOURCE_REF" + value: "${APPLICATION_SOURCE_REF}" - name: "BUILD_CONTEXT_DIR" - value: "demo" + value: "${APPLICATION_CONTEXT_DIR}" - apiVersion: v1 kind: BuildConfig metadata: @@ -78,16 +82,28 @@ parameters: - description: Git source URI for application name: SOURCE_REPOSITORY_URL required: true - value: https://github.com/etsauer/ticket-monster.git + value: https://github.com/redhat-cop/container-pipelines.git - description: Git branch/tag reference name: SOURCE_REPOSITORY_REF value: "master" - description: Path within Git project to build; empty for root project directory. name: CONTEXT_DIR - value: + value: "basic-tomcat" - description: Path within Git project pointing to the pipeline run script name: PIPELINE_SCRIPT - value: pipeline.groovy + value: Jenkinsfile +- description: Source code repo for demo app + name: APPLICATION_SOURCE_REPO + required: true + value: https://github.com/jboss-developer/ticket-monster.git +- description: Source code branch/tag + name: APPLICATION_SOURCE_REF + required: true + value: 2.7.0.Final-with-tutorials +- description: Directory where POM file will be + name: APPLICATION_CONTEXT_DIR + required: true + value: demo - description: GitHub trigger secret from: '[a-zA-Z0-9]{8}' generate: expression diff --git a/basic-tomcat/files/deployment/build/params b/basic-tomcat/.openshift/deployment/build/params similarity index 100% rename from basic-tomcat/files/deployment/build/params rename to basic-tomcat/.openshift/deployment/build/params diff --git a/basic-tomcat/files/deployment/dev/params b/basic-tomcat/.openshift/deployment/dev/params similarity index 100% rename from basic-tomcat/files/deployment/dev/params rename to basic-tomcat/.openshift/deployment/dev/params diff --git a/basic-tomcat/files/deployment/prod/params b/basic-tomcat/.openshift/deployment/prod/params similarity index 100% rename from basic-tomcat/files/deployment/prod/params rename to basic-tomcat/.openshift/deployment/prod/params diff --git a/basic-tomcat/files/deployment/stage/params b/basic-tomcat/.openshift/deployment/stage/params similarity index 100% rename from basic-tomcat/files/deployment/stage/params rename to basic-tomcat/.openshift/deployment/stage/params diff --git a/basic-tomcat/files/deployment/template.yml b/basic-tomcat/.openshift/deployment/template.yml similarity index 97% rename from basic-tomcat/files/deployment/template.yml rename to basic-tomcat/.openshift/deployment/template.yml index 988cd82d..a532b275 100644 --- a/basic-tomcat/files/deployment/template.yml +++ b/basic-tomcat/.openshift/deployment/template.yml @@ -80,6 +80,7 @@ objects: namespace: ${APPLICATION_NAME}${ENV} spec: host: ${HOSTNAME_HTTP} + path: ${ROUTE_PATH} to: name: ${APPLICATION_NAME} - apiVersion: v1 @@ -154,6 +155,9 @@ parameters: - description: 'Custom hostname for http service route. Leave blank for default hostname, e.g.: -.' name: HOSTNAME_HTTP +- description: Path to use for route. + name: ROUTE_PATH + value: /ticket-monster - description: JWS Admin User from: '[a-zA-Z0-9]{8}' generate: expression diff --git a/basic-tomcat/files/projects/projects.yml b/basic-tomcat/.openshift/projects/projects.yml similarity index 74% rename from basic-tomcat/files/projects/projects.yml rename to basic-tomcat/.openshift/projects/projects.yml index 20e2644f..0afe573a 100644 --- a/basic-tomcat/files/projects/projects.yml +++ b/basic-tomcat/.openshift/projects/projects.yml @@ -6,22 +6,22 @@ items: metadata: name: basic-tomcat-dev creationTimestam: null - displayName: Dev - Basic Tomcat App + displayName: Basic Tomcat App - Dev - kind: ProjectRequest apiVersion: v1 metadata: name: basic-tomcat-stage creationTimestam: null - displayName: Staging - Basic Tomcat App + displayName: Basic Tomcat App - Stage - kind: ProjectRequest apiVersion: v1 metadata: name: basic-tomcat-prod creationTimestam: null - displayName: Prod - Basic Tomcat App + displayName: Basic Tomcat App - Prod - kind: ProjectRequest apiVersion: v1 metadata: name: basic-tomcat-build creationTimestam: null - displayName: Build - Jenkins is here + displayName: Basic Tomcat App - Build diff --git a/basic-tomcat/Jenkinsfile b/basic-tomcat/Jenkinsfile new file mode 100644 index 00000000..31425386 --- /dev/null +++ b/basic-tomcat/Jenkinsfile @@ -0,0 +1,96 @@ +#!/usr/bin/groovy + +//// +// This pipeline requires the following plugins: +// Kubernetes Plugin 0.10 +//// + +String ocpApiServer = env.OCP_API_SERVER ? "${env.OCP_API_SERVER}" : "https://openshift.default.svc.cluster.local" + +node('master') { + + env.NAMESPACE = readFile('/var/run/secrets/kubernetes.io/serviceaccount/namespace').trim() + env.TOKEN = readFile('/var/run/secrets/kubernetes.io/serviceaccount/token').trim() + env.OC_CMD = "oc --token=${env.TOKEN} --server=${ocpApiServer} --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt --namespace=${env.NAMESPACE}" + + env.APP_NAME = "${env.JOB_NAME}".replaceAll(/-?pipeline-?/, '').replaceAll(/-?${env.NAMESPACE}-?\/?/, '') + println "Starting Pipeline for Application: ${APP_NAME}" + println "${env.JOB_NAME}, ${env.NAMESPACE}" + def projectBase = "${env.NAMESPACE}".replaceAll(/-build/, '') + env.STAGE0 = "${projectBase}-build" + env.STAGE1 = "${projectBase}-dev" + env.STAGE2 = "${projectBase}-stage" + env.STAGE3 = "${projectBase}-prod" +} + +node('maven') { + + stage('SCM Checkout') { + git url: "${APPLICATION_SOURCE_REPO}", branch: "${APPLICATION_SOURCE_REF}" + } + + stage('Build') { + + String pomFileLocation = env.BUILD_CONTEXT_DIR ? "${env.BUILD_CONTEXT_DIR}/pom.xml" : "pom.xml" + sh "mvn clean install -DskipTests=true -f ${pomFileLocation}" + + } + + stage('Build Image') { + + String target = env.BUILD_CONTEXT_DIR ? "${env.BUILD_CONTEXT_DIR}/target" : "target" + + sh """ + ls ${target}/* + rm -rf oc-build && mkdir -p oc-build/deployments + for t in \$(echo "jar;war;ear" | tr ";" "\\n"); do + cp -rfv ./${target}/*.\$t oc-build/deployments/ 2> /dev/null || echo "No \$t files" + done + """ + openshift.withCluster() { + openshift.withProject("${STAGE0}") { + openshift.selector("bc", "${APP_NAME}").startBuild("--from-dir=oc-build").logs("-f") + } + } + } + + stage ("Promote from Build to Dev") { + openshift.withCluster() { + openshift.tag("${env.STAGE0}/${env.APP_NAME}:latest", "${env.STAGE1}/${env.APP_NAME}:latest") + } + } + + stage("Verify Deployment to ${env.STAGE1}") { + + openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE1}", verifyReplicaCount: true) + + input "Promote Application to Stage?" + } + + stage("Promote To ${env.STAGE2}") { + sh """ + ${env.OC_CMD} tag ${env.STAGE1}/${env.APP_NAME}:latest ${env.STAGE2}/${env.APP_NAME}:latest + """ + } + + stage("Verify Deployment to ${env.STAGE2}") { + + openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE2}", verifyReplicaCount: true) + + input "Promote Application to Prod?" + } + + stage("Promote To ${env.STAGE3}") { + sh """ + ${env.OC_CMD} tag ${env.STAGE2}/${env.APP_NAME}:latest ${env.STAGE3}/${env.APP_NAME}:latest + """ + } + + stage("Verify Deployment to ${env.STAGE3}") { + + openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE3}", verifyReplicaCount: true) + + } +} + +println "Application ${env.APP_NAME} is now in Production!" diff --git a/basic-tomcat/README.md b/basic-tomcat/README.md index 6b915e50..e213962b 100644 --- a/basic-tomcat/README.md +++ b/basic-tomcat/README.md @@ -9,19 +9,14 @@ This example demonstrates how to implement a full end-to-end Jenkins Pipeline fo * Promotion of an application's container image to a separate OpenShift Cluster (using `skopeo`) * Automated rollout using the [openshift-appler](https://github.com/redhat-cop/openshift-applier) project. -## Quickstart +## Automated Deployment -### Requirements -1. [OpenShift Applier](https://github.com/redhat-cop/openshift-applier) - `git clone git@github.com:redhat-cop/openshift-applier.git` - `git checkout v3.6.1` -2. [Ansible](https://www.ansible.com/) - `sudo dnf install ansible` - -### Installation -Run the following commands to instantiate this example. +1. Clone [this repo](https://github.com/redhat-cop/container-pipelines) +2. `cd container-pipelines/basic-tomcat` +3. Run `ansible-galaxy install -r requirements.yml --roles-path=galaxy` +4. Run the following commands to instantiate this example. ``` -ansible-playbook -i inventory/hosts ../openshift-applier/playbooks/openshift-cluster-seed.yml --connection=local +ansible-playbook -i .applier/ galaxy/openshift-applier/playbooks/openshift-cluster-seed.yml ``` The above command will create all the necessary projects and OpenShift objects as well as a Jenkins instance that will build, promote and deploy the application. Run the following commands to instantiate this example. @@ -38,7 +33,7 @@ The first template, `files/builds/template.yml` is what we are calling the "Buil * An `s2i` BuildConfig * An ImageStream for the s2i build config to push to -The build template contains a default source code repo for a java application compatible with this pipelines architecture (https://github.com/etsauer/ticket-monster). +The build template contains a default source code repo for a java application compatible with this pipelines architecture (https://github.com/jboss-developer/ticket-monster.git). The second template, `files/deployment/template.yml` is the "Deploy" template. It contains: @@ -56,9 +51,7 @@ This project includes a sample `pipeline.groovy` Jenkins Pipeline script that co * The `pipeline.groovy` script is placed in the same directory as the `pom.xml` file in the git source. * The OpenShift projects that represent the Application's lifecycle stages are of the naming format: `-dev`, `-stage`, `-prod`. -For convenience, this pipeline script is already included in the following git repository, based on the [JBoss Developers Ticket Monster](https://github.com/jboss-developer/ticket-monster) app. - -https://github.com/etsauer/ticket-monster +For convenience, the project will, by default build and deploy the [JBoss Developers Ticket Monster](https://github.com/jboss-developer/ticket-monster.git) application. ## Bill of Materials diff --git a/basic-tomcat/files/builds/params b/basic-tomcat/files/builds/params deleted file mode 100644 index e2fe86d5..00000000 --- a/basic-tomcat/files/builds/params +++ /dev/null @@ -1,3 +0,0 @@ -NAMESPACE=basic-tomcat-build -SOURCE_REPOSITORY_URL=https://github.com/pabrahamsson/ticket-monster.git -SOURCE_REPOSITORY_REF=build diff --git a/basic-tomcat/inventory/group_vars/all.yml b/basic-tomcat/inventory/group_vars/all.yml deleted file mode 100644 index 1adaf74f..00000000 --- a/basic-tomcat/inventory/group_vars/all.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -openshift_cluster_content: -- object: projectrequest - content: - - name: basic-tomcat-spaces - file: "{{ inventory_dir }}/../files/projects/projects.yml" - file_action: create -- object: deployments - content: - - name: jenkins - namespace: basic-tomcat-build - template: openshift//jenkins-ephemeral - params: "{{ inventory_dir }}/../files/deployment/build/params" - - name: basic-tomcat-dev - template: "{{ inventory_dir }}/../files/deployment/template.yml" - params: "{{ inventory_dir }}/../files/deployment/dev/params" - - name: basic-tomcat-stage - template: "{{ inventory_dir }}/../files/deployment/template.yml" - params: "{{ inventory_dir }}/../files/deployment/stage/params" - - name: basic-tomcat-prod - template: "{{ inventory_dir }}/../files/deployment/template.yml" - params: "{{ inventory_dir }}/../files/deployment/prod/params" -- object: builds - content: - - name: jenkins - template: "{{ inventory_dir }}/../files/builds/template.yml" - params: "{{ inventory_dir }}/../files/builds/params" diff --git a/basic-tomcat/inventory/hosts b/basic-tomcat/inventory/hosts deleted file mode 100644 index 05c07035..00000000 --- a/basic-tomcat/inventory/hosts +++ /dev/null @@ -1,2 +0,0 @@ -[seed-hosts] -localhost diff --git a/basic-tomcat/pipeline.groovy b/basic-tomcat/pipeline.groovy deleted file mode 100644 index 42bc591e..00000000 --- a/basic-tomcat/pipeline.groovy +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/groovy - -//// -// This pipeline requires the following plugins: -// Kubernetes Plugin 0.10 -//// - -String ocpApiServer = env.OCP_API_SERVER ? "${env.OCP_API_SERVER}" : "https://openshift.default.svc.cluster.local" - -node('master') { - - env.NAMESPACE = readFile('/var/run/secrets/kubernetes.io/serviceaccount/namespace').trim() - env.TOKEN = readFile('/var/run/secrets/kubernetes.io/serviceaccount/token').trim() - env.OC_CMD = "oc --token=${env.TOKEN} --server=${ocpApiServer} --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt --namespace=${env.NAMESPACE}" - - env.APP_NAME = "${env.JOB_NAME}".replaceAll(/-?pipeline-?/, '').replaceAll(/-?${env.NAMESPACE}-?/, '') - def projectBase = "${env.NAMESPACE}".replaceAll(/-dev/, '') - env.STAGE1 = "${projectBase}-dev" - env.STAGE2 = "${projectBase}-stage" - env.STAGE3 = "${projectBase}-prod" - - sh(returnStdout: true, script: "${env.OC_CMD} get is jenkins-slave-image-mgmt --template=\'{{ .status.dockerImageRepository }}\' -n openshift > /tmp/jenkins-slave-image-mgmt.out") - env.SKOPEO_SLAVE_IMAGE = readFile('/tmp/jenkins-slave-image-mgmt.out').trim() - println "${env.SKOPEO_SLAVE_IMAGE}" - -} - -node('maven') { -// def artifactory = Artifactory.server(env.ARTIFACTORY_SERVER) - // def artifactoryMaven = Artifactory.newMavenBuild() - // def buildInfo = Artifactory.newBuildInfo() - // def scannerHome = tool env.SONARQUBE_TOOL - def mvnHome = "/usr/share/maven/" - def mvnCmd = "${mvnHome}bin/mvn" - String pomFileLocation = env.BUILD_CONTEXT_DIR ? "${env.BUILD_CONTEXT_DIR}/pom.xml" : "pom.xml" - - stage('SCM Checkout') { - checkout scm - } - - stage('Build') { - - sh "${mvnCmd} clean install -DskipTests=true -f ${pomFileLocation}" - - } - - stage('Build Image') { - - sh """ - rm -rf oc-build && mkdir -p oc-build/deployments - - for t in \$(echo "jar;war;ear" | tr ";" "\\n"); do - cp -rfv ./target/*.\$t oc-build/deployments/ 2> /dev/null || echo "No \$t files" - done - - for i in oc-build/deployments/*.war; do - mv -v oc-build/deployments/\$(basename \$i) oc-build/deployments/ROOT.war - break - done - - ${env.OC_CMD} start-build ${env.APP_NAME} --from-dir=oc-build --wait=true --follow=true || exit 1 - """ - } - - stage("Verify Deployment to ${env.STAGE1}") { - - openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE1}", verifyReplicaCount: true) - - input "Promote Application to Stage?" - } - - stage("Promote To ${env.STAGE2}") { - sh """ - ${env.OC_CMD} tag ${env.STAGE1}/${env.APP_NAME}:latest ${env.STAGE2}/${env.APP_NAME}:latest - """ - } - - stage("Verify Deployment to ${env.STAGE2}") { - - openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE2}", verifyReplicaCount: true) - - input "Promote Application to Prod?" - } - - stage("Promote To ${env.STAGE3}") { - sh """ - ${env.OC_CMD} tag ${env.STAGE2}/${env.APP_NAME}:latest ${env.STAGE3}/${env.APP_NAME}:latest - """ - } - - stage("Verify Deployment to ${env.STAGE3}") { - - openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE3}", verifyReplicaCount: true) - - } -} - -/* -podTemplate(label: 'promotion-slave', cloud: 'openshift', containers: [ - containerTemplate(name: 'jenkins-slave-image-mgmt', image: "${env.SKOPEO_SLAVE_IMAGE}", ttyEnabled: true, command: 'cat'), - containerTemplate(name: 'jnlp', image: 'jenkinsci/jnlp-slave:2.62-alpine', args: '${computer.jnlpmac} ${computer.name}') -]) { - - node('promotion-slave') { - - stage("Promote To ${env.STAGE3}") { - - container('jenkins-slave-image-mgmt') { - sh """ - - set +x - imageRegistry=\$(${env.OC_CMD} get is ${env.APP_NAME} --template='{{ .status.dockerImageRepository }}' -n ${env.STAGE2} | cut -d/ -f1) - - strippedNamespace=\$(echo ${env.NAMESPACE} | cut -d/ -f1) - - echo "Promoting \${imageRegistry}/${env.STAGE2}/${env.APP_NAME} -> \${imageRegistry}/${env.STAGE3}/${env.APP_NAME}" - skopeo --tls-verify=false copy --remove-signatures --src-creds openshift:${env.TOKEN} --dest-creds openshift:${env.TOKEN} docker://\${imageRegistry}/${env.STAGE2}/${env.APP_NAME} docker://\${imageRegistry}/${env.STAGE3}/${env.APP_NAME} - """ - } - } - - stage("Verify Deployment to ${env.STAGE3}") { - - openshiftVerifyDeployment(deploymentConfig: "${env.APP_NAME}", namespace: "${STAGE3}", verifyReplicaCount: true) - - } - - } -} -*/ -println "Application ${env.APP_NAME} is now in Production!" diff --git a/basic-tomcat/requirements.yml b/basic-tomcat/requirements.yml new file mode 100644 index 00000000..de2d8beb --- /dev/null +++ b/basic-tomcat/requirements.yml @@ -0,0 +1,8 @@ +# This is the Ansible Galaxy requirements file to pull in the correct roles +# to support the operation of CASL provisioning/runs. + +# From 'openshift-applier' +- name: openshift-applier + scm: git + src: https://github.com/redhat-cop/openshift-applier + version: v2.0.3