From ace4d1b610565bc7ee5bc50f6401ebc27862ab5c Mon Sep 17 00:00:00 2001 From: Hannes Gustafsson Date: Wed, 15 Jan 2025 16:02:27 +0000 Subject: [PATCH] Support custom generator (#46) * argocd: guard against missing Git configuration If the found ApplicationSet contains no Git configuration Telefonistka crashes. Guarding against the missing configuration should avoid the crash. * Make test parallel * Use component path that works in lab * Support custom generator Adds support for custom generator as long as the generator has an input parameter named "path". Note that it would probably be advisable to make it configurable, but this is left as a future exercise for the reader. --- internal/pkg/argocd/argocd.go | 23 +++++++++++++++++- internal/pkg/argocd/argocd_test.go | 38 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/internal/pkg/argocd/argocd.go b/internal/pkg/argocd/argocd.go index 074ce61..e4fdbc2 100644 --- a/internal/pkg/argocd/argocd.go +++ b/internal/pkg/argocd/argocd.go @@ -222,7 +222,7 @@ func findRelevantAppSetByPath(ctx context.Context, componentPath string, repo st for _, appSet := range foundAppSets.Items { for _, generator := range appSet.Spec.Generators { log.Debugf("Checking ApplicationSet %s for component path %s(repo %s)", appSet.Name, componentPath, repo) - if generator.Git.RepoURL == repo { + if generator.Git != nil && generator.Git.RepoURL == repo { for _, dir := range generator.Git.Directories { match, _ := path.Match(dir.Path, componentPath) if match { @@ -233,6 +233,27 @@ func findRelevantAppSetByPath(ctx context.Context, componentPath string, repo st } } } + + if generator.Plugin != nil && + generator.Plugin.Input.Parameters != nil { + for key, value := range generator.Plugin.Input.Parameters { + if key == "path" { + var parsedPath string + + if err := json.Unmarshal(value.Raw, &parsedPath); err != nil { + return nil, fmt.Errorf("unable to unmarshal plugin generator path: %w", err) + } + + match, _ := path.Match(parsedPath, componentPath) + if match { + log.Debugf("Found ArgoCD ApplicationSet %q for component path %q(repo %s)", appSet.Name, componentPath, repo) + return &appSet, nil + } else { + log.Debugf("No match for %s in %q", componentPath, parsedPath) + } + } + } + } } } return nil, fmt.Errorf("No ArgoCD ApplicationSet found for component path %s(repo %s)", componentPath, repo) diff --git a/internal/pkg/argocd/argocd_test.go b/internal/pkg/argocd/argocd_test.go index a34766b..886c0e7 100644 --- a/internal/pkg/argocd/argocd_test.go +++ b/internal/pkg/argocd/argocd_test.go @@ -11,6 +11,7 @@ import ( "text/template" "time" + "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" "github.com/argoproj/argo-cd/v2/pkg/apiclient/project" "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" @@ -24,6 +25,43 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) +func TestFindRelevantAppSetByPathDoesNotExplode(t *testing.T) { + t.Parallel() + + serverAddr := os.Getenv("ARGOCD_SERVER_ADDR") + authToken := os.Getenv("ARGOCD_TOKEN") + + if serverAddr == "" || authToken == "" { + t.Skipf("Set ARGOCD_SERVER_ADDR and ARGOCD_TOKEN to run test") + } + + componentPath, repo := "clusters/playground/aws/eu-central-1/v1/cloud-tools/humio/logscale-daily-usage-reporter", "commercetools/k8s-gitops" + + opts := apiclient.ClientOptions{ + ServerAddr: serverAddr, + AuthToken: authToken, + PlainText: false, + Insecure: true, + } + c, err := apiclient.NewClient(&opts) + if err != nil { + t.Errorf("NewClient: %v", err) + } + _, ac, err := c.NewApplicationSetClient() + if err != nil { + t.Errorf("NewApplicationClient: %v", err) + } + + if _, err := findRelevantAppSetByPath( + context.Background(), + componentPath, + repo, + ac, + ); err != nil { + t.Errorf("got unexpected error") + } +} + func readLiveTarget(t *testing.T) (live, target *unstructured.Unstructured, expected string) { t.Helper() live = readManifest(t, "testdata/"+t.Name()+".live")