Giter Site home page Giter Site logo

int128 / argocd-commenter Goto Github PK

View Code? Open in Web Editor NEW
125.0 5.0 16.0 1.44 MB

Notify ArgoCD Application status via Pull Request comment or GitHub Deployment API

License: Apache License 2.0

Dockerfile 1.08% Makefile 10.09% Go 88.06% Shell 0.78%
argocd golang kubernetes kubebuilder

argocd-commenter's Introduction

argocd-commenter docker

This is a Kubernetes Controller to notify a change of Argo CD Application status.

Example: Pull Request notification

In the GitOps way, you merge a pull request to deploy a change to Kubernetes cluster. argocd-commenter allows you to receive a notification comment after merging.

When an Application is syncing, synced or healthy, argocd-commenter will create a comment.

image

When the sync was failed, argocd-commenter will create a comment.

image

See the examples in e2e-test fixtures.

Sequence diagram

Here is the sequence diagram of the deployment flow.

sequenceDiagram
  actor User

  User ->>+ GitHub Repository: git push
  GitHub Repository -->>- User: pushed

  loop Argo CD reconciler
    Argo CD Application ->>+ GitHub Repository: git checkout
    GitHub Repository -->>- Argo CD Application: manifest
    note over Argo CD Application: Out of Sync
    Argo CD Application ->>+ Kubernetes Deployment: kubectl apply
    note over Argo CD Application: Syncing
    Kubernetes Deployment -->>- Argo CD Application: applied
    note over Argo CD Application: Synced
  end

  loop Kubernetes reconciler
    Kubernetes Deployment ->>+ Kubernetes Pod: create
    note over Argo CD Application: Progressing
    Kubernetes Pod -->>- Kubernetes Deployment: ready
    note over Argo CD Application: Healthy
  end
Loading

Example: GitHub Deployment notification

In a complex deployment flow, you can receive a notification using GitHub Deployments API. For example, when you deploy a preview environment for a pull request, you can receive the deployment statuses.

To receive a deployment status, set the following annotation to the Argo CD Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-commenter.int128.github.io/deployment-url: https://api.github.com/repos/OWNER/REPO/deployments/ID

Here is an example of workflow to deploy a preview environment:

