diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 6911f81dcb..cb64a2a082 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -18,8 +18,19 @@ jobs: secrets: inherit with: env: test + + Build_easi-frontend_image: + uses: ./.github/workflows/build_frontend_image.yml + secrets: inherit Run_Tests: uses: ./.github/workflows/run_tests.yml needs: [Build_Application_Images,Build_Test_Frontend_Assets] secrets: inherit + + Deploy_to_EKS: + uses: ./.github/workflows/deploy_to_eks.yml + needs: [Build_Application_Images,Build_easi-frontend_image] + secrets: inherit + with: + namespace: easi-${{ github.event.number }} diff --git a/.github/workflows/build_frontend_image.yml b/.github/workflows/build_frontend_image.yml new file mode 100644 index 0000000000..04410fa345 --- /dev/null +++ b/.github/workflows/build_frontend_image.yml @@ -0,0 +1,61 @@ +name: Build easi-frontend image + +on: + workflow_call: + +env: + GIT_HASH: ${{ github.sha }} + GIT_REF_NAME: ${{ github.ref }} + +permissions: + id-token: write + contents: read + +jobs: + build_easi-frontend_image: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_INFRA_OIDC_ROLE_TO_ASSUME }} + aws-region: us-west-2 + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Set env vars with direnv # This allows docker build of FE files to pull from .envrc + uses: HatsuneMiku3939/direnv-action@v1 + - name: Calculate build args + id: calculate-build-args + run: | + echo "VITE_LD_CLIENT_ID=${VITE_LD_CLIENT_ID}" >> $GITHUB_OUTPUT + echo "VITE_OKTA_CLIENT_ID=${VITE_OKTA_CLIENT_ID}" >> $GITHUB_OUTPUT + echo "VITE_OKTA_SERVER_ID=${VITE_OKTA_SERVER_ID}" >> $GITHUB_OUTPUT + echo "VITE_OKTA_ISSUER=${VITE_OKTA_ISSUER}" >> $GITHUB_OUTPUT + echo "VITE_OKTA_DOMAIN=${VITE_OKTA_DOMAIN}" >> $GITHUB_OUTPUT + echo "VITE_OKTA_REDIRECT_URI=${VITE_OKTA_REDIRECT_URI}" >> $GITHUB_OUTPUT + - name: Build, tag, and push image to Amazon ECR + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.frontend_k8s + push: true + cache-to: type=gha,mode=max,scope=${{ env.GIT_REF_NAME }}-easi-frontend + cache-from: type=gha,scope=${{ env.GIT_REF_NAME }}-easi-frontend + tags: ${{ steps.login-ecr.outputs.registry }}/easi-frontend:${{ env.GIT_HASH }} + build-args: | + VITE_LD_CLIENT_ID=${{ steps.calculate-build-args.outputs.VITE_LD_CLIENT_ID }} + VITE_OKTA_CLIENT_ID=${{ steps.calculate-build-args.outputs.VITE_OKTA_CLIENT_ID }} + VITE_OKTA_SERVER_ID=${{ steps.calculate-build-args.outputs.VITE_OKTA_SERVER_ID }} + VITE_OKTA_ISSUER=${{ steps.calculate-build-args.outputs.VITE_OKTA_ISSUER }} + VITE_OKTA_DOMAIN=${{ steps.calculate-build-args.outputs.VITE_OKTA_DOMAIN }} + VITE_OKTA_REDIRECT_URI=${{ steps.calculate-build-args.outputs.VITE_OKTA_REDIRECT_URI }} diff --git a/.github/workflows/deploy_to_eks.yml b/.github/workflows/deploy_to_eks.yml index b2f4070704..375e9e02cc 100644 --- a/.github/workflows/deploy_to_eks.yml +++ b/.github/workflows/deploy_to_eks.yml @@ -1,78 +1,23 @@ -name: Deploy To EKS +name: Deploy branch environment to EKS on: - workflow_dispatch: + workflow_call: + inputs: + namespace: + required: false + type: string + description: 'The namespace to use when deploying to EKS. If not passed, a namespace will attempt to be automatically generated from the branch name.' permissions: id-token: write contents: read + pull-requests: write env: - EASI_APP_NODE_VERSION: "18.20.4" GIT_HASH: ${{ github.sha }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - GIT_REF_NAME: ${{ github.ref }} jobs: - - build_easi-frontend_image: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4.0.2 - with: - role-to-assume: ${{ secrets.AWS_INFRA_OIDC_ROLE_TO_ASSUME }} - aws-region: us-west-2 - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v2 - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Set env vars with direnv # This allows docker build of FE files to pull from .envrc - uses: HatsuneMiku3939/direnv-action@v1 - - name: Calculate build args - id: calculate-build-args - run: | - echo "VITE_LD_CLIENT_ID=${VITE_LD_CLIENT_ID}" >> $GITHUB_OUTPUT - echo "VITE_OKTA_CLIENT_ID=${VITE_OKTA_CLIENT_ID}" >> $GITHUB_OUTPUT - echo "VITE_OKTA_SERVER_ID=${VITE_OKTA_SERVER_ID}" >> $GITHUB_OUTPUT - echo "VITE_OKTA_ISSUER=${VITE_OKTA_ISSUER}" >> $GITHUB_OUTPUT - echo "VITE_OKTA_DOMAIN=${VITE_OKTA_DOMAIN}" >> $GITHUB_OUTPUT - echo "VITE_OKTA_REDIRECT_URI=${VITE_OKTA_REDIRECT_URI}" >> $GITHUB_OUTPUT - - name: Build, tag, and push image to Amazon ECR - uses: docker/build-push-action@v6 - with: - context: . - file: Dockerfile.frontend_k8s - push: true - cache-to: type=gha,mode=max,scope=${{ env.GIT_REF_NAME }}-easi-frontend - cache-from: type=gha,scope=${{ env.GIT_REF_NAME }}-easi-frontend - tags: ${{ steps.login-ecr.outputs.registry }}/easi-frontend:${{ env.GIT_HASH }} - build-args: | - VITE_LD_CLIENT_ID=${{ steps.calculate-build-args.outputs.VITE_LD_CLIENT_ID }} - VITE_OKTA_CLIENT_ID=${{ steps.calculate-build-args.outputs.VITE_OKTA_CLIENT_ID }} - VITE_OKTA_SERVER_ID=${{ steps.calculate-build-args.outputs.VITE_OKTA_SERVER_ID }} - VITE_OKTA_ISSUER=${{ steps.calculate-build-args.outputs.VITE_OKTA_ISSUER }} - VITE_OKTA_DOMAIN=${{ steps.calculate-build-args.outputs.VITE_OKTA_DOMAIN }} - VITE_OKTA_REDIRECT_URI=${{ steps.calculate-build-args.outputs.VITE_OKTA_REDIRECT_URI }} - - name: Announce failure - if: ${{ failure() }} - run: | - ./scripts/github-action-announce-broken-branch - - Build_Application_Images: - uses: ./.github/workflows/build_application_images.yml - secrets: inherit - Deploy_to_EKS: - needs: [build_easi-frontend_image, Build_Application_Images] runs-on: ubuntu-latest environment: "dev" steps: @@ -91,10 +36,26 @@ jobs: - name: Update kubeconfig run: aws eks update-kubeconfig --name dev-easi-poc-cluster --region us-west-2 - name: Deploy to EKS + id: deploy-to-eks run: | - . ./scripts/deploy_eks_env.sh - echo "# EKS Ingress URLs" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- [EASi](http://${EASI_INGRESS})" >> $GITHUB_STEP_SUMMARY - echo "- [Mailcatcher](http://${EMAIL_INGRESS})" >> $GITHUB_STEP_SUMMARY - echo "- [Minio Console](http://${MINIO_CONSOLE_INGRESS})" >> $GITHUB_STEP_SUMMARY + if [ -n "${{ inputs.namespace }}" ]; then + . ./scripts/deploy_eks_env.sh -n ${{ inputs.namespace }} + else + . ./scripts/deploy_eks_env.sh + fi + echo "EASI_INGRESS=http://${EASI_INGRESS}" >> $GITHUB_OUTPUT + echo "EMAIL_INGRESS=http://${EMAIL_INGRESS}" >> $GITHUB_OUTPUT + echo "MINIO_CONSOLE_INGRESS=http://${MINIO_CONSOLE_INGRESS}" >> $GITHUB_OUTPUT + + - name: Comment on PR + if: github.event_name == 'pull_request' + uses: thollander/actions-comment-pull-request@v3 + with: + comment-tag: ingress-urls + pr-number: ${{ github.event.number }} + message: | + # EKS Ingress URLs + - [EASi](${{ steps.deploy-to-eks.outputs.EASI_INGRESS }}) + - [Mailcatcher](${{ steps.deploy-to-eks.outputs.EMAIL_INGRESS }}) + - [Minio Console](${{ steps.deploy-to-eks.outputs.MINIO_CONSOLE_INGRESS }}) + reactions: eyes, rocket diff --git a/.github/workflows/manual_deploy_to_eks.yml b/.github/workflows/manual_deploy_to_eks.yml new file mode 100644 index 0000000000..4db9857ea8 --- /dev/null +++ b/.github/workflows/manual_deploy_to_eks.yml @@ -0,0 +1,36 @@ +name: Manual deploy To EKS + +on: + workflow_dispatch: + inputs: + namespace: + required: false + type: string + description: 'The namespace to use when deploying to EKS. If not passed, a namespace will attempt to be automatically generated from the branch name.' + +permissions: + id-token: write + contents: read + +env: + EASI_APP_NODE_VERSION: "18.20.4" + GIT_HASH: ${{ github.sha }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + GIT_REF_NAME: ${{ github.ref }} + +jobs: + + Build_easi-frontend_image: + uses: ./.github/workflows/build_frontend_image.yml + secrets: inherit + + Build_Application_Images: + uses: ./.github/workflows/build_application_images.yml + secrets: inherit + + Deploy_to_EKS: + needs: [Build_easi-frontend_image, Build_Application_Images] + uses: ./.github/workflows/deploy_to_eks.yml + secrets: inherit + with: + namespace: ${{ github.event.inputs.namespace }} diff --git a/.github/workflows/pr_teardown_env_on_close.yml b/.github/workflows/pr_teardown_env_on_close.yml new file mode 100644 index 0000000000..f7e18bb88c --- /dev/null +++ b/.github/workflows/pr_teardown_env_on_close.yml @@ -0,0 +1,35 @@ +name: Teardown branch environment in EKS on PR close + +on: + pull_request: + types: [closed] + + +permissions: + id-token: write + contents: read + +env: + GIT_HASH: ${{ github.sha }} + GIT_REF_NAME: ${{ github.ref }} + PR_NUMBER: ${{ github.event.number }} + +jobs: + Teardown_env: + name: Teardown EKS branch environment + runs-on: ubuntu-latest + environment: "dev" + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_TO_ASSUME }} + aws-region: us-west-2 + - name: Update kubeconfig + run: aws eks update-kubeconfig --name dev-easi-poc-cluster --region us-west-2 + - name: Teardown branch environment + # The "easi-pr-" prefix needs to match the prefix in build_and_test.yml so that we delete the correct namespace + run: | + kubectl delete namespace "easi-$PR_NUMBER" --force --ignore-not-found diff --git a/scripts/deploy_eks_env.sh b/scripts/deploy_eks_env.sh index ba2d894c43..f0e836f0e8 100755 --- a/scripts/deploy_eks_env.sh +++ b/scripts/deploy_eks_env.sh @@ -58,15 +58,6 @@ fi validate_namespace "$NAMESPACE" echo "Namespace is set to: $NAMESPACE" -# Delete namespace if it exists -if kubectl get ns "$NAMESPACE" > /dev/null 2>&1; then - echo "❄️ Deleting ${NAMESPACE} namespace ❄️" - kubectl delete ns "$NAMESPACE" --force || { - echo "Failed to delete namespace ${NAMESPACE}" - exit 1 - } -fi - # Create Namespace! ( echo "❄️ Creating Namespace via Kubectl ❄️" @@ -77,8 +68,7 @@ fi # Generate and deploy ingress resources ( echo "❄️ Creating Ingress resources via Kustomize ❄️" - TEMPDIR=$(mktemp -d ../tmp.ingress.XXXXX) - cd "$TEMPDIR" || exit + mkdir -p ../tmp.ingress && cd ../tmp.ingress kustomize create --resources ../deploy/overlays/pr/ingress kustomize edit set namespace "$NAMESPACE" kustomize build > manifest-ingress.yaml @@ -94,8 +84,6 @@ fi echo "❄️ Deploying Ingress Objects via Kubectl ❄️" kubectl apply -n "$NAMESPACE" -f manifest-ingress.yaml - - rm -rf "$TEMPDIR" ) # TODO: Fine tune this sleep time, or engineer around it. @@ -112,9 +100,11 @@ export EMAIL_INGRESS # Generate and deploy EASI resources ( + mkdir -p ../tmp.easi && cd ../tmp.easi + echo "❄️ Deleting old resources in namespace, if they exist ❄️" + kubectl delete all --all -n "$NAMESPACE" + echo "❄️ Creating EASi resources via Kustomize ❄️" - TEMPDIR=$(mktemp -d ../tmp.easi.XXXXX) - cd "$TEMPDIR" || exit kustomize create --resources ../deploy/overlays/pr/easi kustomize edit set namespace "$NAMESPACE" kustomize edit set image easi-backend=840301899071.dkr.ecr.us-west-2.amazonaws.com/easi-backend:"$GIT_HASH" @@ -133,10 +123,9 @@ export EMAIL_INGRESS echo "❄️ Deploying Ingress Objects via Kubectl ❄️" kubectl apply -n "$NAMESPACE" -f manifest-easi.yaml - - rm -rf "$TEMPDIR" ) +rm -rf ../tmp.ingress/kustomization.yaml ../tmp.easi/kustomization.yaml echo "EASI: http://$EASI_INGRESS" echo "Mailcatcher: http://$EMAIL_INGRESS" diff --git a/scripts/k8s_dev.sh b/scripts/k8s_dev.sh index 48d7a8152e..aa176ecdc6 100755 --- a/scripts/k8s_dev.sh +++ b/scripts/k8s_dev.sh @@ -81,15 +81,6 @@ fi # Run validate_namespace validate_namespace "$NAMESPACE" -# Delete namespace if it exists -if kubectl get ns "$NAMESPACE" > /dev/null 2>&1; then - echo "❄️ Clear ${NAMESPACE} namespace ❄️" - kubectl delete ns "$NAMESPACE" || { - echo "Failed to delete namespace ${NAMESPACE}" - exit 1 - } -fi - APPLICATION_VERSION="$(git rev-parse @)" APPLICATION_DATETIME="$(date --rfc-3339='seconds' --utc)" APPLICATION_TS="$(date --date="$APPLICATION_DATETIME" '+%s')" @@ -124,12 +115,6 @@ export APPLICATION_TS echo "❄️ Deploying EASi via Kustomize ❄️" -delete_temp_dir() { - if [ -d "$TEMPDIR" ]; then - rm -rf "$TEMPDIR" - fi -} - # Create Namespace! ( echo "❄️ Creating Namespace via Kubectl ❄️" @@ -137,33 +122,35 @@ delete_temp_dir() { ) ( - TEMPDIR=$(mktemp -d ../tmp.ingress.XXXXX) - cd "$TEMPDIR" || exit + mkdir -p ../tmp.ingress && cd ../tmp.ingress kustomize create --resources ../deploy/base/ingress kustomize edit set namespace "$NAMESPACE" - kustomize build > manifest.yaml + kustomize build > manifest-ingress.yaml - sed -i'' -E "s/easi.localdev.me/${NAMESPACE}.localdev.me/" manifest.yaml - sed -i'' -E "s/email.localdev.me/${NAMESPACE}-email.localdev.me/" manifest.yaml - sed -i'' -E "s/minio.localdev.me/${NAMESPACE}-minio.localdev.me/" manifest.yaml - kubectl apply -f manifest.yaml - trap delete_temp_dir EXIT + sed -i'' -E "s/easi.localdev.me/${NAMESPACE}.localdev.me/" manifest-ingress.yaml + sed -i'' -E "s/email.localdev.me/${NAMESPACE}-email.localdev.me/" manifest-ingress.yaml + sed -i'' -E "s/minio.localdev.me/${NAMESPACE}-minio.localdev.me/" manifest-ingress.yaml + kubectl apply -f manifest-ingress.yaml ) ( - TEMPDIR=$(mktemp -d ../tmp.easi.XXXXX) - cd "$TEMPDIR" || exit + mkdir -p ../tmp.easi && cd ../tmp.easi + echo "❄️ Deleting old resources in namespace, if they exist ❄️" + kubectl delete all --all -n "$NAMESPACE" + + echo "❄️ Creating EASi resources via Kustomize ❄️" kustomize create --resources ../deploy/base/easi kustomize edit set namespace "$NAMESPACE" - kustomize build > manifest.yaml - sed -i'' -E "s/easi-frontend:latest/easi-frontend:${NAMESPACE}/" manifest.yaml - sed -i'' -E "s/easi-backend:latest/easi-backend:${NAMESPACE}/" manifest.yaml - sed -i'' -E "s/cedarproxy:latest/cedarproxy:${NAMESPACE}/" manifest.yaml - sed -i'' -E "s/db-migrate:latest/db-migrate:${NAMESPACE}/" manifest.yaml - kubectl apply -f manifest.yaml - trap delete_temp_dir EXIT + kustomize build > manifest-easi.yaml + sed -i'' -E "s/easi-frontend:latest/easi-frontend:${NAMESPACE}/" manifest-easi.yaml + sed -i'' -E "s/easi-backend:latest/easi-backend:${NAMESPACE}/" manifest-easi.yaml + sed -i'' -E "s/cedarproxy:latest/cedarproxy:${NAMESPACE}/" manifest-easi.yaml + sed -i'' -E "s/db-migrate:latest/db-migrate:${NAMESPACE}/" manifest-easi.yaml + kubectl apply -f manifest-easi.yaml ) +rm -rf ../tmp.ingress ../tmp.easi + echo "❄️ EASi: http://${NAMESPACE}.localdev.me ❄️" echo "❄️ Mailcatcher: http://${NAMESPACE}-email.localdev.me ❄️" echo "❄️ Minio: http://${NAMESPACE}-minio.localdev.me ❄️"