Merge pull request #1383 from bcgov/dev #3149
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Deploy | |
| on: | |
| push: | |
| branches: [feature/*, dev, test] | |
| env: | |
| REGISTRY: ghcr.io | |
| REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} | |
| REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Docker meta | |
| id: docker_meta | |
| uses: docker/metadata-action@v3 | |
| with: | |
| images: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal | |
| - name: Set DEPLOY_ID which will deploy a custom deploy to 'dev' environment | |
| run: | | |
| echo '::set-output name=DEPLOY_ID::${{ steps.docker_meta.outputs.version }}' | |
| echo '::set-output name=APP_VERSION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.version'] }}' | |
| echo '::set-output name=APP_REVISION::${{ fromJSON(steps.docker_meta.outputs.json).labels['org.opencontainers.image.revision'] }}' | |
| id: set-deploy-id | |
| - name: Get deploy ID | |
| run: echo "The DEPLOY_ID is ${{ steps.set-deploy-id.outputs.DEPLOY_ID }}" | |
| - uses: actions/checkout@v2 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| version: '4.6' | |
| - name: Authenticate to silver and set context | |
| uses: redhat-actions/oc-login@v1 | |
| with: | |
| openshift_server_url: ${{ secrets.OPENSHIFT_SERVER }} | |
| openshift_token: ${{ secrets.OPENSHIFT_TOKEN }} | |
| # Disables SSL cert checking. Use this if you don't have the certificate authority data. | |
| insecure_skip_tls_verify: true | |
| namespace: ${{ env.OPENSHIFT_NAMESPACE }} | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v1 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USERNAME }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - uses: actions/cache@v4 | |
| with: | |
| path: /tmp/.buildx-cache | |
| key: ${{ runner.os }}-buildx-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-buildx- | |
| - name: Set up Docker Buildx | |
| id: buildx | |
| uses: docker/setup-buildx-action@v1 | |
| - name: Build | |
| uses: docker/build-push-action@v2 | |
| with: | |
| cache-from: type=local,src=/tmp/.buildx-cache | |
| cache-to: type=local,dest=/tmp/.buildx-cache | |
| context: . | |
| file: Dockerfile | |
| tags: ${{ steps.docker_meta.outputs.tags }} | |
| load: true | |
| build-args: | | |
| GITHUB_API_TOKEN=${{ secrets.CONTAINER_REGISTRY_PASSWORD }} | |
| APP_VERSION=${{ steps.set-deploy-id.outputs.APP_VERSION }} | |
| APP_REVISION=${{ steps.set-deploy-id.outputs.APP_REVISION }} | |
| - name: Push | |
| run: docker push ${{ steps.docker_meta.outputs.tags }} | |
| - name: 'Get Helm' | |
| if: github.ref != 'refs/heads/dev' | |
| run: | | |
| curl -L -O https://get.helm.sh/helm-v3.4.2-linux-amd64.tar.gz | |
| tar -xf helm-v3.4.2-linux-amd64.tar.gz | |
| - name: 'Deploy Database' | |
| if: github.ref != 'refs/heads/dev' | |
| run: | | |
| export PATH=$PATH:`pwd`/linux-amd64 | |
| DEPLOY_ID="${{ steps.set-deploy-id.outputs.DEPLOY_ID }}" | |
| DB_NAME="proto-asp-${DEPLOY_ID}-db" | |
| # ConfigMap to create Keystone user and database on first Postgres start | |
| oc create configmap "${DB_NAME}-init" --from-literal=1-init.sql="CREATE ROLE keystonejsuser WITH LOGIN PASSWORD 'keystonejsuser'; CREATE DATABASE keystonejs OWNER keystonejsuser;" --dry-run=client -o yaml | oc apply -f - | |
| # ConfigMap with Keystone schema (run by Job after Postgres is up) | |
| oc create configmap "${DB_NAME}-keystone-schema" --from-file=keystone-init.sql=local/db/keystone-init.sql --dry-run=client -o yaml | oc apply -f - | |
| # PVC for Postgres data (persistence) | |
| cat <<EOF | oc apply -f - | |
| apiVersion: v1 | |
| kind: PersistentVolumeClaim | |
| metadata: | |
| name: ${DB_NAME}-data | |
| spec: | |
| accessModes: [ReadWriteOnce] | |
| resources: | |
| requests: | |
| storage: ${{ startsWith(github.ref_name, 'feature/') && '1Gi' || '2Gi' }} | |
| EOF | |
| # Postgres 15 Deployment (public image) | |
| cat <<EOF | oc apply -f - | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: ${DB_NAME} | |
| spec: | |
| replicas: 1 | |
| selector: | |
| matchLabels: | |
| app: ${DB_NAME} | |
| strategy: | |
| type: Recreate | |
| template: | |
| metadata: | |
| labels: | |
| app: ${DB_NAME} | |
| spec: | |
| containers: | |
| - name: postgres | |
| image: postgres:15 | |
| ports: | |
| - containerPort: 5432 | |
| env: | |
| - name: POSTGRES_USER | |
| value: postgres | |
| - name: POSTGRES_PASSWORD | |
| value: "s3cr3t" | |
| - name: PGDATA | |
| value: /var/lib/postgresql/data/pgdata | |
| volumeMounts: | |
| - name: data | |
| mountPath: /var/lib/postgresql/data | |
| - name: init | |
| mountPath: /docker-entrypoint-initdb.d | |
| resources: | |
| requests: | |
| cpu: 50m | |
| memory: 128Mi | |
| limits: | |
| memory: 256Mi | |
| volumes: | |
| - name: data | |
| persistentVolumeClaim: | |
| claimName: ${DB_NAME}-data | |
| - name: init | |
| configMap: | |
| name: ${DB_NAME}-init | |
| readinessProbe: | |
| exec: | |
| command: [pg_isready, -U, postgres] | |
| initialDelaySeconds: 5 | |
| periodSeconds: 5 | |
| timeoutSeconds: 5 | |
| livenessProbe: | |
| exec: | |
| command: [pg_isready, -U, postgres] | |
| initialDelaySeconds: 30 | |
| periodSeconds: 10 | |
| timeoutSeconds: 5 | |
| EOF | |
| # Service for Postgres | |
| cat <<EOF | oc apply -f - | |
| apiVersion: v1 | |
| kind: Service | |
| metadata: | |
| name: ${DB_NAME} | |
| spec: | |
| ports: | |
| - port: 5432 | |
| targetPort: 5432 | |
| name: postgres | |
| selector: | |
| app: ${DB_NAME} | |
| EOF | |
| # Wait for Postgres to be ready | |
| oc rollout status deployment/${DB_NAME} --timeout=300s | |
| # Run Keystone schema (Job) | |
| cat <<EOF | oc apply -f - | |
| apiVersion: batch/v1 | |
| kind: Job | |
| metadata: | |
| name: ${DB_NAME}-keystone-init | |
| spec: | |
| ttlSecondsAfterFinished: 300 | |
| backoffLimit: 5 | |
| template: | |
| spec: | |
| restartPolicy: OnFailure | |
| containers: | |
| - name: run-schema | |
| image: postgres:15 | |
| command: | |
| - /bin/sh | |
| - -c | |
| - | | |
| until PGPASSWORD=keystonejsuser psql -h ${DB_NAME} -U keystonejsuser -d keystonejs -c '\q' 2>/dev/null; do echo "Waiting for DB..."; sleep 2; done | |
| PGPASSWORD=keystonejsuser psql -h ${DB_NAME} -U keystonejsuser -d keystonejs -f /schema/keystone-init.sql | |
| env: | |
| - name: PGPASSWORD | |
| value: "keystonejsuser" | |
| volumeMounts: | |
| - name: schema | |
| mountPath: /schema | |
| volumes: | |
| - name: schema | |
| configMap: | |
| name: ${DB_NAME}-keystone-schema | |
| EOF | |
| oc wait --for=condition=complete job/${DB_NAME}-keystone-init --timeout=300s | |
| - name: 'Deploy Backend' | |
| if: github.ref != 'refs/heads/dev' | |
| run: | | |
| export PATH=$PATH:`pwd`/linux-amd64 | |
| echo " | |
| podAnnotations: | |
| sha: $GITHUB_SHA | |
| replicaCount: 1 | |
| rollingUpdate: | |
| maxUnavailable: 100% | |
| maxSurge: 0% | |
| image: | |
| repository: ${{ env.REGISTRY }}/bcgov/api-services-portal/api-services-portal | |
| tag: ${{ steps.set-deploy-id.outputs.DEPLOY_ID }} | |
| pullPolicy: Always | |
| imagePullSecrets: | |
| - name: dev-github-read-packages-creds | |
| podSecurityContext: | |
| fsGroup: ${{ secrets.RUNNING_UID_GID }} | |
| securityContext: | |
| runAsUser: ${{ secrets.RUNNING_UID_GID }} | |
| containerPort: 3000 | |
| resources: | |
| requests: | |
| cpu: 20m | |
| memory: 400M | |
| limits: | |
| cpu: 100m | |
| memory: 800M | |
| serviceAccount: | |
| create: false | |
| name: asp-service-account | |
| oauthProxy: | |
| enabled: true | |
| config: | |
| - filename: oauth2-proxy.cfg | |
| mountPath: /oauth2-proxy.cfg | |
| contents: |- | |
| cookie_expire='24h' | |
| cookie_refresh='3m' | |
| cookie_secure='true' | |
| cookie_samesite='strict' | |
| cookie_secret='not_secretenough' | |
| email_domains='*' | |
| redirect_url='https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca/oauth2/callback' | |
| skip_auth_regex='/login|/health|/public|/docs|/redirect|/_next|/images|/devportal|/manager|/about|/maintenance|/admin/session|/ds/api|/feed|/metrics|/signout|/gw/api|/content|^[/]$' | |
| skip_jwt_bearer_tokens='false' | |
| skip_provider_button='true' | |
| whitelist_domains='authz-apps-gov-bc-ca.dev.api.gov.bc.ca' | |
| # redis_connection_url="redis://redis-headless:6379" | |
| # session_store_type="redis" | |
| # redis_password="" | |
| # insecure-oidc-allow-unverified-email: 'true' | |
| # insecure-oidc-skip-issuer-verification: 'true' | |
| # oidc-email-claim: 'sub' | |
| # pass-authorization-header: 'false' | |
| # set-authorization-header: 'false' | |
| - filename: oauth2-proxy.yaml | |
| mountPath: /oauth2-proxy.yaml | |
| yaml: | |
| injectRequestHeaders: | |
| - name: X-Forwarded-Groups | |
| values: | |
| - claim: groups | |
| - name: X-Forwarded-User | |
| values: | |
| - claim: user | |
| - name: X-Forwarded-Email | |
| values: | |
| - claim: email | |
| - name: X-Forwarded-Preferred-Username | |
| values: | |
| - claim: preferred_username | |
| - name: X-Forwarded-Access-Token | |
| values: | |
| - claim: access_token | |
| - name: X-Forwarded-Id-Token | |
| values: | |
| - claim: IDToken | |
| injectResponseHeaders: [] | |
| metricsServer: | |
| BindAddress: "" | |
| SecureBindAddress: "" | |
| TLS: null | |
| providers: | |
| - clientID: ${{ secrets.OIDC_CLIENT_ID }} | |
| clientSecret: ${{ secrets.OIDC_CLIENT_SECRET }} | |
| loginURL: ${{ secrets.OIDC_ISSUER }}/protocol/openid-connect/auth | |
| id: oidc=aps-portal | |
| loginURLParameters: | |
| - default: | |
| - force | |
| name: approval_prompt | |
| - allow: | |
| - pattern: ".*$" | |
| name: kc_idp_hint | |
| oidcConfig: | |
| audienceClaims: | |
| - aud | |
| emailClaim: sub | |
| groupsClaim: groups | |
| insecureAllowUnverifiedEmail: true | |
| insecureSkipNonce: true | |
| issuerURL: ${{ secrets.OIDC_ISSUER }} | |
| userIDClaim: sub | |
| profileURL: ${{ secrets.OIDC_ISSUER }}/protocol/openid-connect/userinfo | |
| provider: oidc | |
| redeemURL: ${{ secrets.OIDC_ISSUER }}/protocol/openid-connect/token | |
| scope: openid | |
| validateURL: ${{ secrets.OIDC_ISSUER }}/protocol/openid-connect/userinfo | |
| server: | |
| BindAddress: 0.0.0.0:7999 | |
| SecureBindAddress: "" | |
| TLS: null | |
| upstreamConfig: | |
| upstreams: | |
| - flushInterval: 1s | |
| id: / | |
| passHostHeader: true | |
| path: / | |
| proxyWebSockets: true | |
| timeout: 30s | |
| uri: http://127.0.0.1:3000 | |
| env: | |
| SESSION_SECRET: | |
| value: '234873290483290' | |
| secure: true | |
| AUTH_STRATEGY: | |
| value: Oauth2Proxy | |
| KONG_URL: | |
| value: '${{ secrets.KONG_URL_DEV}}' | |
| ADAPTER: | |
| value: knex | |
| KNEX_HOST: | |
| value: 'proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-db' | |
| KNEX_PORT: | |
| value: '5432' | |
| KNEX_USER: | |
| value: keystonejsuser | |
| secure: true | |
| KNEX_PASSWORD: | |
| value: keystonejsuser | |
| secure: true | |
| KNEX_DATABASE: | |
| value: keystonejs | |
| FEEDER_URL: | |
| value: 'http://proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api' | |
| GITHUB_API_TOKEN: | |
| value: '${{ secrets.GH_TOKEN_FOR_CONTENT}}' | |
| secure: true | |
| OIDC_ISSUER: | |
| value: '${{ secrets.OIDC_ISSUER }}' | |
| OIDC_CLIENT_ID: | |
| value: '${{ secrets.OIDC_CLIENT_ID }}' | |
| JWKS_URL: | |
| value: '${{ secrets.OIDC_ISSUER }}/protocol/openid-connect/certs' | |
| EXTERNAL_URL: | |
| value: 'https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca' | |
| SSR_API_ROOT: | |
| value: 'http://localhost:7999' | |
| NEXT_PUBLIC_API_ROOT: | |
| value: 'https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca' | |
| NEXT_PUBLIC_GRAFANA_URL: | |
| value: 'https://grafana-apps-gov-bc-ca.dev.api.gov.bc.ca' | |
| NEXT_PUBLIC_KUBE_CLUSTER: | |
| value: 'feature-silver' | |
| NEXT_PUBLIC_HELP_DESK_URL: | |
| value: 'https://dpdd.atlassian.net/servicedesk/customer/portal/1/group/2' | |
| NEXT_PUBLIC_HELP_CHAT_URL: | |
| value: 'https://chat.developer.gov.bc.ca/channel/aps-ops' | |
| NEXT_PUBLIC_HELP_ISSUE_URL: | |
| value: 'https://github.com/bcgov/api-services-portal/issues' | |
| NEXT_PUBLIC_HELP_API_DOCS_URL: | |
| value: '/ds/api/v3/console/' | |
| NEXT_PUBLIC_HELP_SUPPORT_URL: | |
| value: 'https://developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/' | |
| NEXT_PUBLIC_HELP_RELEASE_URL: | |
| value: 'https://developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/reference/releases/' | |
| NEXT_PUBLIC_HELP_STATUS_URL: | |
| value: 'https://status.api.gov.bc.ca/' | |
| NEXT_PUBLIC_DEVELOPER_IDS: | |
| value: 'idir,bceid,bcsc,github' | |
| NEXT_PUBLIC_PROVIDER_IDS: | |
| value: 'idir' | |
| NEXT_PUBLIC_ACCOUNT_BCEID_URL: | |
| value: 'https://www.test.bceid.ca/logon.aspx?returnUrl=/profile_management' | |
| NEXT_PUBLIC_ACCOUNT_BCSC_URL: | |
| value: 'https://id.gov.bc.ca/account/' | |
| GWA_API_URL: | |
| value: 'https://gwa-api-gov-bc-ca.dev.api.gov.bc.ca' | |
| GWA_PROD_ENV_SLUG: | |
| value: 'FB000000' | |
| GWA_RES_SVR_CLIENT_ID: | |
| value: '${{ secrets.OIDC_CLIENT_ID }}' | |
| secure: true | |
| GWA_RES_SVR_CLIENT_SECRET: | |
| value: '${{ secrets.OIDC_CLIENT_SECRET }}' | |
| secure: true | |
| KEYCLOAK_AUTH_URL: | |
| value: '${{ secrets.KEYCLOAK_AUTH }}' | |
| KEYCLOAK_REALM: | |
| value: '${{ secrets.KEYCLOAK_REALM }}' | |
| COOKIE_SECURE: | |
| value: 'true' | |
| LOG_LEVEL: | |
| value: 'debug' | |
| DISABLE_LOGGING: | |
| value: 'true' | |
| EMAIL_ENABLED: | |
| value: 'true' | |
| EMAIL_FROM: | |
| value: 'API.Services.Portal@gov.bc.ca' | |
| EMAIL_HOST: | |
| value: 'apps.smtp.gov.bc.ca' | |
| readinessProbe: | |
| exec: | |
| command: | |
| - sh | |
| - -c | |
| - 'state=\$(curl -XGET -m 2 --silent -f -H \"Accept: application/json\" http://localhost:3000/health | jq -r \".status | ascii_downcase\"); if [ ! \"\$state\" == \"ready\" ]; then exit 1; fi' | |
| timeoutSeconds: 3 | |
| periodSeconds: 10 | |
| " > values.yaml | |
| helm repo add bcgov http://bcgov.github.io/helm-charts | |
| helm upgrade --install proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }} -f values.yaml --history-max 3 bcgov/generic-api | |
| - name: 'Deploy Routes' | |
| if: github.ref != 'refs/heads/dev' | |
| run: | | |
| export PATH=$PATH:`pwd`/linux-amd64 | |
| echo " | |
| routes: | |
| - host: api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca | |
| targetPort: http | |
| service: proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-generic-api | |
| wildcardPolicy: None | |
| tls: | |
| termination: edge | |
| " > values.yaml | |
| helm repo add bcgov http://bcgov.github.io/helm-charts | |
| helm upgrade --install proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-routes -f values.yaml --history-max 3 bcgov/ocp-route | |
| - name: 'Seed Data' | |
| if: github.ref != 'refs/heads/dev' | |
| run: | | |
| export PATH=$PATH:`pwd`/linux-amd64 | |
| cd .github/workflows | |
| SERVICE=proto-asp-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}-feeder-generic-api \ | |
| PORTAL_URL=https://api-services-portal-${{ steps.set-deploy-id.outputs.DEPLOY_ID }}.apps.silver.devops.gov.bc.ca \ | |
| OIDC_ISSUER=${{ secrets.OIDC_ISSUER }} \ | |
| OIDC_CLIENT_ID=${{ secrets.OIDC_CLIENT_ID }} \ | |
| OIDC_CLIENT_SECRET=${{ secrets.OIDC_CLIENT_SECRET }} \ | |
| ./scripts/init.sh | |
| - name: Authenticate to Gold and set context | |
| if: github.ref == 'refs/heads/test' | |
| uses: redhat-actions/oc-login@v1 | |
| with: | |
| openshift_server_url: ${{ secrets.OPENSHIFT_GOLD_SERVER }} | |
| openshift_token: ${{ secrets.OPENSHIFT_GOLD_TOKEN }} | |
| insecure_skip_tls_verify: true | |
| namespace: ${{ secrets.OPENSHIFT_GOLD_TEST_NAMESPACE }} | |
| - name: 'Restart Portal in Gold Test Namespace' | |
| if: github.ref == 'refs/heads/test' | |
| run: | | |
| oc rollout restart deployment/bcgov-aps-portal-generic-api -n ${{ secrets.OPENSHIFT_GOLD_TEST_NAMESPACE }} | |
| oc rollout restart deployment/bcgov-aps-portal-batch-generic-api -n ${{ secrets.OPENSHIFT_GOLD_TEST_NAMESPACE }} | |
| - name: 'Create Pull Request for Release' | |
| if: github.ref == 'refs/heads/test' | |
| uses: actions/github-script@v6 | |
| with: | |
| script: | | |
| const { repo, owner } = context.repo; | |
| const openPrs = await github.rest.pulls.list({ | |
| owner, | |
| repo, | |
| head: '${{ github.ref_name }}', | |
| base: 'main', | |
| state: 'open' | |
| }) | |
| if(openPrs.data.length === 0){ | |
| await github.rest.pulls.create({ | |
| title: 'Create Latest Release', | |
| owner, | |
| repo, | |
| head: '${{ github.ref_name }}', | |
| base: 'main', | |
| body: [ | |
| 'This Pull Request is auto-created by [actions/github-script](https://github.com/actions/github-script).', | |
| 'Please update this PR with appropriate labels to target specific type of release' | |
| ].join('\n\n'), | |
| draft: true | |
| }); | |
| } else { | |
| console.log("There is already an open Pull Request in place.\n") | |
| openPrs.data.forEach((item) => { | |
| console.log(item.html_url) | |
| }) | |
| } |