diff --git a/.github/workflows/api.yml b/.github/workflows/ci-api-build.and.test.yml similarity index 60% rename from .github/workflows/api.yml rename to .github/workflows/ci-api-build.and.test.yml index 5d2fb51..ee9102e 100644 --- a/.github/workflows/api.yml +++ b/.github/workflows/ci-api-build.and.test.yml @@ -1,6 +1,7 @@ name: API CI on: + workflow_dispatch: push: branches: - master @@ -17,27 +18,41 @@ on: jobs: quality_profile: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 defaults: run: working-directory: api steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v3 with: - java-version: 11 - - uses: actions/cache@v1 + java-version: 17 + distribution: oracle + - uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Run unit tests - run: mvn clean package + run: mvn -f pom.xml clean package + - name: Run Trivy vulnerability scanner in repo mode + uses: aquasecurity/trivy-action@0.2.5 + with: + scan-type: 'fs' + ignore-unfixed: true + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'CRITICAL' + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: 'trivy-results.sarif' - name: Cache SonarCloud packages uses: actions/cache@v1 with: diff --git a/.github/workflows/deploy-to.openshift-dev.yml b/.github/workflows/deploy-to.openshift-dev.yml new file mode 100644 index 0000000..cbb6ecb --- /dev/null +++ b/.github/workflows/deploy-to.openshift-dev.yml @@ -0,0 +1,170 @@ +name: Build & Deploy to DEV + +env: + # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context. + # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values. + # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions + OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} + OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }} + OPENSHIFT_NAMESPACE_DEV: ${{ secrets.COMMON_NAMESPACE_NO_ENV }}-dev + + DB_JDBC_CONNECT_STRING: ${{ secrets.DB_JDBC_CONNECT_STRING }} + DB_PWD: ${{ secrets.DB_PWD }} + DB_USER: ${{ secrets.DB_USER }} + SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }} + + # 🖊️ EDIT to change the image registry settings. + # Registries such as GHCR, Quay.io, and Docker Hub are supported. + IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} + IMAGE_REGISTRY_USER: ${{ github.actor }} + IMAGE_REGISTRY_PASSWORD: ${{ github.token }} + + # 🖊️ EDIT to specify custom tags for the container image, or default tags will be generated below. + IMAGE_TAGS: "" + + SPRING_BOOT_IMAGE_NAME: student-profile-api-master + DOCKER_ARTIFACTORY_REPO: artifacts.developer.gov.bc.ca/docker-remote + ARTIFACTORY_REPO: artifacts.developer.gov.bc.ca + + APP_NAME: 'student-profile-api' + REPO_NAME: "educ-student-profile-api" + BRANCH: "master" + APP_NAME_FULL: "student-profile-api-master" + NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + COMMON_NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + TAG: "latest" + MIN_REPLICAS_DEV: "1" + MAX_REPLICAS_DEV: "1" + MIN_CPU: "15m" + MAX_CPU: "150m" + MIN_MEM: "650Mi" + MAX_MEM: "750Mi" + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + build-and-deploy-dev: + name: Build and deploy to OpenShift DEV + # ubuntu-20.04 can also be used. + runs-on: ubuntu-20.04 + environment: dev + + outputs: + ROUTE: ${{ steps.deploy-and-expose.outputs.route }} + SELECTOR: ${{ steps.deploy-and-expose.outputs.selector }} + + steps: + - name: Check for required secrets + uses: actions/github-script@v6 + with: + script: | + const secrets = { + OPENSHIFT_SERVER: `${{ secrets.OPENSHIFT_SERVER }}`, + OPENSHIFT_TOKEN: `${{ secrets.OPENSHIFT_TOKEN }}`, + }; + const GHCR = "ghcr.io"; + if (`${{ env.IMAGE_REGISTRY }}`.startsWith(GHCR)) { + core.info(`Image registry is ${GHCR} - no registry password required`); + } + else { + core.info("A registry password is required"); + secrets["IMAGE_REGISTRY_PASSWORD"] = `${{ secrets.IMAGE_REGISTRY_PASSWORD }}`; + } + const missingSecrets = Object.entries(secrets).filter(([ name, value ]) => { + if (value.length === 0) { + core.error(`Secret "${name}" is not set`); + return true; + } + core.info(`✔️ Secret "${name}" is set`); + return false; + }); + if (missingSecrets.length > 0) { + core.setFailed(`❌ At least one required secret is not set in the repository. \n` + + "You can add it using:\n" + + "GitHub UI: https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository \n" + + "GitHub CLI: https://cli.github.com/manual/gh_secret_set \n" + + "Also, refer to https://github.com/redhat-actions/oc-login#getting-started-with-the-action-or-see-example"); + } + else { + core.info(`✅ All the required secrets are set`); + } + - name: Check out repository + uses: actions/checkout@v3 + + - name: Determine image tags + if: env.IMAGE_TAGS == '' + run: | + echo "IMAGE_TAGS=latest ${GITHUB_SHA::12}" | tee -a $GITHUB_ENV + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + registry: ${{ env.DOCKER_ARTIFACTORY_REPO }} + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + # https://github.com/redhat-actions/buildah-build#readme + - name: Build from Dockerfile + id: build-image + uses: redhat-actions/buildah-build@v2 + with: + image: ${{ env.APP_NAME_FULL }} + tags: ${{ env.IMAGE_TAGS }} + + # If you don't have a Dockerfile/Containerfile, refer to https://github.com/redhat-actions/buildah-build#scratch-build-inputs + # Or, perform a source-to-image build using https://github.com/redhat-actions/s2i-build + # Otherwise, point this to your Dockerfile/Containerfile relative to the repository root. + dockerfiles: | + ./Dockerfile + # https://github.com/redhat-actions/push-to-registry#readme + - name: Push to registry + id: push-image + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.build-image.outputs.image }} + tags: ${{ steps.build-image.outputs.tags }} + registry: ${{ env.IMAGE_REGISTRY }} + username: ${{ env.IMAGE_REGISTRY_USER }} + password: ${{ env.IMAGE_REGISTRY_PASSWORD }} + + # The path the image was pushed to is now stored in ${{ steps.push-image.outputs.registry-path }} + + - name: Install oc + uses: redhat-actions/openshift-tools-installer@v1 + with: + oc: 4 + + # https://github.com/redhat-actions/oc-login#readme + - uses: actions/checkout@v3 + + - name: Deploy API + run: | + set -eu + # Login to OpenShift and select project + oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }} + oc project ${{ env.OPENSHIFT_NAMESPACE_DEV }} + # Cancel any rollouts in progress + oc rollout cancel dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "No rollout in progress" + + oc tag ${{ steps.push-image.outputs.registry-path }} ${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ env.TAG }} + + # Process and apply deployment template + oc process -f tools/openshift/api.dc.yaml -p APP_NAME=${{ env.APP_NAME }} -p REPO_NAME=${{ env.REPO_NAME }} -p BRANCH=${{ env.BRANCH }} -p NAMESPACE=${{ env.OPENSHIFT_NAMESPACE_DEV }} -p TAG=${{ env.TAG }} -p MIN_REPLICAS=${{ env.MIN_REPLICAS_DEV }} -p MAX_REPLICAS=${{ env.MAX_REPLICAS_DEV }} -p MIN_CPU=${{ env.MIN_CPU }} -p MAX_CPU=${{ env.MAX_CPU }} -p MIN_MEM=${{ env.MIN_MEM }} -p MAX_MEM=${{ env.MAX_MEM }} \ + | oc apply -f - + + curl -s https://raw.githubusercontent.com/bcgov/${{ env.REPO_NAME }}/master/tools/config/update-configmap.sh | bash /dev/stdin dev ${{ env.APP_NAME }} ${{ env.NAMESPACE }} ${{ env.COMMON_NAMESPACE }} ${{ env.DB_JDBC_CONNECT_STRING }} ${{ env.DB_PWD }} ${{ env.DB_USER }} ${{ env.SPLUNK_TOKEN }} + + # Start rollout (if necessary) and follow it + oc rollout latest dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "Rollout in progress" + oc logs -f dc/${{ env.SPRING_BOOT_IMAGE_NAME }} + # Get status, returns 0 if rollout is successful + oc rollout status dc/${{ env.SPRING_BOOT_IMAGE_NAME }} + - name: ZAP Scan + uses: zaproxy/action-api-scan@v0.1.1 + with: + target: 'https://${{ env.APP_NAME }}-${{ env.OPENSHIFT_NAMESPACE_DEV }}.apps.silver.devops.gov.bc.ca/v3/api-docs' \ No newline at end of file diff --git a/.github/workflows/deploy-to.openshift-prod.yml b/.github/workflows/deploy-to.openshift-prod.yml new file mode 100644 index 0000000..d4a627c --- /dev/null +++ b/.github/workflows/deploy-to.openshift-prod.yml @@ -0,0 +1,131 @@ +name: Deploy to PROD + +env: + # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context. + # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values. + # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions + # Added this comment + OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} + OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }} + OPENSHIFT_NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }}-prod + + DB_JDBC_CONNECT_STRING: ${{ secrets.DB_JDBC_CONNECT_STRING }} + DB_PWD: ${{ secrets.DB_PWD }} + DB_USER: ${{ secrets.DB_USER }} + SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }} + + # 🖊️ EDIT to change the image registry settings. + # Registries such as GHCR, Quay.io, and Docker Hub are supported. + IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} + IMAGE_REGISTRY_USER: ${{ github.actor }} + IMAGE_REGISTRY_PASSWORD: ${{ github.token }} + + SPRING_BOOT_IMAGE_NAME: student-profile-api-master + + APP_NAME: 'student-profile-api' + REPO_NAME: "educ-student-profile-api" + BRANCH: "master" + NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + COMMON_NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + TAG: "latest" + TARGET_ENV: "prod" + MIN_REPLICAS: "3" + MAX_REPLICAS: "3" + MIN_CPU: "15m" + MAX_CPU: "300m" + MIN_MEM: "650Mi" + MAX_MEM: "750Mi" + +on: + # https://docs.github.com/en/actions/reference/events-that-trigger-workflows + workflow_dispatch: + +jobs: + openshift-ci-cd: + name: Deploy to OpenShift PROD + # ubuntu-20.04 can also be used. + runs-on: ubuntu-20.04 + environment: production + + outputs: + ROUTE: ${{ steps.deploy-and-expose.outputs.route }} + SELECTOR: ${{ steps.deploy-and-expose.outputs.selector }} + + steps: + - name: Check for required secrets + uses: actions/github-script@v6 + with: + script: | + const secrets = { + OPENSHIFT_SERVER: `${{ secrets.OPENSHIFT_SERVER }}`, + OPENSHIFT_TOKEN: `${{ secrets.OPENSHIFT_TOKEN }}`, + }; + + const GHCR = "ghcr.io"; + if (`${{ env.IMAGE_REGISTRY }}`.startsWith(GHCR)) { + core.info(`Image registry is ${GHCR} - no registry password required`); + } + else { + core.info("A registry password is required"); + secrets["IMAGE_REGISTRY_PASSWORD"] = `${{ secrets.IMAGE_REGISTRY_PASSWORD }}`; + } + + const missingSecrets = Object.entries(secrets).filter(([ name, value ]) => { + if (value.length === 0) { + core.error(`Secret "${name}" is not set`); + return true; + } + core.info(`✔️ Secret "${name}" is set`); + return false; + }); + + if (missingSecrets.length > 0) { + core.setFailed(`❌ At least one required secret is not set in the repository. \n` + + "You can add it using:\n" + + "GitHub UI: https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository \n" + + "GitHub CLI: https://cli.github.com/manual/gh_secret_set \n" + + "Also, refer to https://github.com/redhat-actions/oc-login#getting-started-with-the-action-or-see-example"); + } + else { + core.info(`✅ All the required secrets are set`); + } + + - name: Check out repository + uses: actions/checkout@v3 + + - name: Get latest tag + uses: actions-ecosystem/action-get-latest-tag@v1 + id: get-latest-tag + + - name: Install oc + uses: redhat-actions/openshift-tools-installer@v1 + with: + oc: 4 + + # https://github.com/redhat-actions/oc-login#readme + - uses: actions/checkout@v3 + + - name: Deploy + run: | + set -eux + # Login to OpenShift and select project + oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }} + oc project ${{ env.OPENSHIFT_NAMESPACE }} + # Cancel any rollouts in progress + oc rollout cancel dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "No rollout in progress" + + oc tag ${{ env.NAMESPACE }}-dev/${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ steps.get-latest-tag.outputs.tag }} ${{ env.NAMESPACE }}-prod/${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ steps.get-latest-tag.outputs.tag }} + + # Process and apply deployment template + oc process -f tools/openshift/api.dc.yaml -p APP_NAME=${{ env.APP_NAME }} -p REPO_NAME=${{ env.REPO_NAME }} -p BRANCH=${{ env.BRANCH }} -p NAMESPACE=${{ env.OPENSHIFT_NAMESPACE }} -p TAG=${{ steps.get-latest-tag.outputs.tag }} -p MIN_REPLICAS=${{ env.MIN_REPLICAS }} -p MAX_REPLICAS=${{ env.MAX_REPLICAS }} -p MIN_CPU=${{ env.MIN_CPU }} -p MAX_CPU=${{ env.MAX_CPU }} -p MIN_MEM=${{ env.MIN_MEM }} -p MAX_MEM=${{ env.MAX_MEM }} \ + | oc apply -f - + + curl -s https://raw.githubusercontent.com/bcgov/${{ env.REPO_NAME }}/${{ steps.get-latest-tag.outputs.tag }}/tools/config/update-configmap.sh | bash /dev/stdin ${{ env.TARGET_ENV }} ${{ env.APP_NAME }} ${{ env.NAMESPACE }} ${{ env.COMMON_NAMESPACE }} ${{ env.DB_JDBC_CONNECT_STRING }} ${{ env.DB_PWD }} ${{ env.DB_USER }} ${{ env.SPLUNK_TOKEN }} + + # Start rollout (if necessary) and follow it + oc rollout latest dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "Rollout in progress" + oc logs -f dc/${{ env.SPRING_BOOT_IMAGE_NAME }} + # Get status, returns 0 if rollout is successful + oc rollout status dc/${{ env.SPRING_BOOT_IMAGE_NAME }} \ No newline at end of file diff --git a/.github/workflows/deploy-to.openshift-test.yml b/.github/workflows/deploy-to.openshift-test.yml new file mode 100644 index 0000000..10830bc --- /dev/null +++ b/.github/workflows/deploy-to.openshift-test.yml @@ -0,0 +1,132 @@ +name: Build & Deploy to TEST + +env: + # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context. + # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values. + # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions + OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} + OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }} + OPENSHIFT_NAMESPACE_TEST: ${{ secrets.COMMON_NAMESPACE_NO_ENV }}-test + + DB_JDBC_CONNECT_STRING: ${{ secrets.DB_JDBC_CONNECT_STRING }} + DB_PWD: ${{ secrets.DB_PWD }} + DB_USER: ${{ secrets.DB_USER }} + SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }} + + # 🖊️ EDIT to change the image registry settings. + # Registries such as GHCR, Quay.io, and Docker Hub are supported. + IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} + IMAGE_REGISTRY_USER: ${{ github.actor }} + IMAGE_REGISTRY_PASSWORD: ${{ github.token }} + + # 🖊️ EDIT to specify custom tags for the container image, or default tags will be generated below. + IMAGE_TAGS: "" + + SPRING_BOOT_IMAGE_NAME: student-profile-api-master + DOCKER_ARTIFACTORY_REPO: artifacts.developer.gov.bc.ca/docker-remote + ARTIFACTORY_REPO: artifacts.developer.gov.bc.ca + + APP_NAME: 'student-profile-api' + REPO_NAME: "educ-student-profile-api" + BRANCH: "master" + APP_NAME_FULL: "student-profile-api-master" + NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + COMMON_NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + TAG: "latest" + MIN_REPLICAS_TEST: "2" + MAX_REPLICAS_TEST: "2" + MIN_CPU: "15m" + MAX_CPU: "150m" + MIN_MEM: "650Mi" + MAX_MEM: "750Mi" + +on: + workflow_dispatch: + +jobs: + + deploy-test: + name: Deploy to OpenShift TEST + runs-on: ubuntu-20.04 + environment: test + + outputs: + ROUTE: ${{ steps.deploy-and-expose.outputs.route }} + SELECTOR: ${{ steps.deploy-and-expose.outputs.selector }} + + steps: + - name: Check for required secrets + uses: actions/github-script@v6 + with: + script: | + const secrets = { + OPENSHIFT_SERVER: `${{ secrets.OPENSHIFT_SERVER }}`, + OPENSHIFT_TOKEN: `${{ secrets.OPENSHIFT_TOKEN }}`, + }; + + const GHCR = "ghcr.io"; + if (`${{ env.IMAGE_REGISTRY }}`.startsWith(GHCR)) { + core.info(`Image registry is ${GHCR} - no registry password required`); + } + else { + core.info("A registry password is required"); + secrets["IMAGE_REGISTRY_PASSWORD"] = `${{ secrets.IMAGE_REGISTRY_PASSWORD }}`; + } + + const missingSecrets = Object.entries(secrets).filter(([ name, value ]) => { + if (value.length === 0) { + core.error(`Secret "${name}" is not set`); + return true; + } + core.info(`✔️ Secret "${name}" is set`); + return false; + }); + + if (missingSecrets.length > 0) { + core.setFailed(`❌ At least one required secret is not set in the repository. \n` + + "You can add it using:\n" + + "GitHub UI: https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository \n" + + "GitHub CLI: https://cli.github.com/manual/gh_secret_set \n" + + "Also, refer to https://github.com/redhat-actions/oc-login#getting-started-with-the-action-or-see-example"); + } + else { + core.info(`✅ All the required secrets are set`); + } + + - name: Check out repository + uses: actions/checkout@v3 + + - name: Install oc + uses: redhat-actions/openshift-tools-installer@v1 + with: + oc: 4 + + - name: Deploy API + run: | + set -eu + # Login to OpenShift and select project + oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }} + oc project ${{ env.OPENSHIFT_NAMESPACE_TEST }} + # Cancel any rollouts in progress + oc rollout cancel dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "No rollout in progress" + + oc tag ${{ env.NAMESPACE }}-dev/${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ env.TAG }} ${{ env.NAMESPACE }}-test/${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ env.TAG }} + + # Process and apply deployment template + oc process -f tools/openshift/api.dc.yaml -p APP_NAME=${{ env.APP_NAME }} -p REPO_NAME=${{ env.REPO_NAME }} -p BRANCH=${{ env.BRANCH }} -p NAMESPACE=${{ env.OPENSHIFT_NAMESPACE_TEST }} -p TAG=${{ env.TAG }} -p MIN_REPLICAS=${{ env.MIN_REPLICAS_TEST }} -p MAX_REPLICAS=${{ env.MAX_REPLICAS_TEST }} -p MIN_CPU=${{ env.MIN_CPU }} -p MAX_CPU=${{ env.MAX_CPU }} -p MIN_MEM=${{ env.MIN_MEM }} -p MAX_MEM=${{ env.MAX_MEM }} \ + | oc apply -f - + + curl -s https://raw.githubusercontent.com/bcgov/${{ env.REPO_NAME }}/master/tools/config/update-configmap.sh | bash /dev/stdin test ${{ env.APP_NAME }} ${{ env.NAMESPACE }} ${{ env.COMMON_NAMESPACE }} ${{ env.DB_JDBC_CONNECT_STRING }} ${{ env.DB_PWD }} ${{ env.DB_USER }} ${{ env.SPLUNK_TOKEN }} + + # Start rollout (if necessary) and follow it + oc rollout latest dc/${{ env.SPRING_BOOT_IMAGE_NAME }} 2> /dev/null \ + || true && echo "Rollout in progress" + oc logs -f dc/${{ env.SPRING_BOOT_IMAGE_NAME }} + # Get status, returns 0 if rollout is successful + oc rollout status dc/${{ env.SPRING_BOOT_IMAGE_NAME }} + + - name: ZAP Scan + uses: zaproxy/action-api-scan@v0.1.1 + with: + target: 'https://${{ env.APP_NAME }}-${{ env.OPENSHIFT_NAMESPACE_TEST }}.apps.silver.devops.gov.bc.ca/v3/api-docs' \ No newline at end of file diff --git a/.github/workflows/tag-create.git.and.imagestream.tag.yml b/.github/workflows/tag-create.git.and.imagestream.tag.yml new file mode 100644 index 0000000..f79600a --- /dev/null +++ b/.github/workflows/tag-create.git.and.imagestream.tag.yml @@ -0,0 +1,63 @@ +name: Create Tag + +env: + # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context. + # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values. + # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions + OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} + OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }} + OPENSHIFT_NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }}-dev + + REPO_NAME: "educ-student-profile-api" + BRANCH: "master" + NAMESPACE: ${{ secrets.COMMON_NAMESPACE_NO_ENV }} + +on: + # https://docs.github.com/en/actions/reference/events-that-trigger-workflows + workflow_dispatch: + inputs: + version: + description: 'Version Number' + required: true + +jobs: + openshift-ci-cd: + name: Tag Image + # ubuntu-latest can also be used. + runs-on: ubuntu-22.04 + environment: dev + + outputs: + ROUTE: ${{ steps.deploy-and-expose.outputs.route }} + SELECTOR: ${{ steps.deploy-and-expose.outputs.selector }} + + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Create tag + uses: actions/github-script@v6 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ github.event.inputs.version }}', + sha: context.sha + }) + + - name: Install oc + uses: redhat-actions/openshift-tools-installer@v1 + with: + oc: 4 + + # https://github.com/redhat-actions/oc-login#readme + - uses: actions/checkout@v3 + - name: Tag in OpenShift + run: | + set -eux + # Login to OpenShift and select project + oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }} + oc project ${{ env.OPENSHIFT_NAMESPACE }} + + oc tag ${{ env.NAMESPACE }}-dev/${{ env.REPO_NAME }}-${{ env.BRANCH }}:latest ${{ env.NAMESPACE }}-dev/${{ env.REPO_NAME }}-${{ env.BRANCH }}:${{ github.event.inputs.version }} diff --git a/Dockerfile b/Dockerfile index ec16e3d..bdff8d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM artifacts.developer.gov.bc.ca/docker-remote/maven:3-jdk-11 as build +FROM artifacts.developer.gov.bc.ca/docker-remote/maven:3.8.5-openjdk-17 as build WORKDIR /workspace/app COPY api/pom.xml . @@ -6,7 +6,7 @@ COPY api/src src RUN mvn package -DskipTests RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) -FROM artifacts.developer.gov.bc.ca/docker-remote/openjdk:11-jdk +FROM artifacts.developer.gov.bc.ca/docker-remote/openjdk:17.0.2-jdk-oracle RUN useradd -ms /bin/bash spring RUN mkdir -p /logs RUN chown -R spring:spring /logs diff --git a/api/pom.xml b/api/pom.xml index a21c145..99f22df 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 ca.bc.gov.educ.api.student.profile @@ -24,15 +24,15 @@ src/main/java/ca/bc/gov/educ/api/student/profile/props/**, src/main/java/ca/bc/gov/educ/api/student/profile/helpers/LogHelper.java, - 11 + 17 - 3.8.0 + 3.10.1 ${java.version} ${java.version} - 1.4.1.Final - 4.15.1 - 1.4.8 - 1.18.12 + 1.5.3.Final + 4.20.0 + 1.6.8 + 1.18.24 2.11.0 21.3.0.0 30.1.1-jre @@ -42,7 +42,7 @@ org.springframework.boot spring-boot-starter-parent - 2.4.3 + 3.0.2 @@ -93,8 +93,8 @@ commons-lang3 - javax.persistence - javax.persistence-api + jakarta.persistence + jakarta.persistence-api org.springframework.boot @@ -114,13 +114,8 @@ org.springdoc - springdoc-openapi-webmvc-core - ${springdoc.version} - - - org.springdoc - springdoc-openapi-ui - ${springdoc.version} + springdoc-openapi-starter-webmvc-ui + 2.0.4 org.mapstruct @@ -214,7 +209,7 @@ org.jacoco jacoco-maven-plugin - 0.8.4 + 0.8.8 org.hibernate.orm.tooling @@ -265,16 +260,16 @@ ${java.version} ${java.version} - - org.mapstruct - mapstruct-processor - ${org.mapstruct.version} - org.projectlombok lombok ${lombok.version} + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + org.springframework spring-context-indexer diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/StudentProfileApiResourceApplication.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/StudentProfileApiResourceApplication.java index e1280b1..4d03724 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/StudentProfileApiResourceApplication.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/StudentProfileApiResourceApplication.java @@ -12,16 +12,16 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.retry.annotation.EnableRetry; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.transaction.PlatformTransactionManager; @SpringBootApplication -@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableCaching @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "1s") @@ -36,8 +36,9 @@ public static void main(String[] args) { * Add security exceptions for swagger UI and prometheus. */ @Configuration + @EnableMethodSecurity static - class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + class WebSecurityConfiguration { /** * Instantiates a new Web security configuration. @@ -45,20 +46,21 @@ class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { */ public WebSecurityConfiguration() { super(); - SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); } - @Override - public void configure(WebSecurity web) { - web.ignoring().antMatchers("/v3/api-docs/**", - "/actuator/health","/actuator/prometheus", - "/swagger-ui/**"); - } - @Override - protected void configure(final HttpSecurity http) throws Exception { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeRequests() - .anyRequest().authenticated().and() - .oauth2ResourceServer().jwt(); + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/v3/api-docs/**", + "/actuator/health", "/actuator/prometheus","/actuator/**", + "/swagger-ui/**").permitAll() + .anyRequest().authenticated() + ) + .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); + return http.build(); } } @Bean diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/adapter/CustomRequestBodyAdviceAdapter.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/adapter/CustomRequestBodyAdviceAdapter.java index 0152808..a6180dd 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/adapter/CustomRequestBodyAdviceAdapter.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/adapter/CustomRequestBodyAdviceAdapter.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.lang.reflect.Type; @ControllerAdvice diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/config/RequestResponseInterceptor.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/config/RequestResponseInterceptor.java index 9096d0b..b575287 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/config/RequestResponseInterceptor.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/config/RequestResponseInterceptor.java @@ -8,8 +8,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.servlet.AsyncHandlerInterceptor; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.time.Instant; @Component diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/controller/BaseController.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/controller/BaseController.java index e37f1fe..a9f1e7d 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/controller/BaseController.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/controller/BaseController.java @@ -4,7 +4,7 @@ import ca.bc.gov.educ.api.student.profile.struct.BaseRequest; import org.apache.commons.lang3.StringUtils; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; public abstract class BaseController { diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/RestExceptionHandler.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/RestExceptionHandler.java index 2466b69..6143e7d 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/RestExceptionHandler.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/RestExceptionHandler.java @@ -5,7 +5,7 @@ import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -26,7 +26,7 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler { private static Logger log = Logger.getLogger(RestExceptionHandler.class); @Override - protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { + protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { log.warn("handleHttpMessageNotReadable: ", ex); String error = "Malformed JSON request"; log.error("{} ", error, ex); @@ -38,7 +38,7 @@ private ResponseEntity buildResponseEntity(ApiError apiError) { } /** - * Handles EntityNotFoundException. Created to encapsulate errors with more detail than javax.persistence.EntityNotFoundException. + * Handles EntityNotFoundException. Created to encapsulate errors with more detail than jakarta.persistence.EntityNotFoundException. * * @param ex the EntityNotFoundException * @return the ApiError object @@ -86,7 +86,7 @@ protected ResponseEntity handleInvalidParameter(RuntimeException ex) { * * @param ex the MethodArgumentNotValidException that is thrown when @Valid validation fails * @param headers HttpHeaders - * @param status HttpStatus + * @param status HttpStatusCode * @param request WebRequest * @return the ApiError object */ @@ -94,7 +94,7 @@ protected ResponseEntity handleInvalidParameter(RuntimeException ex) { protected ResponseEntity handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, - HttpStatus status, + HttpStatusCode status, WebRequest request) { log.warn("handleMethodArgumentNotValid", ex); ApiError apiError = new ApiError(BAD_REQUEST); diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/errors/ApiError.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/errors/ApiError.java index 895ba50..162806e 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/errors/ApiError.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/exception/errors/ApiError.java @@ -10,7 +10,7 @@ import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; -import javax.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolation; import java.io.Serializable; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/Converters.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/Converters.java index 818b805..7b1a8f4 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/Converters.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/Converters.java @@ -2,7 +2,7 @@ import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.chrono.ChronoLocalDate; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterCriteria.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterCriteria.java index 0360c0f..f22ec68 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterCriteria.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterCriteria.java @@ -2,12 +2,11 @@ import org.apache.commons.lang3.StringUtils; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.function.Function; -import java.util.stream.Collectors; /** * Filter Criteria Holder @@ -101,7 +100,7 @@ private void validateAndAssign(String[] operationValues) { //For 'in' or 'nin' operation } else if (FilterOperation.IN == operation || FilterOperation.NOT_IN == operation) { - convertedValues.addAll(originalValues.stream().map(converterFunction).collect(Collectors.toList())); + convertedValues.addAll(originalValues.stream().map(converterFunction).toList()); } else { //All other operation this.convertedSingleValue = converterFunction.apply(operationValues[0]); diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterSpecifications.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterSpecifications.java index 9b19286..fa532fa 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterSpecifications.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/filter/FilterSpecifications.java @@ -3,7 +3,7 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.EnumMap; import java.util.function.Function; @Service diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/helpers/LogHelper.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/helpers/LogHelper.java index b1ae2ff..69a7b60 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/helpers/LogHelper.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/helpers/LogHelper.java @@ -8,8 +8,8 @@ import org.slf4j.MDC; import org.springframework.lang.NonNull; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.time.Instant; import java.util.HashMap; import java.util.Map; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/messaging/MessageSubscriber.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/messaging/MessageSubscriber.java index 08c24b2..e046494 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/messaging/MessageSubscriber.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/messaging/MessageSubscriber.java @@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import static ca.bc.gov.educ.api.student.profile.constants.Topics.STUDENT_PROFILE_API_TOPIC; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentEntity.java index b8dd639..0d131bd 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentEntity.java @@ -6,8 +6,8 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import javax.persistence.*; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; import java.util.UUID; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentTypeCodeEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentTypeCodeEntity.java index b7ec8b5..022cdfc 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentTypeCodeEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/DocumentTypeCodeEntity.java @@ -3,11 +3,11 @@ import lombok.Getter; import lombok.Setter; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; @Getter diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/GenderCodeEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/GenderCodeEntity.java index 03d808f..b31abf1 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/GenderCodeEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/GenderCodeEntity.java @@ -5,12 +5,12 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; @Data diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileCommentsEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileCommentsEntity.java index bae0911..31556b8 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileCommentsEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileCommentsEntity.java @@ -5,8 +5,8 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import javax.persistence.*; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; import java.util.UUID; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileEntity.java index ade5557..5fe942f 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileEntity.java @@ -7,9 +7,9 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Set; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroEntity.java index 10dc55b..6d9f1bc 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroEntity.java @@ -3,8 +3,8 @@ import lombok.Data; import org.hibernate.annotations.GenericGenerator; -import javax.persistence.*; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; import java.util.UUID; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroTypeCodeEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroTypeCodeEntity.java index 1f622cb..46589a7 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroTypeCodeEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileMacroTypeCodeEntity.java @@ -5,12 +5,12 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileRequestEvent.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileRequestEvent.java index 4d9f992..88513ac 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileRequestEvent.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileRequestEvent.java @@ -8,8 +8,8 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import javax.persistence.*; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.PastOrPresent; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.UUID; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileStatusCodeEntity.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileStatusCodeEntity.java index 060353f..57987b1 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileStatusCodeEntity.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/model/v1/StudentProfileStatusCodeEntity.java @@ -3,9 +3,9 @@ import lombok.Getter; import lombok.Setter; -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PastOrPresent; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; import java.time.LocalDateTime; @Getter @@ -15,7 +15,6 @@ public class StudentProfileStatusCodeEntity { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "student_profile_request_status_code", unique = true, updatable = false) String studentRequestStatusCode; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/repository/v1/impl/StudentProfileRepositoryCustomImpl.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/repository/v1/impl/StudentProfileRepositoryCustomImpl.java index 81aaf00..cf9febf 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/repository/v1/impl/StudentProfileRepositoryCustomImpl.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/repository/v1/impl/StudentProfileRepositoryCustomImpl.java @@ -8,11 +8,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; +import jakarta.persistence.EntityManager; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.ArrayList; import java.util.List; import java.util.UUID; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/schedulers/PurgeOldRecordsScheduler.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/schedulers/PurgeOldRecordsScheduler.java index 939e7a5..c273c37 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/schedulers/PurgeOldRecordsScheduler.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/schedulers/PurgeOldRecordsScheduler.java @@ -10,7 +10,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import java.time.LocalDateTime; import static lombok.AccessLevel.PRIVATE; diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/BaseRequest.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/BaseRequest.java index c985c74..dd2a3aa 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/BaseRequest.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/BaseRequest.java @@ -2,8 +2,8 @@ import lombok.Data; -import javax.validation.constraints.Null; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Size; @Data public abstract class BaseRequest { diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/SearchCriteria.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/SearchCriteria.java index 2b51e30..3a55719 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/SearchCriteria.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/SearchCriteria.java @@ -6,7 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; @AllArgsConstructor @NoArgsConstructor diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfile.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfile.java index 028def3..e879009 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfile.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfile.java @@ -4,9 +4,9 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import java.io.Serializable; @EqualsAndHashCode(callSuper = true) diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileComments.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileComments.java index cc17b3d..e91d876 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileComments.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileComments.java @@ -3,8 +3,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.io.Serializable; @EqualsAndHashCode(callSuper = true) diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocMetadata.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocMetadata.java index e2e57c8..258880f 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocMetadata.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocMetadata.java @@ -5,8 +5,8 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Null; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; import java.io.Serializable; @Data diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocument.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocument.java index 5af5a62..2b7a956 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocument.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileDocument.java @@ -4,8 +4,8 @@ import lombok.EqualsAndHashCode; import lombok.ToString; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.io.Serializable; @EqualsAndHashCode(callSuper = true) diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileMacro.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileMacro.java index 3d2db3d..89dfd3c 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileMacro.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileMacro.java @@ -4,8 +4,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; @Data @EqualsAndHashCode(callSuper = true) diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileStatusCode.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileStatusCode.java index ff4a61a..63b69ad 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileStatusCode.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/struct/StudentProfileStatusCode.java @@ -5,7 +5,7 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import java.io.Serializable; @Data diff --git a/api/src/main/java/ca/bc/gov/educ/api/student/profile/validator/StudentProfileDocumentsValidator.java b/api/src/main/java/ca/bc/gov/educ/api/student/profile/validator/StudentProfileDocumentsValidator.java index 449ce55..dadf796 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/student/profile/validator/StudentProfileDocumentsValidator.java +++ b/api/src/main/java/ca/bc/gov/educ/api/student/profile/validator/StudentProfileDocumentsValidator.java @@ -10,7 +10,7 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.time.LocalDateTime; import java.util.List; diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index 1d25a90..f219f14 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -9,7 +9,7 @@ spring.mvc.log-request-details=${SPRING_SHOW_REQUEST_DETAILS} spring.datasource.url=${JDBC_URL} spring.datasource.username=${ORACLE_USERNAME} spring.datasource.password=${ORACLE_PASSWORD} -spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect spring.jpa.hibernate.ddl-auto=none #So that unexpected request body parameters cause error @@ -17,7 +17,7 @@ spring.jackson.deserialization.fail-on-unknown-properties=true management.endpoint.metrics.enabled=true management.endpoints.web.exposure.include=* management.endpoint.prometheus.enabled=true -management.metrics.export.prometheus.enabled=true +management.prometheus.metrics.export.enabled=true spring.jpa.properties.hibernate.generate_statistics=${HIBERNATE_STATISTICS} #File Upload Requirement properties diff --git a/api/src/test/java/ca/bc/gov/educ/api/student/profile/controller/RequestControllerTest.java b/api/src/test/java/ca/bc/gov/educ/api/student/profile/controller/RequestControllerTest.java index 9d49ce9..c93de9a 100644 --- a/api/src/test/java/ca/bc/gov/educ/api/student/profile/controller/RequestControllerTest.java +++ b/api/src/test/java/ca/bc/gov/educ/api/student/profile/controller/RequestControllerTest.java @@ -108,6 +108,13 @@ public void testRetrieveRequest_GivenRandomID_ShouldThrowEntityNotFoundException .andDo(print()).andExpect(status().isNotFound()); } + @Test + public void testRetrieveRequest_WithoutScope_ShouldReturnStatusForbidden() throws Exception { + this.mockMvc.perform(get(URL.BASE_URL + URL.STUDENT_PROFILE_REQUEST_ID, UUID.randomUUID()) + .with(jwt().jwt((jwt) -> jwt.claim("scope", "WRONG_SCOPE")))) + .andDo(print()).andExpect(status().isForbidden()); + } + @Test public void testRetrieveRequest_GivenValidID_ShouldReturnOkStatus() throws Exception { StudentProfileEntity entity = repository.save(mapper.toModel(getStudentProfileEntityFromJsonString())); @@ -116,13 +123,6 @@ public void testRetrieveRequest_GivenValidID_ShouldReturnOkStatus() throws Excep .andDo(print()).andExpect(status().isOk()).andExpect(MockMvcResultMatchers.jsonPath("$.studentRequestID").value(entity.getStudentRequestID().toString())); } -// @Test -// @WithMockOAuth2Scope(scope = "READ_PEN_REQUEST") -// public void testFindRequest_GivenOnlyPenInQueryParam_ShouldReturnOkStatusAndEntities() throws Exception { -// StudentProfileEntity entity = repository.save(mapper.toModel(getStudentProfileEntityFromJsonString())); -// this.mockMvc.perform(get("?pen" + entity.getPen())).andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(1))).andExpect(MockMvcResultMatchers.jsonPath("$[0].pen").value(entity.getPen())); -// } - @Test public void testRetrieveRequest_GivenRandomDigitalIdAndStatusCode_ShouldReturnOkStatus() throws Exception { this.mockMvc.perform(get(URL.BASE_URL).queryParam("digitalID", String.valueOf(UUID.randomUUID())) @@ -207,13 +207,6 @@ public void testReadRequestStatus_Always_ShouldReturnStatusOkAndAllDataFromDB() .andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(1))); } - -// @Test -// public void testHealth_GivenServerIsRunning_ShouldReturnOK() throws Exception { -// this.mockMvc.perform(get("/health")).andDo(print()).andExpect(status().isOk()) -// .andExpect(content().string(containsString("OK"))); -// } - @Test public void testDeleteRequest_GivenInvalidId_ShouldReturn404() throws Exception { this.mockMvc.perform(delete(URL.BASE_URL + URL.STUDENT_PROFILE_REQUEST_ID, UUID.randomUUID().toString()) diff --git a/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/ReqDocumentJpaTests.java b/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/ReqDocumentJpaTests.java index 20d6aa6..d8178b5 100644 --- a/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/ReqDocumentJpaTests.java +++ b/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/ReqDocumentJpaTests.java @@ -1,16 +1,19 @@ package ca.bc.gov.educ.api.student.profile.model; +import ca.bc.gov.educ.api.student.profile.StudentProfileApiResourceApplication; import ca.bc.gov.educ.api.student.profile.model.v1.DocumentEntity; import ca.bc.gov.educ.api.student.profile.model.v1.StudentProfileEntity; import ca.bc.gov.educ.api.student.profile.repository.v1.DocumentRepository; +import ca.bc.gov.educ.api.student.profile.repository.v1.StudentProfileRepository; import ca.bc.gov.educ.api.student.profile.support.DocumentBuilder; import ca.bc.gov.educ.api.student.profile.support.RequestBuilder; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import java.util.Optional; @@ -18,14 +21,15 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@DataJpaTest +@SpringBootTest(classes = {StudentProfileApiResourceApplication.class}) +@ActiveProfiles("test") public class ReqDocumentJpaTests { @Autowired - private TestEntityManager entityManager; + private DocumentRepository repository; @Autowired - private DocumentRepository repository; + private StudentProfileRepository studentProfileRepository; private DocumentEntity document; @@ -33,17 +37,19 @@ public class ReqDocumentJpaTests { @Before public void setUp() { - this.request = new RequestBuilder() - .withoutRequestID().build(); + this.request = studentProfileRepository.save(new RequestBuilder().withoutRequestID().build()); + this.document = new DocumentBuilder() .withoutDocumentID() .withRequest(this.request).build(); - this.entityManager.persist(this.request); - this.entityManager.persist(this.document); - this.entityManager.flush(); - //document = this.repository.save(document); - this.entityManager.clear(); + document = this.repository.save(document); + } + + @After + public void after() { + this.repository.deleteAll(); + this.studentProfileRepository.deleteAll(); } @Test diff --git a/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/RequestJpaTests.java b/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/RequestJpaTests.java index 6fd49be..de06ff4 100644 --- a/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/RequestJpaTests.java +++ b/api/src/test/java/ca/bc/gov/educ/api/student/profile/model/RequestJpaTests.java @@ -1,5 +1,6 @@ package ca.bc.gov.educ.api.student.profile.model; +import ca.bc.gov.educ.api.student.profile.StudentProfileApiResourceApplication; import ca.bc.gov.educ.api.student.profile.model.v1.StudentProfileEntity; import ca.bc.gov.educ.api.student.profile.repository.v1.StudentProfileRepository; import ca.bc.gov.educ.api.student.profile.support.RequestBuilder; @@ -7,13 +8,15 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@DataJpaTest +@SpringBootTest(classes = {StudentProfileApiResourceApplication.class}) +@ActiveProfiles("test") public class RequestJpaTests { @Autowired private StudentProfileRepository repository; diff --git a/tools/jenkins/update-configmap.sh b/tools/config/update-configmap.sh similarity index 92% rename from tools/jenkins/update-configmap.sh rename to tools/config/update-configmap.sh index a6bf994..4c8162d 100644 --- a/tools/jenkins/update-configmap.sh +++ b/tools/config/update-configmap.sh @@ -1,18 +1,18 @@ envValue=$1 APP_NAME=$2 OPENSHIFT_NAMESPACE=$3 -APP_NAME_UPPER=${APP_NAME^^} +DB_JDBC_CONNECT_STRING=$5 +DB_PWD=$6 +DB_USER=$7 +SPLUNK_TOKEN=$8 TZVALUE="America/Vancouver" SOAM_KC_REALM_ID="master" +SOAM_KC=soam-$envValue.apps.silver.devops.gov.bc.ca SOAM_KC_LOAD_USER_ADMIN=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get secret sso-admin-"${envValue}" | sed -n 's/.*"username": "\(.*\)"/\1/p' | base64 --decode) SOAM_KC_LOAD_USER_PASS=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get secret sso-admin-"${envValue}" | sed -n 's/.*"password": "\(.*\)",/\1/p' | base64 --decode) -DB_JDBC_CONNECT_STRING=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get configmaps "${APP_NAME}"-"${envValue}"-setup-config | sed -n 's/.*"DB_JDBC_CONNECT_STRING": "\(.*\)",/\1/p') -DB_PWD=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get configmaps "${APP_NAME}"-"${envValue}"-setup-config | sed -n "s/.*\"DB_PWD_${APP_NAME_UPPER}\": \"\(.*\)\",/\1/p") -DB_USER=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get configmaps "${APP_NAME}"-"${envValue}"-setup-config | sed -n "s/.*\"DB_USER_${APP_NAME_UPPER}\": \"\(.*\)\",/\1/p") -SPLUNK_TOKEN=$(oc -n "$OPENSHIFT_NAMESPACE"-"$envValue" -o json get configmaps "${APP_NAME}"-"${envValue}"-setup-config | sed -n "s/.*\"SPLUNK_TOKEN_${APP_NAME_UPPER}\": \"\(.*\)\"/\1/p") -SOAM_KC=soam-$envValue.apps.silver.devops.gov.bc.ca + NATS_CLUSTER=educ_nats_cluster NATS_URL="nats://nats.${OPENSHIFT_NAMESPACE}-${envValue}.svc.cluster.local:4222" diff --git a/tools/jenkins/Jenkinsfile b/tools/jenkins/Jenkinsfile deleted file mode 100644 index 486e68f..0000000 --- a/tools/jenkins/Jenkinsfile +++ /dev/null @@ -1,107 +0,0 @@ -pipeline{ - agent any - environment{ - extJSHelper = ''; - DEBUG_OUTPUT = 'false' - - NAMESPACE='mvubjx' - TOOLS = "${NAMESPACE}-tools" - DEV = "${NAMESPACE}-dev" - - APP_NAME = 'student-profile-api' - REPO_NAME = "educ-${APP_NAME}" - OWNER = 'bcgov' - JOB_NAME = 'master' - TAG = 'latest' - TARGET_ENV = 'dev' - STAGING_ENV = 'Dev' - TARGET_ENVIRONMENT = "${NAMESPACE}-${TARGET_ENV}" - - APP_DOMAIN = 'pathfinder.gov.bc.ca' - SOURCE_REPO_REF = 'master' - SOURCE_REPO_URL = 'https://github.com/${OWNER}/${REPO_NAME}.git' - DC_URL = "https://raw.githubusercontent.com/${OWNER}/${REPO_NAME}/master/tools/openshift/api.dc.yaml" - MIN_REPLICAS = "1" - MAX_REPLICAS = "1" - MIN_CPU = "50m" - MAX_CPU = "150m" - MIN_MEM = "400Mi" - MAX_MEM = "750Mi" - } - stages{ - stage('Initialize') { - steps { - script { - if(DEBUG_OUTPUT.equalsIgnoreCase('true')) { - // Force OpenShift Plugin directives to be verbose - openshift.logLevel(1) - - // Print all environment variables - echo 'DEBUG - All pipeline environment variables:' - echo sh(returnStdout: true, script: 'env') - } - - sh "wget -O - https://raw.githubusercontent.com/bcgov/EDUC-INFRA-COMMON/master/openshift/common-deployment/deployHelpers.js > deployHelpers.js" - extJSHelper = evaluate readFile('deployHelpers.js') - } - } - } - stage('Build App') { - steps { - script { - openshift.withCluster() { - openshift.withProject(TOOLS) { - try { - echo "Building API..." - def bcBackend = openshift.process('-f', 'tools/openshift/api.bc.yaml', "REPO_NAME=${REPO_NAME}-${JOB_NAME}", "JOB_NAME=${JOB_NAME}", "SOURCE_REPO_URL=${SOURCE_REPO_URL}", "SOURCE_REPO_REF=${SOURCE_REPO_REF}") - openshift.apply(bcBackend).narrow('bc').startBuild('-w').logs('-f') - - openshift.tag("${REPO_NAME}-${JOB_NAME}:latest", "${REPO_NAME}-${JOB_NAME}:${JOB_NAME}") - } catch (e) { - echo "API build failed" - throw e - } - } - } - } - } - post { - success { - echo 'Cleanup BuildConfigs' - script { - openshift.withCluster() { - openshift.withProject(TOOLS) { - def bcApi = openshift.selector('bc', "${REPO_NAME}-${JOB_NAME}") - - if(bcApi.exists()) { - echo "Removing BuildConfig ${REPO_NAME}-${JOB_NAME}" - bcApi.delete() - } - } - } - } - } - failure { - echo 'Build stage failed' - } - } - } - stage('Promote and configure DEV') { - steps{ - script{ - extJSHelper.performApiDeploy(STAGING_ENV, TARGET_ENVIRONMENT, REPO_NAME, APP_NAME, JOB_NAME, TAG, TOOLS, TARGET_ENVIRONMENT, APP_DOMAIN, DC_URL, MIN_REPLICAS, MAX_REPLICAS, MIN_CPU, MAX_CPU, MIN_MEM, MAX_MEM, TARGET_ENV, NAMESPACE) - } - } - post{ - success{ - echo 'Deployment to Dev was successful' - } - failure{ - echo 'Deployment to Dev failed' - } - } - } - } -} - - diff --git a/tools/jenkins/Jenkinsfile-ocp4 b/tools/jenkins/Jenkinsfile-ocp4 deleted file mode 100644 index 311df6a..0000000 --- a/tools/jenkins/Jenkinsfile-ocp4 +++ /dev/null @@ -1,107 +0,0 @@ -pipeline{ - agent any - environment{ - extJSHelper = ''; - DEBUG_OUTPUT = 'false' - - NAMESPACE='75e61b' - TOOLS = "${NAMESPACE}-tools" - DEV = "${NAMESPACE}-dev" - - APP_NAME = 'student-profile-api' - REPO_NAME = "educ-${APP_NAME}" - OWNER = 'bcgov' - JOB_NAME = 'master' - TAG = 'latest' - TARGET_ENV = 'dev' - STAGING_ENV = 'Dev' - TARGET_ENVIRONMENT = "${NAMESPACE}-${TARGET_ENV}" - - APP_DOMAIN = 'apps.silver.devops.gov.bc.ca' - SOURCE_REPO_REF = 'master' - SOURCE_REPO_URL = 'https://github.com/${OWNER}/${REPO_NAME}.git' - DC_URL = "https://raw.githubusercontent.com/${OWNER}/${REPO_NAME}/master/tools/openshift/api.dc.ocp4.yaml" - MIN_REPLICAS = "1" - MAX_REPLICAS = "1" - MIN_CPU = "20m" - MAX_CPU = "300m" - MIN_MEM = "650Mi" - MAX_MEM = "750Mi" - } - stages{ - stage('Initialize') { - steps { - script { - if(DEBUG_OUTPUT.equalsIgnoreCase('true')) { - // Force OpenShift Plugin directives to be verbose - openshift.logLevel(1) - - // Print all environment variables - echo 'DEBUG - All pipeline environment variables:' - echo sh(returnStdout: true, script: 'env') - } - - sh "wget -O - https://raw.githubusercontent.com/bcgov/EDUC-INFRA-COMMON/master/openshift/common-deployment/deployHelpers.js > deployHelpers.js" - extJSHelper = evaluate readFile('deployHelpers.js') - } - } - } - stage('Build App') { - steps { - script { - openshift.withCluster() { - openshift.withProject(TOOLS) { - try { - echo "Building API..." - def bcBackend = openshift.process('-f', 'https://raw.githubusercontent.com/${OWNER}/${REPO_NAME}/master/tools/openshift/api.bc.yaml', "REPO_NAME=${REPO_NAME}-${JOB_NAME}", "JOB_NAME=${JOB_NAME}", "SOURCE_REPO_URL=${SOURCE_REPO_URL}", "SOURCE_REPO_REF=${SOURCE_REPO_REF}") - openshift.apply(bcBackend).narrow('bc').startBuild('-w').logs('-f') - - openshift.tag("${REPO_NAME}-${JOB_NAME}:latest", "${REPO_NAME}-${JOB_NAME}:${JOB_NAME}") - } catch (e) { - echo "API build failed" - throw e - } - } - } - } - } - post { - success { - echo 'Cleanup BuildConfigs' - script { - openshift.withCluster() { - openshift.withProject(TOOLS) { - def bcApi = openshift.selector('bc', "${REPO_NAME}-${JOB_NAME}") - - if(bcApi.exists()) { - echo "Removing BuildConfig ${REPO_NAME}-${JOB_NAME}" - bcApi.delete() - } - } - } - } - } - failure { - echo 'Build stage failed' - } - } - } - stage('Promote and configure DEV') { - steps{ - script{ - extJSHelper.performApiDeploy(STAGING_ENV, TARGET_ENVIRONMENT, REPO_NAME, APP_NAME, JOB_NAME, TAG, TOOLS, TARGET_ENVIRONMENT, APP_DOMAIN, DC_URL, MIN_REPLICAS, MAX_REPLICAS, MIN_CPU, MAX_CPU, MIN_MEM, MAX_MEM, TARGET_ENV, NAMESPACE) - } - } - post{ - success{ - echo 'Deployment to Dev was successful' - } - failure{ - echo 'Deployment to Dev failed' - } - } - } - } -} - - diff --git a/tools/openshift/api.bc.yaml b/tools/openshift/api.bc.yaml deleted file mode 100644 index 0c15e2c..0000000 --- a/tools/openshift/api.bc.yaml +++ /dev/null @@ -1,73 +0,0 @@ ---- -apiVersion: template.openshift.io/v1 -kind: Template -labels: - template: '${REPO_NAME}-template' -metadata: - name: '${REPO_NAME}-bc' -objects: - - apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewBuild - creationTimestamp: - labels: - build: "${REPO_NAME}" - name: "${REPO_NAME}" - spec: - lookupPolicy: - local: false - - apiVersion: v1 - kind: BuildConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewBuild - creationTimestamp: - labels: - build: "${REPO_NAME}" - name: "${REPO_NAME}" - spec: - completionDeadlineSeconds: 1200 - successfulBuildsHistoryLimit: 3 - failedBuildsHistoryLimit: 3 - nodeSelector: - output: - to: - kind: ImageStreamTag - name: "${REPO_NAME}:latest" - postCommit: {} - resources: - requests: - cpu: 100m - memory: 2Gi - limits: - cpu: 1000m - memory: 4Gi - runPolicy: SerialLatestOnly - source: - git: - ref: "${SOURCE_REPO_REF}" - uri: "${SOURCE_REPO_URL}" - type: Git - strategy: - dockerStrategy: - pullSecret: - name: artifactory-creds - env: - - name: BUILD_LOGLEVEL - value: '2' - type: Docker -parameters: - - name: REPO_NAME - description: Application repository name - required: true - - name: JOB_NAME - description: Job identifier (i.e. 'pr-5' OR 'master') - required: true - - name: SOURCE_REPO_REF - description: Git Pull Request Reference (i.e. 'pull/CHANGE_ID/head') - required: true - - name: SOURCE_REPO_URL - description: Git Repository URL - required: true diff --git a/tools/openshift/api.dc.ocp4.yaml b/tools/openshift/api.dc.ocp4.yaml deleted file mode 100644 index 4394cba..0000000 --- a/tools/openshift/api.dc.ocp4.yaml +++ /dev/null @@ -1,200 +0,0 @@ ---- -apiVersion: template.openshift.io/v1 -kind: Template -labels: - template: "${REPO_NAME}-template" -metadata: - name: "${REPO_NAME}-${JOB_NAME}-dc" -objects: - - apiVersion: v1 - kind: DeploymentConfig - metadata: - labels: - app: "${APP_NAME}-${JOB_NAME}" - name: "${APP_NAME}-${JOB_NAME}" - spec: - replicas: ${{MIN_REPLICAS}} - selector: - app: "${APP_NAME}-${JOB_NAME}" - deploymentConfig: "${APP_NAME}-${JOB_NAME}" - strategy: - resources: {} - type: Rolling - template: - metadata: - annotations: - openshift.io/generated-by: studentprofileapi - prometheus.io/path: /actuator/prometheus - prometheus.io/port: '8080' - prometheus.io/scrape: 'true' - labels: - app: "${APP_NAME}-${JOB_NAME}" - deploymentConfig: "${APP_NAME}-${JOB_NAME}" - spec: - containers: - - image: image-registry.openshift-image-registry.svc:5000/${NAMESPACE}/${REPO_NAME}-${JOB_NAME}:${TAG} - imagePullPolicy: Always - volumeMounts: - - name: tls-certs - mountPath: "/etc/tls-certs" - readOnly: true - - name: log-storage - mountPath: /logs - readinessProbe: - tcpSocket: - port: 8080 - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 20 - successThreshold: 1 - livenessProbe: - httpGet: - path: /actuator/health - port: 8080 - initialDelaySeconds: 300 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - name: "${APP_NAME}-${JOB_NAME}" - ports: - - containerPort: ${{CONTAINER_PORT}} - protocol: TCP - resources: - requests: - cpu: "${MIN_CPU}" - memory: "${MIN_MEM}" - limits: - cpu: "${MAX_CPU}" - memory: "${MAX_MEM}" - - image: artifacts.developer.gov.bc.ca/docker-remote/fluent/fluent-bit:1.5.7 - name: "${APP_NAME}-${JOB_NAME}-fluent-bit-sidecar" - imagePullPolicy: Always - imagePullSecrets: - - name: artifactory-creds - volumeMounts: - - name: log-storage - mountPath: /mnt/log - - name: flb-sc-config-volume - mountPath: /fluent-bit/etc/ - readinessProbe: - tcpSocket: - port: 2020 - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - livenessProbe: - httpGet: - path: / - port: 2020 - initialDelaySeconds: 10 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - ports: - - containerPort: 2020 - protocol: TCP - name: metrics - resources: - requests: - cpu: "5m" - memory: "25Mi" - limits: - cpu: "10m" - memory: "50Mi" - volumes: - - name: tls-certs - secret: - secretName: student-profile-api-cert - - name: log-storage - emptyDir: {} - - name: flb-sc-config-volume - configMap: - name: "${APP_NAME}-flb-sc-config-map" - test: false - triggers: - - type: ConfigChange - - apiVersion: v1 - kind: Service - metadata: - annotations: - service.alpha.openshift.io/serving-cert-secret-name: "student-profile-api-cert" - labels: - app: "${APP_NAME}-${JOB_NAME}" - name: "${APP_NAME}-${JOB_NAME}" - spec: - ports: - - name: ${CONTAINER_PORT}-tcp - port: ${{CONTAINER_PORT}} - protocol: TCP - selector: - app: "${APP_NAME}-${JOB_NAME}" - deploymentconfig: "${APP_NAME}-${JOB_NAME}" - - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - metadata: - name: "${APP_NAME}-${JOB_NAME}-cpu-autoscaler" - spec: - scaleTargetRef: - apiVersion: apps.openshift.io/v1 - kind: DeploymentConfig - name: "${APP_NAME}-${JOB_NAME}" - subresource: scale - minReplicas: ${{MIN_REPLICAS}} - maxReplicas: ${{MAX_REPLICAS}} - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 200 -parameters: - - name: REPO_NAME - description: Application repository name - required: true - - name: JOB_NAME - description: Job identifier (i.e. 'backend' OR 'frontend') - required: true - - name: NAMESPACE - description: Target namespace reference (i.e. 'k8vopl-dev') - required: true - - name: APP_NAME - description: Application name - required: true - - name: HOST_ROUTE - description: The host the route will use to expose service outside cluster - required: true - - name: CONTAINER_PORT - description: The port on which the application will be accessible - value: "8080" - required: false - - name: TAG - description: The identifying tag for this specific deployment - required: true - - name: HOST_PATH - description: The path appended to the HOST_ROUTE where the root of this project will be served - value: "/" - required: false - - name: MIN_REPLICAS - description: The minimum amount of replicas - required: true - - name: MAX_REPLICAS - description: The maximum amount of replicas - required: true - - name: MIN_CPU - description: The minimum amount of cpu - required: true - - name: MAX_CPU - description: The maximum amount of cpu - required: true - - name: MIN_MEM - description: The minimum amount of memory - required: true - - name: MAX_MEM - description: The maximum amount of memory - required: true diff --git a/tools/openshift/api.dc.yaml b/tools/openshift/api.dc.yaml index 5ab20a6..6f5a2f5 100644 --- a/tools/openshift/api.dc.yaml +++ b/tools/openshift/api.dc.yaml @@ -4,19 +4,19 @@ kind: Template labels: template: "${REPO_NAME}-template" metadata: - name: "${REPO_NAME}-${JOB_NAME}-dc" + name: "${REPO_NAME}-${BRANCH}-dc" objects: - apiVersion: v1 kind: DeploymentConfig metadata: labels: - app: "${APP_NAME}-${JOB_NAME}" - name: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${BRANCH}" + name: "${APP_NAME}-${BRANCH}" spec: replicas: ${{MIN_REPLICAS}} selector: - app: "${APP_NAME}-${JOB_NAME}" - deploymentConfig: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${BRANCH}" + deploymentConfig: "${APP_NAME}-${BRANCH}" strategy: resources: {} type: Rolling @@ -28,11 +28,11 @@ objects: prometheus.io/port: '8080' prometheus.io/scrape: 'true' labels: - app: "${APP_NAME}-${JOB_NAME}" - deploymentConfig: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${BRANCH}" + deploymentConfig: "${APP_NAME}-${BRANCH}" spec: containers: - - image: docker-registry.default.svc:5000/${NAMESPACE}/${REPO_NAME}-${JOB_NAME}:${TAG} + - image: image-registry.openshift-image-registry.svc:5000/${NAMESPACE}/${REPO_NAME}-${BRANCH}:${TAG} imagePullPolicy: Always volumeMounts: - name: tls-certs @@ -57,7 +57,7 @@ objects: timeoutSeconds: 5 failureThreshold: 5 successThreshold: 1 - name: "${APP_NAME}-${JOB_NAME}" + name: "${APP_NAME}-${BRANCH}" ports: - containerPort: ${{CONTAINER_PORT}} protocol: TCP @@ -68,9 +68,11 @@ objects: limits: cpu: "${MAX_CPU}" memory: "${MAX_MEM}" - - image: fluent/fluent-bit - name: "${APP_NAME}-${JOB_NAME}-fluent-bit-sidecar" + - image: artifacts.developer.gov.bc.ca/docker-remote/fluent/fluent-bit:1.5.7 + name: "${APP_NAME}-${BRANCH}-fluent-bit-sidecar" imagePullPolicy: Always + imagePullSecrets: + - name: artifactory-creds volumeMounts: - name: log-storage mountPath: /mnt/log @@ -122,25 +124,25 @@ objects: annotations: service.alpha.openshift.io/serving-cert-secret-name: "student-profile-api-cert" labels: - app: "${APP_NAME}-${JOB_NAME}" - name: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${BRANCH}" + name: "${APP_NAME}-${BRANCH}" spec: ports: - name: ${CONTAINER_PORT}-tcp port: ${{CONTAINER_PORT}} protocol: TCP selector: - app: "${APP_NAME}-${JOB_NAME}" - deploymentconfig: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${BRANCH}" + deploymentconfig: "${APP_NAME}-${BRANCH}" - apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: - name: "${APP_NAME}-${JOB_NAME}-cpu-autoscaler" + name: "${APP_NAME}-${BRANCH}-cpu-autoscaler" spec: scaleTargetRef: apiVersion: apps.openshift.io/v1 kind: DeploymentConfig - name: "${APP_NAME}-${JOB_NAME}" + name: "${APP_NAME}-${BRANCH}" subresource: scale minReplicas: ${{MIN_REPLICAS}} maxReplicas: ${{MAX_REPLICAS}} @@ -155,7 +157,7 @@ parameters: - name: REPO_NAME description: Application repository name required: true - - name: JOB_NAME + - name: BRANCH description: Job identifier (i.e. 'backend' OR 'frontend') required: true - name: NAMESPACE @@ -166,7 +168,7 @@ parameters: required: true - name: HOST_ROUTE description: The host the route will use to expose service outside cluster - required: true + required: false - name: CONTAINER_PORT description: The port on which the application will be accessible value: "8080" diff --git a/tools/openshift/student-profile-api-pipeline.bc.yaml b/tools/openshift/student-profile-api-pipeline.bc.yaml deleted file mode 100644 index 1b48823..0000000 --- a/tools/openshift/student-profile-api-pipeline.bc.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: template.openshift.io/v1 -kind: Template -labels: - template: 'student-profile-api-template' -metadata: - name: 'student-profile-api-template' -objects: - - apiVersion: v1 - kind: BuildConfig - metadata: - labels: - build: student-profile-api-pipeline - name: student-profile-api-pipeline - spec: - source: - git: - ref: master - uri: 'https://github.com/bcgov/EDUC-STUDENT-PROFILE-API' - type: Git - strategy: - jenkinsPipelineStrategy: - jenkinsfilePath: tools/jenkins/Jenkinsfile