apiVersion: template.openshift.io/v1
kind: Template
labels:
  template: bluegreen-pipeline
message: A Jenkins server must be instantiated in this project to manage
  the Pipeline BuildConfig created by this template.  You will be able to log in to
  it using your OpenShift user credentials.
metadata:
  annotations:
    description: This example showcases a blue green deployment using a Jenkins
      pipeline that pauses for approval.
    iconClass: icon-jenkins
    tags: instant-app,jenkins
  name: bluegreen-pipeline
objects:
- apiVersion: build.openshift.io/v1
  kind: BuildConfig
  metadata:
    annotations:
      pipeline.alpha.openshift.io/uses: '[{"name": "${NAME}", "namespace": "", "kind": "DeploymentConfig"}]'
    creationTimestamp: null
    labels:
      name: bluegreen-pipeline
    name: bluegreen-pipeline
  spec:
    strategy:
      jenkinsPipelineStrategy:
        jenkinsfile: |-
          try {
             timeout(time: 20, unit: 'MINUTES') {
                def appName="${NAME}"
                def project=""
                def tag="blue"
                def altTag="green"
                def verbose="${VERBOSE}"

                node {
                  project = env.PROJECT_NAME
                  stage("Initialize") {
                    sh "oc get route ${appName} -n ${project} -o jsonpath='{ .spec.to.name }' --loglevel=4 > activeservice"
                    activeService = readFile('activeservice').trim()
                    if (activeService == "${appName}-blue") {
                      tag = "green"
                      altTag = "blue"
                    }
                    sh "oc get route ${tag}-${appName} -n ${project} -o jsonpath='{ .spec.host }' --loglevel=4 > routehost"
                    routeHost = readFile('routehost').trim()
                  }

                  openshift.withCluster() {
                    openshift.withProject() {
                      stage("Build") {
                        echo "building tag ${tag}"
                        def bld = openshift.startBuild("${appName}")
                        bld.untilEach {
                          return it.object().status.phase == "Running"
                        }
                        bld.logs('-f')
                      }

                      stage("Deploy Test") {
                        openshift.tag("${appName}:latest", "${appName}:${tag}")
                        def dc = openshift.selector('dc', "${appName}-${tag}")
                        dc.rollout().status()
                      }

                      stage("Test") {
                        input message: "Test deployment: http://${routeHost}. Approve?", id: "approval"
                      }

                      stage("Go Live") {
                        sh "oc set -n ${project} route-backends ${appName} ${appName}-${tag}=100 ${appName}-${altTag}=0 --loglevel=4"
                      }

                    }
                  }
                }
             }
          } catch (err) {
             echo "in catch block"
             echo "Caught: ${err}"
             currentBuild.result = 'FAILURE'
             throw err
          }
      type: JenkinsPipeline
    triggers:
    - github:
        secret: "${GITHUB_WEBHOOK_SECRET}"
      type: GitHub
    - generic:
        secret: "${GENERIC_WEBHOOK_SECRET}"
      type: Generic
- apiVersion: v1
  kind: Secret
  metadata:
    name: ${NAME}
  stringData:
    database-admin-password: ${DATABASE_ADMIN_PASSWORD}
    database-password: ${DATABASE_PASSWORD}
    database-user: ${DATABASE_USER}
- apiVersion: route.openshift.io/v1
  kind: Route
  metadata:
    name: blue-${NAME}
  spec:
    to:
      kind: Service
      name: ${NAME}-blue
- apiVersion: route.openshift.io/v1
  kind: Route
  metadata:
    name: green-${NAME}
  spec:
    to:
      kind: Service
      name: ${NAME}-green
- apiVersion: route.openshift.io/v1
  kind: Route
  metadata:
    name: ${NAME}
  spec:
    alternateBackends:
    - name: ${NAME}-green
      weight: 0
    to:
      kind: Service
      name: ${NAME}-blue
      weight: 100
- apiVersion: image.openshift.io/v1
  kind: ImageStream
  metadata:
    annotations:
      description: Keeps track of changes in the application image
    name: ${NAME}
