From 2d92a15a0576181eea690b558ffbdc4836a9ec8e Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 11:32:19 +0000 Subject: [PATCH 01/69] create-pr --- .github/workflows/pr-deploy.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index adc0e2d25c376..2b576089d71e7 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -217,7 +217,7 @@ jobs: needs: [build, get_info] # Run deploy job only if build job was successful or skipped if: | - always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && + always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false') runs-on: "ubuntu-latest" env: @@ -438,6 +438,8 @@ jobs: # Create template coder templates init --id kubernetes && cd ./kubernetes/ && coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} + #git clone https://github.com/matifali/coder-templates.git + #cd ./coder-templates/k8s-namespace/ && coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} # Create workspace cat < workspace.yaml From 3ffb0c8f5e61770ee0bfdced99cb31db21f1d941 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 12:19:30 +0000 Subject: [PATCH 02/69] add permission to create serviceaccounts --- .github/workflows/pr-deploy.yaml | 2 ++ helm/templates/rbac.yaml | 12 ++++++++++++ helm/values.yaml | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 2b576089d71e7..5cf1edc5c4755 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -338,6 +338,8 @@ jobs: enable: true secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls + serviceAccount: + serviceAccountPerms: true env: - name: "CODER_ACCESS_URL" value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}" diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index 3105e1a604b63..7d2fff4266044 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -41,6 +41,18 @@ rules: - patch - update - watch +{{- if .Values.coder.serviceAccount.serviceAccountPerms }} + - apiGroups: [""] + resources: ["serviceaccounts"] + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch {{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/helm/values.yaml b/helm/values.yaml index 43d317507d609..68d1445887b49 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -76,6 +76,10 @@ coder: # coder.serviceAccount.enableDeployments -- Provides the service account permission # to manage Kubernetes deployments. enableDeployments: true + # coder.serviceAccount.serviceAccountPerms -- Whether or not to grant the coder + # service account permissions to manage service accounts. This includes + # permission to manage service accounts in the deployment namespace. + serviceAccountPerms: false # coder.serviceAccount.annotations -- The Coder service account annotations. annotations: {} # coder.serviceAccount.name -- The service account name From 24f78d5b60ff4391c51ef73f0e39f8bea66598d9 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 12:23:14 +0000 Subject: [PATCH 03/69] refactor --- .github/workflows/pr-deploy.yaml | 2 +- helm/templates/rbac.yaml | 4 ++-- helm/values.yaml | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 5cf1edc5c4755..6747d9019fa11 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -339,7 +339,7 @@ jobs: secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls serviceAccount: - serviceAccountPerms: true + namespaceAccess: true env: - name: "CODER_ACCESS_URL" value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}" diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index 7d2fff4266044..8def492344b99 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -41,9 +41,9 @@ rules: - patch - update - watch -{{- if .Values.coder.serviceAccount.serviceAccountPerms }} +{{- if .Values.coder.serviceAccount.namespaceAccess }} - apiGroups: [""] - resources: ["serviceaccounts"] + resources: ["serviceaccounts", "roles", "rolebindings"] verbs: - create - delete diff --git a/helm/values.yaml b/helm/values.yaml index 68d1445887b49..fa76dd2603073 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -76,10 +76,8 @@ coder: # coder.serviceAccount.enableDeployments -- Provides the service account permission # to manage Kubernetes deployments. enableDeployments: true - # coder.serviceAccount.serviceAccountPerms -- Whether or not to grant the coder - # service account permissions to manage service accounts. This includes - # permission to manage service accounts in the deployment namespace. - serviceAccountPerms: false + # coder.serviceAccount.namespaceAccess -- Allow full access to the template namespace. + namespaceAccess: false # coder.serviceAccount.annotations -- The Coder service account annotations. annotations: {} # coder.serviceAccount.name -- The service account name From 52faafc233dbcbe3e7be553a873ea9c706a41507 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 12:34:43 +0000 Subject: [PATCH 04/69] lint --- helm/templates/rbac.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index 8def492344b99..d0942e83fbf5e 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -41,6 +41,7 @@ rules: - patch - update - watch +{{- end }} {{- if .Values.coder.serviceAccount.namespaceAccess }} - apiGroups: [""] resources: ["serviceaccounts", "roles", "rolebindings"] From 8b6ba6dae4e336172e592bc94a938e331af05328 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 12:42:08 +0000 Subject: [PATCH 05/69] only build if needed --- .github/workflows/pr-deploy.yaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 6747d9019fa11..648405fe3d894 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -158,11 +158,10 @@ jobs: build: needs: get_info # Skips the build job if the workflow was triggered by a workflow_dispatch event and the skip_build input is set to true - # or if the workflow was triggered by an issue_comment event and the comment body contains --skip-build # always run the build job if a pull_request event triggered the workflow if: | - (github.event_name == 'workflow_dispatch' && github.event.inputs.skip_build == 'false') || - (github.event_name == 'pull_request' && needs.get_info.result == 'success' && needs.get_info.outputs.NEW == 'false') + ((github.event_name == 'workflow_dispatch' && github.event.inputs.skip_build == 'false') || + github.event_name == 'pull_request') && needs.get_info.outputs.BUILD == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: DOCKER_CLI_EXPERIMENTAL: "enabled" @@ -177,19 +176,15 @@ jobs: fetch-depth: 0 - name: Setup Node - if: needs.get_info.outputs.BUILD == 'true' uses: ./.github/actions/setup-node - name: Setup Go - if: needs.get_info.outputs.BUILD == 'true' uses: ./.github/actions/setup-go - name: Setup sqlc - if: needs.get_info.outputs.BUILD == 'true' uses: ./.github/actions/setup-sqlc - name: GHCR Login - if: needs.get_info.outputs.BUILD == 'true' uses: docker/login-action@v2 with: registry: ghcr.io @@ -197,7 +192,6 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Linux amd64 Docker image - if: needs.get_info.outputs.BUILD == 'true' run: | set -euxo pipefail go mod download From f8121dd673f0daa971c31e33bcd12c6338a38eb4 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 6 Aug 2023 16:06:12 +0300 Subject: [PATCH 06/69] Discard changes to helm/templates/rbac.yaml --- helm/templates/rbac.yaml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml index d0942e83fbf5e..3105e1a604b63 100644 --- a/helm/templates/rbac.yaml +++ b/helm/templates/rbac.yaml @@ -42,19 +42,6 @@ rules: - update - watch {{- end }} -{{- if .Values.coder.serviceAccount.namespaceAccess }} - - apiGroups: [""] - resources: ["serviceaccounts", "roles", "rolebindings"] - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -{{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding From c633feccae05af69f6f826116d5752ad3622036d Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 6 Aug 2023 16:06:19 +0300 Subject: [PATCH 07/69] Discard changes to helm/values.yaml --- helm/values.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/helm/values.yaml b/helm/values.yaml index fa76dd2603073..43d317507d609 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -76,8 +76,6 @@ coder: # coder.serviceAccount.enableDeployments -- Provides the service account permission # to manage Kubernetes deployments. enableDeployments: true - # coder.serviceAccount.namespaceAccess -- Allow full access to the template namespace. - namespaceAccess: false # coder.serviceAccount.annotations -- The Coder service account annotations. annotations: {} # coder.serviceAccount.name -- The service account name From 51413ccb88a824c078938850837816dd17d4e209 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 13:28:21 +0000 Subject: [PATCH 08/69] refactor --- .github/workflows/pr-deploy.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 648405fe3d894..28c48c3da1d46 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -332,8 +332,6 @@ jobs: enable: true secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls - serviceAccount: - namespaceAccess: true env: - name: "CODER_ACCESS_URL" value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}" From 4d370f79a769f9c20c973d7419815ad9433bc695 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Sun, 6 Aug 2023 14:13:12 +0000 Subject: [PATCH 09/69] wip --- .github/workflows/pr-deploy.yaml | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 28c48c3da1d46..eb23f4d7e6a85 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -407,6 +407,48 @@ jobs: "${DEST}" version mv "${DEST}" /usr/local/bin/coder + - name: Create a service account, role and rolebinding for coder-workspace + if: needs.get_info.outputs.NEW == 'true' + # This service account will be used to grant full access to the namespace from the workspace + run: | + set -euxo pipefail + cat < Date: Mon, 7 Aug 2023 12:38:31 +0000 Subject: [PATCH 10/69] update --- .github/workflows/pr-deploy.yaml | 155 ++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index eb23f4d7e6a85..1a8fd3858510b 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -53,7 +53,7 @@ jobs: - name: Get PR number, title, and branch name id: pr_info run: | - set -euxo pipefail + set -e pipefail PR_NUMBER=${{ github.event.inputs.pr_number || github.event.pull_request.number }} PR_TITLE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.title') PR_BRANCH=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.head.ref') @@ -65,7 +65,7 @@ jobs: - name: Set required tags id: set_tags run: | - set -euxo pipefail + set -e pipefail echo "CODER_BASE_IMAGE_TAG=$CODER_BASE_IMAGE_TAG" >> $GITHUB_OUTPUT echo "CODER_IMAGE_TAG=$CODER_IMAGE_TAG" >> $GITHUB_OUTPUT env: @@ -74,7 +74,7 @@ jobs: - name: Set up kubeconfig run: | - set -euxo pipefail + set -e pipefail mkdir -p ~/.kube echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config export KUBECONFIG=~/.kube/config @@ -82,7 +82,7 @@ jobs: - name: Check if the helm deployment already exists id: check_deployment run: | - set -euxo pipefail + set -e pipefail if helm status "pr${{ steps.pr_info.outputs.PR_NUMBER }}" --namespace "pr${{ steps.pr_info.outputs.PR_NUMBER }}" > /dev/null 2>&1; then echo "Deployment already exists. Skipping deployment." new=false @@ -151,7 +151,7 @@ jobs: - name: Print number of changed files if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' run: | - set -euxo pipefail + set -e pipefail echo "Total number of changed files: ${{ steps.filter.outputs.all_count }}" echo "Number of ignored files: ${{ steps.filter.outputs.ignored_count }}" @@ -193,7 +193,7 @@ jobs: - name: Build and push Linux amd64 Docker image run: | - set -euxo pipefail + set -e pipefail go mod download make gen/mark-fresh export DOCKER_IMAGE_NO_PREREQUISITES=true @@ -224,7 +224,7 @@ jobs: steps: - name: Set up kubeconfig run: | - set -euxo pipefail + set -e pipefail mkdir -p ~/.kube echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config export KUBECONFIG=~/.kube/config @@ -232,7 +232,7 @@ jobs: - name: Check if image exists if: needs.get_info.outputs.NEW == 'true' run: | - set -euxo pipefail + set -e pipefail foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) if [ -z "$foundTag" ]; then echo "Image not found" @@ -257,7 +257,7 @@ jobs: - name: Create PR namespace if: needs.get_info.outputs.NEW == 'true' run: | - set -euxo pipefail + set -e pipefail # try to delete the namespace, but don't fail if it doesn't exist kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true kubectl create namespace "pr${{ env.PR_NUMBER }}" @@ -312,6 +312,90 @@ jobs: kubectl create secret generic coder-db-url -n pr${{ env.PR_NUMBER }} \ --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" + - name: Create a kubeconfig for the workspace + if: needs.get_info.outputs.NEW == 'true' + # This service account will be used to grant full access to the namespace from the workspace + run: | + set -e pipefail + # Create service account, role, rolebinding and secret + cat < namespace-kubeconfig.yaml + apiVersion: v1 + kind: Config + clusters: + - cluster: + certificate-authority-data: $CLUSTER_CA + server: $CLUSTER_ENDPOINT + name: pr${{ env.PR_NUMBER }} + contexts: + - context: + cluster: pr${{ env.PR_NUMBER }} + namespace: pr${{ env.PR_NUMBER }} + user: coder-workspace + name: pr${{ env.PR_NUMBER }} + current-context: pr${{ env.PR_NUMBER }} + users: + - name: coder-workspace + user: + token: $TOKEN + EOF + + # Create a secret from the kubeconfig + kubectl create secret generic coder-namespace-kubeconfig -n pr${{ env.PR_NUMBER }} --from-file=kubeconfig=./namespace-kubeconfig.yaml + - name: Create values.yaml if: github.event_name == 'workflow_dispatch' run: | @@ -332,6 +416,11 @@ jobs: enable: true secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls + volumeMounts: + - name: coder-namespace-kubeconfig + mountPath: /home/coder/.kube/config + subPath: kubeconfig + readOnly: true env: - name: "CODER_ACCESS_URL" value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}" @@ -356,7 +445,7 @@ jobs: - name: Install/Upgrade Helm chart run: | - set -euxo pipefail + set -e pipefail if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \ --namespace "pr${{ env.PR_NUMBER }}" \ @@ -384,7 +473,7 @@ jobs: - name: Get Coder binary if: needs.get_info.outputs.NEW == 'true' run: | - set -euxo pipefail + set -e pipefail DEST="${HOME}/coder" URL="https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}/bin/coder-linux-amd64" @@ -407,53 +496,11 @@ jobs: "${DEST}" version mv "${DEST}" /usr/local/bin/coder - - name: Create a service account, role and rolebinding for coder-workspace - if: needs.get_info.outputs.NEW == 'true' - # This service account will be used to grant full access to the namespace from the workspace - run: | - set -euxo pipefail - cat < Date: Mon, 7 Aug 2023 12:47:30 +0000 Subject: [PATCH 11/69] add volume --- .github/workflows/pr-deploy.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 1a8fd3858510b..20657cf8a7d42 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -416,6 +416,10 @@ jobs: enable: true secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls + volume: + - name: coder-namespace-kubeconfig + secret: + secretName: coder-namespace-kubeconfig volumeMounts: - name: coder-namespace-kubeconfig mountPath: /home/coder/.kube/config From b0aaa69f27eefdcf342dec3e8d769653f6a9903c Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Mon, 7 Aug 2023 12:51:49 +0000 Subject: [PATCH 12/69] set KUBECONFIG env variable --- .github/workflows/pr-deploy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 20657cf8a7d42..3610249dfa228 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -445,6 +445,8 @@ jobs: value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }}" - name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS" value: "coder" + - name: "KUBECONFIG" + value: "/home/coder/.kube/config" EOF - name: Install/Upgrade Helm chart From cc65580f6e32c8c7721232441e59f61e9e453ab6 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 08:24:20 +0000 Subject: [PATCH 13/69] remove `--skip-build` and add `--force` --- .github/workflows/pr-deploy.yaml | 17 +++++++---------- docs/CONTRIBUTING.md | 2 +- scripts/deploy-pr.sh | 26 +++++++------------------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 3610249dfa228..a380a094303a4 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -12,16 +12,16 @@ on: description: "PR number" type: number required: true - skip_build: - description: "Skip build job" - required: false - type: boolean - default: false experiments: description: "Experiments to enable" required: false type: string default: "*" + force: + description: "Force new build and deploy" + required: false + type: boolean + default: false env: REPO: ghcr.io/coder/coder-preview @@ -157,11 +157,8 @@ jobs: build: needs: get_info - # Skips the build job if the workflow was triggered by a workflow_dispatch event and the skip_build input is set to true - # always run the build job if a pull_request event triggered the workflow - if: | - ((github.event_name == 'workflow_dispatch' && github.event.inputs.skip_build == 'false') || - github.event_name == 'pull_request') && needs.get_info.outputs.BUILD == 'true' + # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --force + if: needs.get_info.outputs.BUILD == 'true' || github.event.inputs.force == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: DOCKER_CLI_EXPERIMENTAL: "enabled" diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index e794828520e81..bb0466c9b252b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -89,7 +89,7 @@ You can test your changes by creating a PR deployment. There are two ways to do #### Available options -- `-s` or `--skip-build`, force prevents the build of the Docker image.(generally not needed as we are intelligently checking if the image needs to be built) +- `-f` or `--force`, force builds the Docker image. (generally not needed as we are intelligently checking if the image needs to be built) - `-e EXPERIMENT1,EXPERIMENT2` or `--experiments EXPERIMENT1,EXPERIMENT2`, will enable the specified experiments. (defaults to `*`) - `-n` or `--dry-run` will display the context without deployment. e.g., branch name and PR number, etc. - `-y` or `--yes`, will skip the CLI confirmation prompt. diff --git a/scripts/deploy-pr.sh b/scripts/deploy-pr.sh index 84ee6ed6266f4..2650f3fd67945 100755 --- a/scripts/deploy-pr.sh +++ b/scripts/deploy-pr.sh @@ -1,21 +1,21 @@ #!/usr/bin/env bash -# Usage: ./deploy-pr.sh [--skip-build -s] [--dry-run -n] [--yes -y] +# Usage: ./deploy-pr.sh [--dry-run -n] [--yes -y] [--experiments -e ] [--force -f] # deploys the current branch to a PR environment and posts login credentials to # [#pr-deployments](https://codercom.slack.com/archives/C05DNE982E8) Slack channel set -euo pipefail # default settings -skipBuild=false dryRun=false confirm=true +force=false experiments="" # parse arguments while (("$#")); do case "$1" in - -s | --skip-build) - skipBuild=true + -f | --force) + force=true shift ;; -n | --dry-run) @@ -63,30 +63,18 @@ fi branchName=$(gh pr view --json headRefName | jq -r .headRefName) prNumber=$(gh pr view --json number | jq -r .number) -if $skipBuild; then - #check if the image exists - foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o "$prNumber" | head -n 1) || true - echo "foundTag is: '${foundTag}'" - if [[ -z "${foundTag}" ]]; then - echo "Image not found" - echo "${prNumber} tag not found in ghcr.io/coder/coder-preview" - echo "Please remove --skip-build and try again" - exit 1 - fi -fi - if $dryRun; then echo "dry run" echo "branchName: ${branchName}" echo "prNumber: ${prNumber}" - echo "skipBuild: ${skipBuild}" echo "experiments: ${experiments}" + echo "force: ${force}" exit 0 fi echo "branchName: ${branchName}" echo "prNumber: ${prNumber}" -echo "skipBuild: ${skipBuild}" echo "experiments: ${experiments}" +echo "force: ${force}" -gh workflow run pr-deploy.yaml --ref "${branchName}" -f "pr_number=${prNumber}" -f "skip_build=${skipBuild}" -f "experiments=${experiments}" +gh workflow run pr-deploy.yaml --ref "${branchName}" -f "pr_number=${prNumber}" -f "experiments=${experiments}" -f "force=${force}" From 003caf05b8b541d90954ce9340a1de71ee6cf0ed Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 08:40:25 +0000 Subject: [PATCH 14/69] typo --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index a380a094303a4..ef0db606603a7 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -413,7 +413,7 @@ jobs: enable: true secretName: pr${{ env.PR_NUMBER }}-tls wildcardSecretName: pr${{ env.PR_NUMBER }}-tls - volume: + volumes: - name: coder-namespace-kubeconfig secret: secretName: coder-namespace-kubeconfig From 24dc6ca264913c917c5e563be122a9a40407d1d7 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 08:53:13 +0000 Subject: [PATCH 15/69] test --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index ef0db606603a7..1d340726fee79 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -310,7 +310,7 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a kubeconfig for the workspace - if: needs.get_info.outputs.NEW == 'true' + # if: needs.get_info.outputs.NEW == 'true' uncomment this after testing # This service account will be used to grant full access to the namespace from the workspace run: | set -e pipefail From 3e95af79d39df440380347488bce036a8d47d078 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 09:59:39 +0000 Subject: [PATCH 16/69] use a custom template --- .github/workflows/pr-deploy.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 1d340726fee79..1eea8afcebdd7 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -442,8 +442,6 @@ jobs: value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }}" - name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS" value: "coder" - - name: "KUBECONFIG" - value: "/home/coder/.kube/config" EOF - name: Install/Upgrade Helm chart @@ -523,9 +521,8 @@ jobs: https://${{ env.PR_DEPLOYMENT_ACCESS_URL }} # Create template - coder templates init --id kubernetes && cd ./kubernetes/ && coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} - #git clone https://github.com/matifali/coder-templates.git - #cd ./coder-templates/k8s-namespace/ && coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} + git clone https://github.com/matifali/coder-templates.git && cd ./coder-templates/k8s-namespace/ + coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} # Create workspace cat < workspace.yaml @@ -534,7 +531,7 @@ jobs: home_disk_size: "2" EOF - coder create --template="kubernetes" test --rich-parameter-file ./workspace.yaml -y + coder create --template="k8s-namespace" test --rich-parameter-file ./workspace.yaml -y coder stop test -y - name: Send Slack notification From 4ff09662aa7dbd4c8a869d47b2cb37ceae6f9b3a Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 10:07:36 +0000 Subject: [PATCH 17/69] finalize --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 1eea8afcebdd7..4f5a9f3f59b5a 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -310,7 +310,7 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a kubeconfig for the workspace - # if: needs.get_info.outputs.NEW == 'true' uncomment this after testing + if: needs.get_info.outputs.NEW == 'true' # This service account will be used to grant full access to the namespace from the workspace run: | set -e pipefail From c64a7b4f99349dbd006e227786818fc9130dbd25 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 15:56:17 +0000 Subject: [PATCH 18/69] use `set -euo pipefail` --- .github/workflows/pr-deploy.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 4f5a9f3f59b5a..f4c05d997e6d7 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -53,7 +53,7 @@ jobs: - name: Get PR number, title, and branch name id: pr_info run: | - set -e pipefail + set -euo pipefail PR_NUMBER=${{ github.event.inputs.pr_number || github.event.pull_request.number }} PR_TITLE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.title') PR_BRANCH=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.head.ref') @@ -65,7 +65,7 @@ jobs: - name: Set required tags id: set_tags run: | - set -e pipefail + set -euo pipefail echo "CODER_BASE_IMAGE_TAG=$CODER_BASE_IMAGE_TAG" >> $GITHUB_OUTPUT echo "CODER_IMAGE_TAG=$CODER_IMAGE_TAG" >> $GITHUB_OUTPUT env: @@ -74,7 +74,7 @@ jobs: - name: Set up kubeconfig run: | - set -e pipefail + set -euo pipefail mkdir -p ~/.kube echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config export KUBECONFIG=~/.kube/config @@ -82,7 +82,7 @@ jobs: - name: Check if the helm deployment already exists id: check_deployment run: | - set -e pipefail + set -euo pipefail if helm status "pr${{ steps.pr_info.outputs.PR_NUMBER }}" --namespace "pr${{ steps.pr_info.outputs.PR_NUMBER }}" > /dev/null 2>&1; then echo "Deployment already exists. Skipping deployment." new=false @@ -151,7 +151,7 @@ jobs: - name: Print number of changed files if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' run: | - set -e pipefail + set -euo pipefail echo "Total number of changed files: ${{ steps.filter.outputs.all_count }}" echo "Number of ignored files: ${{ steps.filter.outputs.ignored_count }}" @@ -190,7 +190,7 @@ jobs: - name: Build and push Linux amd64 Docker image run: | - set -e pipefail + set -euo pipefail go mod download make gen/mark-fresh export DOCKER_IMAGE_NO_PREREQUISITES=true @@ -221,7 +221,7 @@ jobs: steps: - name: Set up kubeconfig run: | - set -e pipefail + set -euo pipefail mkdir -p ~/.kube echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config export KUBECONFIG=~/.kube/config @@ -229,7 +229,7 @@ jobs: - name: Check if image exists if: needs.get_info.outputs.NEW == 'true' run: | - set -e pipefail + set -euo pipefail foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) if [ -z "$foundTag" ]; then echo "Image not found" @@ -254,7 +254,7 @@ jobs: - name: Create PR namespace if: needs.get_info.outputs.NEW == 'true' run: | - set -e pipefail + set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true kubectl create namespace "pr${{ env.PR_NUMBER }}" @@ -313,7 +313,7 @@ jobs: if: needs.get_info.outputs.NEW == 'true' # This service account will be used to grant full access to the namespace from the workspace run: | - set -e pipefail + set -euo pipefail # Create service account, role, rolebinding and secret cat < Date: Tue, 8 Aug 2023 16:25:02 +0000 Subject: [PATCH 19/69] use `envsubst` --- .github/pr-deployments/certificate.yaml | 13 +++ .github/pr-deployments/kubeconfig.yaml | 18 ++++ .github/pr-deployments/rbac.yaml | 43 ++++++++ .github/pr-deployments/values.yaml | 45 ++++++++ .github/workflows/pr-deploy.yaml | 137 ++---------------------- 5 files changed, 128 insertions(+), 128 deletions(-) create mode 100644 .github/pr-deployments/certificate.yaml create mode 100644 .github/pr-deployments/kubeconfig.yaml create mode 100644 .github/pr-deployments/rbac.yaml create mode 100644 .github/pr-deployments/values.yaml diff --git a/.github/pr-deployments/certificate.yaml b/.github/pr-deployments/certificate.yaml new file mode 100644 index 0000000000000..f707762ca4ae0 --- /dev/null +++ b/.github/pr-deployments/certificate.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: pr${PR_NUMBER}-tls + namespace: pr-deployment-certs +spec: + secretName: pr${PR_NUMBER}-tls + issuerRef: + name: letsencrypt + kind: ClusterIssuer + dnsNames: + - "${PR_DEPLOYMENT_ACCESS_URL}" + - "*.{$PR_DEPLOYMENT_ACCESS_URL}" diff --git a/.github/pr-deployments/kubeconfig.yaml b/.github/pr-deployments/kubeconfig.yaml new file mode 100644 index 0000000000000..fc727fb77a45d --- /dev/null +++ b/.github/pr-deployments/kubeconfig.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + certificate-authority-data: $CLUSTER_CA + server: $CLUSTER_ENDPOINT + name: pr${PR_NUMBER} +contexts: +- context: + cluster: pr${PR_NUMBER} + namespace: pr${PR_NUMBER} + user: coder-workspace + name: pr${PR_NUMBER} +current-context: pr${PR_NUMBER} +users: +- name: coder-workspace + user: + token: $TOKEN diff --git a/.github/pr-deployments/rbac.yaml b/.github/pr-deployments/rbac.yaml new file mode 100644 index 0000000000000..1137c82062289 --- /dev/null +++ b/.github/pr-deployments/rbac.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: coder-workspace + namespace: pr${PR_NUMBER} +secrets: +- name: coder-workspace-token + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: coder-workspace + namespace: pr${PR_NUMBER} +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: coder-workspace + namespace: pr${PR_NUMBER} +subjects: +- kind: ServiceAccount + name: coder-workspace + namespace: pr${PR_NUMBER} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: coder-workspace + +--- +apiVersion: v1 +kind: Secret +metadata: + name: coder-workspace-token + namespace: pr${PR_NUMBER} + annotations: + kubernetes.io/service-account.name: coder-workspace +type: kubernetes.io/service-account-token diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml new file mode 100644 index 0000000000000..60b494051a911 --- /dev/null +++ b/.github/pr-deployments/values.yaml @@ -0,0 +1,45 @@ +coder: + image: + repo: ${REPO} + tag: pr${PR_NUMBER} + pullPolicy: Always + service: + type: ClusterIP + ingress: + enable: true + className: traefik + host: ${PR_DEPLOYMENT_ACCESS_URL} + wildcardHost: "*.${PR_DEPLOYMENT_ACCESS_URL}" + tls: + enable: true + secretName: pr${PR_NUMBER}-tls + wildcardSecretName: pr${PR_NUMBER}-tls + volumes: + - name: coder-namespace-kubeconfig + secret: + secretName: coder-namespace-kubeconfig + volumeMounts: + - name: coder-namespace-kubeconfig + mountPath: /home/coder/.kube/config + subPath: kubeconfig + readOnly: true + env: + - name: "CODER_ACCESS_URL" + value: "https://${PR_DEPLOYMENT_ACCESS_URL}" + - name: "CODER_WILDCARD_ACCESS_URL" + value: "*.${env.PR_DEPLOYMENT_ACCESS_URL}" + - name: "CODER_EXPERIMENTS" + value: "${EXPERIMENTS}" + - name: CODER_PG_CONNECTION_URL + valueFrom: + secretKeyRef: + name: coder-db-url + key: url + - name: "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS" + value: "true" + - name: "CODER_OAUTH2_GITHUB_CLIENT_ID" + value: "${PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID}" + - name: "CODER_OAUTH2_GITHUB_CLIENT_SECRET" + value: "${PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET}" + - name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS" + value: "coder" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index f4c05d997e6d7..aaf301fdacc04 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -266,21 +266,7 @@ jobs: # we are doing this to avoid letsenrypt rate limits if ! kubectl get certificate pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs > /dev/null 2>&1; then echo "Certificate doesn't exist. Creating a new one." - cat < namespace-kubeconfig.yaml - apiVersion: v1 - kind: Config - clusters: - - cluster: - certificate-authority-data: $CLUSTER_CA - server: $CLUSTER_ENDPOINT - name: pr${{ env.PR_NUMBER }} - contexts: - - context: - cluster: pr${{ env.PR_NUMBER }} - namespace: pr${{ env.PR_NUMBER }} - user: coder-workspace - name: pr${{ env.PR_NUMBER }} - current-context: pr${{ env.PR_NUMBER }} - users: - - name: coder-workspace - user: - token: $TOKEN - EOF + envsubst < ./.github/pr-deployments/kubeconfig.yaml > ./namespace-kubeconfig.yaml # Create a secret from the kubeconfig kubectl create secret generic coder-namespace-kubeconfig -n pr${{ env.PR_NUMBER }} --from-file=kubeconfig=./namespace-kubeconfig.yaml - name: Create values.yaml if: github.event_name == 'workflow_dispatch' + env: + EXPERIMENTS: ${{ github.event.inputs.experiments }} + PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID: ${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID }} + PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET: ${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }} run: | - cat < pr-deploy-values.yaml - coder: - image: - repo: ${{ env.REPO }} - tag: pr${{ env.PR_NUMBER }} - pullPolicy: Always - service: - type: ClusterIP - ingress: - enable: true - className: traefik - host: ${{ env.PR_DEPLOYMENT_ACCESS_URL }} - wildcardHost: "*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}" - tls: - enable: true - secretName: pr${{ env.PR_NUMBER }}-tls - wildcardSecretName: pr${{ env.PR_NUMBER }}-tls - volumes: - - name: coder-namespace-kubeconfig - secret: - secretName: coder-namespace-kubeconfig - volumeMounts: - - name: coder-namespace-kubeconfig - mountPath: /home/coder/.kube/config - subPath: kubeconfig - readOnly: true - env: - - name: "CODER_ACCESS_URL" - value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}" - - name: "CODER_WILDCARD_ACCESS_URL" - value: "*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}" - - name: "CODER_EXPERIMENTS" - value: "${{ github.event.inputs.experiments }}" - - name: CODER_PG_CONNECTION_URL - valueFrom: - secretKeyRef: - name: coder-db-url - key: url - - name: "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS" - value: "true" - - name: "CODER_OAUTH2_GITHUB_CLIENT_ID" - value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID }}" - - name: "CODER_OAUTH2_GITHUB_CLIENT_SECRET" - value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }}" - - name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS" - value: "coder" - EOF + set -euo pipefail + envsubst < ./.github/pr-deployments/values.yaml > ./pr-deploy-values.yaml - name: Install/Upgrade Helm chart run: | From 9fa3d6799053cb243f380d3cf17c1b071b1217aa Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 8 Aug 2023 16:30:35 +0000 Subject: [PATCH 20/69] fmt --- .github/pr-deployments/certificate.yaml | 4 ++-- .github/pr-deployments/kubeconfig.yaml | 24 ++++++++++++------------ .github/pr-deployments/rbac.yaml | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/pr-deployments/certificate.yaml b/.github/pr-deployments/certificate.yaml index f707762ca4ae0..2476b88990942 100644 --- a/.github/pr-deployments/certificate.yaml +++ b/.github/pr-deployments/certificate.yaml @@ -9,5 +9,5 @@ spec: name: letsencrypt kind: ClusterIssuer dnsNames: - - "${PR_DEPLOYMENT_ACCESS_URL}" - - "*.{$PR_DEPLOYMENT_ACCESS_URL}" + - "${PR_DEPLOYMENT_ACCESS_URL}" + - "*.{$PR_DEPLOYMENT_ACCESS_URL}" diff --git a/.github/pr-deployments/kubeconfig.yaml b/.github/pr-deployments/kubeconfig.yaml index fc727fb77a45d..92057ef21e921 100644 --- a/.github/pr-deployments/kubeconfig.yaml +++ b/.github/pr-deployments/kubeconfig.yaml @@ -1,18 +1,18 @@ apiVersion: v1 kind: Config clusters: -- cluster: - certificate-authority-data: $CLUSTER_CA - server: $CLUSTER_ENDPOINT - name: pr${PR_NUMBER} + - cluster: + certificate-authority-data: $CLUSTER_CA + server: $CLUSTER_ENDPOINT + name: pr${PR_NUMBER} contexts: -- context: - cluster: pr${PR_NUMBER} - namespace: pr${PR_NUMBER} - user: coder-workspace - name: pr${PR_NUMBER} + - context: + cluster: pr${PR_NUMBER} + namespace: pr${PR_NUMBER} + user: coder-workspace + name: pr${PR_NUMBER} current-context: pr${PR_NUMBER} users: -- name: coder-workspace - user: - token: $TOKEN + - name: coder-workspace + user: + token: $TOKEN diff --git a/.github/pr-deployments/rbac.yaml b/.github/pr-deployments/rbac.yaml index 1137c82062289..7d3d666f196d2 100644 --- a/.github/pr-deployments/rbac.yaml +++ b/.github/pr-deployments/rbac.yaml @@ -4,7 +4,7 @@ metadata: name: coder-workspace namespace: pr${PR_NUMBER} secrets: -- name: coder-workspace-token + - name: coder-workspace-token --- apiVersion: rbac.authorization.k8s.io/v1 @@ -13,9 +13,9 @@ metadata: name: coder-workspace namespace: pr${PR_NUMBER} rules: -- apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] --- apiVersion: rbac.authorization.k8s.io/v1 @@ -24,9 +24,9 @@ metadata: name: coder-workspace namespace: pr${PR_NUMBER} subjects: -- kind: ServiceAccount - name: coder-workspace - namespace: pr${PR_NUMBER} + - kind: ServiceAccount + name: coder-workspace + namespace: pr${PR_NUMBER} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role From 3403530ff106c52f2fa0a2c58c90dd4bf87da71b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 05:47:59 +0000 Subject: [PATCH 21/69] fix typos --- .github/pr-deployments/certificate.yaml | 2 +- .github/pr-deployments/values.yaml | 2 +- .github/workflows/pr-deploy.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/pr-deployments/certificate.yaml b/.github/pr-deployments/certificate.yaml index 2476b88990942..c61d6ec61a664 100644 --- a/.github/pr-deployments/certificate.yaml +++ b/.github/pr-deployments/certificate.yaml @@ -10,4 +10,4 @@ spec: kind: ClusterIssuer dnsNames: - "${PR_DEPLOYMENT_ACCESS_URL}" - - "*.{$PR_DEPLOYMENT_ACCESS_URL}" + - "*.${PR_DEPLOYMENT_ACCESS_URL}" diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index 60b494051a911..8a9fe6b8992e6 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -27,7 +27,7 @@ coder: - name: "CODER_ACCESS_URL" value: "https://${PR_DEPLOYMENT_ACCESS_URL}" - name: "CODER_WILDCARD_ACCESS_URL" - value: "*.${env.PR_DEPLOYMENT_ACCESS_URL}" + value: "*.${PR_DEPLOYMENT_ACCESS_URL}" - name: "CODER_EXPERIMENTS" value: "${EXPERIMENTS}" - name: CODER_PG_CONNECTION_URL diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index aaf301fdacc04..73777f840f96c 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -300,7 +300,7 @@ jobs: run: | set -euo pipefail # Create service account, role, rolebinding and secret - envsubst < ./.github/pr-deployments/rbac.yaml | kubectl -n pr${{ env.PR_NUMBER }} apply -f - + envsubst < ./.github/pr-deployments/rbac.yaml | kubectl apply -f - # Get the token for the service account TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) From fdbdf20b994731b19a42675f2d461f45c720fac2 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 05:48:12 +0000 Subject: [PATCH 22/69] add template --- .github/pr-deployments/kubernetes/main.tf | 346 ++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 .github/pr-deployments/kubernetes/main.tf diff --git a/.github/pr-deployments/kubernetes/main.tf b/.github/pr-deployments/kubernetes/main.tf new file mode 100644 index 0000000000000..d5ddf7deec682 --- /dev/null +++ b/.github/pr-deployments/kubernetes/main.tf @@ -0,0 +1,346 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "~> 0.11.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.22" + } + } +} + +provider "coder" { +} + +variable "use_kubeconfig" { + type = bool + description = <<-EOF + Use host kubeconfig? (true/false) + + Set this to false if the Coder host is itself running as a Pod on the same + Kubernetes cluster as you are deploying workspaces to. + + Set this to true if the Coder host is running outside the Kubernetes cluster + for workspaces. A valid "~/.kube/config" must be present on the Coder host. + EOF + default = false +} + +variable "namespace" { + type = string + description = "The Kubernetes namespace to create workspaces in (must exist prior to creating workspaces)" +} + +data "coder_parameter" "cpu" { + name = "cpu" + display_name = "CPU" + description = "The number of CPU cores" + default = "2" + icon = "/icon/memory.svg" + mutable = true + option { + name = "2 Cores" + value = "2" + } + option { + name = "4 Cores" + value = "4" + } + option { + name = "6 Cores" + value = "6" + } + option { + name = "8 Cores" + value = "8" + } +} + +data "coder_parameter" "memory" { + name = "memory" + display_name = "Memory" + description = "The amount of memory in GB" + default = "2" + icon = "/icon/memory.svg" + mutable = true + option { + name = "2 GB" + value = "2" + } + option { + name = "4 GB" + value = "4" + } + option { + name = "6 GB" + value = "6" + } + option { + name = "8 GB" + value = "8" + } +} + +data "coder_parameter" "home_disk_size" { + name = "home_disk_size" + display_name = "Home disk size" + description = "The size of the home disk in GB" + default = "10" + type = "number" + icon = "/emojis/1f4be.png" + mutable = false + validation { + min = 1 + max = 99999 + } +} + +provider "kubernetes" { + # Authenticate via ~/.kube/config or a Coder-specific ServiceAccount, depending on admin preferences + config_path = var.use_kubeconfig == true ? "~/.kube/config" : null +} + +data "coder_workspace" "me" {} + +resource "coder_agent" "main" { + os = "linux" + arch = "amd64" + startup_script_timeout = 180 + startup_script = <<-EOT + set -e + + # install and start code-server + curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.11.0 + + # Set KUBECONFIG env var to the path of the mounted secret + mkdir -p /home/coder/.kube + sudo cp /tmp/config /home/coder/.kube/config + export KUBECONFIG=/home/coder/.kube/config + + EOT + + # The following metadata blocks are optional. They are used to display + # information about your workspace in the dashboard. You can remove them + # if you don't want to display any information. + # For basic resources, you can use the `coder stat` command. + # If you need more control, you can write your own script. + metadata { + display_name = "CPU Usage" + key = "0_cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "1_ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Home Disk" + key = "3_home_disk" + script = "coder stat disk --path $${HOME}" + interval = 60 + timeout = 1 + } + + metadata { + display_name = "CPU Usage (Host)" + key = "4_cpu_usage_host" + script = "coder stat cpu --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Memory Usage (Host)" + key = "5_mem_usage_host" + script = "coder stat mem --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Load Average (Host)" + key = "6_load_host" + # get load avg scaled by number of cores + script = < Date: Wed, 9 Aug 2023 06:00:32 +0000 Subject: [PATCH 23/69] use the included template --- .github/pr-deployments/{kubernetes => template}/main.tf | 0 .github/workflows/pr-deploy.yaml | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename .github/pr-deployments/{kubernetes => template}/main.tf (100%) diff --git a/.github/pr-deployments/kubernetes/main.tf b/.github/pr-deployments/template/main.tf similarity index 100% rename from .github/pr-deployments/kubernetes/main.tf rename to .github/pr-deployments/template/main.tf diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 73777f840f96c..e1625b54935e4 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -402,8 +402,8 @@ jobs: https://${{ env.PR_DEPLOYMENT_ACCESS_URL }} # Create template - git clone https://github.com/matifali/coder-templates.git && cd ./coder-templates/k8s-namespace/ - coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} + cd ./.github/pr-deployments/template + coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} kubernetes # Create workspace cat < workspace.yaml @@ -412,8 +412,8 @@ jobs: home_disk_size: "2" EOF - coder create --template="k8s-namespace" test --rich-parameter-file ./workspace.yaml -y - coder stop test -y + coder create --template="kubernetes" kube --rich-parameter-file ./workspace.yaml -y + coder stop kube -y - name: Send Slack notification if: needs.get_info.outputs.NEW == 'true' From 27c175c1588afa2a97bb954052bfbc6ac7a15b9c Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 06:16:56 +0000 Subject: [PATCH 24/69] update --- .github/workflows/pr-deploy.yaml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index e1625b54935e4..0e3bfc998f04f 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -46,7 +46,7 @@ jobs: CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }} CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }} NEW: ${{ steps.check_deployment.outputs.new }} - BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new }} + BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new || github.event.inputs.force == 'true' }} runs-on: "ubuntu-latest" steps: @@ -158,7 +158,7 @@ jobs: build: needs: get_info # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --force - if: needs.get_info.outputs.BUILD == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.BUILD == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: DOCKER_CLI_EXPERIMENTAL: "enabled" @@ -227,19 +227,18 @@ jobs: export KUBECONFIG=~/.kube/config - name: Check if image exists - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | set -euo pipefail foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) if [ -z "$foundTag" ]; then echo "Image not found" echo "${{ env.CODER_IMAGE_TAG }} not found in ghcr.io/coder/coder-preview" - echo "Please remove --skip-build from the comment and try again" exit 1 fi - name: Add DNS record to Cloudflare - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ @@ -252,7 +251,7 @@ jobs: ref: ${{ env.PR_BRANCH }} - name: Create PR namespace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist @@ -260,7 +259,7 @@ jobs: kubectl create namespace "pr${{ env.PR_NUMBER }}" - name: Check and Create Certificate - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | # Using kubectl to check if a Certificate resource already exists # we are doing this to avoid letsenrypt rate limits @@ -283,7 +282,7 @@ jobs: ) - name: Set up PostgreSQL database - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | helm repo add bitnami https://charts.bitnami.com/bitnami helm install coder-db bitnami/postgresql \ @@ -296,7 +295,7 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a kubeconfig for the workspace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | set -euo pipefail # Create service account, role, rolebinding and secret @@ -345,7 +344,7 @@ jobs: fi - name: Install coder-logstream-kube - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ @@ -353,7 +352,7 @@ jobs: --set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" - name: Get Coder binary - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | set -euo pipefail @@ -379,7 +378,7 @@ jobs: mv "${DEST}" /usr/local/bin/coder - name: Create first user, template and workspace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' id: setup_deployment run: | set -euo pipefail @@ -416,7 +415,7 @@ jobs: coder stop kube -y - name: Send Slack notification - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' run: | curl -s -o /dev/null -X POST -H 'Content-type: application/json' \ -d \ From 0ec9c8ae6a61bee59df6720d1e3a2db5f723808d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 06:28:05 +0000 Subject: [PATCH 25/69] separate build and deploy --- .github/pr-deployments/kubeconfig.yaml | 6 ++-- .github/workflows/pr-deploy.yaml | 39 +++++++++++++++----------- scripts/deploy-pr.sh | 21 +++++++++----- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.github/pr-deployments/kubeconfig.yaml b/.github/pr-deployments/kubeconfig.yaml index 92057ef21e921..6a19c85df685f 100644 --- a/.github/pr-deployments/kubeconfig.yaml +++ b/.github/pr-deployments/kubeconfig.yaml @@ -2,8 +2,8 @@ apiVersion: v1 kind: Config clusters: - cluster: - certificate-authority-data: $CLUSTER_CA - server: $CLUSTER_ENDPOINT + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_ENDPOINT} name: pr${PR_NUMBER} contexts: - context: @@ -15,4 +15,4 @@ current-context: pr${PR_NUMBER} users: - name: coder-workspace user: - token: $TOKEN + token: ${TOKEN} diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 0e3bfc998f04f..221b5e7b0a766 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -17,8 +17,13 @@ on: required: false type: string default: "*" - force: - description: "Force new build and deploy" + build: + description: "Force new build" + required: false + type: boolean + default: false + deploy: + description: "Force new deployment" required: false type: boolean default: false @@ -46,7 +51,7 @@ jobs: CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }} CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }} NEW: ${{ steps.check_deployment.outputs.new }} - BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new || github.event.inputs.force == 'true' }} + BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new || github.event.inputs.build == 'true' }} runs-on: "ubuntu-latest" steps: @@ -209,7 +214,7 @@ jobs: # Run deploy job only if build job was successful or skipped if: | always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && - (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false') + (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false' || github.event.inputs.deploy == 'true') runs-on: "ubuntu-latest" env: CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }} @@ -227,7 +232,7 @@ jobs: export KUBECONFIG=~/.kube/config - name: Check if image exists - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) @@ -238,7 +243,7 @@ jobs: fi - name: Add DNS record to Cloudflare - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ @@ -251,7 +256,7 @@ jobs: ref: ${{ env.PR_BRANCH }} - name: Create PR namespace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist @@ -259,7 +264,7 @@ jobs: kubectl create namespace "pr${{ env.PR_NUMBER }}" - name: Check and Create Certificate - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | # Using kubectl to check if a Certificate resource already exists # we are doing this to avoid letsenrypt rate limits @@ -282,7 +287,7 @@ jobs: ) - name: Set up PostgreSQL database - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add bitnami https://charts.bitnami.com/bitnami helm install coder-db bitnami/postgresql \ @@ -295,18 +300,18 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a kubeconfig for the workspace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # Create service account, role, rolebinding and secret envsubst < ./.github/pr-deployments/rbac.yaml | kubectl apply -f - # Get the token for the service account - TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) + export TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) # get CLUSTER_CA and CLUSTER_ENDPOINT - CLUSTER_CA=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}') - CLUSTER_ENDPOINT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}') + export CLUSTER_CA=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}') + export CLUSTER_ENDPOINT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}') # Create a kubeconfig for the namespace to be used in the workspace envsubst < ./.github/pr-deployments/kubeconfig.yaml > ./namespace-kubeconfig.yaml @@ -344,7 +349,7 @@ jobs: fi - name: Install coder-logstream-kube - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ @@ -352,7 +357,7 @@ jobs: --set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" - name: Get Coder binary - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail @@ -378,7 +383,7 @@ jobs: mv "${DEST}" /usr/local/bin/coder - name: Create first user, template and workspace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' id: setup_deployment run: | set -euo pipefail @@ -415,7 +420,7 @@ jobs: coder stop kube -y - name: Send Slack notification - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.force == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | curl -s -o /dev/null -X POST -H 'Content-type: application/json' \ -d \ diff --git a/scripts/deploy-pr.sh b/scripts/deploy-pr.sh index 2650f3fd67945..15d48dda7c7e7 100755 --- a/scripts/deploy-pr.sh +++ b/scripts/deploy-pr.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Usage: ./deploy-pr.sh [--dry-run -n] [--yes -y] [--experiments -e ] [--force -f] +# Usage: ./deploy-pr.sh [--dry-run -n] [--yes -y] [--experiments -e ] [--build -b] [--deploy -d] # deploys the current branch to a PR environment and posts login credentials to # [#pr-deployments](https://codercom.slack.com/archives/C05DNE982E8) Slack channel @@ -8,14 +8,19 @@ set -euo pipefail # default settings dryRun=false confirm=true -force=false +build=false +deploy=false experiments="" # parse arguments while (("$#")); do case "$1" in - -f | --force) - force=true + -b | --build) + build=true + shift + ;; + -d | --deploy) + deploy=true shift ;; -n | --dry-run) @@ -68,13 +73,15 @@ if $dryRun; then echo "branchName: ${branchName}" echo "prNumber: ${prNumber}" echo "experiments: ${experiments}" - echo "force: ${force}" + echo "build: ${build}" + echo "deploy: ${deploy}" exit 0 fi echo "branchName: ${branchName}" echo "prNumber: ${prNumber}" echo "experiments: ${experiments}" -echo "force: ${force}" +echo "build: ${build}" +echo "deploy: ${deploy}" -gh workflow run pr-deploy.yaml --ref "${branchName}" -f "pr_number=${prNumber}" -f "experiments=${experiments}" -f "force=${force}" +gh workflow run pr-deploy.yaml --ref "${branchName}" -f "pr_number=${prNumber}" -f "experiments=${experiments}" -f "build=${build}" -f "deploy=${deploy}" From 219a44bddee24f8d246f6d3b05b066c383a5d5cd Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 06:30:37 +0000 Subject: [PATCH 26/69] do not force certificate creation --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 221b5e7b0a766..67e08ac317fe8 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -243,7 +243,7 @@ jobs: fi - name: Add DNS record to Cloudflare - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' + if: needs.get_info.outputs.NEW == 'true' run: | curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ From c5cbd1667338c8efe61e793af26b66d8de6c5f58 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 06:37:36 +0000 Subject: [PATCH 27/69] update docs --- docs/CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 4b8c03ab59aa4..801f82bdbf5d4 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -88,7 +88,8 @@ You can test your changes by creating a PR deployment. There are two ways to do #### Available options -- `-f` or `--force`, force builds the Docker image. (generally not needed as we are intelligently checking if the image needs to be built) +- `-d` or `--deploy`, force deploys the PR by deleting the existing deployment. +- `-b` or `--build`, force builds the Docker image. (generally not needed as we are intelligently checking if the image needs to be built) - `-e EXPERIMENT1,EXPERIMENT2` or `--experiments EXPERIMENT1,EXPERIMENT2`, will enable the specified experiments. (defaults to `*`) - `-n` or `--dry-run` will display the context without deployment. e.g., branch name and PR number, etc. - `-y` or `--yes`, will skip the CLI confirmation prompt. From 2ac3378308ada4b663fa29ba4d0c764d4c2e5850 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 06:50:22 +0000 Subject: [PATCH 28/69] fix template --- .github/pr-deployments/template/main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/pr-deployments/template/main.tf b/.github/pr-deployments/template/main.tf index d5ddf7deec682..04d2d49b971e4 100644 --- a/.github/pr-deployments/template/main.tf +++ b/.github/pr-deployments/template/main.tf @@ -112,7 +112,8 @@ resource "coder_agent" "main" { set -e # install and start code-server - curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.11.0 + curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server + /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 & # Set KUBECONFIG env var to the path of the mounted secret mkdir -p /home/coder/.kube From 1f3c2e2e80dadc5a9151ef602cf8f4c3c9a8047e Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:05:42 +0000 Subject: [PATCH 29/69] use HOSTNAME --- .github/pr-deployments/certificate.yaml | 4 ++-- .github/workflows/pr-deploy.yaml | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/pr-deployments/certificate.yaml b/.github/pr-deployments/certificate.yaml index c61d6ec61a664..181ae7dd34f71 100644 --- a/.github/pr-deployments/certificate.yaml +++ b/.github/pr-deployments/certificate.yaml @@ -9,5 +9,5 @@ spec: name: letsencrypt kind: ClusterIssuer dnsNames: - - "${PR_DEPLOYMENT_ACCESS_URL}" - - "*.${PR_DEPLOYMENT_ACCESS_URL}" + - "${HOSTNAME}" + - "*.${HOSTNAME}" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 67e08ac317fe8..21195593c1d83 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -222,7 +222,7 @@ jobs: PR_TITLE: ${{ needs.get_info.outputs.PR_TITLE }} PR_URL: ${{ needs.get_info.outputs.PR_URL }} PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }} - PR_DEPLOYMENT_ACCESS_URL: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" + HOSTNAME: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" steps: - name: Set up kubeconfig run: | @@ -248,7 +248,7 @@ jobs: curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ -H "Content-Type:application/json" \ - --data '{"type":"CNAME","name":"*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}","content":"${{ env.PR_DEPLOYMENT_ACCESS_URL }}","ttl":1,"proxied":false}' + --data '{"type":"CNAME","name":"*.${{ env.HOSTNAME }}","content":"${{ env.HOSTNAME }}","ttl":1,"proxied":false}' - name: Checkout uses: actions/checkout@v3 @@ -362,7 +362,7 @@ jobs: set -euo pipefail DEST="${HOME}/coder" - URL="https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}/bin/coder-linux-amd64" + URL="https://${{ env.HOSTNAME }}/bin/coder-linux-amd64" mkdir -p "$(dirname ${DEST})" @@ -403,7 +403,7 @@ jobs: --first-user-password $password \ --first-user-trial \ --use-token-as-session \ - https://${{ env.PR_DEPLOYMENT_ACCESS_URL }} + https://${{ env.HOSTNAME }} # Create template cd ./.github/pr-deployments/template @@ -428,7 +428,7 @@ jobs: "pr_number": "'"${{ env.PR_NUMBER }}"'", "pr_url": "'"${{ env.PR_URL }}"'", "pr_title": "'"${{ env.PR_TITLE }}"'", - "pr_access_url": "'"https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}"'", + "pr_access_url": "'"https://${{ env.HOSTNAME }}"'", "pr_username": "'"test"'", "pr_email": "'"pr${{ env.PR_NUMBER }}@coder.com"'", "pr_password": "'"${{ steps.setup_deployment.outputs.password }}"'", From d3f57b0295e5af82a6d547855a0516a4d614d813 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:07:51 +0000 Subject: [PATCH 30/69] use better condition --- scripts/deploy-pr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy-pr.sh b/scripts/deploy-pr.sh index 15d48dda7c7e7..e852368fd8bbe 100755 --- a/scripts/deploy-pr.sh +++ b/scripts/deploy-pr.sh @@ -68,7 +68,7 @@ fi branchName=$(gh pr view --json headRefName | jq -r .headRefName) prNumber=$(gh pr view --json number | jq -r .number) -if $dryRun; then +if [[ "$dryRun" = true ]]; then echo "dry run" echo "branchName: ${branchName}" echo "prNumber: ${prNumber}" From 296d352a94bd399c03a51a763aab7cc6c131553d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:32:19 +0000 Subject: [PATCH 31/69] test `service_account_name` --- .github/pr-deployments/rbac.yaml | 32 ++++++++++++------------- .github/pr-deployments/template/main.tf | 9 +++---- .github/pr-deployments/values.yaml | 18 +++++++------- .github/workflows/pr-deploy.yaml | 20 ++++++++-------- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/.github/pr-deployments/rbac.yaml b/.github/pr-deployments/rbac.yaml index 7d3d666f196d2..bad02e6b250b8 100644 --- a/.github/pr-deployments/rbac.yaml +++ b/.github/pr-deployments/rbac.yaml @@ -1,16 +1,16 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: coder-workspace + name: coder-workspace-pr${PR_NUMBER} namespace: pr${PR_NUMBER} -secrets: - - name: coder-workspace-token +# secrets: +# - name: coder-workspace-token --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: coder-workspace + name: coder-workspace-pr${PR_NUMBER} namespace: pr${PR_NUMBER} rules: - apiGroups: ["*"] @@ -21,23 +21,23 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: coder-workspace + name: coder-workspace-pr${PR_NUMBER} namespace: pr${PR_NUMBER} subjects: - kind: ServiceAccount - name: coder-workspace + name: coder-workspace-pr${PR_NUMBER} namespace: pr${PR_NUMBER} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: coder-workspace + name: coder-workspace-pr${PR_NUMBER} ---- -apiVersion: v1 -kind: Secret -metadata: - name: coder-workspace-token - namespace: pr${PR_NUMBER} - annotations: - kubernetes.io/service-account.name: coder-workspace -type: kubernetes.io/service-account-token +# --- +# apiVersion: v1 +# kind: Secret +# metadata: +# name: coder-workspace-token-pr${PR_NUMBER} +# namespace: pr${PR_NUMBER} +# annotations: +# kubernetes.io/service-account.name: coder-workspace +# type: kubernetes.io/service-account-token diff --git a/.github/pr-deployments/template/main.tf b/.github/pr-deployments/template/main.tf index 04d2d49b971e4..36ad75763fd99 100644 --- a/.github/pr-deployments/template/main.tf +++ b/.github/pr-deployments/template/main.tf @@ -115,10 +115,10 @@ resource "coder_agent" "main" { curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 & - # Set KUBECONFIG env var to the path of the mounted secret - mkdir -p /home/coder/.kube - sudo cp /tmp/config /home/coder/.kube/config - export KUBECONFIG=/home/coder/.kube/config + # # Set KUBECONFIG env var to the path of the mounted secret + # mkdir -p /home/coder/.kube + # sudo cp /tmp/config /home/coder/.kube/config + # export KUBECONFIG=/home/coder/.kube/config EOT @@ -271,6 +271,7 @@ resource "kubernetes_deployment" "main" { fs_group = 1000 } + service_account_name = "coder-workspace-${var.namespace}" container { name = "dev" image = "bencdr/devops-tools" diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index 8a9fe6b8992e6..8e96d47f73124 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -14,15 +14,15 @@ coder: enable: true secretName: pr${PR_NUMBER}-tls wildcardSecretName: pr${PR_NUMBER}-tls - volumes: - - name: coder-namespace-kubeconfig - secret: - secretName: coder-namespace-kubeconfig - volumeMounts: - - name: coder-namespace-kubeconfig - mountPath: /home/coder/.kube/config - subPath: kubeconfig - readOnly: true + # volumes: + # - name: coder-namespace-kubeconfig + # secret: + # secretName: coder-namespace-kubeconfig + # volumeMounts: + # - name: coder-namespace-kubeconfig + # mountPath: /home/coder/.kube/config + # subPath: kubeconfig + # readOnly: true env: - name: "CODER_ACCESS_URL" value: "https://${PR_DEPLOYMENT_ACCESS_URL}" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 21195593c1d83..fa93f628809f0 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -303,21 +303,21 @@ jobs: if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail - # Create service account, role, rolebinding and secret + # Create service account, role, rolebinding envsubst < ./.github/pr-deployments/rbac.yaml | kubectl apply -f - - # Get the token for the service account - export TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) + # # Get the token for the service account + # export TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) - # get CLUSTER_CA and CLUSTER_ENDPOINT - export CLUSTER_CA=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}') - export CLUSTER_ENDPOINT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}') + # # get CLUSTER_CA and CLUSTER_ENDPOINT + # export CLUSTER_CA=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}') + # export CLUSTER_ENDPOINT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}') - # Create a kubeconfig for the namespace to be used in the workspace - envsubst < ./.github/pr-deployments/kubeconfig.yaml > ./namespace-kubeconfig.yaml + # # Create a kubeconfig for the namespace to be used in the workspace + # envsubst < ./.github/pr-deployments/kubeconfig.yaml > ./namespace-kubeconfig.yaml - # Create a secret from the kubeconfig - kubectl create secret generic coder-namespace-kubeconfig -n pr${{ env.PR_NUMBER }} --from-file=kubeconfig=./namespace-kubeconfig.yaml + # # Create a secret from the kubeconfig + # kubectl create secret generic coder-namespace-kubeconfig -n pr${{ env.PR_NUMBER }} --from-file=kubeconfig=./namespace-kubeconfig.yaml - name: Create values.yaml if: github.event_name == 'workflow_dispatch' From de998be95f046095ccb889bd98d4362b136e05fd Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:33:14 +0000 Subject: [PATCH 32/69] make fmt --- .github/pr-deployments/rbac.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/pr-deployments/rbac.yaml b/.github/pr-deployments/rbac.yaml index bad02e6b250b8..b7860626ce3d7 100644 --- a/.github/pr-deployments/rbac.yaml +++ b/.github/pr-deployments/rbac.yaml @@ -31,7 +31,6 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: coder-workspace-pr${PR_NUMBER} - # --- # apiVersion: v1 # kind: Secret From 0a9eeebf4c911b5dc3b6d1fd13dd9e412a58d20c Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:34:48 +0000 Subject: [PATCH 33/69] remove volumes --- .github/pr-deployments/template/main.tf | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/pr-deployments/template/main.tf b/.github/pr-deployments/template/main.tf index 36ad75763fd99..7035ff7c64375 100644 --- a/.github/pr-deployments/template/main.tf +++ b/.github/pr-deployments/template/main.tf @@ -299,12 +299,12 @@ resource "kubernetes_deployment" "main" { name = "home" read_only = false } - volume_mount { - mount_path = "/tmp/config" - sub_path = "kubeconfig" - name = "kubeconfig" - read_only = true - } + # volume_mount { + # mount_path = "/tmp/config" + # sub_path = "kubeconfig" + # name = "kubeconfig" + # read_only = true + # } } volume { @@ -316,12 +316,12 @@ resource "kubernetes_deployment" "main" { } # mount kubeconfig secret as a volume to /home/coder/.kube/config - volume { - name = "kubeconfig" - secret { - secret_name = "coder-namespace-kubeconfig" - } - } + # volume { + # name = "kubeconfig" + # secret { + # secret_name = "coder-namespace-kubeconfig" + # } + # } affinity { // This affinity attempts to spread out all workspace pods evenly across From f637501a6f13248f10a3ec927607b82cf6efb940 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:39:03 +0000 Subject: [PATCH 34/69] fix renaming --- .github/pr-deployments/values.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index 8e96d47f73124..68275840456d2 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -8,8 +8,8 @@ coder: ingress: enable: true className: traefik - host: ${PR_DEPLOYMENT_ACCESS_URL} - wildcardHost: "*.${PR_DEPLOYMENT_ACCESS_URL}" + host: ${HOSTNAME} + wildcardHost: "*.${HOSTNAME}" tls: enable: true secretName: pr${PR_NUMBER}-tls @@ -25,9 +25,9 @@ coder: # readOnly: true env: - name: "CODER_ACCESS_URL" - value: "https://${PR_DEPLOYMENT_ACCESS_URL}" + value: "https://${HOSTNAME}" - name: "CODER_WILDCARD_ACCESS_URL" - value: "*.${PR_DEPLOYMENT_ACCESS_URL}" + value: "*.${HOSTNAME}" - name: "CODER_EXPERIMENTS" value: "${EXPERIMENTS}" - name: CODER_PG_CONNECTION_URL From a1f2b8e5acbfa62c2de2809b87fead89502dd40b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:44:09 +0000 Subject: [PATCH 35/69] remove comments --- .github/pr-deployments/kubeconfig.yaml | 18 ------------------ .github/pr-deployments/rbac.yaml | 11 ----------- .github/pr-deployments/template/main.tf | 14 -------------- .github/pr-deployments/values.yaml | 9 --------- .github/workflows/pr-deploy.yaml | 13 ------------- 5 files changed, 65 deletions(-) delete mode 100644 .github/pr-deployments/kubeconfig.yaml diff --git a/.github/pr-deployments/kubeconfig.yaml b/.github/pr-deployments/kubeconfig.yaml deleted file mode 100644 index 6a19c85df685f..0000000000000 --- a/.github/pr-deployments/kubeconfig.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Config -clusters: - - cluster: - certificate-authority-data: ${CLUSTER_CA} - server: ${CLUSTER_ENDPOINT} - name: pr${PR_NUMBER} -contexts: - - context: - cluster: pr${PR_NUMBER} - namespace: pr${PR_NUMBER} - user: coder-workspace - name: pr${PR_NUMBER} -current-context: pr${PR_NUMBER} -users: - - name: coder-workspace - user: - token: ${TOKEN} diff --git a/.github/pr-deployments/rbac.yaml b/.github/pr-deployments/rbac.yaml index b7860626ce3d7..0d37cae7daebe 100644 --- a/.github/pr-deployments/rbac.yaml +++ b/.github/pr-deployments/rbac.yaml @@ -3,8 +3,6 @@ kind: ServiceAccount metadata: name: coder-workspace-pr${PR_NUMBER} namespace: pr${PR_NUMBER} -# secrets: -# - name: coder-workspace-token --- apiVersion: rbac.authorization.k8s.io/v1 @@ -31,12 +29,3 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: coder-workspace-pr${PR_NUMBER} -# --- -# apiVersion: v1 -# kind: Secret -# metadata: -# name: coder-workspace-token-pr${PR_NUMBER} -# namespace: pr${PR_NUMBER} -# annotations: -# kubernetes.io/service-account.name: coder-workspace -# type: kubernetes.io/service-account-token diff --git a/.github/pr-deployments/template/main.tf b/.github/pr-deployments/template/main.tf index 7035ff7c64375..01999a17cd54b 100644 --- a/.github/pr-deployments/template/main.tf +++ b/.github/pr-deployments/template/main.tf @@ -299,12 +299,6 @@ resource "kubernetes_deployment" "main" { name = "home" read_only = false } - # volume_mount { - # mount_path = "/tmp/config" - # sub_path = "kubeconfig" - # name = "kubeconfig" - # read_only = true - # } } volume { @@ -315,14 +309,6 @@ resource "kubernetes_deployment" "main" { } } - # mount kubeconfig secret as a volume to /home/coder/.kube/config - # volume { - # name = "kubeconfig" - # secret { - # secret_name = "coder-namespace-kubeconfig" - # } - # } - affinity { // This affinity attempts to spread out all workspace pods evenly across // nodes. diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index 68275840456d2..7c10b52b2e7ae 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -14,15 +14,6 @@ coder: enable: true secretName: pr${PR_NUMBER}-tls wildcardSecretName: pr${PR_NUMBER}-tls - # volumes: - # - name: coder-namespace-kubeconfig - # secret: - # secretName: coder-namespace-kubeconfig - # volumeMounts: - # - name: coder-namespace-kubeconfig - # mountPath: /home/coder/.kube/config - # subPath: kubeconfig - # readOnly: true env: - name: "CODER_ACCESS_URL" value: "https://${HOSTNAME}" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index fa93f628809f0..cc22895b185d2 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -306,19 +306,6 @@ jobs: # Create service account, role, rolebinding envsubst < ./.github/pr-deployments/rbac.yaml | kubectl apply -f - - # # Get the token for the service account - # export TOKEN=$(kubectl -n pr${{ env.PR_NUMBER }} get secret coder-workspace-token -o jsonpath='{.data.token}' | base64 --decode) - - # # get CLUSTER_CA and CLUSTER_ENDPOINT - # export CLUSTER_CA=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}') - # export CLUSTER_ENDPOINT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}') - - # # Create a kubeconfig for the namespace to be used in the workspace - # envsubst < ./.github/pr-deployments/kubeconfig.yaml > ./namespace-kubeconfig.yaml - - # # Create a secret from the kubeconfig - # kubectl create secret generic coder-namespace-kubeconfig -n pr${{ env.PR_NUMBER }} --from-file=kubeconfig=./namespace-kubeconfig.yaml - - name: Create values.yaml if: github.event_name == 'workflow_dispatch' env: From 55524c69398a2be6b1131003ec71753043ddaa7b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:52:47 +0000 Subject: [PATCH 36/69] add prefix --- .github/pr-deployments/certificate.yaml | 4 ++-- .github/pr-deployments/values.yaml | 8 ++++---- .github/workflows/pr-deploy.yaml | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/pr-deployments/certificate.yaml b/.github/pr-deployments/certificate.yaml index 181ae7dd34f71..cf441a98bbc88 100644 --- a/.github/pr-deployments/certificate.yaml +++ b/.github/pr-deployments/certificate.yaml @@ -9,5 +9,5 @@ spec: name: letsencrypt kind: ClusterIssuer dnsNames: - - "${HOSTNAME}" - - "*.${HOSTNAME}" + - "${PR_HOSTNAME}" + - "*.${PR_HOSTNAME}" diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index 7c10b52b2e7ae..b925bea5ab908 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -8,17 +8,17 @@ coder: ingress: enable: true className: traefik - host: ${HOSTNAME} - wildcardHost: "*.${HOSTNAME}" + host: ${PR_HOSTNAME} + wildcardHost: "*.${PR_HOSTNAME}" tls: enable: true secretName: pr${PR_NUMBER}-tls wildcardSecretName: pr${PR_NUMBER}-tls env: - name: "CODER_ACCESS_URL" - value: "https://${HOSTNAME}" + value: "https://${PR_HOSTNAME}" - name: "CODER_WILDCARD_ACCESS_URL" - value: "*.${HOSTNAME}" + value: "*.${PR_HOSTNAME}" - name: "CODER_EXPERIMENTS" value: "${EXPERIMENTS}" - name: CODER_PG_CONNECTION_URL diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index cc22895b185d2..1a905860e85c0 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -222,7 +222,7 @@ jobs: PR_TITLE: ${{ needs.get_info.outputs.PR_TITLE }} PR_URL: ${{ needs.get_info.outputs.PR_URL }} PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }} - HOSTNAME: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" + PR_HOSTNAME: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" steps: - name: Set up kubeconfig run: | @@ -248,7 +248,7 @@ jobs: curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ -H "Content-Type:application/json" \ - --data '{"type":"CNAME","name":"*.${{ env.HOSTNAME }}","content":"${{ env.HOSTNAME }}","ttl":1,"proxied":false}' + --data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}' - name: Checkout uses: actions/checkout@v3 @@ -349,7 +349,7 @@ jobs: set -euo pipefail DEST="${HOME}/coder" - URL="https://${{ env.HOSTNAME }}/bin/coder-linux-amd64" + URL="https://${{ env.PR_HOSTNAME }}/bin/coder-linux-amd64" mkdir -p "$(dirname ${DEST})" @@ -390,7 +390,7 @@ jobs: --first-user-password $password \ --first-user-trial \ --use-token-as-session \ - https://${{ env.HOSTNAME }} + https://${{ env.PR_HOSTNAME }} # Create template cd ./.github/pr-deployments/template @@ -415,7 +415,7 @@ jobs: "pr_number": "'"${{ env.PR_NUMBER }}"'", "pr_url": "'"${{ env.PR_URL }}"'", "pr_title": "'"${{ env.PR_TITLE }}"'", - "pr_access_url": "'"https://${{ env.HOSTNAME }}"'", + "pr_access_url": "'"https://${{ env.PR_HOSTNAME }}"'", "pr_username": "'"test"'", "pr_email": "'"pr${{ env.PR_NUMBER }}@coder.com"'", "pr_password": "'"${{ steps.setup_deployment.outputs.password }}"'", From 4835b2930b07aee2ad97d5023d1a7bf5f6ea4db4 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:54:15 +0000 Subject: [PATCH 37/69] `terraform init` --- .github/workflows/pr-deploy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 1a905860e85c0..a3f5af71bcaf6 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -394,6 +394,7 @@ jobs: # Create template cd ./.github/pr-deployments/template + terraform init coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} kubernetes # Create workspace From 9576a3f2d331e7cfd9d61e067d52899b63787810 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 07:57:13 +0000 Subject: [PATCH 38/69] remove comments --- .github/pr-deployments/template/main.tf | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/.github/pr-deployments/template/main.tf b/.github/pr-deployments/template/main.tf index 01999a17cd54b..bef767547b2a0 100644 --- a/.github/pr-deployments/template/main.tf +++ b/.github/pr-deployments/template/main.tf @@ -14,20 +14,6 @@ terraform { provider "coder" { } -variable "use_kubeconfig" { - type = bool - description = <<-EOF - Use host kubeconfig? (true/false) - - Set this to false if the Coder host is itself running as a Pod on the same - Kubernetes cluster as you are deploying workspaces to. - - Set this to true if the Coder host is running outside the Kubernetes cluster - for workspaces. A valid "~/.kube/config" must be present on the Coder host. - EOF - default = false -} - variable "namespace" { type = string description = "The Kubernetes namespace to create workspaces in (must exist prior to creating workspaces)" @@ -98,8 +84,7 @@ data "coder_parameter" "home_disk_size" { } provider "kubernetes" { - # Authenticate via ~/.kube/config or a Coder-specific ServiceAccount, depending on admin preferences - config_path = var.use_kubeconfig == true ? "~/.kube/config" : null + config_path = null } data "coder_workspace" "me" {} @@ -115,11 +100,6 @@ resource "coder_agent" "main" { curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server /tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 & - # # Set KUBECONFIG env var to the path of the mounted secret - # mkdir -p /home/coder/.kube - # sudo cp /tmp/config /home/coder/.kube/config - # export KUBECONFIG=/home/coder/.kube/config - EOT # The following metadata blocks are optional. They are used to display @@ -251,7 +231,6 @@ resource "kubernetes_deployment" "main" { } spec { - # replicas = data.coder_workspace.me.start_count replicas = 1 selector { match_labels = { From 56d582c4c06c9b813576ca8ee8ddae2813ed1b4c Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 08:01:23 +0000 Subject: [PATCH 39/69] change username to coder --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index a3f5af71bcaf6..f01585e271b2f 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -385,7 +385,7 @@ jobs: echo "password=$password" >> $GITHUB_OUTPUT coder login \ - --first-user-username test \ + --first-user-username coder \ --first-user-email pr${{ env.PR_NUMBER }}@coder.com \ --first-user-password $password \ --first-user-trial \ From 459b898533565cc513bce2b382407932edde39d5 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 08:13:25 +0000 Subject: [PATCH 40/69] update docs --- docs/CONTRIBUTING.md | 2 +- docs/images/deploy-pr-manually.png | Bin 0 -> 13583 bytes docs/images/pr-deploy-manual.png | Bin 27155 -> 0 bytes 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/images/deploy-pr-manually.png delete mode 100644 docs/images/pr-deploy-manual.png diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 801f82bdbf5d4..291f4e1444e4b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -84,7 +84,7 @@ You can test your changes by creating a PR deployment. There are two ways to do 1. By running `./scripts/deploy-pr.sh` 2. By manually triggering the [`pr-deploy.yaml`](https://github.com/coder/coder/actions/workflows/pr-deploy.yaml) GitHub Action workflow - ![Deploy PR manually](./images/pr-deploy-manual.png) + ![Deploy PR manually](./images/deploy-pr-manually.png) #### Available options diff --git a/docs/images/deploy-pr-manually.png b/docs/images/deploy-pr-manually.png new file mode 100644 index 0000000000000000000000000000000000000000..718d00c65d1cced5f5defe15e4d07aefc4b6f16c GIT binary patch literal 13583 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 literal 0 HcmV?d00001 diff --git a/docs/images/pr-deploy-manual.png b/docs/images/pr-deploy-manual.png deleted file mode 100644 index eab92cc2249e75e08119bc1d1e4897545f6f75e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27155 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 Date: Wed, 9 Aug 2023 11:44:54 +0000 Subject: [PATCH 41/69] test parameter fro CLI --- .github/workflows/pr-deploy.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index f01585e271b2f..8d187d1ae329c 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -398,13 +398,14 @@ jobs: coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} kubernetes # Create workspace - cat < workspace.yaml - cpu: "2" - memory: "4" - home_disk_size: "2" - EOF - - coder create --template="kubernetes" kube --rich-parameter-file ./workspace.yaml -y + # cat < workspace.yaml + # cpu: "2" + # memory: "4" + # home_disk_size: "2" + # EOF + + # coder create --template="kubernetes" kube --rich-parameter-file ./workspace.yaml -y + coder create --template="kubernetes" kube --parameter cpu=2 --parameter memory=4 --parameter home_disk_size=2 -y coder stop kube -y - name: Send Slack notification From 4c8ab01caf1a0015205b975912b6434614d0faa2 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 11:58:05 +0000 Subject: [PATCH 42/69] update condition --- .github/workflows/pr-deploy.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 8d187d1ae329c..c072ae9a3eee6 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -51,7 +51,7 @@ jobs: CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }} CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }} NEW: ${{ steps.check_deployment.outputs.new }} - BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new || github.event.inputs.build == 'true' }} + BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new }} runs-on: "ubuntu-latest" steps: @@ -163,7 +163,7 @@ jobs: build: needs: get_info # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --force - if: needs.get_info.outputs.BUILD == 'true' + if: needs.get_info.outputs.BUILD == 'true' || github.event.inputs.build == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: DOCKER_CLI_EXPERIMENTAL: "enabled" From 96888a2b5f2b123539c4c443caf653c77398802e Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 12:01:37 +0000 Subject: [PATCH 43/69] update comment --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index c072ae9a3eee6..ce38cce3ef370 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -162,7 +162,7 @@ jobs: build: needs: get_info - # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --force + # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --build flag if: needs.get_info.outputs.BUILD == 'true' || github.event.inputs.build == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: From b198d33abadaa2a3a4bb9a5b8176e279868daa3e Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Aug 2023 12:08:27 +0000 Subject: [PATCH 44/69] remove comments --- .github/workflows/pr-deploy.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index ce38cce3ef370..38806f2f9a5c9 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -398,13 +398,6 @@ jobs: coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }} kubernetes # Create workspace - # cat < workspace.yaml - # cpu: "2" - # memory: "4" - # home_disk_size: "2" - # EOF - - # coder create --template="kubernetes" kube --rich-parameter-file ./workspace.yaml -y coder create --template="kubernetes" kube --parameter cpu=2 --parameter memory=4 --parameter home_disk_size=2 -y coder stop kube -y From 780f51c0085cd7fb668c045374bfd769fc065218 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 08:54:13 +0000 Subject: [PATCH 45/69] use tailscale derpmap --- .github/pr-deployments/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index b925bea5ab908..bd183b32aa7ca 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -34,3 +34,5 @@ coder: value: "${PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET}" - name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS" value: "coder" + - name: "CODER_DERP_CONFIG_URL" + value: "https://controlplane.tailscale.com/derpmap/default" From e3dac1c05aea8e4d4f3ae263ff99953e6ac8b8bb Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 10:33:17 +0000 Subject: [PATCH 46/69] use updated path of helm chart --- .github/workflows/pr-deploy.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 38806f2f9a5c9..267d3eb7ac4ec 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -320,13 +320,13 @@ jobs: run: | set -euo pipefail if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then - helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \ + helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \ --namespace "pr${{ env.PR_NUMBER }}" \ --values ./pr-deploy-values.yaml \ --force else if [[ ${{ needs.get_info.outputs.BUILD }} == "true" ]]; then - helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \ + helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \ --namespace "pr${{ env.PR_NUMBER }}" \ --reuse-values \ --force From 832e237d5e3cad72f05852109ee3be4b7707f2f4 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 10:55:26 +0000 Subject: [PATCH 47/69] refactor to run on push --- .github/workflows/pr-deploy.yaml | 37 +++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 267d3eb7ac4ec..02516d9c0c653 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -4,8 +4,7 @@ # 3. when a PR is updated name: Deploy PR on: - pull_request: - types: synchronize + push: workflow_dispatch: inputs: pr_number: @@ -37,12 +36,30 @@ permissions: pull-requests: write concurrency: - group: ${{ github.workflow }}-PR-${{ github.event.pull_request.number || github.event.inputs.pr_number }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: + check_pr: + runs-on: ubuntu-latest + outputs: + PR_OPEN: ${{ steps.check_pr.outputs.pr_open }} + steps: + - name: Check if PR is open + id: check_pr + run: | + set -euo pipefail + if [[ $(gh pr view --json state | jq -r '.state') != "OPEN" ]]; then + echo "a PR is not open. skipping" + pr_open=$(gh pr view --json state | jq -r '.state' != "OPEN") + fi + echo "pr_open=$pr_open" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + get_info: - if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' + needs: check_pr + if: ${{ needs.check_pr.outputs.PR_OPEN == 'true' }} outputs: PR_NUMBER: ${{ steps.pr_info.outputs.PR_NUMBER }} PR_TITLE: ${{ steps.pr_info.outputs.PR_TITLE }} @@ -59,13 +76,16 @@ jobs: id: pr_info run: | set -euo pipefail - PR_NUMBER=${{ github.event.inputs.pr_number || github.event.pull_request.number }} - PR_TITLE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.title') - PR_BRANCH=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.head.ref') - echo "PR_URL=https://github.com/coder/coder/pull/$PR_NUMBER" >> $GITHUB_OUTPUT + PR_NUMBER=$(gh pr view --json number | jq -r '.number') + PR_TITLE=$(gh pr view --json title | jq -r '.title') + PR_URL=$(gh pr view --json url | jq -r '.url') + echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT echo "PR_TITLE=$PR_TITLE" >> $GITHUB_OUTPUT echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_BRANCH: ${{ github.ref }} - name: Set required tags id: set_tags @@ -134,6 +154,7 @@ jobs: uses: dorny/paths-filter@v2 id: filter with: + base: ${{ steps.pr_info.outputs.PR_BRANCH }} filters: | all: - "**" From 76dbe1bf309e68c40333d6e51b801d70cad96a1d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 12:23:44 +0000 Subject: [PATCH 48/69] fix --- .github/workflows/pr-deploy.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 02516d9c0c653..e8b469af4370d 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -45,13 +45,17 @@ jobs: outputs: PR_OPEN: ${{ steps.check_pr.outputs.pr_open }} steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Check if PR is open id: check_pr run: | set -euo pipefail - if [[ $(gh pr view --json state | jq -r '.state') != "OPEN" ]]; then - echo "a PR is not open. skipping" - pr_open=$(gh pr view --json state | jq -r '.state' != "OPEN") + pr_open=$(gh pr view --json state | jq -r '.state' != "OPEN") + if [[ "$pr_open" == "true" ]]; then + echo "PR is closed. Exiting." + exit 0 fi echo "pr_open=$pr_open" >> $GITHUB_OUTPUT env: From 2062915706b3ee5cbe3aeb056b7e7bbe80ee2728 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 12:24:37 +0000 Subject: [PATCH 49/69] update permissions --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index e8b469af4370d..a9136355ec87b 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -33,7 +33,7 @@ env: permissions: contents: read packages: write - pull-requests: write + pull-requests: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 5be2f0215db0baa9a52dd532583c6bf014fca4ad Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 12:49:46 +0000 Subject: [PATCH 50/69] update --- .github/workflows/pr-deploy.yaml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index a9136355ec87b..bc96f2a158a6f 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -45,21 +45,19 @@ jobs: outputs: PR_OPEN: ${{ steps.check_pr.outputs.pr_open }} steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Check if PR is open id: check_pr run: | set -euo pipefail - pr_open=$(gh pr view --json state | jq -r '.state' != "OPEN") - if [[ "$pr_open" == "true" ]]; then - echo "PR is closed. Exiting." - exit 0 + pr_open=true + if [[ "$(gh pr view $PR_BRANCH --json state | jq -r '.state')" != "true" ]]; then + echo "PR doesn't exist or is closed." + pr_open=false fi echo "pr_open=$pr_open" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_BRANCH: ${{ github.ref }} get_info: needs: check_pr From 4f5abfd6a96064b6df66072055f601fc963f012e Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 13:17:38 +0000 Subject: [PATCH 51/69] test --- .github/workflows/pr-deploy.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index bc96f2a158a6f..8a7b6cd23f694 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -45,19 +45,23 @@ jobs: outputs: PR_OPEN: ${{ steps.check_pr.outputs.pr_open }} steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.ref }} + - name: Check if PR is open id: check_pr run: | set -euo pipefail pr_open=true - if [[ "$(gh pr view $PR_BRANCH --json state | jq -r '.state')" != "true" ]]; then + if [[ "$(gh pr view --json state | jq -r '.state')" != "OPEN" ]]; then echo "PR doesn't exist or is closed." pr_open=false fi echo "pr_open=$pr_open" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_BRANCH: ${{ github.ref }} get_info: needs: check_pr @@ -87,7 +91,7 @@ jobs: echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_BRANCH: ${{ github.ref }} + PR_BRANCH: ${${{ github.ref}}#refs/heads/} - name: Set required tags id: set_tags From 62bcb8ee970e91b3c03b93dec626b17448408f85 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 13:28:47 +0000 Subject: [PATCH 52/69] remove BRANCH NAME --- .github/workflows/pr-deploy.yaml | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 8a7b6cd23f694..9d0639a8cdb3d 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -47,8 +47,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - with: - ref: ${{ github.ref }} - name: Check if PR is open id: check_pr @@ -70,7 +68,6 @@ jobs: PR_NUMBER: ${{ steps.pr_info.outputs.PR_NUMBER }} PR_TITLE: ${{ steps.pr_info.outputs.PR_TITLE }} PR_URL: ${{ steps.pr_info.outputs.PR_URL }} - PR_BRANCH: ${{ steps.pr_info.outputs.PR_BRANCH }} CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }} CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }} NEW: ${{ steps.check_deployment.outputs.new }} @@ -78,6 +75,11 @@ jobs: runs-on: "ubuntu-latest" steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Get PR number, title, and branch name id: pr_info run: | @@ -88,10 +90,9 @@ jobs: echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT echo "PR_TITLE=$PR_TITLE" >> $GITHUB_OUTPUT - echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_OUTPUT + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_BRANCH: ${${{ github.ref}}#refs/heads/} - name: Set required tags id: set_tags @@ -148,19 +149,12 @@ jobs: reactions: eyes reactions-edit-mode: replace - - name: Checkout - if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' - uses: actions/checkout@v3 - with: - ref: ${{ steps.pr_info.outputs.PR_BRANCH }} - fetch-depth: 0 - - name: Check changed files if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' uses: dorny/paths-filter@v2 id: filter with: - base: ${{ steps.pr_info.outputs.PR_BRANCH }} + base: ${{ github.ref }} filters: | all: - "**" @@ -195,13 +189,10 @@ jobs: env: DOCKER_CLI_EXPERIMENTAL: "enabled" CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }} - PR_NUMBER: ${{ needs.get_info.outputs.PR_NUMBER }} - PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }} steps: - name: Checkout uses: actions/checkout@v3 with: - ref: ${{ env.PR_BRANCH }} fetch-depth: 0 - name: Setup Node @@ -248,7 +239,6 @@ jobs: PR_NUMBER: ${{ needs.get_info.outputs.PR_NUMBER }} PR_TITLE: ${{ needs.get_info.outputs.PR_TITLE }} PR_URL: ${{ needs.get_info.outputs.PR_URL }} - PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }} PR_HOSTNAME: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" steps: - name: Set up kubeconfig @@ -279,8 +269,6 @@ jobs: - name: Checkout uses: actions/checkout@v3 - with: - ref: ${{ env.PR_BRANCH }} - name: Create PR namespace if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' From 8a5f3f8585b56f155145e0d13bfdf24fc6e9e01a Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 13:32:50 +0000 Subject: [PATCH 53/69] fix permission --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 9d0639a8cdb3d..ff3957c09f930 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -33,7 +33,7 @@ env: permissions: contents: read packages: write - pull-requests: read + pull-requests: write # needed for commenting on PRs concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 667acefa0c78d231473c08b0247a1785c8e16332 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 13:33:58 +0000 Subject: [PATCH 54/69] update checkout action --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index ff3957c09f930..2569555bce7f6 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -46,7 +46,7 @@ jobs: PR_OPEN: ${{ steps.check_pr.outputs.pr_open }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Check if PR is open id: check_pr From 40c3b74f24ade2e1d5642be3216da25970e7c072 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 13:45:21 +0000 Subject: [PATCH 55/69] update conditions --- .github/workflows/pr-deploy.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 2569555bce7f6..fe2f0e6248891 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -232,7 +232,7 @@ jobs: # Run deploy job only if build job was successful or skipped if: | always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && - (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false' || github.event.inputs.deploy == 'true') + (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false') runs-on: "ubuntu-latest" env: CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }} @@ -267,9 +267,6 @@ jobs: -H "Content-Type:application/json" \ --data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}' - - name: Checkout - uses: actions/checkout@v3 - - name: Create PR namespace if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | @@ -278,6 +275,10 @@ jobs: kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true kubectl create namespace "pr${{ env.PR_NUMBER }}" + - name: Checkout + if: github.event_name == 'workflow_dispatch' || needs.get_info.outputs.BUILD == 'true' + uses: actions/checkout@v3 + - name: Check and Create Certificate if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | @@ -332,6 +333,7 @@ jobs: envsubst < ./.github/pr-deployments/values.yaml > ./pr-deploy-values.yaml - name: Install/Upgrade Helm chart + if: github.event_name == 'workflow_dispatch' || needs.get_info.outputs.BUILD == 'true' run: | set -euo pipefail if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then @@ -345,8 +347,6 @@ jobs: --namespace "pr${{ env.PR_NUMBER }}" \ --reuse-values \ --force - else - echo "Skipping helm upgrade, as there is no new image to deploy" fi fi From fb29a3c0aa23a461c169c4f228b15757b21b3253 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 14:11:23 +0000 Subject: [PATCH 56/69] refactor --- .github/workflows/pr-deploy.yaml | 70 +++++++++++++------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index fe2f0e6248891..71783b2826792 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -90,7 +90,6 @@ jobs: echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT echo "PR_TITLE=$PR_TITLE" >> $GITHUB_OUTPUT - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -124,31 +123,6 @@ jobs: fi echo "new=$new" >> $GITHUB_OUTPUT - - name: Find Comment - uses: peter-evans/find-comment@v2 - if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' - id: fc - with: - issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} - comment-author: "github-actions[bot]" - body-includes: ":rocket:" - direction: last - - - name: Comment on PR - id: comment_id - if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' - uses: peter-evans/create-or-update-comment@v3 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} - edit-mode: replace - body: | - --- - :rocket: Deploying PR ${{ steps.pr_info.outputs.PR_NUMBER }} ... - --- - reactions: eyes - reactions-edit-mode: replace - - name: Check changed files if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' uses: dorny/paths-filter@v2 @@ -175,12 +149,39 @@ jobs: - "scripts/**/*[^D][^o][^c][^k][^e][^r][^f][^i][^l][^e][.][b][^a][^s][^e]*" - name: Print number of changed files - if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' run: | set -euo pipefail echo "Total number of changed files: ${{ steps.filter.outputs.all_count }}" echo "Number of ignored files: ${{ steps.filter.outputs.ignored_count }}" + comment-pr: + needs: [check_pr, get_info] + if: ${{ needs.get_info.outputs.BUILD == 'true' || github.event.inputs.deploy == 'true' || github.event.inputs.build == 'true' }} + runs-on: "ubuntu-latest" + steps: + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} + comment-author: "github-actions[bot]" + body-includes: ":rocket:" + direction: last + + - name: Comment on PR + id: comment_id + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} + edit-mode: replace + body: | + --- + :rocket: Deploying PR ${{ steps.pr_info.outputs.PR_NUMBER }} ... + --- + reactions: eyes + reactions-edit-mode: replace + build: needs: get_info # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --build flag @@ -232,7 +233,7 @@ jobs: # Run deploy job only if build job was successful or skipped if: | always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && - (github.event_name == 'workflow_dispatch' || needs.get_info.outputs.NEW == 'false') + (needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true') runs-on: "ubuntu-latest" env: CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }} @@ -249,7 +250,6 @@ jobs: export KUBECONFIG=~/.kube/config - name: Check if image exists - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) @@ -260,7 +260,6 @@ jobs: fi - name: Add DNS record to Cloudflare - if: needs.get_info.outputs.NEW == 'true' run: | curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ @@ -268,7 +267,6 @@ jobs: --data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}' - name: Create PR namespace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist @@ -276,11 +274,9 @@ jobs: kubectl create namespace "pr${{ env.PR_NUMBER }}" - name: Checkout - if: github.event_name == 'workflow_dispatch' || needs.get_info.outputs.BUILD == 'true' uses: actions/checkout@v3 - name: Check and Create Certificate - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | # Using kubectl to check if a Certificate resource already exists # we are doing this to avoid letsenrypt rate limits @@ -303,7 +299,6 @@ jobs: ) - name: Set up PostgreSQL database - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add bitnami https://charts.bitnami.com/bitnami helm install coder-db bitnami/postgresql \ @@ -316,14 +311,12 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a kubeconfig for the workspace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # Create service account, role, rolebinding envsubst < ./.github/pr-deployments/rbac.yaml | kubectl apply -f - - name: Create values.yaml - if: github.event_name == 'workflow_dispatch' env: EXPERIMENTS: ${{ github.event.inputs.experiments }} PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID: ${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID }} @@ -333,7 +326,6 @@ jobs: envsubst < ./.github/pr-deployments/values.yaml > ./pr-deploy-values.yaml - name: Install/Upgrade Helm chart - if: github.event_name == 'workflow_dispatch' || needs.get_info.outputs.BUILD == 'true' run: | set -euo pipefail if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then @@ -351,7 +343,6 @@ jobs: fi - name: Install coder-logstream-kube - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ @@ -359,7 +350,6 @@ jobs: --set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" - name: Get Coder binary - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail @@ -385,7 +375,6 @@ jobs: mv "${DEST}" /usr/local/bin/coder - name: Create first user, template and workspace - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' id: setup_deployment run: | set -euo pipefail @@ -417,7 +406,6 @@ jobs: coder stop kube -y - name: Send Slack notification - if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | curl -s -o /dev/null -X POST -H 'Content-type: application/json' \ -d \ From 232bed4c3bba431f593518168a74bbcb3e8935a3 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 14:16:26 +0000 Subject: [PATCH 57/69] fix commenting --- .github/workflows/pr-deploy.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 71783b2826792..ee6eaf0878071 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -163,7 +163,7 @@ jobs: uses: peter-evans/find-comment@v2 id: fc with: - issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} + issue-number: ${{ needs.get_info.outputs.PR_NUMBER }} comment-author: "github-actions[bot]" body-includes: ":rocket:" direction: last @@ -173,11 +173,11 @@ jobs: uses: peter-evans/create-or-update-comment@v3 with: comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }} + issue-number: ${{ needs.get_info.outputs.PR_NUMBER }} edit-mode: replace body: | --- - :rocket: Deploying PR ${{ steps.pr_info.outputs.PR_NUMBER }} ... + :rocket: Deploying PR ${{ needs.get_info.outputs.PR_NUMBER }} ... --- reactions: eyes reactions-edit-mode: replace From e18a2c74f71e279e0a17ee0fa4623e48ff19cc3f Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 14:50:39 +0000 Subject: [PATCH 58/69] fix tag lookup --- .github/workflows/pr-deploy.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index ee6eaf0878071..c98efe8050779 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -252,12 +252,22 @@ jobs: - name: Check if image exists run: | set -euo pipefail - foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1) + foundTag=$( + gh api /orgs/coder/packages/container/coder-preview/versions | + jq -r --arg tag "${{ env.CODER_IMAGE_TAG }}" '.[] | + select(.metadata.container.tags == [$tag]) | + .metadata.container.tags[0]' + ) if [ -z "$foundTag" ]; then echo "Image not found" echo "${{ env.CODER_IMAGE_TAG }} not found in ghcr.io/coder/coder-preview" exit 1 + else + echo "Image found" + echo "$foundTag tag found in ghcr.io/coder/coder-preview" fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Add DNS record to Cloudflare run: | From 57567e4fb73dca5d8f076572ab7518ba941bb543 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 14:56:05 +0000 Subject: [PATCH 59/69] fixup! --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index c98efe8050779..1a66fa6cc178d 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -254,7 +254,7 @@ jobs: set -euo pipefail foundTag=$( gh api /orgs/coder/packages/container/coder-preview/versions | - jq -r --arg tag "${{ env.CODER_IMAGE_TAG }}" '.[] | + jq -r --arg tag "pr${{ env.PR_NUMBER }}" '.[] | select(.metadata.container.tags == [$tag]) | .metadata.container.tags[0]' ) From 1f5a5be8d3678d8e7c094090ac9ace026326d3a3 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 15:02:35 +0000 Subject: [PATCH 60/69] remove extra condition --- .github/workflows/pr-deploy.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 1a66fa6cc178d..af125f2c378aa 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -124,7 +124,6 @@ jobs: echo "new=$new" >> $GITHUB_OUTPUT - name: Check changed files - if: github.event_name == 'workflow_dispatch' || steps.check_deployment.outputs.NEW == 'false' uses: dorny/paths-filter@v2 id: filter with: From 1a94dbb17c01aac5e42753bca01b8c438dc354f0 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 10 Aug 2023 15:08:29 +0000 Subject: [PATCH 61/69] debug --- .github/workflows/pr-deploy.yaml | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index af125f2c378aa..5f9fb47bb5608 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -70,8 +70,8 @@ jobs: PR_URL: ${{ steps.pr_info.outputs.PR_URL }} CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }} CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }} - NEW: ${{ steps.check_deployment.outputs.new }} - BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.new }} + NEW: ${{ steps.check_deployment.outputs.NEW }} + BUILD: ${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.NEW }} runs-on: "ubuntu-latest" steps: @@ -116,12 +116,12 @@ jobs: set -euo pipefail if helm status "pr${{ steps.pr_info.outputs.PR_NUMBER }}" --namespace "pr${{ steps.pr_info.outputs.PR_NUMBER }}" > /dev/null 2>&1; then echo "Deployment already exists. Skipping deployment." - new=false + NEW=false else echo "Deployment doesn't exist." - new=true + NEW=true fi - echo "new=$new" >> $GITHUB_OUTPUT + echo "NEW=$new" >> $GITHUB_OUTPUT - name: Check changed files uses: dorny/paths-filter@v2 @@ -153,6 +153,19 @@ jobs: echo "Total number of changed files: ${{ steps.filter.outputs.all_count }}" echo "Number of ignored files: ${{ steps.filter.outputs.ignored_count }}" + - name: Print job outputs + run: | + set -euo pipefail + # Print all outputs of this job + echo "PR_NUMBER=${{ steps.pr_info.outputs.PR_NUMBER }}" + echo "PR_TITLE=${{ steps.pr_info.outputs.PR_TITLE }}" + echo "PR_URL=${{ steps.pr_info.outputs.PR_URL }}" + echo "CODER_BASE_IMAGE_TAG=${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }}" + echo "CODER_IMAGE_TAG=${{ steps.set_tags.outputs.CODER_IMAGE_TAG }}" + echo "NEW=${{ steps.check_deployment.outputs.NEW }}" + echo "BUILD=${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.NEW }}" + echo "GITHUB_REF=${{ github.ref }}" + comment-pr: needs: [check_pr, get_info] if: ${{ needs.get_info.outputs.BUILD == 'true' || github.event.inputs.deploy == 'true' || github.event.inputs.build == 'true' }} From f3b56a38662c082d60d3fe0626f5a1ee8f58338e Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Thu, 10 Aug 2023 18:52:07 +0300 Subject: [PATCH 62/69] Update pr-deploy.yaml --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 5f9fb47bb5608..d22971c13ba58 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -121,7 +121,7 @@ jobs: echo "Deployment doesn't exist." NEW=true fi - echo "NEW=$new" >> $GITHUB_OUTPUT + echo "NEW=$NEW" >> $GITHUB_OUTPUT - name: Check changed files uses: dorny/paths-filter@v2 From 0bc368ac53fe34b118f3da54f909b47a2e328efa Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 05:42:04 +0000 Subject: [PATCH 63/69] use PR_HOSTNAME --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index d22971c13ba58..4815fade6bcc1 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -369,7 +369,7 @@ jobs: helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ --namespace "pr${{ env.PR_NUMBER }}" \ - --set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" + --set url="https://${{ env.PR_HOSTNAME }}" - name: Get Coder binary run: | From b69af83e558daa96c0c5083b4e0a66a6475f8a5c Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 05:55:10 +0000 Subject: [PATCH 64/69] quoting --- .github/pr-deployments/values.yaml | 10 +++++----- .github/workflows/pr-deploy.yaml | 19 +++++-------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/.github/pr-deployments/values.yaml b/.github/pr-deployments/values.yaml index bd183b32aa7ca..9d246ec8aaa83 100644 --- a/.github/pr-deployments/values.yaml +++ b/.github/pr-deployments/values.yaml @@ -1,19 +1,19 @@ coder: image: - repo: ${REPO} - tag: pr${PR_NUMBER} + repo: "${REPO}" + tag: "pr${PR_NUMBER}" pullPolicy: Always service: type: ClusterIP ingress: enable: true className: traefik - host: ${PR_HOSTNAME} + host: "${PR_HOSTNAME}" wildcardHost: "*.${PR_HOSTNAME}" tls: enable: true - secretName: pr${PR_NUMBER}-tls - wildcardSecretName: pr${PR_NUMBER}-tls + secretName: "pr${PR_NUMBER}-tls" + wildcardSecretName: "pr${PR_NUMBER}-tls" env: - name: "CODER_ACCESS_URL" value: "https://${PR_HOSTNAME}" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 4815fade6bcc1..d1e13d58bf590 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -332,7 +332,7 @@ jobs: kubectl create secret generic coder-db-url -n pr${{ env.PR_NUMBER }} \ --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - - name: Create a kubeconfig for the workspace + - name: Create a service account, role, and rolebinding for the PR namespace run: | set -euo pipefail # Create service account, role, rolebinding @@ -350,19 +350,10 @@ jobs: - name: Install/Upgrade Helm chart run: | set -euo pipefail - if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then - helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \ - --namespace "pr${{ env.PR_NUMBER }}" \ - --values ./pr-deploy-values.yaml \ - --force - else - if [[ ${{ needs.get_info.outputs.BUILD }} == "true" ]]; then - helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \ - --namespace "pr${{ env.PR_NUMBER }}" \ - --reuse-values \ - --force - fi - fi + helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \ + --namespace "pr${{ env.PR_NUMBER }}" \ + --values ./pr-deploy-values.yaml \ + --force - name: Install coder-logstream-kube run: | From ef13b945cc6d6203128e6b7a35c5a1c7b5a7fbb8 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 06:17:12 +0000 Subject: [PATCH 65/69] run when build is true --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index d1e13d58bf590..18e45c1b3586a 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -245,7 +245,7 @@ jobs: # Run deploy job only if build job was successful or skipped if: | always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && - (needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true') + (needs.get_info.outputs.BUILD == 'true' || github.event.inputs.deploy == 'true') runs-on: "ubuntu-latest" env: CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }} From 5906e8e7e8e7c525f08d5f2bd8f2eadbf54a7233 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 06:21:15 +0000 Subject: [PATCH 66/69] set BUILD to true if forced --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 18e45c1b3586a..4c26c4200ed92 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -163,7 +163,7 @@ jobs: echo "CODER_BASE_IMAGE_TAG=${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }}" echo "CODER_IMAGE_TAG=${{ steps.set_tags.outputs.CODER_IMAGE_TAG }}" echo "NEW=${{ steps.check_deployment.outputs.NEW }}" - echo "BUILD=${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.NEW }}" + echo "BUILD=${{ steps.filter.outputs.all_count > steps.filter.outputs.ignored_count || steps.check_deployment.outputs.NEW || github.event.inputs.build == 'true' }}" echo "GITHUB_REF=${{ github.ref }}" comment-pr: From 49f79f3944cebf47999fca50a834c1fe3c71af71 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 06:22:23 +0000 Subject: [PATCH 67/69] simplify condition --- .github/workflows/pr-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 4c26c4200ed92..bb20d420be733 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -197,7 +197,7 @@ jobs: build: needs: get_info # Run build job only if there are changes in the files that we care about or if the workflow is manually triggered with --build flag - if: needs.get_info.outputs.BUILD == 'true' || github.event.inputs.build == 'true' + if: needs.get_info.outputs.BUILD == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }} env: DOCKER_CLI_EXPERIMENTAL: "enabled" From bb6cd551fb5a5d8ca62de3e111085182b8698d8b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 06:35:01 +0000 Subject: [PATCH 68/69] update deploy conditions --- .github/workflows/pr-deploy.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index bb20d420be733..3af702d033e47 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -282,6 +282,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Add DNS record to Cloudflare + if: needs.get_info.outputs.NEW == 'true' run: | curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \ -H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \ @@ -289,6 +290,7 @@ jobs: --data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}' - name: Create PR namespace + if: needs.get_info.outputs.NEW == 'true' run: | set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist @@ -299,6 +301,7 @@ jobs: uses: actions/checkout@v3 - name: Check and Create Certificate + if: needs.get_info.outputs.NEW == 'true' run: | # Using kubectl to check if a Certificate resource already exists # we are doing this to avoid letsenrypt rate limits @@ -321,6 +324,7 @@ jobs: ) - name: Set up PostgreSQL database + if: needs.get_info.outputs.NEW == 'true' run: | helm repo add bitnami https://charts.bitnami.com/bitnami helm install coder-db bitnami/postgresql \ @@ -333,6 +337,7 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a service account, role, and rolebinding for the PR namespace + if: needs.get_info.outputs.NEW == 'true' run: | set -euo pipefail # Create service account, role, rolebinding @@ -356,6 +361,7 @@ jobs: --force - name: Install coder-logstream-kube + if: needs.get_info.outputs.NEW == 'true' run: | helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ @@ -363,6 +369,7 @@ jobs: --set url="https://${{ env.PR_HOSTNAME }}" - name: Get Coder binary + if: needs.get_info.outputs.NEW == 'true' run: | set -euo pipefail @@ -388,6 +395,7 @@ jobs: mv "${DEST}" /usr/local/bin/coder - name: Create first user, template and workspace + if: needs.get_info.outputs.NEW == 'true' id: setup_deployment run: | set -euo pipefail @@ -419,6 +427,7 @@ jobs: coder stop kube -y - name: Send Slack notification + if: needs.get_info.outputs.NEW == 'true' run: | curl -s -o /dev/null -X POST -H 'Content-type: application/json' \ -d \ From d3a4c98b5bbd5305e56674f41efdeff70d36582b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Fri, 11 Aug 2023 07:14:03 +0000 Subject: [PATCH 69/69] do a force deploy --- .github/workflows/pr-deploy.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 3af702d033e47..9cae6f7f3520e 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -290,7 +290,7 @@ jobs: --data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}' - name: Create PR namespace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # try to delete the namespace, but don't fail if it doesn't exist @@ -301,7 +301,7 @@ jobs: uses: actions/checkout@v3 - name: Check and Create Certificate - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | # Using kubectl to check if a Certificate resource already exists # we are doing this to avoid letsenrypt rate limits @@ -324,7 +324,7 @@ jobs: ) - name: Set up PostgreSQL database - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add bitnami https://charts.bitnami.com/bitnami helm install coder-db bitnami/postgresql \ @@ -337,7 +337,7 @@ jobs: --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable" - name: Create a service account, role, and rolebinding for the PR namespace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail # Create service account, role, rolebinding @@ -361,7 +361,7 @@ jobs: --force - name: Install coder-logstream-kube - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \ @@ -369,7 +369,7 @@ jobs: --set url="https://${{ env.PR_HOSTNAME }}" - name: Get Coder binary - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | set -euo pipefail @@ -395,7 +395,7 @@ jobs: mv "${DEST}" /usr/local/bin/coder - name: Create first user, template and workspace - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' id: setup_deployment run: | set -euo pipefail @@ -427,7 +427,7 @@ jobs: coder stop kube -y - name: Send Slack notification - if: needs.get_info.outputs.NEW == 'true' + if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true' run: | curl -s -o /dev/null -X POST -H 'Content-type: application/json' \ -d \