From 9491dd47fdaf7c9c855ac7c1ab7e49142bf6bbd9 Mon Sep 17 00:00:00 2001 From: Shruti Chaturvedi Date: Sun, 22 Jan 2023 11:04:30 +0530 Subject: [PATCH] Integrate Uffizzi --- .github/workflows/uffizzi-build.yml | 98 +++++++++++++++++++++++++++ .github/workflows/uffizzi-preview.yml | 89 ++++++++++++++++++++++++ docker-compose.uffizzi.yml | 22 ++++++ uffizzi/Dockerfile.uffizzi | 78 +++++++++++++++++++++ 4 files changed, 287 insertions(+) create mode 100644 .github/workflows/uffizzi-build.yml create mode 100644 .github/workflows/uffizzi-preview.yml create mode 100644 docker-compose.uffizzi.yml create mode 100644 uffizzi/Dockerfile.uffizzi diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml new file mode 100644 index 00000000..737bdf65 --- /dev/null +++ b/.github/workflows/uffizzi-build.yml @@ -0,0 +1,98 @@ +name: Build PR Image +on: + pull_request: + types: [opened, synchronize, reopened, closed, review_requested] + +jobs: + build-acme: + name: Build and push `acme` + runs-on: ubuntu-latest + outputs: + tags: ${{ steps.meta.outputs.tags }} + if: ${{ github.event.action != 'closed' }} + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Generate UUID image name + id: uuid + run: echo "UUID_WORKER=$(uuidgen)" >> $GITHUB_ENV + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: registry.uffizzi.com/${{ env.UUID_WORKER }} + tags: | + type=raw,value=60d + + - name: Build and Push Image to registry.uffizzi.com - Uffizzi's ephemeral Registry + uses: docker/build-push-action@v3 + with: + context: ./ + file: ./uffizzi/Dockerfile.uffizzi + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: true + cache-from: type=gha + cache-to: type=gha, mode=max + + render-compose-file: + name: Render Docker Compose File + # Pass output of this workflow to another triggered by `workflow_run` event. + runs-on: ubuntu-latest + needs: + - build-acme + outputs: + compose-file-cache-key: ${{ steps.hash.outputs.hash }} + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + - name: Render Compose File + run: | + ACME_IMAGE=${{ needs.build-acme.outputs.tags }} + export ACME_IMAGE + export UFFIZZI_URL=\$UFFIZZI_URL + # Render simple template from environment variables. + envsubst < docker-compose.uffizzi.yml > docker-compose.rendered.yml + cat docker-compose.rendered.yml + - name: Upload Rendered Compose File as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: docker-compose.rendered.yml + retention-days: 2 + - name: Serialize PR Event to File + run: | + cat << EOF > event.json + ${{ toJSON(github.event) }} + + EOF + - name: Upload PR Event as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: event.json + retention-days: 2 + + delete-preview: + name: Call for Preview Deletion + runs-on: ubuntu-latest + if: ${{ github.event.action == 'closed' }} + steps: + # If this PR is closing, we will not render a compose file nor pass it to the next workflow. + - name: Serialize PR Event to File + run: | + cat << EOF > event.json + ${{ toJSON(github.event) }} + + EOF + - name: Upload PR Event as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: event.json + retention-days: 2 diff --git a/.github/workflows/uffizzi-preview.yml b/.github/workflows/uffizzi-preview.yml new file mode 100644 index 00000000..400dd2e7 --- /dev/null +++ b/.github/workflows/uffizzi-preview.yml @@ -0,0 +1,89 @@ +name: Deploy Uffizzi Preview + +# Workflow run — runs only when the Build PR/ uffizzi-build.yml completes successfully. +on: + workflow_run: + workflows: + - "Build PR Image" + types: + - completed + +jobs: + cache-compose-file: + name: Cache Compose File + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + outputs: + compose-file-cache-key: ${{ env.HASH }} + pr-number: ${{ env.PR_NUMBER }} + steps: + - name: 'Download artifacts' + # Fetch output (zip archive) from the workflow run that triggered this workflow. + uses: actions/github-script@v6 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "preview-spec" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); + + - name: 'Unzip artifact' + run: unzip preview-spec.zip + - name: Read Event into ENV + run: | + echo 'EVENT_JSON<> $GITHUB_ENV + cat event.json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Hash Rendered Compose File + id: hash + # If the previous workflow was triggered by a PR close event, we will not have a compose file artifact. + if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + run: echo "HASH=$(md5sum docker-compose.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV + - name: Cache Rendered Compose File + if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + uses: actions/cache@v3 + with: + path: docker-compose.rendered.yml + key: ${{ env.HASH }} + + - name: Read PR Number From Event Object + id: pr + run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV + - name: DEBUG - Print Job Outputs + if: ${{ runner.debug }} + run: | + echo "PR number: ${{ env.PR_NUMBER }}" + echo "Compose file hash: ${{ env.HASH }}" + cat event.json + + deploy-uffizzi-preview: + name: Use Remote Workflow to Preview on Uffizzi + needs: + - cache-compose-file + if: ${{ github.event.workflow_run.conclusion == 'success' }} + uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2 + with: + # If this workflow was triggered by a PR close event, cache-key will be an empty string + # and this reusable workflow will delete the preview deployment. + compose-file-cache-key: ${{ needs.cache-compose-file.outputs.compose-file-cache-key }} + compose-file-cache-path: docker-compose.rendered.yml + server: https://app.uffizzi.com + pr-number: ${{ needs.cache-compose-file.outputs.pr-number }} + permissions: + contents: read + pull-requests: write + id-token: write + diff --git a/docker-compose.uffizzi.yml b/docker-compose.uffizzi.yml new file mode 100644 index 00000000..d9179130 --- /dev/null +++ b/docker-compose.uffizzi.yml @@ -0,0 +1,22 @@ +version: "3" + +x-uffizzi: + ingress: + service: acmesh + port: 7681 + +services: + + acmesh: + image: "${ACME_IMAGE}" + volumes: + - ./acme.sh:/acme.sh + entrypoint: ["/bin/bash", "-c"] + command: ["ttyd /bin/bash"] + ports: + - "7700:7700" + - "7681:7681" + deploy: + resources: + limits: + memory: 4000M diff --git a/uffizzi/Dockerfile.uffizzi b/uffizzi/Dockerfile.uffizzi new file mode 100644 index 00000000..9cad96d4 --- /dev/null +++ b/uffizzi/Dockerfile.uffizzi @@ -0,0 +1,78 @@ +FROM uffizzi/ttyd:golang1.18-alpine + +RUN apk --no-cache add -f \ + openssl \ + openssh-client \ + coreutils \ + bind-tools \ + curl \ + sed \ + socat \ + tzdata \ + oath-toolkit-oathtool \ + tar \ + libidn \ + jq + +ENV LE_CONFIG_HOME /acme.sh + +ARG AUTO_UPGRADE=1 + +ENV AUTO_UPGRADE $AUTO_UPGRADE + +#Install +COPY ./ /install_acme.sh/ +RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ + +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - + +RUN for verb in help \ + version \ + install \ + uninstall \ + upgrade \ + issue \ + signcsr \ + deploy \ + install-cert \ + renew \ + renew-all \ + revoke \ + remove \ + list \ + info \ + showcsr \ + install-cronjob \ + uninstall-cronjob \ + cron \ + toPkcs \ + toPkcs8 \ + update-account \ + register-account \ + create-account-key \ + create-domain-key \ + createCSR \ + deactivate \ + deactivate-account \ + set-notify \ + set-default-ca \ + set-default-chain \ + ; do \ + printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ + ; done + +RUN printf "%b" '#!'"/usr/bin/env sh\n \ +if [ \"\$1\" = \"daemon\" ]; then \n \ + trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \ + crond && sleep infinity &\n \ + wait \n \ +else \n \ + exec -- \"\$@\"\n \ +fi" >/entry.sh && chmod +x /entry.sh + +VOLUME /acme.sh + +RUN apk update --quiet && \ + apk add -q --no-cache libgcc tini + +EXPOSE 7700/tcp