- apiVersion: build.openshift.io/v1
  kind: BuildConfig
  metadata:
    annotations:
      description: Defines how to build the application
    name: ${NAME}
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: ${NAME}:latest
    postCommit:
      script: npm test
    source:
      contextDir: ${CONTEXT_DIR}
      git:
        ref: ${SOURCE_REPOSITORY_REF}
        uri: ${SOURCE_REPOSITORY_URL}
      type: Git
    strategy:
      sourceStrategy:
        env:
        - name: NPM_MIRROR
          value: ${NPM_MIRROR}
        from:
          kind: ImageStreamTag
          name: nodejs:${NODEJS_VERSION}
          namespace: ${NAMESPACE}
      type: Source
    triggers:
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - generic:
        secret: ${GENERIC_WEBHOOK_SECRET}
      type: Generic
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      service.alpha.openshift.io/dependencies: '[{"name": "${DATABASE_SERVICE_NAME}", "namespace": "", "kind": "Service"}]'
    name: ${NAME}-blue
  spec:
    ports:
    - name: web
      port: 8080
      targetPort: 8080
    selector:
      name: ${NAME}-blue
- apiVersion: apps.openshift.io/v1
  kind: DeploymentConfig
  metadata:
    annotations:
      description: Defines how to deploy the application server
    name: ${NAME}-blue
  spec:
    replicas: 1
    selector:
      name: ${NAME}-blue
    strategy:
      type: Rolling
    template:
      metadata:
        labels:
          name: ${NAME}-blue
        name: ${NAME}-blue
      spec:
        containers:
        - env:
          - name: DATABASE_SERVICE_NAME
            value: ${DATABASE_SERVICE_NAME}
          - name: MYSQL_USER
            value: ${DATABASE_USER}
          - name: MYSQL_PASSWORD
            value: ${DATABASE_PASSWORD}
          - name: MYSQL_DATABASE
            value: ${DATABASE_NAME}
          - name: MYSQL_ROOT_PASSWORD
            value: ${DATABASE_ROOT_PASSWORD}
          image: ' '
          livenessProbe:
            httpGet:
              path: /pagecount
              port: 8080
            initialDelaySeconds: 30
            timeoutSeconds: 3
          name: nodejs-postgresql-example
          ports:
          - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /pagecount
              port: 8080
            initialDelaySeconds: 3
            timeoutSeconds: 3
          resources:
            limits:
              memory: ${MEMORY_LIMIT}
    triggers:
    - imageChangeParams:
        automatic: true
        containerNames:
        - nodejs-postgresql-example
        from:
          kind: ImageStreamTag
          name: ${NAME}:blue
      type: ImageChange
    - type: ConfigChange
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      service.alpha.openshift.io/dependencies: '[{"name": "${DATABASE_SERVICE_NAME}", "namespace": "", "kind": "Service"}]'
    name: ${NAME}-green
  spec:
    ports:
    - name: web
      port: 8080
      targetPort: 8080
    selector:
      name: ${NAME}-green
- apiVersion: apps.openshift.io/v1
  kind: DeploymentConfig
  metadata:
    annotations:
      description: Defines how to deploy the application server
    name: ${NAME}-green
  spec:
    replicas: 1
    selector:
      name: ${NAME}-green
    strategy:
      type: Rolling
    template:
      metadata:
        labels:
          name: ${NAME}-green
        name: ${NAME}-green
      spec:
        containers:
        - env:
            - name: POSTGRESQL_USER
              valueFrom:
                secretKeyRef:
                  key: database-user
                  name: ${NAME}
            - name: POSTGRESQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-password
                  name: ${NAME}
            - name: POSTGRESQL_DATABASE
              value: ${DATABASE_NAME}
            - name: POSTGRESQL_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-admin-password
                  name: ${NAME}
          image: ' '
          livenessProbe:
            httpGet:
              path: /pagecount
              port: 8080
            initialDelaySeconds: 30
            timeoutSeconds: 3
          name: nodejs-postgresql-example
          ports:
          - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /pagecount
              port: 8080
            initialDelaySeconds: 3
            timeoutSeconds: 3
          resources:
            limits:
              memory: ${MEMORY_LIMIT}
    triggers:
    - imageChangeParams:
        automatic: true
        containerNames:
        - nodejs-postgresql-example
        from:
          kind: ImageStreamTag
          name: ${NAME}:green
      type: ImageChange
    - type: ConfigChange
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      description: Exposes the database server
    name: ${DATABASE_SERVICE_NAME}
  spec:
    ports:
    - name: postgresql
      port: 5432
      targetPort: 5432
    selector:
      name: ${DATABASE_SERVICE_NAME}
