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  }