diff --git a/Dockerfile b/Dockerfile index c374bae7..412d7176 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,9 @@ RUN go mod download COPY . . RUN mkdir -p dist && \ - make controller + make controller -FROM alpine:latest +FROM alpine:3.18 RUN apk update && \ apk upgrade && \ diff --git a/cmd/main.go b/cmd/main.go index 3a4019dd..5fbc20b1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -45,6 +45,7 @@ type ImageUpdaterConfig struct { GitCommitMail string GitCommitMessage *template.Template DisableKubeEvents bool + Namespaced bool } // newRootCommand implements the root command of argocd-image-updater diff --git a/cmd/run.go b/cmd/run.go index 305863db..5c3ef0e8 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -10,6 +10,10 @@ import ( "text/template" "time" + "github.com/spf13/cobra" + "golang.org/x/sync/semaphore" + v1 "k8s.io/api/core/v1" + "github.com/argoproj-labs/argocd-image-updater/pkg/argocd" "github.com/argoproj-labs/argocd-image-updater/pkg/common" "github.com/argoproj-labs/argocd-image-updater/pkg/env" @@ -18,10 +22,6 @@ import ( "github.com/argoproj-labs/argocd-image-updater/pkg/metrics" "github.com/argoproj-labs/argocd-image-updater/pkg/registry" "github.com/argoproj-labs/argocd-image-updater/pkg/version" - - "github.com/spf13/cobra" - - "golang.org/x/sync/semaphore" ) // newRunCommand implements "run" command @@ -108,7 +108,11 @@ func newRunCommand() *cobra.Command { var err error if !disableKubernetes { ctx := context.Background() - cfg.KubeClient, err = getKubeConfig(ctx, cfg.ArgocdNamespace, kubeConfig) + ns := cfg.ArgocdNamespace + if !cfg.Namespaced { + ns = v1.NamespaceAll + } + cfg.KubeClient, err = getKubeConfig(ctx, ns, cfg.Namespaced, kubeConfig) if err != nil { log.Fatalf("could not create K8s client: %v", err) } @@ -125,13 +129,15 @@ func newRunCommand() *cobra.Command { cfg.ClientOpts.AuthToken = token } - log.Infof("ArgoCD configuration: [apiKind=%s, server=%s, auth_token=%v, insecure=%v, grpc_web=%v, plaintext=%v]", + log.Infof("ArgoCD configuration: [apiKind=%s, server=%s, auth_token=%v, insecure=%v, grpc_web=%v, plaintext=%v, namespaced=%v, namespace=%s]", cfg.ApplicationsAPIKind, cfg.ClientOpts.ServerAddr, cfg.ClientOpts.AuthToken != "", cfg.ClientOpts.Insecure, cfg.ClientOpts.GRPCWeb, cfg.ClientOpts.Plaintext, + cfg.Namespaced, + cfg.ArgocdNamespace, ) // Health server will start in a go routine and run asynchronously @@ -223,6 +229,7 @@ func newRunCommand() *cobra.Command { runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "noreply@argoproj.io"), "E-Mail address to use for Git commits") runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages") runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events") + runCmd.Flags().BoolVar(&cfg.Namespaced, "namespaced", env.GetBoolVal("IMAGE_UPDATER_NAMESPACED", false), "Use namespace-scoped K8s client") return runCmd } diff --git a/cmd/test.go b/cmd/test.go index afc9cfbe..202fbde4 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -68,7 +68,7 @@ argocd-image-updater test nginx --allow-tags '^1.19.\d+(\-.*)*$' --update-strate var err error if !disableKubernetes { ctx := context.Background() - kubeClient, err = getKubeConfig(ctx, "", kubeConfig) + kubeClient, err = getKubeConfig(ctx, "", true, kubeConfig) if err != nil { log.Fatalf("could not create K8s client: %v", err) } diff --git a/cmd/util.go b/cmd/util.go index 7b6a944d..bddd6608 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -26,7 +26,7 @@ func getPrintableHealthPort(port int) string { } } -func getKubeConfig(ctx context.Context, namespace string, kubeConfig string) (*kube.KubernetesClient, error) { +func getKubeConfig(ctx context.Context, namespace string, namespaced bool, kubeConfig string) (*kube.KubernetesClient, error) { var fullKubeConfigPath string var kubeClient *kube.KubernetesClient var err error @@ -39,12 +39,12 @@ func getKubeConfig(ctx context.Context, namespace string, kubeConfig string) (*k } if fullKubeConfigPath != "" { - log.Debugf("Creating Kubernetes client from %s", fullKubeConfigPath) + log.Debugf("Creating Kubernetes client from %s for namespace '%s'", fullKubeConfigPath, namespace) } else { - log.Debugf("Creating in-cluster Kubernetes client") + log.Debugf("Creating in-cluster Kubernetes client for namespace '%s'", namespace) } - kubeClient, err = kube.NewKubernetesClientFromConfig(ctx, namespace, fullKubeConfigPath) + kubeClient, err = kube.NewKubernetesClientFromConfig(ctx, namespace, namespaced, fullKubeConfigPath) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 021546e7..aa41b47d 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/distribution/distribution/v3 v3.0.0-20230722181636-7b502560cad4 github.com/go-git/go-git/v5 v5.8.1 - github.com/miracl/conflate v1.3.2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc.3 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -32,20 +31,6 @@ require ( ) require ( - cloud.google.com/go v0.110.4 // indirect - cloud.google.com/go/iam v1.1.0 // indirect - cloud.google.com/go/storage v1.33.0 // indirect - github.com/BurntSushi/toml v0.3.1 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/google/s2a-go v0.1.4 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.opencensus.io v0.24.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.132.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect ) @@ -168,7 +153,7 @@ require ( golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.6.0 // indirect + golang.org/x/tools v0.9.1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect google.golang.org/grpc v1.56.2 // indirect diff --git a/go.sum b/go.sum index 99ee8867..d055fb4b 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,6 @@ cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34h cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= @@ -211,8 +209,6 @@ cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3Q cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= @@ -353,8 +349,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.33.0 h1:PVrDOkIC8qQVa1P3SXGpQvfuJhN2LHOoyZvWs8D2X5M= -cloud.google.com/go/storage v1.33.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= @@ -422,7 +416,6 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= @@ -632,7 +625,6 @@ github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqF github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -759,12 +751,10 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -782,8 +772,6 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -793,8 +781,6 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -805,8 +791,6 @@ github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -953,8 +937,6 @@ github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pR github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.58/go.mod h1:NUDy4A4oXPq1l2yK6LTSvCEzAMeIcoz9lcj5dbzSrRE= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/miracl/conflate v1.3.2 h1:ZESwG8pEfwZE9hQ5nPfG/ik+Mnl8jxCGQZSy0qV92nc= -github.com/miracl/conflate v1.3.2/go.mod h1:6UvcI1qeZJSdytXlb0i6bsYnXWCl1UF59DRh/jSJOy4= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1199,11 +1181,7 @@ github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= @@ -1237,7 +1215,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= @@ -1291,7 +1268,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -1704,8 +1680,9 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1713,7 +1690,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -1774,8 +1750,6 @@ google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91 google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= -google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/pkg/argocd/argocd.go b/pkg/argocd/argocd.go index 4584dbe0..354ce735 100644 --- a/pkg/argocd/argocd.go +++ b/pkg/argocd/argocd.go @@ -176,41 +176,41 @@ func FilterApplicationsForUpdate(apps []v1alpha1.Application, patterns []string, var appsForUpdate = make(map[string]ApplicationImages) for _, app := range apps { - logCtx := log.WithContext().AddField("application", app.GetName()) + logCtx := log.WithContext().AddField("application", app.GetName()).AddField("namespace", app.GetNamespace()) sourceType := getApplicationSourceType(&app) // Check whether application has our annotation set annotations := app.GetAnnotations() if _, ok := annotations[common.ImageUpdaterAnnotation]; !ok { - logCtx.Tracef("skipping app '%s' of type '%s' because required annotation is missing", app.GetName(), sourceType) + logCtx.Tracef("skipping app '%s' of type '%s' because required annotation is missing", app.QualifiedName(), sourceType) continue } // Check for valid application type if !IsValidApplicationType(&app) { - logCtx.Warnf("skipping app '%s' of type '%s' because it's not of supported source type", app.GetName(), sourceType) + logCtx.Warnf("skipping app '%s' of type '%s' because it's not of supported source type", app.QualifiedName(), sourceType) continue } // Check if application name matches requested patterns if !nameMatchesPattern(app.GetName(), patterns) { - logCtx.Debugf("Skipping app '%s' because it does not match requested patterns", app.GetName()) + logCtx.Debugf("Skipping app '%s' because it does not match requested patterns", app.QualifiedName()) continue } // Check if application carries requested label if !matchAppLabels(app.GetName(), app.GetLabels(), appLabel) { - logCtx.Debugf("Skipping app '%s' because it does not carry requested label", app.GetName()) + logCtx.Debugf("Skipping app '%s' because it does not carry requested label", app.QualifiedName()) continue } - logCtx.Tracef("processing app '%s' of type '%v'", app.GetName(), sourceType) + logCtx.Tracef("processing app '%s' of type '%v'", app.QualifiedName(), sourceType) imageList := parseImageList(annotations) appImages := ApplicationImages{} appImages.Application = app appImages.Images = *imageList - appsForUpdate[app.GetName()] = appImages + appsForUpdate[app.QualifiedName()] = appImages } return appsForUpdate, nil @@ -388,6 +388,7 @@ func SetHelmImage(app *v1alpha1.Application, newImage *image.ContainerImage) err } appName := app.GetName() + appNamespace := app.GetNamespace() var hpImageName, hpImageTag, hpImageSpec string @@ -407,6 +408,7 @@ func SetHelmImage(app *v1alpha1.Application, newImage *image.ContainerImage) err log.WithContext(). AddField("application", appName). AddField("image", newImage.GetFullNameWithoutTag()). + AddField("namespace", appNamespace). Debugf("target parameters: image-spec=%s image-name=%s, image-tag=%s", hpImageSpec, hpImageName, hpImageTag) mergeParams := make([]v1alpha1.HelmParameter, 0) @@ -484,16 +486,26 @@ func SetKustomizeImage(app *v1alpha1.Application, newImage *image.ContainerImage // GetImagesFromApplication returns the list of known images for the given application func GetImagesFromApplication(app *v1alpha1.Application) image.ContainerImageList { images := make(image.ContainerImageList, 0) + annotations := app.Annotations + imagesFromAnnotations := parseImageList(annotations) + appImgs := make(map[string]*image.ContainerImage, len(app.Status.Summary.Images)) for _, imageStr := range app.Status.Summary.Images { - image := image.NewFromIdentifier(imageStr) - images = append(images, image) + img := image.NewFromIdentifier(imageStr) + appImgs[img.ImageName] = img + } + + for _, img := range *imagesFromAnnotations { + if appImg, ok := appImgs[img.ImageName]; ok { + i := *appImg + i.ImageAlias = img.ImageAlias + images = append(images, &i) + } } // The Application may wish to update images that don't create a container we can detect. // Check the image list for images with a force-update annotation, and add them if they are not already present. - annotations := app.Annotations - for _, img := range *parseImageList(annotations) { + for _, img := range *imagesFromAnnotations { if img.HasForceUpdateOptionAnnotation(annotations) { img.ImageTag = nil // the tag from the image list will be a version constraint, which isn't a valid tag images = append(images, img) diff --git a/pkg/argocd/argocd_test.go b/pkg/argocd/argocd_test.go index 95553570..c84841aa 100644 --- a/pkg/argocd/argocd_test.go +++ b/pkg/argocd/argocd_test.go @@ -23,10 +23,14 @@ import ( func Test_GetImagesFromApplication(t *testing.T) { t.Run("Get list of images from application", func(t *testing.T) { + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "nginx:1.12.2, that/image, quay.io/dexidp/dex:v1.23.0", + } application := &v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "test-app", - Namespace: "argocd", + Name: "test-app", + Namespace: "argocd", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{}, Status: v1alpha1.ApplicationStatus{ @@ -435,8 +439,8 @@ func Test_FilterApplicationsForUpdate(t *testing.T) { filtered, err := FilterApplicationsForUpdate(applicationList, []string{}, "") require.NoError(t, err) require.Len(t, filtered, 1) - require.Contains(t, filtered, "app1") - assert.Len(t, filtered["app1"].Images, 2) + require.Contains(t, filtered, "argocd/app1") + assert.Len(t, filtered["argocd/app1"].Images, 2) }) t.Run("Filter for applications with patterns", func(t *testing.T) { @@ -487,9 +491,9 @@ func Test_FilterApplicationsForUpdate(t *testing.T) { filtered, err := FilterApplicationsForUpdate(applicationList, []string{"app*"}, "") require.NoError(t, err) require.Len(t, filtered, 2) - require.Contains(t, filtered, "app1") - require.Contains(t, filtered, "app2") - assert.Len(t, filtered["app1"].Images, 2) + require.Contains(t, filtered, "argocd/app1") + require.Contains(t, filtered, "argocd/app2") + assert.Len(t, filtered["argocd/app1"].Images, 2) }) t.Run("Filter for applications with label", func(t *testing.T) { @@ -529,8 +533,8 @@ func Test_FilterApplicationsForUpdate(t *testing.T) { filtered, err := FilterApplicationsForUpdate(applicationList, []string{}, "custom.label/name=xyz") require.NoError(t, err) require.Len(t, filtered, 1) - require.Contains(t, filtered, "app1") - assert.Len(t, filtered["app1"].Images, 2) + require.Contains(t, filtered, "argocd/app1") + assert.Len(t, filtered["argocd/app1"].Images, 2) }) } diff --git a/pkg/argocd/update.go b/pkg/argocd/update.go index 855bbdd0..8910c37c 100644 --- a/pkg/argocd/update.go +++ b/pkg/argocd/update.go @@ -21,7 +21,6 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/miracl/conflate" "gopkg.in/yaml.v2" ) @@ -141,6 +140,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat result := ImageUpdaterResult{} app := updateConf.UpdateApp.Application.GetName() + namespace := updateConf.UpdateApp.Application.GetNamespace() changeList := make([]ChangeEntry, 0) // Get all images that are deployed with the current application @@ -157,7 +157,10 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat for _, applicationImage := range updateConf.UpdateApp.Images { updateableImage := applicationImages.ContainsImage(applicationImage, false) if updateableImage == nil { - log.WithContext().AddField("application", app).Debugf("Image '%s' seems not to be live in this application, skipping", applicationImage.ImageName) + log.WithContext(). + AddField("application", app). + AddField("namespace", namespace). + Debugf("Image '%s' seems not to be live in this application, skipping", applicationImage.ImageName) result.NumSkipped += 1 continue } @@ -173,6 +176,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat imgCtx := log.WithContext(). AddField("application", app). + AddField("namespace", namespace). AddField("registry", updateableImage.RegistryURL). AddField("image_name", updateableImage.ImageName). AddField("image_tag", updateableImage.ImageTag). @@ -416,38 +420,42 @@ func marshalParamsOverride(app *v1alpha1.Application, originalData []byte) ([]by } if strings.HasPrefix(app.Annotations[common.WriteBackTargetAnnotation], common.HelmPrefix) { - images := GetImagesFromApplication(app) + values := make(map[interface{}]interface{}) + err := yaml.Unmarshal(originalData, &values) + if err != nil { + return nil, err + } + newValues := make(map[string]string) + images := GetImagesFromApplication(app) for _, c := range images { - helmAnnotationParamName, helmAnnotationParamVersion := getHelmParamNamesFromAnnotation(app.Annotations, c.ImageName) + image := c.ImageAlias + if image == "" { + image = c.ImageName + } + helmAnnotationParamName, helmAnnotationParamVersion := getHelmParamNamesFromAnnotation(app.Annotations, image) if helmAnnotationParamName == "" { - return nil, fmt.Errorf("could not find an image-name annotation for image %s", c.ImageName) + return nil, fmt.Errorf("could not find an image-name annotation for image %s", image) } if helmAnnotationParamVersion == "" { - return nil, fmt.Errorf("could not find an image-tag annotation for image %s", c.ImageName) + return nil, fmt.Errorf("could not find an image-tag annotation for image %s", image) } helmParamName := getHelmParam(appSource.Helm.Parameters, helmAnnotationParamName) if helmParamName == nil { return nil, fmt.Errorf("%s parameter not found", helmAnnotationParamName) } + newValues[helmAnnotationParamName] = helmParamName.Value helmParamVersion := getHelmParam(appSource.Helm.Parameters, helmAnnotationParamVersion) if helmParamVersion == nil { return nil, fmt.Errorf("%s parameter not found", helmAnnotationParamVersion) } - - // Build string with YAML format to merge with originalData values - helmValues := fmt.Sprintf("%s: %s\n%s: %s", helmAnnotationParamName, helmParamName.Value, helmAnnotationParamVersion, helmParamVersion.Value) - - var mergedParams *conflate.Conflate - mergedParams, err = conflate.FromData(originalData, []byte(helmValues)) - if err != nil { - return nil, err - } - - override, err = mergedParams.MarshalYAML() + newValues[helmAnnotationParamVersion] = helmParamVersion.Value } + + mergeHelmValues(values, newValues) + override, _ = yaml.Marshal(values) } else { var params helmOverride newParams := helmOverride{ @@ -492,6 +500,23 @@ func mergeHelmOverride(t *helmOverride, o *helmOverride) { } } +func mergeHelmValues(values map[interface{}]interface{}, newValues map[string]string) { + for fieldPath, newValue := range newValues { + fields := strings.Split(fieldPath, ".") + lastFieldIndex := len(fields) - 1 + node := values + for i, name := range fields { + if i == lastFieldIndex { + node[name] = newValue + break + } else if _, ok := node[name]; !ok { + node[name] = make(map[interface{}]interface{}) + } + node = node[name].(map[interface{}]interface{}) + } + } +} + func mergeKustomizeOverride(t *kustomizeOverride, o *kustomizeOverride) { for _, image := range *o.Kustomize.Images { idx := t.Kustomize.Images.Find(image) diff --git a/pkg/argocd/update_test.go b/pkg/argocd/update_test.go index 1d1246fa..46643d85 100644 --- a/pkg/argocd/update_test.go +++ b/pkg/argocd/update_test.go @@ -109,11 +109,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.0", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -167,11 +171,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.0,jannfis/barbar:1.0.0", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -354,11 +362,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.x", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -412,14 +424,16 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeClientsetWithResources(fixture.NewSecret("foo", "bar", map[string][]byte{"creds": []byte("myuser:mypass")})), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.0", + fmt.Sprintf(common.PullSecretAnnotation, "dummy"): "secret:foo/bar#creds", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", - Annotations: map[string]string{ - fmt.Sprintf(common.PullSecretAnnotation, "dummy"): "secret:foo/bar#creds", - }, + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -526,11 +540,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.1", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -716,15 +734,17 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "dummy=jannfis/foobar", + fmt.Sprintf(common.AllowTagsOptionAnnotation, "dummy"): "regexp:^foobar$", + fmt.Sprintf(common.UpdateStrategyAnnotation, "dummy"): "name", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", - Annotations: map[string]string{ - fmt.Sprintf(common.AllowTagsOptionAnnotation, "dummy"): "regexp:^foobar$", - fmt.Sprintf(common.UpdateStrategyAnnotation, "dummy"): "name", - }, + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -792,15 +812,17 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "dummy=jannfis/foobar", + fmt.Sprintf(common.IgnoreTagsOptionAnnotation, "dummy"): "*", + fmt.Sprintf(common.UpdateStrategyAnnotation, "dummy"): "name", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", - Annotations: map[string]string{ - fmt.Sprintf(common.IgnoreTagsOptionAnnotation, "dummy"): "*", - fmt.Sprintf(common.UpdateStrategyAnnotation, "dummy"): "name", - }, + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -852,11 +874,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "example.io/jannfis/example:1.0.x", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -905,11 +931,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.0", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -961,11 +991,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:1.0.0", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -1017,11 +1051,15 @@ func Test_UpdateApplication(t *testing.T) { kubeClient := kube.KubernetesClient{ Clientset: fake.NewFakeKubeClient(), } + annotations := map[string]string{ + common.ImageUpdaterAnnotation: "jannfis/foobar:stable", + } appImages := &ApplicationImages{ Application: v1alpha1.Application{ ObjectMeta: v1.ObjectMeta{ - Name: "guestbook", - Namespace: "guestbook", + Name: "guestbook", + Namespace: "guestbook", + Annotations: annotations, }, Spec: v1alpha1.ApplicationSpec{ Source: &v1alpha1.ApplicationSource{ @@ -1320,8 +1358,9 @@ helm: t.Run("Valid Helm source with Helm values file", func(t *testing.T) { expected := ` -image.name: nginx -image.tag: v1.0.0 +image: + name: nginx + tag: v1.0.0 replicas: 1 ` app := v1alpha1.Application{ @@ -1366,8 +1405,9 @@ replicas: 1 } originalData := []byte(` -image.name: nginx -image.tag: v0.0.0 +image: + name: nginx + tag: v0.0.0 replicas: 1 `) yaml, err := marshalParamsOverride(&app, originalData) @@ -1417,7 +1457,7 @@ replicas: 1 }, } - originalData := []byte(`random content`) + originalData := []byte(`random: content`) _, err := marshalParamsOverride(&app, originalData) assert.Error(t, err) assert.Equal(t, "could not find an image-tag annotation for image nginx", err.Error()) @@ -1464,7 +1504,7 @@ replicas: 1 }, } - originalData := []byte(`random content`) + originalData := []byte(`random: content`) _, err := marshalParamsOverride(&app, originalData) assert.Error(t, err) assert.Equal(t, "could not find an image-name annotation for image nginx", err.Error()) @@ -1512,7 +1552,7 @@ replicas: 1 }, } - originalData := []byte(`random content`) + originalData := []byte(`random: content`) _, err := marshalParamsOverride(&app, originalData) assert.Error(t, err) assert.Equal(t, "wrongimage.name parameter not found", err.Error()) @@ -1560,7 +1600,7 @@ replicas: 1 }, } - originalData := []byte(`random content`) + originalData := []byte(`random: content`) _, err := marshalParamsOverride(&app, originalData) assert.Error(t, err) assert.Equal(t, "wrongimage.tag parameter not found", err.Error()) diff --git a/pkg/kube/kubernetes.go b/pkg/kube/kubernetes.go index 3ec66cfd..ddcbc4a8 100644 --- a/pkg/kube/kubernetes.go +++ b/pkg/kube/kubernetes.go @@ -8,6 +8,7 @@ import ( "os" "time" + "github.com/argoproj-labs/argocd-image-updater/pkg/log" "github.com/argoproj-labs/argocd-image-updater/pkg/metrics" appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -38,7 +39,7 @@ func NewKubernetesClient(ctx context.Context, client kubernetes.Interface, appli // NewKubernetesClient creates a new Kubernetes client object from given // configuration file. If configuration file is the empty string, in-cluster // client will be created. -func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeconfig string) (*KubernetesClient, error) { +func NewKubernetesClientFromConfig(ctx context.Context, namespace string, namespaced bool, kubeconfig string) (*KubernetesClient, error) { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig loadingRules.ExplicitPath = kubeconfig @@ -50,7 +51,7 @@ func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeco return nil, err } - if namespace == "" { + if namespace == "" && namespaced { namespace, _, err = clientConfig.Namespace() if err != nil { return nil, err @@ -67,6 +68,7 @@ func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeco return nil, err } + log.Debugf("Creating Kubernetes client for ns '%s'", namespace) return NewKubernetesClient(ctx, clientset, applicationsClientset, namespace), nil } diff --git a/pkg/kube/kubernetes_test.go b/pkg/kube/kubernetes_test.go index 56ca6204..87f9181c 100644 --- a/pkg/kube/kubernetes_test.go +++ b/pkg/kube/kubernetes_test.go @@ -16,14 +16,14 @@ import ( func Test_NewKubernetesClient(t *testing.T) { t.Run("Get new K8s client for remote cluster instance", func(t *testing.T) { - client, err := NewKubernetesClientFromConfig(context.TODO(), "", "../../test/testdata/kubernetes/config") + client, err := NewKubernetesClientFromConfig(context.TODO(), "", true, "../../test/testdata/kubernetes/config") require.NoError(t, err) assert.NotNil(t, client) assert.Equal(t, "default", client.Namespace) }) t.Run("Get new K8s client for remote cluster instance specified namespace", func(t *testing.T) { - client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", "../../test/testdata/kubernetes/config") + client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", true, "../../test/testdata/kubernetes/config") require.NoError(t, err) assert.NotNil(t, client) assert.Equal(t, "argocd", client.Namespace)