-
Notifications
You must be signed in to change notification settings - Fork 0
ArgoCD
ArgoCD keeps your kubernetes cluster in sync with git.
As small changes in configuration files, for example a helm chart version update, can result in big changes to the deployed manifests the code-diff does not reflect the actual impact of the PR.
ArgoCD includes a cli with a app diff command that we can run from our CI system and use the resulting output to add a commend with the diff to the PR.
As GitHub has a limit to the size of comments it's a good idea to split the application diff along some axis. I have not run into issues when splitting on project level but this might not be good enough if a large set of apps is in the same project.
Steps:
- List projects
- Per project, list apps
- Per app, call
app diff
To use the CLI without an argocd login is using the --auth-token option.
For this, create a local user with ApiKey capabilities. When the user is created an admin can generate a new ApiKey for that user using the GUI.
This user should also get the required RBAC rules to access the resources we need.
config:
cm:
accounts.automation: apiKey
rbac:
policy.csv: |
p, role:automation, applications, get, *, allow
p, role:automation, projects, get, *, allow
g, automation, role:automationIf ArgoCD is deployed behind a cloudflare tunnel which requires additional login we'll have to include a cloudflare Service Token with the correct permissions in the headers. ArgoCD allows adding arbitrary headers to all requests done using the -H flag.
Once you have the Service Token, in cloudflare, add a Policy to the ArgoCD Application with the "Service Auth" Action. Then in the "Additional Rules", add an "Include" rule with Selector "Service Token" and Value the created service token name.
These two scripts and workflow run a diff for all apps the argocd API key has access to, grouped by project.
Note that it is assumed the $REVISION of all the applications is the same, so they are all sources from the same repository.
If some applications have a different source, they will report a Failed to checkout revision message.
All diffs for a single project are written to a single file.
#!/usr/bin/env bash
PROJECT_LIST=$(argocd \
-H "CF-Access-Client-Id: $CLOUDFLARE_SA_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CLOUDFLARE_SA_CLIENT_SECRET" \
--auth-token="$ARGOCD_AUTH_TOKEN" \
--server="$ARGOCD_SERVER" \
--grpc-web \
-o name \
proj list)
echo "projects=$(jq -ncR '[inputs]' <<< "$PROJECT_LIST")" >> "$GITHUB_OUTPUT"#!/usr/bin/env bash
# https://github.com/argoproj/argo-cd/issues/9773
export KUBECTL_EXTERNAL_DIFF="diff -u -N -I 'helm\.sh/chart: .*$' -I 'argocd.argoproj.io/tracking-id: .*$'"
EXIT_CODE=0
HAS_DIFF=false
APP_LIST=$(argocd \
-H "CF-Access-Client-Id: $CLOUDFLARE_SA_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CLOUDFLARE_SA_CLIENT_SECRET" \
--auth-token="$ARGOCD_AUTH_TOKEN" \
--server="$ARGOCD_SERVER" \
--grpc-web \
-o name \
-p "$PROJECT" \
-l argcd.chain-stock.com/pr-diff!=false \
app list)
FILE="/tmp/$PROJECT.diff"
if [ -f "$FILE" ]; then
rm "$FILE"
fi
for APP in $APP_LIST
do
echo "::group::$APP"
DIFF=$(argocd \
-H "CF-Access-Client-Id: $CLOUDFLARE_SA_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CLOUDFLARE_SA_CLIENT_SECRET" \
--auth-token="$ARGOCD_AUTH_TOKEN" \
--server="$ARGOCD_SERVER" \
--grpc-web \
--revision="$REVISION" \
app diff "$APP" 2>&1)
if [ $? -gt 1 ]
then
# argocd diff returns 1 on diff, 0 on no diff and 2 or higher on error.
# Continue with the diffs but ensure the script as a whole exits with an error.
EXIT_CODE=1
fi
echo "$DIFF"
echo "::endgroup::"
if [ "$DIFF" != "" ]
then
HAS_DIFF=true
printf "### $APP\n" >> $FILE
printf "<details>\n" >> $FILE
printf "\n\`\`\`diff\n" >> $FILE
printf "$DIFF" >> $FILE
printf "\n\`\`\`\n\n" >> $FILE
printf "</details>\n\n" >> $FILE
fi
done
# printf "$DIFF" >> /tmp/diff.txt
echo "diff-file=$FILE" >> "$GITHUB_OUTPUT"
echo "has-diff=$HAS_DIFF" >> "$GITHUB_OUTPUT"
exit $EXIT_CODE
name: ArgoCD diff
on:
pull_request:
branches:
- main
concurrency:
# Cancel existing runs when pushing to the same branch of a PR
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }}
ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }}
CLOUDFLARE_SA_CLIENT_ID: ${{ secrets.CLOUDFLARE_SA_CLIENT_ID }}
CLOUDFLARE_SA_CLIENT_SECRET: ${{ secrets.CLOUDFLARE_SA_CLIENT_SECRET }}
REVISION: ${{ github.sha }}
jobs:
list-projects:
runs-on: ubuntu-latest
outputs:
projects: ${{ steps.list-projects.outputs.projects }}
steps:
- name: Install argocd
shell: bash
run: |
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
- uses: actions/checkout@v3
- name: List Projects
shell: bash
id: list-projects
run: ./.github/scripts/argocd-proj-list.sh
diff-apps:
runs-on: ubuntu-latest
needs: [list-projects]
strategy:
matrix:
project: ${{fromJson(needs.list-projects.outputs.projects)}}
steps:
- name: Install argocd
shell: bash
run: |
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
- uses: actions/checkout@v3
# To exlude an app from PR diff, add the argcd.chain-stock.com/pr-diff=false label
- name: Diff apps
shell: bash
continue-on-error: true
id: app-diff
env:
PROJECT: ${{ matrix.project }}
run: ./.github/scripts/argocd-diff.sh
- uses: mshick/add-pr-comment@v2
if: steps.app-diff.outputs.has-diff == 'true'
with:
message-id: ${{ matrix.project }}
message-path: ${{ steps.app-diff.outputs.diff-file }}