github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/cmd/tk/flags.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/rs/zerolog/log" 8 "github.com/spf13/pflag" 9 "k8s.io/apimachinery/pkg/labels" 10 11 "github.com/grafana/tanka/pkg/spec/v1alpha1" 12 "github.com/grafana/tanka/pkg/tanka" 13 ) 14 15 type workflowFlagVars struct { 16 name string 17 targets []string 18 jsonnetImplementation string 19 } 20 21 func workflowFlags(fs *pflag.FlagSet) *workflowFlagVars { 22 v := workflowFlagVars{} 23 fs.StringVar(&v.name, "name", "", "string that only a single inline environment contains in its name") 24 fs.StringSliceVarP(&v.targets, "target", "t", nil, "Regex filter on '<kind>/<name>'. See https://tanka.dev/output-filtering") 25 fs.StringVar(&v.jsonnetImplementation, "jsonnet-implementation", "go", "Use `go` to use native go-jsonnet implementation and `binary:<path>` to delegate evaluation to a binary (with the same API as the regular `jsonnet` binary, see the BinaryImplementation docstrings for more details)") 26 return &v 27 } 28 29 func addDiffFlags(fs *pflag.FlagSet, opts *tanka.DiffBaseOpts) { 30 fs.StringVar(&opts.Color, "color", "auto", `controls color in diff output, must be "auto", "always", or "never"`) 31 } 32 33 func addApplyFlags(fs *pflag.FlagSet, opts *tanka.ApplyBaseOpts, autoApproveDeprecated *bool, autoApprove *string) { 34 fs.StringVar(&opts.DryRun, "dry-run", "", `--dry-run parameter to pass down to kubectl, must be "none", "server", or "client"`) 35 fs.BoolVar(&opts.Force, "force", false, "force applying (kubectl apply --force)") 36 37 // Parse the auto-approve flag (choice), still supporting the deprecated dangerous-auto-approve flag (boolean) 38 fs.BoolVar(autoApproveDeprecated, "dangerous-auto-approve", false, "skip interactive approval. Only for automation!") 39 if err := fs.MarkDeprecated("dangerous-auto-approve", "use --auto-approve instead"); err != nil { 40 log.Fatal().Msgf("failed to mark deprecated flag: %s", err) 41 } 42 fs.StringVar(autoApprove, "auto-approve", "", "skip interactive approval. Only for automation! Allowed values: 'always', 'never', 'if-no-changes'") 43 } 44 45 func labelSelectorFlag(fs *pflag.FlagSet) func() labels.Selector { 46 labelSelector := fs.StringP("selector", "l", "", "Label selector. Uses the same syntax as kubectl does") 47 48 return func() labels.Selector { 49 if *labelSelector != "" { 50 selector, err := labels.Parse(*labelSelector) 51 if err != nil { 52 log.Fatal().Msgf("Could not parse selector (-l) %s", *labelSelector) 53 } 54 return selector 55 } 56 return nil 57 } 58 } 59 60 func jsonnetFlags(fs *pflag.FlagSet) func() tanka.JsonnetOpts { 61 getExtCode, getTLACode := cliCodeParser(fs) 62 maxStack := fs.Int("max-stack", 0, "Jsonnet VM max stack. The default value is the value set in the go-jsonnet library. Increase this if you get: max stack frames exceeded") 63 64 return func() tanka.JsonnetOpts { 65 return tanka.JsonnetOpts{ 66 MaxStack: *maxStack, 67 ExtCode: getExtCode(), 68 TLACode: getTLACode(), 69 } 70 } 71 } 72 73 func cliCodeParser(fs *pflag.FlagSet) (func() map[string]string, func() map[string]string) { 74 // need to use StringArray instead of StringSlice, because pflag attempts to 75 // parse StringSlice using the csv parser, which breaks when passing objects 76 extCode := fs.StringArray("ext-code", nil, "Set code value of extVar (Format: key=<code>)") 77 extStr := fs.StringArrayP("ext-str", "V", nil, "Set string value of extVar (Format: key=value)") 78 79 tlaCode := fs.StringArray("tla-code", nil, "Set code value of top level function (Format: key=<code>)") 80 tlaStr := fs.StringArrayP("tla-str", "A", nil, "Set string value of top level function (Format: key=value)") 81 82 newParser := func(kind string, code, str *[]string) func() map[string]string { 83 return func() map[string]string { 84 m := make(map[string]string) 85 for _, s := range *code { 86 split := strings.SplitN(s, "=", 2) 87 if len(split) != 2 { 88 log.Fatal().Msgf(kind+"-code argument has wrong format: `%s`. Expected `key=<code>`", s) 89 } 90 m[split[0]] = split[1] 91 } 92 93 for _, s := range *str { 94 split := strings.SplitN(s, "=", 2) 95 if len(split) != 2 { 96 log.Fatal().Msgf(kind+"-str argument has wrong format: `%s`. Expected `key=<value>`", s) 97 } 98 m[split[0]] = fmt.Sprintf(`"%s"`, split[1]) 99 } 100 return m 101 } 102 } 103 104 return newParser("ext", extCode, extStr), 105 newParser("tla", tlaCode, tlaStr) 106 } 107 108 func envSettingsFlags(env *v1alpha1.Environment, fs *pflag.FlagSet) { 109 fs.StringVar(&env.Spec.APIServer, "server", env.Spec.APIServer, "endpoint of the Kubernetes API") 110 fs.StringVar(&env.Spec.APIServer, "server-from-context", env.Spec.APIServer, "set the server to a known one from $KUBECONFIG") 111 fs.StringSliceVar(&env.Spec.ContextNames, "context-name", env.Spec.ContextNames, "valid context name for environment, can pass multiple, regex supported.") 112 fs.StringVar(&env.Spec.Namespace, "namespace", env.Spec.Namespace, "namespace to create objects in") 113 fs.StringVar(&env.Spec.DiffStrategy, "diff-strategy", env.Spec.DiffStrategy, "specify diff-strategy. Automatically detected otherwise.") 114 fs.BoolVar(&env.Spec.InjectLabels, "inject-labels", env.Spec.InjectLabels, "add tanka environment label to each created resource. Required for 'tk prune'.") 115 }