From 496ac5e2943d1cc7768a1680ec70a5014674300f Mon Sep 17 00:00:00 2001 From: Young-Zen <40934357+Young-Zen@users.noreply.github.com> Date: Sat, 6 Apr 2024 00:37:16 +0800 Subject: [PATCH] fix(cli): ARGOCD_OPTS supports --header and other parameters (#17553) Signed-off-by: yanghaojia <2453883990@qq.com> --- cmd/argocd/commands/root.go | 6 ++-- util/config/env.go | 37 ++++++++++++++++++++++-- util/config/env_test.go | 57 +++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) diff --git a/cmd/argocd/commands/root.go b/cmd/argocd/commands/root.go index 5c3b984e5bff5..1ad9f4e798ddc 100644 --- a/cmd/argocd/commands/root.go +++ b/cmd/argocd/commands/root.go @@ -75,11 +75,11 @@ func NewCommand() *cobra.Command { command.PersistentFlags().StringVar(&clientOpts.GRPCWebRootPath, "grpc-web-root-path", config.GetFlag("grpc-web-root-path", ""), "Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root.") command.PersistentFlags().StringVar(&cmdutil.LogFormat, "logformat", config.GetFlag("logformat", "text"), "Set the logging format. One of: text|json") command.PersistentFlags().StringVar(&cmdutil.LogLevel, "loglevel", config.GetFlag("loglevel", "info"), "Set the logging level. One of: debug|info|warn|error") - command.PersistentFlags().StringSliceVarP(&clientOpts.Headers, "header", "H", []string{}, "Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers)") + command.PersistentFlags().StringSliceVarP(&clientOpts.Headers, "header", "H", config.GetStringSliceFlag("header", []string{}), "Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers)") command.PersistentFlags().BoolVar(&clientOpts.PortForward, "port-forward", config.GetBoolFlag("port-forward"), "Connect to a random argocd-server port using port forwarding") command.PersistentFlags().StringVar(&clientOpts.PortForwardNamespace, "port-forward-namespace", config.GetFlag("port-forward-namespace", ""), "Namespace name which should be used for port forwarding") - command.PersistentFlags().IntVar(&clientOpts.HttpRetryMax, "http-retry-max", 0, "Maximum number of retries to establish http connection to Argo CD server") - command.PersistentFlags().BoolVar(&clientOpts.Core, "core", false, "If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server") + command.PersistentFlags().IntVar(&clientOpts.HttpRetryMax, "http-retry-max", config.GetIntFlag("http-retry-max", 0), "Maximum number of retries to establish http connection to Argo CD server") + command.PersistentFlags().BoolVar(&clientOpts.Core, "core", config.GetBoolFlag("core"), "If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server") command.PersistentFlags().StringVar(&clientOpts.ServerName, "server-name", env.StringFromEnv(common.EnvServerName, common.DefaultServerName), fmt.Sprintf("Name of the Argo CD API server; set this or the %s environment variable when the server's name label differs from the default, for example when installing via the Helm chart", common.EnvServerName)) command.PersistentFlags().StringVar(&clientOpts.AppControllerName, "controller-name", env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName), fmt.Sprintf("Name of the Argo CD Application controller; set this or the %s environment variable when the controller's name label differs from the default, for example when installing via the Helm chart", common.EnvAppControllerName)) command.PersistentFlags().StringVar(&clientOpts.RedisHaProxyName, "redis-haproxy-name", env.StringFromEnv(common.EnvRedisHaProxyName, common.DefaultRedisHaProxyName), fmt.Sprintf("Name of the Redis HA Proxy; set this or the %s environment variable when the HA Proxy's name label differs from the default, for example when installing via the Helm chart", common.EnvRedisHaProxyName)) diff --git a/util/config/env.go b/util/config/env.go index b6679bca7e460..d2007fba6af49 100644 --- a/util/config/env.go +++ b/util/config/env.go @@ -1,8 +1,10 @@ package config import ( + "encoding/csv" "errors" "os" + "strconv" "strings" "github.com/kballard/go-shellquote" @@ -46,8 +48,8 @@ func loadFlags() error { // pkg shellquota doesn't recognize `=` so that the opts in format `foo=bar` could not work. // issue ref: https://github.com/argoproj/argo-cd/issues/6822 for k, v := range flags { - if strings.Contains(k, "=") && strings.Count(k, "=") == 1 && v == "true" { - kv := strings.Split(k, "=") + if strings.Contains(k, "=") && v == "true" { + kv := strings.SplitN(k, "=", 2) actualKey, actualValue := kv[0], kv[1] if _, ok := flags[actualKey]; !ok { flags[actualKey] = actualValue @@ -68,3 +70,34 @@ func GetFlag(key, fallback string) string { func GetBoolFlag(key string) bool { return GetFlag(key, "false") == "true" } + +func GetIntFlag(key string, fallback int) int { + val, ok := flags[key] + if !ok { + return fallback + } + + v, err := strconv.Atoi(val) + if err != nil { + log.Fatal(err) + } + return v +} + +func GetStringSliceFlag(key string, fallback []string) []string { + val, ok := flags[key] + if !ok { + return fallback + } + + if val == "" { + return []string{} + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + v, err := csvReader.Read() + if err != nil { + log.Fatal(err) + } + return v +} diff --git a/util/config/env_test.go b/util/config/env_test.go index c19961813a457..da0ae71ba18da 100644 --- a/util/config/env_test.go +++ b/util/config/env_test.go @@ -54,6 +54,63 @@ func TestBooleanFlagAtEnd(t *testing.T) { assert.True(t, GetBoolFlag("foo")) } +func TestIntFlag(t *testing.T) { + loadOpts(t, "--foo 2") + + assert.Equal(t, 2, GetIntFlag("foo", 0)) +} + +func TestIntFlagAtStart(t *testing.T) { + loadOpts(t, "--foo 2 --bar baz") + + assert.Equal(t, 2, GetIntFlag("foo", 0)) +} + +func TestIntFlagInMiddle(t *testing.T) { + loadOpts(t, "--bar baz --foo 2 --qux") + + assert.Equal(t, 2, GetIntFlag("foo", 0)) +} + +func TestIntFlagAtEnd(t *testing.T) { + loadOpts(t, "--bar baz --foo 2") + + assert.Equal(t, 2, GetIntFlag("foo", 0)) +} + +func TestStringSliceFlag(t *testing.T) { + loadOpts(t, "--header='Content-Type: application/json; charset=utf-8,Strict-Transport-Security: max-age=31536000'") + strings := GetStringSliceFlag("header", []string{}) + + assert.Equal(t, 2, len(strings)) + assert.Equal(t, "Content-Type: application/json; charset=utf-8", strings[0]) + assert.Equal(t, "Strict-Transport-Security: max-age=31536000", strings[1]) +} + +func TestStringSliceFlagAtStart(t *testing.T) { + loadOpts(t, "--header='Strict-Transport-Security: max-age=31536000' --bar baz") + strings := GetStringSliceFlag("header", []string{}) + + assert.Equal(t, 1, len(strings)) + assert.Equal(t, "Strict-Transport-Security: max-age=31536000", strings[0]) +} + +func TestStringSliceFlagInMiddle(t *testing.T) { + loadOpts(t, "--bar baz --header='Strict-Transport-Security: max-age=31536000' --qux") + strings := GetStringSliceFlag("header", []string{}) + + assert.Equal(t, 1, len(strings)) + assert.Equal(t, "Strict-Transport-Security: max-age=31536000", strings[0]) +} + +func TestStringSliceFlagAtEnd(t *testing.T) { + loadOpts(t, "--bar baz --header='Strict-Transport-Security: max-age=31536000'") + strings := GetStringSliceFlag("header", []string{}) + + assert.Equal(t, 1, len(strings)) + assert.Equal(t, "Strict-Transport-Security: max-age=31536000", strings[0]) +} + func TestFlagAtStart(t *testing.T) { loadOpts(t, "--foo bar")