From 403ef1afbd9f7ba9c35019ae66398dfbb8298bda Mon Sep 17 00:00:00 2001 From: GitStart-SourceGraph <89894075+gitstart-sourcegraph@users.noreply.github.com> Date: Wed, 20 Apr 2022 20:14:57 +0530 Subject: [PATCH] [SG-33486] Periodically clean up old preview services (#33859) * feat: prepare github action and script to clean up render.com pr preview Co-authored-by: gitstart-sourcegraph --- .github/workflows/pr-preview.yml | 28 ++++++-- dev/ci/render-pr-preview-cleanup.sh | 96 ++++++++++++++++++++++++++++ doc/dev/how-to/client_pr_previews.md | 12 ++++ 3 files changed, 132 insertions(+), 4 deletions(-) create mode 100755 dev/ci/render-pr-preview-cleanup.sh diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 28b44f851e2..dfe58823a83 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -2,10 +2,15 @@ name: PR Preview on: pull_request: - types: [opened, synchronize, closed] + types: [closed] + + schedule: + # At minute 0 past every 12th hour + - cron: '0 */12 * * *' jobs: - preview-deployment: + remove-pr-preview-app: + if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: @@ -15,11 +20,26 @@ jobs: fetch-depth: 1 - name: Delete PR preview app - if: github.event.action == 'closed' run: ./dev/ci/render-pr-preview.sh -d env: RENDER_COM_API_KEY: ${{ secrets.RENDER_COM_API_KEY }} RENDER_COM_OWNER_ID: ${{ secrets.RENDER_COM_OWNER_ID }} - BUILDKITE_PULL_REQUEST_REPO: "https://github.com/${{ github.repository }}" BUILDKITE_BRANCH: ${{ github.head_ref }} + + clean-up-inactive-pr-preview-apps: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 1 + + - name: Clean up inactive PR preview apps + # This job removes PR preview apps which don't have any updates in last 5 days + run: ./dev/ci/render-pr-preview-cleanup.sh -e 5 + env: + RENDER_COM_API_KEY: ${{ secrets.RENDER_COM_API_KEY }} + RENDER_COM_OWNER_ID: ${{ secrets.RENDER_COM_OWNER_ID }} diff --git a/dev/ci/render-pr-preview-cleanup.sh b/dev/ci/render-pr-preview-cleanup.sh new file mode 100755 index 00000000000..6bf17bc367e --- /dev/null +++ b/dev/ci/render-pr-preview-cleanup.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -e + +# Env variables: +# - RENDER_COM_API_KEY (required) +# - RENDER_COM_OWNER_ID (required) + +print_usage() { + echo "Usage: [-e EXPIRE_AFTER_DAYS]" 1>&2 + echo "-e: Number of days since the last time PR previews were updated (defaults: 5 days)" 1>&2 +} + +urlencode() { + echo "$1" | curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- | sed -e 's/%0A//' +} + +get_days_ago_in_ISO() { + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) machine=Linux ;; + Darwin*) machine=Mac ;; + *) ;; + esac + + # `date` in macos is different from Linux + if [[ $machine = "Mac" ]]; then + date -u "-v-$1d" +"%Y-%m-%dT%H:%M:%SZ" + else + date -d "$1 days ago" +"%Y-%m-%dT%H:%M:%SZ" + fi +} + +expire_after_days="5" + +while getopts 'e:' flag; do + case "${flag}" in + e) expire_after_days="${OPTARG}" ;; + *) + print_usage + exit 1 + ;; + esac +done + +render_api_key="${RENDER_COM_API_KEY}" +render_owner_id="${RENDER_COM_OWNER_ID}" + +expiration_date_ISO=$(get_days_ago_in_ISO "$expire_after_days") + +if [[ -z "${render_api_key}" || -z "${render_owner_id}" ]]; then + echo "RENDER_COM_API_KEY or RENDER_COM_OWNER_ID is not set" + exit 1 +fi + +# Get id list of services which are created before expiration date +# We should take care about render.com rate limit (https://api-docs.render.com/reference/rate-limiting) +# GET 100/minute +# DELETE 30/minute + +cursor="" +ids=() + +# Collect ids of all services which are updated before expiration date and `not_suspended` +# We use `updatedBefore` since the services are updated on deployments +for (( ; ; )); do + # render.com API > List services: https://api-docs.render.com/reference/get-services + service_list=$(curl -sSf --request GET \ + --url "https://api.render.com/v1/services?type=web_service&updatedBefore=$(urlencode "$expiration_date_ISO")&suspended=not_suspended&ownerId=${render_owner_id}&limit=100&cursor=${cursor}" \ + --header 'Accept: application/json' \ + --header "Authorization: Bearer ${render_api_key}") + + num_of_records=$(echo "$service_list" | jq -r '. | length') + + if [ "${num_of_records}" == "0" ]; then + break + fi + + while IFS='' read -r line; do + ids+=("$line") + done < <(echo "$service_list" | jq -r '.[].service.id') + + cursor=$(echo "$service_list" | jq -r '.[-1].cursor') +done + +for service_id in "${ids[@]}"; do + echo "Deleting service: $service_id" + + curl -sSf -o /dev/null --request DELETE \ + --url "https://api.render.com/v1/services/${service_id}" \ + --header 'Accept: application/json' \ + --header "Authorization: Bearer ${render_api_key}" + + # To make sure we don't reach the limitation of 30/minute DELETE requests + sleep 2 +done diff --git a/doc/dev/how-to/client_pr_previews.md b/doc/dev/how-to/client_pr_previews.md index 39349dbadec..6ba7d16abdc 100644 --- a/doc/dev/how-to/client_pr_previews.md +++ b/doc/dev/how-to/client_pr_previews.md @@ -28,3 +28,15 @@ We do not create client PR previews [if Go or GraphQL is changed](https://source ## Why does a search query fail with an error? The preview app is deployed with `SOURCEGRAPHDOTCOM_MODE=false`, which means that the user should be authenticated to use all web application features similar to [the dogfood instance](https://k8s.sgdev.org/). Make sure that you're logged in. If it doesn't fix the issue, please report it in Slack. + +## Why is my preview inactive? + +Previews are made inactive, when they exceeds the preview liftime. This is done to save resource (which is required to keep preview active over an extended period) from beign spent on redundant previews. + +## Where to find the script that cleans up previews? + +The preview cleanup script is located [here](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/dev/ci/render-pr-preview-cleanup.sh) + +## What is the default cleanup schedule and the default preview lifetime? + +The Default cleanup schedule runs every 12th hour, where default preview lifetime is 5 days. This can be modified through the `-e` (e.g `-e 5` for 5 days) flag passed to the preview script. Preview would also be removed once a PR gets closed or merged.