k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/flags/flags.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package flags
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"os"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/spf13/pflag"
    28  	"k8s.io/klog/v2"
    29  )
    30  
    31  func init() {
    32  	pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
    33  	klog.InitFlags(nil)
    34  	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
    35  }
    36  
    37  var flags []flagFunc
    38  
    39  // StringVar creates string flag with given parameters.
    40  func StringVar(s *string, flagName, defaultValue, description string) {
    41  	pflag.StringVar(s, flagName, defaultValue, description)
    42  }
    43  
    44  // IntVar creates int flag with given parameters.
    45  func IntVar(i *int, flagName string, defaultValue int, description string) {
    46  	pflag.IntVar(i, flagName, defaultValue, description)
    47  }
    48  
    49  // BoolVar creates a bool flag with given parameters.
    50  func BoolVar(b *bool, flagName string, defaultValue bool, description string) {
    51  	pflag.BoolVar(b, flagName, defaultValue, description)
    52  }
    53  
    54  // DurationVar creates a time.Duration flag with given parameters.
    55  func DurationVar(d *time.Duration, flagName string, defaultValue time.Duration, description string) {
    56  	pflag.DurationVar(d, flagName, defaultValue, description)
    57  }
    58  
    59  // StringEnvVar creates string flag with given parameters.
    60  // If flag is not provided, it will try to get env variable.
    61  func StringEnvVar(s *string, flagName, envVariable, defaultValue, description string) {
    62  	stringFlag := &stringFlagFunc{
    63  		valPtr:         s,
    64  		initializeFunc: func() error { return parseEnvString(s, envVariable, defaultValue) },
    65  	}
    66  	pflag.Var(stringFlag, flagName, description)
    67  	flags = append(flags, stringFlag)
    68  }
    69  
    70  // StringArrayVar creates string flag with given parameters. Flag can be used multiple times.
    71  func StringArrayVar(s *[]string, flagName string, defaultValue []string, description string) {
    72  	pflag.StringArrayVar(s, flagName, defaultValue, description)
    73  }
    74  
    75  // StringSliceEnvVar creates a string slice flag with the given parameters.
    76  // If the flag is not provided, it will try to get the env variable.
    77  // Flag accepts multiple values separated by commas.
    78  func StringSliceEnvVar(s *[]string, flagName, envVariable string, defaultValue []string, description string) {
    79  	stringSliceFlag := &stringSliceFlagFunc{
    80  		valPtr:         s,
    81  		initializeFunc: func() error { return parseEnvStringSlice(s, envVariable, defaultValue) },
    82  	}
    83  	pflag.Var(stringSliceFlag, flagName, description)
    84  	flags = append(flags, stringSliceFlag)
    85  }
    86  
    87  // IntEnvVar creates int flag with given parameters.
    88  // If flag is not provided, it will try to get env variable.
    89  func IntEnvVar(i *int, flagName, envVariable string, defaultValue int, description string) {
    90  	intFlag := &intFlagFunc{
    91  		valPtr:         i,
    92  		initializeFunc: func() error { return parseEnvInt(i, envVariable, defaultValue) },
    93  	}
    94  	pflag.Var(intFlag, flagName, description)
    95  	flags = append(flags, intFlag)
    96  }
    97  
    98  // BoolEnvVar creates bool flag with given parameters.
    99  // If flag is not provided, it will try to get env variable.
   100  func BoolEnvVar(b *bool, flagName, envVariable string, defaultValue bool, description string) {
   101  	boolFlag := &boolFlagFunc{
   102  		valPtr:         b,
   103  		initializeFunc: func() error { return parseEnvBool(b, envVariable, defaultValue) },
   104  	}
   105  	// Set NoOptDefValue, to make --flag-name equivalent to --flag-name=true
   106  	pflag.CommandLine.VarPF(boolFlag, flagName, "", description).NoOptDefVal = "true"
   107  	flags = append(flags, boolFlag)
   108  }
   109  
   110  // DurationEnvVar creates time.Duration flag with given parameters.
   111  // If flag is not provided, it will try to get env variable.
   112  func DurationEnvVar(d *time.Duration, flagName, envVariable string, defaultValue time.Duration, description string) {
   113  	durationFlag := &durationFlagFunc{
   114  		valPtr:         d,
   115  		initializeFunc: func() error { return parseEnvDuration(d, envVariable, defaultValue) },
   116  	}
   117  	pflag.Var(durationFlag, flagName, description)
   118  	flags = append(flags, durationFlag)
   119  }
   120  
   121  // Parse parses provided flags and env variables.
   122  func Parse() error {
   123  	for i := range flags {
   124  		if err := flags[i].initialize(); err != nil {
   125  			return err
   126  		}
   127  	}
   128  	if err := pflag.CommandLine.Parse(os.Args[1:]); err != nil {
   129  		return err
   130  	}
   131  	return nil
   132  }
   133  
   134  // MarkDeprecated indicates that a flag is deprecated
   135  func MarkDeprecated(name string, usageMessage string) error {
   136  	return pflag.CommandLine.MarkDeprecated(name, usageMessage)
   137  }
   138  
   139  func parseEnvString(s *string, envVariable, defaultValue string) error {
   140  	*s = defaultValue
   141  	if envVariable != "" {
   142  		if val, ok := os.LookupEnv(envVariable); ok {
   143  			*s = val
   144  			return nil
   145  		}
   146  	}
   147  	return nil
   148  }
   149  
   150  func parseEnvStringSlice(s *[]string, envVariable string, defaultValue []string) error {
   151  	*s = defaultValue
   152  	if envVariable != "" {
   153  		if val, ok := os.LookupEnv(envVariable); ok && val != "" {
   154  			*s = strings.Split(val, ",")
   155  		}
   156  	}
   157  	return nil
   158  }
   159  
   160  func parseEnvInt(i *int, envVariable string, defaultValue int) error {
   161  	*i = defaultValue
   162  	if envVariable != "" {
   163  		if val, ok := os.LookupEnv(envVariable); ok {
   164  			iVal, err := strconv.Atoi(val)
   165  			if err != nil {
   166  				return fmt.Errorf("parsing env variable %s failed", envVariable)
   167  			}
   168  			*i = iVal
   169  			return nil
   170  		}
   171  	}
   172  	return nil
   173  }
   174  
   175  func parseEnvBool(b *bool, envVariable string, defaultValue bool) error {
   176  	*b = defaultValue
   177  	if envVariable != "" {
   178  		if val, ok := os.LookupEnv(envVariable); ok {
   179  			bVal, err := strconv.ParseBool(val)
   180  			if err != nil {
   181  				return fmt.Errorf("parsing env variable %s failed", envVariable)
   182  			}
   183  			*b = bVal
   184  			return nil
   185  		}
   186  	}
   187  	return nil
   188  }
   189  
   190  func parseEnvDuration(d *time.Duration, envVariable string, defaultValue time.Duration) error {
   191  	*d = defaultValue
   192  	if envVariable != "" {
   193  		if val, ok := os.LookupEnv(envVariable); ok {
   194  			dVal, err := time.ParseDuration(val)
   195  			if err != nil {
   196  				return fmt.Errorf("parsing env variable %s failed", envVariable)
   197  			}
   198  			*d = dVal
   199  			return nil
   200  		}
   201  	}
   202  	return nil
   203  }