jobs:
  deploy:
    steps:
      # Create a deployment
      - uses: int128/deployment-action@v1
        id: deployment

      # Generate the manifests for a preview environment
      - uses: actions/checkout@v2
        with:
          repository: your/manifests-repository
          path: manifests-repository
          token: # PAT or GitHub App token is required to write
      - run: |
          cp -a manifests "manifests-repository/pr-${{ github.event.pull_request.number }}"
          cd "manifests-repository/pr-${{ github.event.pull_request.number }}"
          sed -e 's|DEPLOYMENT_URL|${{ steps.deployment.outputs.url }}|g' applications/*.yaml

      # Push the manifests for a preview environment
      - run: |
          git add .
          git commit -m 'Deploy pr-${{ github.event.pull_request.number }}'
          git push manifests-repository main

When the Application status is changed, argocd-commenter will create a deployment status.

image

See the e2e test for details.

Sequence diagram

Here is the sequence diagram of the deployment flow.

sequenceDiagram
  actor User

  User ->>+ Application Repository: git push
  Application Repository -->>- User: pushed

  Application Repository ->>+ GitHub Actions: start
  GitHub Actions ->>+ GitHub Deployment: create
  GitHub Deployment -->>- GitHub Actions: created
  note over GitHub Deployment: Pending
  GitHub Actions ->>+ Manifest Repository: git push
  Manifest Repository -->>- GitHub Actions: pushed
  GitHub Actions -->>- Application Repository: success

  loop Argo CD reconciler
    Argo CD Application ->>+ Manifest Repository: git checkout
    Manifest Repository -->>- Argo CD Application: manifest
    note over Argo CD Application: Out of Sync
    note over GitHub Deployment: Queued
    Argo CD Application ->>+ Kubernetes Deployment: kubectl apply
    note over Argo CD Application: Syncing
    Kubernetes Deployment -->>- Argo CD Application: applied
    note over Argo CD Application: Synced
    note over GitHub Deployment: In progress
  end

  loop Kubernetes reconciler
    Kubernetes Deployment ->>+ Kubernetes Pod: create
    note over Argo CD Application: Progressing
    Kubernetes Pod -->>- Kubernetes Deployment: ready
    note over Argo CD Application: Healthy
    note over GitHub Deployment: Active
  end
Loading

Getting Started

Prerequisite

Argo CD is running in your Kubernetes cluster.

Setup

To deploy the manifest:

kubectl apply -f https://github.com/int128/argocd-commenter/releases/download/v1.8.0/argocd-commenter.yaml

You need to create either Personal Access Token or GitHub App.

  • Personal Access Token
    • Belong to a user
    • Share the rate limit in a user
  • GitHub App
    • Belong to a user or organization
    • Have each rate limit for an installation

Option 1: Using a Personal Access Token

  1. Open https://github.com/settings/tokens
  2. Generate a new token
  3. Create a secret as follows:
    kubectl -n argocd-commenter-system create secret generic controller-manager \
      --from-literal="GITHUB_TOKEN=$YOUR_PERSONAL_ACCESS_TOKEN"

Option 2: Using a GitHub App

  1. Create your GitHub App from either link:
  2. Get the App ID from the setting page
  3. Download a private key of the GitHub App
  4. Set a custom badge for the GitHub App
  5. Install your GitHub App on your repository or organization
  6. Get the Installation ID from the URL, like https://github.com/settings/installations/ID
  7. Create a secret as follows:
    kubectl -n argocd-commenter-system create secret generic controller-manager \
      --from-literal="GITHUB_APP_ID=$YOUR_GITHUB_APP_ID" \
      --from-literal="GITHUB_APP_INSTALLATION_ID=$YOUR_GITHUB_APP_INSTALLATION_ID" \
      --from-file="GITHUB_APP_PRIVATE_KEY=/path/to/private-key.pem"

Verify setup

Make sure the controller is running.

kubectl -n argocd-commenter-system rollout status deployment argocd-commenter-controller-manager

Configuration

GitHub Enterprise Server

Set the environment variable GITHUB_ENTERPRISE_URL.

kubectl -n argocd-commenter-system create secret generic controller-manager \
  --from-literal="GITHUB_TOKEN=$YOUR_PERSONAL_ACCESS_TOKEN" \
  --from-literal="GITHUB_ENTERPRISE_URL=$YOUR_GITHUB_ENTERPRISE_URL"

Contribution

This is an open source software. Feel free to contribute to it.

argocd-commenter's People

Contributors

int128 avatar matthiaswinzeler avatar renovate[bot] avatar yuya-takeyama avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

argocd-commenter's Issues

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: Cannot find preset's package (github>int128/go-actions)

Cant use ssh github URL

ArgoCd-Commenter Pod log says
{"application": "argocd/adapter-instafin-dev", "url": "[email protected]:org_name/repo.git", "error": "invalid url: parse "[email protected]:org_name/repo.git"": first path segment in URL cannot contain colon"}

I have my argocd applications configured using ssh url, with ssh priv key
It should also use ssh github url.

Healthy event is notified even if Application is not yet healthy

Problem to solve

When the cluster load is heavy, it may take a long time before rolling out of pods.

  • Argo CD sync completion (Sync status is changed to Synced)
  • Currently, this lag should be within 3 sec
  • Pod rolling out (Health status is changed to Progressing)

argocd-commenter may notify a healthy event even if the Application is not yet healthy.

How to solve

Increase the threshold:

// When an application is synced but the health status is not changed,
// the controller will evaluate the health status after this time.
requeueTimeToEvaluateHealthStatusAfterSyncOperation = 3 * time.Second

No comment if multiple sources are given

After #955, the controller does not create a comment to a pull request if multiple sources are given. For example, int128/argocd-commenter-e2e-test#2531.

It needs to consider Sources here:

func isPullRequestRelatedToEvent(pull github.PullRequest, app argocdv1alpha1.Application) bool {
if app.Spec.Source == nil {
return false
}
// support manifest path annotation
// see https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/#webhook-and-manifest-paths-annotation
// https://github.com/int128/argocd-commenter/pull/656
manifestGeneratePaths := getManifestGeneratePaths(app)
for _, file := range pull.Files {
if strings.HasPrefix(file, app.Spec.Source.Path) {
return true
}
for _, path := range manifestGeneratePaths {
if strings.HasPrefix(file, path) {
return true
}
}
}
return false
}
// getManifestGeneratePaths returns canonical paths of "argocd.argoproj.io/manifest-generate-paths" annotation.
// It returns nil if the field is nil or empty.
// https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/#webhook-and-manifest-paths-annotation
func getManifestGeneratePaths(app argocdv1alpha1.Application) []string {
if app.Annotations == nil {
return nil
}
if app.Spec.Source == nil {
return nil
}
var canonicalPaths []string
annotatedPaths := strings.Split(app.Annotations["argocd.argoproj.io/manifest-generate-paths"], ";")
for _, path := range annotatedPaths {
if path == "" {
return nil
}
// convert to absolute path
absolutePath := path
if !filepath.IsAbs(path) {
absolutePath = filepath.Join(app.Spec.Source.Path, path)
}
// remove leading slash
if absolutePath[0:1] == "/" {
absolutePath = absolutePath[1:]
}
// add to list of manifest paths
canonicalPaths = append(canonicalPaths, absolutePath)
}
return canonicalPaths
}

Preview environments using ApplicationSets

Context

ArgoCD has a concept of ApplicationSets, which are basically templates for ArgoCD Applications. These offer various different Generators to essentially template full Apps from some data source.

One very interesting looking generator is the Pull Request Generator, which will generate one Application for each pull request in a repository.
The templated Application manifest may use any of the template variables that the generator provides, such as branch name or PR number.

This, in theory already lets you implement per-PR preview environments purely in ArgoCD.

Where argocd-commenter comes in

I'd like to use GitHub deployment statuses for preview environments as described above. The readme already has an example on how to use deployment statuses with argocd-commenter.
However, that example doesn't use ApplicationSets, but rather manually commits a copy of the Application into the sync repository for every pull request.

What I'd love to be able to do is somehow have argocd-commenter (in GitHub deployment mode, not comment mode) work with the pull request generator:

  • someone creates a PR
  • argocd picks up the PR, templates an application, creates resources
  • argocd-commenter sees this and (through arcane magic) creates/updates a deployment status for the pull request, linking to a known preview url (a combination of repo+branch+sha, maybe?)
  • PR gets merged or closed
  • the pull request generator deletes the application and cleans up after itself
  • argocd-commenter updates the deployment status accordingly

GitHub deployments already support "transient environments" that are meant to come and go for things like temporary previews.

Additional information

I know this is a big and very vague feature request, and I'm sorry if it's out of scope for argocd-commenter.
I just love the way GitHub deployment statuses are presented to the user. I tried making something like this a while ago, but realized I was (accidentally) trying to build argocd+argocd-commenter from scratch :b
image

soo.. let me know what you think!

Retry notification until Application is synced with valid Deployment URL

Problem to solve

For App of Apps, the GitHub Deployment annotation is eventually old if the parent application is synced after the child application.

Applications structure

For example, think about the following repository.

/
  applications/
    app1.yaml
  app1/
    rollout.yaml

It contains the following applications.

  • Parent application
    • It points to the source directory applications
  • Child application Application/app1
    • It points to the source directory app1
    • It has the GitHub Deployment annotation (argocd-commenter.int128.github.io/deployment-url)

Scenario

Here is a scenario of case which the GitHub Deployment annotation is old.

  1. GitHub Actions creates a new GitHub Deployment
  2. GitHub Actions pushes both applications/app1.yaml and app1/rollout.yaml
  3. Argo CD syncs the child application
  4. At this time, the parent application has the annotation of old GitHub Deployment. argocd-commenter cannot create a GitHub Deployment Status
  5. Argo CD syncs the parent application
  6. At this time, the parent application has the annotation of new GitHub Deployment

How to solve

Permission error with organization GitHub App

I created a GitHub App in our organization but got the following error:

2021-02-26T04:10:32.399Z	ERROR	controllers.ApplicationSyncStatus	unable to add a comment	{"application": "...", "comment": ..., "error": "query error from GitHub API: Resource not accessible by integration"}

It seems this query caused the issue:

var q struct {
Repository struct {
Object struct {
Commit struct {
AssociatedPullRequests struct {
Nodes []struct {
ID githubv4.ID
Number int
}
} `graphql:"associatedPullRequests(first: 1)"`
} `graphql:"... on Commit"`
} `graphql:"object(oid: $commitSHA)"`
} `graphql:"repository(owner: $owner, name: $name)"`
}

no pem block found

Seeing issues when trying to utilize any other secrets provider that is not kubectl create secret --file method

2024-02-20T20:59:04.493385146Z	ERROR	setup	unable to set up GitHub client	{"error": "could not create an OAuth2 client: invalid GITHUB_APP_PRIVATE_KEY: no pem block found"}
main.main

The key is stored in a string, is there a reason the service can't interpret it?

Pod has terminated by panic

v1.5.1

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x48 pc=0x195fa15]

goroutine 313 [running]:
github.com/int128/argocd-commenter/controllers.(*ApplicationPhaseReconciler).Reconcile(0xc000a790b0, {0x2112d78, 0xc005b20b10}, {{{0xc003de5090, 0x1ce60a0}, {0xc005441020, 0xc001a5cd00}}})
        /workspace/controllers/applicationphase_controller.go:51 +0x1d5
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile(0xc0003e5e00, {0x2112d78, 0xc005b20a80}, {{{0xc003de5090, 0x1ce60a0}, {0xc005441020, 0xc0000b5ac0}}})

Sometimes comment is not created after synced

Problem to solve

Sometimes argocd-commenter does not create a comment to the synced pull request. It seems GitHub API returns no associated pull request.

2024-02-27T23:39:18.20573481Z	INFO	no pull request related to the revision

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
Dockerfile
github-actions
.github/workflows/delete-outdated-deployments.yaml
  • int128/delete-deployments-action v1
.github/workflows/deployment-status.yaml
  • actions/github-script v7
.github/workflows/docker.yaml
  • actions/checkout v4
  • int128/docker-build-workflow v1
  • actions/checkout v4
  • actions/setup-go v5
  • actions/create-github-app-token v1
  • actions/checkout v4
  • docker/metadata-action v5
  • int128/wait-for-docker-image-action v1
  • int128/deployment-action v1
  • int128/deployment-action v1
  • int128/deployment-action v1
.github/workflows/go.yaml
  • int128/kubebuilder-workflows v1
.github/workflows/manifest.yaml
  • int128/kubebuilder-workflows v1
.github/workflows/release.yaml
  • actions/checkout v4
gomod
go.mod
  • go 1.21.6
  • github.com/argoproj/argo-cd/v2 v2.11.6
  • github.com/go-logr/logr v1.4.2
  • github.com/google/go-cmp v0.6.0
  • github.com/google/go-github/v62 v62.0.0
  • github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79@901d90724c79
  • github.com/int128/oauth2-github-app v1.1.1
  • github.com/onsi/ginkgo/v2 v2.19.0
  • github.com/onsi/gomega v1.33.1
  • go.uber.org/zap v1.27.0
  • golang.org/x/oauth2 v0.21.0
  • sigs.k8s.io/controller-runtime v0.14.7
regex
.github/workflows/docker.yaml
.github/workflows/go.yaml
  • golangci/golangci-lint v1.59.1
e2e_test/argocd/kustomization.yaml
  • argoproj/argo-cd v2.11.6

  • Check this box to trigger a request for Renovate to run again on this repository

Notify deployment status once

Problem to solve

argocd-commenter sends deployment status even if a deployment is already success (Active).
We use the deployment-status event on GitHub Actions and it triggers an unexpected workflow run.

How to solve

Don't send a deployment status twice.

Cannot use argocd-commenter with multiple sources

ArgoCD v2.6 ships with a very nice feature that enables people to use multiple sources in a single Application.

This can come very handy when you want for example to define helm values in separate file in the Git repository, or for many other use cases. For further references, see here https://github.com/argoproj/argo-cd/blob/master/docs/proposals/multiple-sources-for-applications.md and here argoproj/argo-cd#10432

The current implementation of argocd-commenter is using only the .source part of the spec, ignoring the .sources one, in this function:

func NewCommentOnOnPhaseChanged(app argocdv1alpha1.Application, argocdURL string) *Comment {
repository := github.ParseRepositoryURL(app.Spec.Source.RepoURL)
if repository == nil {
return nil
}
revision := argocd.GetDeployedRevision(app)
if revision == "" {
return nil
}
body := generateCommentOnPhaseChanged(app, argocdURL)
if body == "" {
return nil
}
return &Comment{
GitHubRepository: *repository,
Revision: revision,
Body: body,
}
}

A workaround like using both source and sources in the Application definition (so that ArgoCD will ignore the source while using the sources, while argocd-commenter will pick the source and will ignore the sources) won't work because of how the status is now: instead of using .revision, now we have .revisions, so the following function will return an empty string, causing the caller to return nil and thus not creating any comment

func GetDeployedRevision(a argocdv1alpha1.Application) string {
if a.Status.OperationState == nil {
return ""
}
if a.Status.OperationState.Operation.Sync == nil {
return ""
}
return a.Status.OperationState.Operation.Sync.Revision
}

It would be great to have the new "multiple sources" feature implemented also on this project

Deployment URL cannot be parsed for GitHub Enterprise

Problem

The deployment URL for GitHub Enterprise cannot be parsed. As a result, ParseDeploymentURL in pkg/github/deployment.go will always return nil and deployment statuses in GitHub will never be updated when phases change.

var patternDeploymentURL = regexp.MustCompile(`^https://api\.github\.com/repos/(.+?)/(.+?)/deployments/(\d+)$`)
// ParseDeploymentURL parses the URL.
// For example, https://api.github.com/repos/int128/sandbox/deployments/422988781
func ParseDeploymentURL(s string) *Deployment {
m := patternDeploymentURL.FindStringSubmatch(s)
if len(m) != 4 {
return nil
}

As an example, our GitHub Enterprise URL https://api.github.some-company.com/repos/IOTA/repo/deployments/54392 will never match the regex.

This also does not seem to be the only place the issue occurs. In pkg/github/types.go there are also some hardcoded regexes for the public github.com.

var (
patternRepositoryHTTPS = regexp.MustCompile(`^https://github\.com/([^/]+?)/([^/]+?)(\.git)?$`)
patternRepositorySSH = regexp.MustCompile(`^git@github\.com:([^/]+?)/([^/]+?)(\.git)?$`)
)

Edit
I just discovered that the issue also occurs in https://github.com/int128/oauth2-github-app. The config.go file also has the hardcoded public github.com URL.

Solution

Can the regex either be made less strict on the hostname, or be constructed using the GITHUB_ENTERPRISE_URL from the secret?

Last healthy annotations are eventually removed in App of Apps

Sometimes the following annotations are removed when Argo CD syncs an application:

  • argocd-commenter.int128.github.io/last-revision-healthy
  • argocd-commenter.int128.github.io/last-deployment-healthy

For App of Apps, it seems the parent Application removes the annotations while syncing.

Support multiple sources

Related issue

Design

Relationship

classDiagram
  Application -- ApplicationSpec
  Application -- ApplicationStatus
  ApplicationSpec : sources
  ApplicationSpec "1" -- "*" ApplicationSource
  ApplicationSource -- GitHubRepository
  ApplicationSource : repoURL
  ApplicationStatus -- OperationState
  OperationState -- Operation
  Operation -- SyncOperation
  SyncOperation "1" -- "*" GitHubCommit
  SyncOperation : revisions
  GitHubCommit "1" -- "*" GitHubPullRequest
  Application -- ApplicationHealth
  ApplicationHealth -- ApplicationHealthStatus
  ApplicationHealthStatus : lastHealthyRevision
Loading

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.