- apiVersion: apps.openshift.io/v1
  kind: DeploymentConfig
  metadata:
    annotations:
      description: Defines how to deploy the database
    name: ${DATABASE_SERVICE_NAME}
  spec:
    replicas: 1
    selector:
      name: ${DATABASE_SERVICE_NAME}
    strategy:
      type: Recreate
    template:
      metadata:
        labels:
          name: ${DATABASE_SERVICE_NAME}
        name: ${DATABASE_SERVICE_NAME}
      spec:
        containers:
        - env:
            - name: POSTGRESQL_USER
              valueFrom:
                secretKeyRef:
                  key: database-user
                  name: ${NAME}
            - name: POSTGRESQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-password
                  name: ${NAME}
            - name: POSTGRESQL_DATABASE
              value: ${DATABASE_NAME}
            - name: POSTGRESQL_ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-admin-password
                  name: ${NAME}
          image: ' '
          livenessProbe:
            initialDelaySeconds: 30
            tcpSocket:
              port: 5432
            timeoutSeconds: 1
          name: postgresql
          ports:
          - containerPort: 5432
          resources:
            limits:
              memory: ${MEMORY_MYSQL_LIMIT}
          volumeMounts:
          - mountPath: /var/lib/mysql/data
            name: ${DATABASE_SERVICE_NAME}-data
        volumes:
        - emptyDir:
            medium: ""
          name: ${DATABASE_SERVICE_NAME}-data
    triggers:
    - imageChangeParams:
        automatic: true
        containerNames:
        - postgresql
        from:
          kind: ImageStreamTag
          name: postgresql:${POSTGRESQL_VERSION}
          namespace: ${NAMESPACE}
      type: ImageChange
    - type: ConfigChange
parameters:
- description: The name assigned to all of the frontend objects defined in this template.
  displayName: Name
  name: NAME
  required: true
  value: nodejs-postgresql-example
- description: The OpenShift Namespace where the NodeJS and postgresql ImageStreams reside.
  displayName: Namespace
  name: NAMESPACE
  required: true
  value: openshift
- description: Version of NodeJS image to be used (14-ubi8, or latest).
  displayName: Version of NodeJS Image
  name: NODEJS_VERSION
  required: true
  value: 14-ubi8
- description: Version of PostgreSQL image to be used (12-el8, or latest).
  displayName: Version of PostgreSQL Image
  name: POSTGRESQL_VERSION
  required: true
  value: 12-el8
- description: The exposed hostname that will route to the Node.js service, if left
    blank a value will be defaulted.
  displayName: Application Hostname
  name: APPLICATION_DOMAIN
- description: The URL of the repository with your application source code.
  displayName: Git Repository URL
  name: SOURCE_REPOSITORY_URL
  required: true
  value: https://github.com/openshift/nodejs-ex.git
- description: The reference of the repository with your application source code.
  displayName: Git Repository Ref
  name: SOURCE_REPOSITORY_REF
  required: true
  value: master
- description: Password for the database admin user.
  displayName: Database Administrator Password
  from: '[a-zA-Z0-9]{16}'
  generate: expression
  name: DATABASE_ADMIN_PASSWORD
- displayName: Database Name
  name: DATABASE_NAME
  required: true
  value: sampledb
- description: Username for postgresql user that will be used for accessing the database.
  displayName: postgresql Username
  from: user[A-Z0-9]{3}
  generate: expression
  name: DATABASE_USER
- description: Password for the postgresql user.
  displayName: postgresql Password
  from: '[a-zA-Z0-9]{16}'
  generate: expression
  name: DATABASE_PASSWORD
- description: Maximum amount of memory the Node.js container can use.
  displayName: Memory Limit
  name: MEMORY_LIMIT
  required: true
  value: 512Mi
- description: Maximum amount of memory the postgresql container can use.
  displayName: Memory Limit (postgresql)
  name: MEMORY_MYSQL_LIMIT
  required: true
  value: 512Mi
- displayName: Database Service Name
  name: DATABASE_SERVICE_NAME
  required: true
  value: postgresql
- description: Password for the database admin user.
  displayName: Database Administrator Password
  from: '[a-zA-Z0-9]{16}'
  generate: expression
  name: DATABASE_ROOT_PASSWORD
- description: Set this to the relative path to your project if it is not in the root
    of your repository.
  displayName: Context Directory
  name: CONTEXT_DIR
- description: Github trigger secret.  A difficult to guess string encoded as part of the webhook URL.  Not encrypted.
  displayName: GitHub Webhook Secret
  from: '[a-zA-Z0-9]{40}'
  generate: expression
  name: GITHUB_WEBHOOK_SECRET
- description: A secret string used to configure the Generic webhook.
  displayName: Generic Webhook Secret
  from: '[a-zA-Z0-9]{40}'
  generate: expression
  name: GENERIC_WEBHOOK_SECRET
- description: The custom NPM mirror URL
  displayName: Custom NPM Mirror URL
  name: NPM_MIRROR
- description: Whether to enable verbose logging of Jenkinsfile steps in pipeline
  displayName: Verbose
  name: VERBOSE
  required: true
  value: "false"