diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 373e038cc0c..a9051577450 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -61,9 +61,13 @@ import ( var viperConfig = flag.String("viper-config", "", "The name of a viper config file (https://github.com/spf13/viper#what-is-viper). All e2e command line parameters can also be configured in such a file. May contain a path and may or may not contain the file suffix. The default is to look for an optional file with `e2e` as base name. If a file is specified explicitly, it must be present.") func init() { - // Register framework flags, then handle flags and Viper config. + // Register framework and test flags, then parse flags. framework.HandleFlags() - if err := viperconfig.ViperizeFlags(*viperConfig, "e2e"); err != nil { + + // Now that we know which Viper config (if any) was chosen, + // parse it and update those options which weren't already set via command line flags + // (which have higher priority). + if err := viperconfig.ViperizeFlags(*viperConfig, "e2e", flag.CommandLine); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } diff --git a/test/e2e/framework/config/config.go b/test/e2e/framework/config/config.go index 1cd4a052f62..5fa37bcae73 100644 --- a/test/e2e/framework/config/config.go +++ b/test/e2e/framework/config/config.go @@ -15,11 +15,22 @@ limitations under the License. */ // Package config simplifies the declaration of configuration options. -// Right now the implementation maps them directly command line -// flags. When combined with test/e2e/framework/viper in a test suite, -// those flags then can also be read from a config file. +// Right now the implementation maps them directly to command line +// flags. When combined with test/e2e/framework/viperconfig in a test +// suite, those flags then can also be read from a config file. // -// Instead of defining flags one-by-one, developers annotate a +// The command line flags all get stored in a private flag set. The +// developer of the E2E test suite decides how they are exposed. Options +// include: +// - exposing as normal flags in the actual command line: +// CopyFlags(Flags, flag.CommandLine) +// - populate via test/e2e/framework/viperconfig: +// viperconfig.ViperizeFlags("my-config.yaml", "", Flags) +// - a combination of both: +// CopyFlags(Flags, flag.CommandLine) +// viperconfig.ViperizeFlags("my-config.yaml", "", flag.CommandLine) +// +// Instead of defining flags one-by-one, test developers annotate a // structure with tags and then call a single function. This is the // same approach as in https://godoc.org/github.com/jessevdk/go-flags, // but implemented so that a test suite can continue to use the normal @@ -84,10 +95,23 @@ import ( "unicode/utf8" ) -// CommandLine is the flag set that AddOptions adds to. Usually this -// is the same as the default in the flag package, but can also be -// something else (for example during testing). -var CommandLine = flag.CommandLine +// Flags is the flag set that AddOptions adds to. Test authors should +// also use it instead of directly adding to the global command line. +var Flags = flag.NewFlagSet("", flag.ContinueOnError) + +// CopyFlags ensures that all flags that are defined in the source flag +// set appear in the target flag set as if they had been defined there +// directly. From the flag package it inherits the behavior that there +// is a panic if the target already contains a flag from the source. +func CopyFlags(source *flag.FlagSet, target *flag.FlagSet) { + source.VisitAll(func(flag *flag.Flag) { + // We don't need to copy flag.DefValue. The original + // default (from, say, flag.String) was stored in + // the value and gets extracted by Var for the help + // message. + target.Var(flag.Value, flag.Name, flag.Usage) + }) +} // AddOptions analyzes the options value and creates the necessary // flags to populate it. @@ -102,6 +126,11 @@ var CommandLine = flag.CommandLine // It panics when it encounters an error, like unsupported types // or option name conflicts. func AddOptions(options interface{}, prefix string) bool { + return AddOptionsToSet(Flags, options, prefix) +} + +// AddOptionsToSet is the same as AddOption, except that it allows choosing the flag set. +func AddOptionsToSet(flags *flag.FlagSet, options interface{}, prefix string) bool { optionsType := reflect.TypeOf(options) if optionsType == nil { panic("options parameter without a type - nil?!") @@ -109,11 +138,11 @@ func AddOptions(options interface{}, prefix string) bool { if optionsType.Kind() != reflect.Ptr || optionsType.Elem().Kind() != reflect.Struct { panic(fmt.Sprintf("need a pointer to a struct, got instead: %T", options)) } - addStructFields(optionsType.Elem(), reflect.Indirect(reflect.ValueOf(options)), prefix) + addStructFields(flags, optionsType.Elem(), reflect.Indirect(reflect.ValueOf(options)), prefix) return true } -func addStructFields(structType reflect.Type, structValue reflect.Value, prefix string) { +func addStructFields(flags *flag.FlagSet, structType reflect.Type, structValue reflect.Value, prefix string) { for i := 0; i < structValue.NumField(); i++ { entry := structValue.Field(i) addr := entry.Addr() @@ -134,12 +163,12 @@ func addStructFields(structType reflect.Type, structValue reflect.Value, prefix // Entries in embedded fields are treated like // entries, in the struct itself, i.e. we add // them with the same prefix. - addStructFields(structField.Type, entry, prefix) + addStructFields(flags, structField.Type, entry, prefix) continue } if structField.Type.Kind() == reflect.Struct { // Add nested options. - addStructFields(structField.Type, entry, name) + addStructFields(flags, structField.Type, entry, name) continue } // We could switch based on structField.Type. Doing a @@ -153,33 +182,33 @@ func addStructFields(structType reflect.Type, structValue reflect.Value, prefix case *bool: var defValue bool parseDefault(&defValue, name, def) - CommandLine.BoolVar(ptr, name, defValue, usage) + flags.BoolVar(ptr, name, defValue, usage) case *time.Duration: var defValue time.Duration parseDefault(&defValue, name, def) - CommandLine.DurationVar(ptr, name, defValue, usage) + flags.DurationVar(ptr, name, defValue, usage) case *float64: var defValue float64 parseDefault(&defValue, name, def) - CommandLine.Float64Var(ptr, name, defValue, usage) + flags.Float64Var(ptr, name, defValue, usage) case *string: - CommandLine.StringVar(ptr, name, def, usage) + flags.StringVar(ptr, name, def, usage) case *int: var defValue int parseDefault(&defValue, name, def) - CommandLine.IntVar(ptr, name, defValue, usage) + flags.IntVar(ptr, name, defValue, usage) case *int64: var defValue int64 parseDefault(&defValue, name, def) - CommandLine.Int64Var(ptr, name, defValue, usage) + flags.Int64Var(ptr, name, defValue, usage) case *uint: var defValue uint parseDefault(&defValue, name, def) - CommandLine.UintVar(ptr, name, defValue, usage) + flags.UintVar(ptr, name, defValue, usage) case *uint64: var defValue uint64 parseDefault(&defValue, name, def) - CommandLine.Uint64Var(ptr, name, defValue, usage) + flags.Uint64Var(ptr, name, defValue, usage) default: panic(fmt.Sprintf("unsupported struct entry type %q: %T", name, entry.Interface())) } diff --git a/test/e2e/framework/config/config_test.go b/test/e2e/framework/config/config_test.go index d6856e696ad..a5e8b495d3d 100644 --- a/test/e2e/framework/config/config_test.go +++ b/test/e2e/framework/config/config_test.go @@ -17,6 +17,7 @@ limitations under the License. package config import ( + "bytes" "flag" "testing" "time" @@ -26,12 +27,12 @@ import ( ) func TestInt(t *testing.T) { - CommandLine = flag.NewFlagSet("test", 0) + flags := flag.NewFlagSet("test", 0) var context struct { Number int `default:"5" usage:"some number"` } require.NotPanics(t, func() { - AddOptions(&context, "") + AddOptionsToSet(flags, &context, "") }) require.Equal(t, []simpleFlag{ { @@ -39,18 +40,18 @@ func TestInt(t *testing.T) { usage: "some number", defValue: "5", }}, - allFlags(CommandLine)) + allFlags(flags)) assert.Equal(t, 5, context.Number) } func TestLower(t *testing.T) { - CommandLine = flag.NewFlagSet("test", 0) + flags := flag.NewFlagSet("test", 0) var context struct { Ähem string MixedCase string } require.NotPanics(t, func() { - AddOptions(&context, "") + AddOptionsToSet(flags, &context, "") }) require.Equal(t, []simpleFlag{ { @@ -60,16 +61,16 @@ func TestLower(t *testing.T) { name: "ähem", }, }, - allFlags(CommandLine)) + allFlags(flags)) } func TestPrefix(t *testing.T) { - CommandLine = flag.NewFlagSet("test", 0) + flags := flag.NewFlagSet("test", 0) var context struct { Number int `usage:"some number"` } require.NotPanics(t, func() { - AddOptions(&context, "some.prefix") + AddOptionsToSet(flags, &context, "some.prefix") }) require.Equal(t, []simpleFlag{ { @@ -77,11 +78,11 @@ func TestPrefix(t *testing.T) { usage: "some number", defValue: "0", }}, - allFlags(CommandLine)) + allFlags(flags)) } func TestRecursion(t *testing.T) { - CommandLine = flag.NewFlagSet("test", 0) + flags := flag.NewFlagSet("test", 0) type Nested struct { Number1 int `usage:"embedded number"` } @@ -96,7 +97,7 @@ func TestRecursion(t *testing.T) { } } require.NotPanics(t, func() { - AddOptions(&context, "") + AddOptionsToSet(flags, &context, "") }) require.Equal(t, []simpleFlag{ { @@ -110,38 +111,39 @@ func TestRecursion(t *testing.T) { defValue: "0", }, }, - allFlags(CommandLine)) + allFlags(flags)) } func TestPanics(t *testing.T) { + flags := flag.NewFlagSet("test", 0) assert.PanicsWithValue(t, `invalid default "a" for int entry prefix.number: strconv.Atoi: parsing "a": invalid syntax`, func() { var context struct { Number int `default:"a"` } - AddOptions(&context, "prefix") + AddOptionsToSet(flags, &context, "prefix") }) assert.PanicsWithValue(t, `invalid default "10000000000000000000" for int entry prefix.number: strconv.Atoi: parsing "10000000000000000000": value out of range`, func() { var context struct { Number int `default:"10000000000000000000"` } - AddOptions(&context, "prefix") + AddOptionsToSet(flags, &context, "prefix") }) assert.PanicsWithValue(t, `options parameter without a type - nil?!`, func() { - AddOptions(nil, "") + AddOptionsToSet(flags, nil, "") }) assert.PanicsWithValue(t, `need a pointer to a struct, got instead: *int`, func() { number := 0 - AddOptions(&number, "") + AddOptionsToSet(flags, &number, "") }) assert.PanicsWithValue(t, `struct entry "prefix.number" not exported`, func() { var context struct { number int } - AddOptions(&context, "prefix") + AddOptionsToSet(flags, &context, "prefix") }) assert.PanicsWithValue(t, `unsupported struct entry type "prefix.someNumber": config.MyInt`, func() { @@ -149,12 +151,28 @@ func TestPanics(t *testing.T) { var context struct { SomeNumber MyInt } - AddOptions(&context, "prefix") + AddOptionsToSet(flags, &context, "prefix") }) } +type TypesTestCase struct { + name string + copyFlags bool +} + func TestTypes(t *testing.T) { - CommandLine = flag.NewFlagSet("test", 0) + testcases := []TypesTestCase{ + {name: "directly"}, + {name: "CopyFlags", copyFlags: true}, + } + + for _, testcase := range testcases { + testTypes(t, testcase) + } +} + +func testTypes(t *testing.T, testcase TypesTestCase) { + flags := flag.NewFlagSet("test", 0) type Context struct { Bool bool `default:"true"` Duration time.Duration `default:"1ms"` @@ -167,8 +185,25 @@ func TestTypes(t *testing.T) { } var context Context require.NotPanics(t, func() { - AddOptions(&context, "") + AddOptionsToSet(flags, &context, "") }) + + if testcase.copyFlags { + original := bytes.Buffer{} + flags.SetOutput(&original) + flags.PrintDefaults() + + flags2 := flag.NewFlagSet("test", 0) + CopyFlags(flags, flags2) + flags = flags2 + + copy := bytes.Buffer{} + flags.SetOutput(©) + flags.PrintDefaults() + assert.Equal(t, original.String(), copy.String(), testcase.name+": help messages equal") + assert.Contains(t, copy.String(), "some number", testcase.name+": copied help message contains defaults") + } + require.Equal(t, []simpleFlag{ { name: "bool", @@ -205,14 +240,14 @@ func TestTypes(t *testing.T) { defValue: "1234567890123456789", }, }, - allFlags(CommandLine)) + allFlags(flags), testcase.name) assert.Equal(t, Context{true, time.Millisecond, 1.23456789, "hello world", -1, -1234567890123456789, 1, 1234567890123456789, }, context, "default values must match") - require.NoError(t, CommandLine.Parse([]string{ + require.NoError(t, flags.Parse([]string{ "-int", "-2", "-int64", "-9123456789012345678", "-uint", "2", @@ -221,13 +256,13 @@ func TestTypes(t *testing.T) { "-float64", "-1.23456789", "-bool=false", "-duration=1s", - })) + }), testcase.name) assert.Equal(t, Context{false, time.Second, -1.23456789, "pong", -2, -9123456789012345678, 2, 9123456789012345678, }, context, - "parsed values must match") + testcase.name+": parsed values must match") } func allFlags(fs *flag.FlagSet) []simpleFlag { diff --git a/test/e2e/framework/test_context.go b/test/e2e/framework/test_context.go index fdc2524435c..970ecfc4b3a 100644 --- a/test/e2e/framework/test_context.go +++ b/test/e2e/framework/test_context.go @@ -33,6 +33,7 @@ import ( cliflag "k8s.io/component-base/cli/flag" "k8s.io/klog" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" + e2econfig "k8s.io/kubernetes/test/e2e/framework/config" e2elog "k8s.io/kubernetes/test/e2e/framework/log" ) @@ -230,7 +231,17 @@ type CloudConfig struct { var TestContext TestContextType // RegisterCommonFlags registers flags common to all e2e test suites. -func RegisterCommonFlags() { +// The flag set can be flag.CommandLine (if desired) or a custom +// flag set that then gets passed to viperconfig.ViperizeFlags. +// +// The other Register*Flags methods below can be used to add more +// test-specific flags. However, those settings then get added +// regardless whether the test is actually in the test suite. +// +// For tests that have been converted to registering their +// options themselves, copy flags from test/e2e/framework/config +// as shown in HandleFlags. +func RegisterCommonFlags(flags *flag.FlagSet) { // Turn on verbose by default to get spec names config.DefaultReporterConfig.Verbose = true @@ -240,117 +251,118 @@ func RegisterCommonFlags() { // Randomize specs as well as suites config.GinkgoConfig.RandomizeAllSpecs = true - flag.StringVar(&TestContext.GatherKubeSystemResourceUsageData, "gather-resource-usage", "false", "If set to 'true' or 'all' framework will be monitoring resource usage of system all add-ons in (some) e2e tests, if set to 'master' framework will be monitoring master node only, if set to 'none' of 'false' monitoring will be turned off.") - flag.BoolVar(&TestContext.GatherLogsSizes, "gather-logs-sizes", false, "If set to true framework will be monitoring logs sizes on all machines running e2e tests.") - flag.IntVar(&TestContext.MaxNodesToGather, "max-nodes-to-gather-from", 20, "The maximum number of nodes to gather extended info from on test failure.") - flag.StringVar(&TestContext.GatherMetricsAfterTest, "gather-metrics-at-teardown", "false", "If set to 'true' framework will gather metrics from all components after each test. If set to 'master' only master component metrics would be gathered.") - flag.BoolVar(&TestContext.GatherSuiteMetricsAfterTest, "gather-suite-metrics-at-teardown", false, "If set to true framwork will gather metrics from all components after the whole test suite completes.") - flag.BoolVar(&TestContext.AllowGatheringProfiles, "allow-gathering-profiles", true, "If set to true framework will allow to gather CPU/memory allocation pprof profiles from the master.") - flag.BoolVar(&TestContext.IncludeClusterAutoscalerMetrics, "include-cluster-autoscaler", false, "If set to true, framework will include Cluster Autoscaler when gathering metrics.") - flag.StringVar(&TestContext.OutputPrintType, "output-print-type", "json", "Format in which summaries should be printed: 'hr' for human readable, 'json' for JSON ones.") - flag.BoolVar(&TestContext.DumpLogsOnFailure, "dump-logs-on-failure", true, "If set to true test will dump data about the namespace in which test was running.") - flag.BoolVar(&TestContext.DisableLogDump, "disable-log-dump", false, "If set to true, logs from master and nodes won't be gathered after test run.") - flag.StringVar(&TestContext.LogexporterGCSPath, "logexporter-gcs-path", "", "Path to the GCS artifacts directory to dump logs from nodes. Logexporter gets enabled if this is non-empty.") - flag.BoolVar(&TestContext.DeleteNamespace, "delete-namespace", true, "If true tests will delete namespace after completion. It is only designed to make debugging easier, DO NOT turn it off by default.") - flag.BoolVar(&TestContext.DeleteNamespaceOnFailure, "delete-namespace-on-failure", true, "If true, framework will delete test namespace on failure. Used only during test debugging.") - flag.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If non-zero, framework will allow for that many non-ready nodes when checking for all ready nodes.") + flags.StringVar(&TestContext.GatherKubeSystemResourceUsageData, "gather-resource-usage", "false", "If set to 'true' or 'all' framework will be monitoring resource usage of system all add-ons in (some) e2e tests, if set to 'master' framework will be monitoring master node only, if set to 'none' of 'false' monitoring will be turned off.") + flags.BoolVar(&TestContext.GatherLogsSizes, "gather-logs-sizes", false, "If set to true framework will be monitoring logs sizes on all machines running e2e tests.") + flags.IntVar(&TestContext.MaxNodesToGather, "max-nodes-to-gather-from", 20, "The maximum number of nodes to gather extended info from on test failure.") + flags.StringVar(&TestContext.GatherMetricsAfterTest, "gather-metrics-at-teardown", "false", "If set to 'true' framework will gather metrics from all components after each test. If set to 'master' only master component metrics would be gathered.") + flags.BoolVar(&TestContext.GatherSuiteMetricsAfterTest, "gather-suite-metrics-at-teardown", false, "If set to true framwork will gather metrics from all components after the whole test suite completes.") + flags.BoolVar(&TestContext.AllowGatheringProfiles, "allow-gathering-profiles", true, "If set to true framework will allow to gather CPU/memory allocation pprof profiles from the master.") + flags.BoolVar(&TestContext.IncludeClusterAutoscalerMetrics, "include-cluster-autoscaler", false, "If set to true, framework will include Cluster Autoscaler when gathering metrics.") + flags.StringVar(&TestContext.OutputPrintType, "output-print-type", "json", "Format in which summaries should be printed: 'hr' for human readable, 'json' for JSON ones.") + flags.BoolVar(&TestContext.DumpLogsOnFailure, "dump-logs-on-failure", true, "If set to true test will dump data about the namespace in which test was running.") + flags.BoolVar(&TestContext.DisableLogDump, "disable-log-dump", false, "If set to true, logs from master and nodes won't be gathered after test run.") + flags.StringVar(&TestContext.LogexporterGCSPath, "logexporter-gcs-path", "", "Path to the GCS artifacts directory to dump logs from nodes. Logexporter gets enabled if this is non-empty.") + flags.BoolVar(&TestContext.DeleteNamespace, "delete-namespace", true, "If true tests will delete namespace after completion. It is only designed to make debugging easier, DO NOT turn it off by default.") + flags.BoolVar(&TestContext.DeleteNamespaceOnFailure, "delete-namespace-on-failure", true, "If true, framework will delete test namespace on failure. Used only during test debugging.") + flags.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If non-zero, framework will allow for that many non-ready nodes when checking for all ready nodes.") - flag.StringVar(&TestContext.Host, "host", "", fmt.Sprintf("The host, or apiserver, to connect to. Will default to %s if this argument and --kubeconfig are not set", defaultHost)) - flag.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.") - flag.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.") - flag.Var(cliflag.NewMapStringBool(&TestContext.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features.") - flag.StringVar(&TestContext.ContainerRuntime, "container-runtime", "docker", "The container runtime of cluster VM instances (docker/remote).") - flag.StringVar(&TestContext.ContainerRuntimeEndpoint, "container-runtime-endpoint", "unix:///var/run/dockershim.sock", "The container runtime endpoint of cluster VM instances.") - flag.StringVar(&TestContext.ContainerRuntimeProcessName, "container-runtime-process-name", "dockerd", "The name of the container runtime process.") - flag.StringVar(&TestContext.ContainerRuntimePidFile, "container-runtime-pid-file", "/var/run/docker.pid", "The pid file of the container runtime.") - flag.StringVar(&TestContext.SystemdServices, "systemd-services", "docker", "The comma separated list of systemd services the framework will dump logs for.") - flag.BoolVar(&TestContext.DumpSystemdJournal, "dump-systemd-journal", false, "Whether to dump the full systemd journal.") - flag.StringVar(&TestContext.ImageServiceEndpoint, "image-service-endpoint", "", "The image service endpoint of cluster VM instances.") - flag.StringVar(&TestContext.DockershimCheckpointDir, "dockershim-checkpoint-dir", "/var/lib/dockershim/sandbox", "The directory for dockershim to store sandbox checkpoints.") - flag.StringVar(&TestContext.KubernetesAnywherePath, "kubernetes-anywhere-path", "/workspace/k8s.io/kubernetes-anywhere", "Which directory kubernetes-anywhere is installed to.") + flags.StringVar(&TestContext.Host, "host", "", fmt.Sprintf("The host, or apiserver, to connect to. Will default to %s if this argument and --kubeconfig are not set", defaultHost)) + flags.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.") + flags.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.") + flags.Var(cliflag.NewMapStringBool(&TestContext.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features.") + flags.StringVar(&TestContext.ContainerRuntime, "container-runtime", "docker", "The container runtime of cluster VM instances (docker/remote).") + flags.StringVar(&TestContext.ContainerRuntimeEndpoint, "container-runtime-endpoint", "unix:///var/run/dockershim.sock", "The container runtime endpoint of cluster VM instances.") + flags.StringVar(&TestContext.ContainerRuntimeProcessName, "container-runtime-process-name", "dockerd", "The name of the container runtime process.") + flags.StringVar(&TestContext.ContainerRuntimePidFile, "container-runtime-pid-file", "/var/run/docker.pid", "The pid file of the container runtime.") + flags.StringVar(&TestContext.SystemdServices, "systemd-services", "docker", "The comma separated list of systemd services the framework will dump logs for.") + flags.BoolVar(&TestContext.DumpSystemdJournal, "dump-systemd-journal", false, "Whether to dump the full systemd journal.") + flags.StringVar(&TestContext.ImageServiceEndpoint, "image-service-endpoint", "", "The image service endpoint of cluster VM instances.") + flags.StringVar(&TestContext.DockershimCheckpointDir, "dockershim-checkpoint-dir", "/var/lib/dockershim/sandbox", "The directory for dockershim to store sandbox checkpoints.") + flags.StringVar(&TestContext.KubernetesAnywherePath, "kubernetes-anywhere-path", "/workspace/k8s.io/kubernetes-anywhere", "Which directory kubernetes-anywhere is installed to.") - flag.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for runnning tests.") + flags.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for runnning tests.") } // RegisterClusterFlags registers flags specific to the cluster e2e test suite. -func RegisterClusterFlags() { - flag.BoolVar(&TestContext.VerifyServiceAccount, "e2e-verify-service-account", true, "If true tests will verify the service account before running.") - flag.StringVar(&TestContext.KubeConfig, clientcmd.RecommendedConfigPathFlag, os.Getenv(clientcmd.RecommendedConfigPathEnvVar), "Path to kubeconfig containing embedded authinfo.") - flag.StringVar(&TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'") - flag.StringVar(&TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver") +func RegisterClusterFlags(flags *flag.FlagSet) { + flags.BoolVar(&TestContext.VerifyServiceAccount, "e2e-verify-service-account", true, "If true tests will verify the service account before running.") + flags.StringVar(&TestContext.KubeConfig, clientcmd.RecommendedConfigPathFlag, os.Getenv(clientcmd.RecommendedConfigPathEnvVar), "Path to kubeconfig containing embedded authinfo.") + flags.StringVar(&TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'") + flags.StringVar(&TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver") - flag.StringVar(&TestContext.KubeVolumeDir, "volume-dir", "/var/lib/kubelet", "Path to the directory containing the kubelet volumes.") - flag.StringVar(&TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.") - flag.StringVar(&TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.") - flag.StringVar(&TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)") - flag.StringVar(&TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)") - flag.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.") - flag.StringVar(&TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.") - flag.StringVar(&TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.") - flag.StringVar(&TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).") - flag.StringVar(&TestContext.NodeOSDistro, "node-os-distro", "debian", "The OS distribution of cluster VM instances (debian, ubuntu, gci, coreos, or custom).") - flag.StringVar(&TestContext.ClusterMonitoringMode, "cluster-monitoring-mode", "standalone", "The monitoring solution that is used in the cluster.") - flag.BoolVar(&TestContext.EnablePrometheusMonitoring, "prometheus-monitoring", false, "Separate Prometheus monitoring deployed in cluster.") - flag.StringVar(&TestContext.ClusterDNSDomain, "dns-domain", "cluster.local", "The DNS Domain of the cluster.") + flags.StringVar(&TestContext.KubeVolumeDir, "volume-dir", "/var/lib/kubelet", "Path to the directory containing the kubelet volumes.") + flags.StringVar(&TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.") + flags.StringVar(&TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.") + flags.StringVar(&TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)") + flags.StringVar(&TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)") + flags.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.") + flags.StringVar(&TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.") + flags.StringVar(&TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.") + flags.StringVar(&TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).") + flags.StringVar(&TestContext.NodeOSDistro, "node-os-distro", "debian", "The OS distribution of cluster VM instances (debian, ubuntu, gci, coreos, or custom).") + flags.StringVar(&TestContext.ClusterMonitoringMode, "cluster-monitoring-mode", "standalone", "The monitoring solution that is used in the cluster.") + flags.BoolVar(&TestContext.EnablePrometheusMonitoring, "prometheus-monitoring", false, "Separate Prometheus monitoring deployed in cluster.") + flags.StringVar(&TestContext.ClusterDNSDomain, "dns-domain", "cluster.local", "The DNS Domain of the cluster.") // TODO: Flags per provider? Rename gce-project/gce-zone? cloudConfig := &TestContext.CloudConfig - flag.StringVar(&cloudConfig.MasterName, "kube-master", "", "Name of the kubernetes master. Only required if provider is gce or gke") - flag.StringVar(&cloudConfig.APIEndpoint, "gce-api-endpoint", "", "The GCE APIEndpoint being used, if applicable") - flag.StringVar(&cloudConfig.ProjectID, "gce-project", "", "The GCE project being used, if applicable") - flag.StringVar(&cloudConfig.Zone, "gce-zone", "", "GCE zone being used, if applicable") - flag.StringVar(&cloudConfig.Region, "gce-region", "", "GCE region being used, if applicable") - flag.BoolVar(&cloudConfig.MultiZone, "gce-multizone", false, "If true, start GCE cloud provider with multizone support.") - flag.BoolVar(&cloudConfig.MultiMaster, "gce-multimaster", false, "If true, the underlying GCE/GKE cluster is assumed to be multi-master.") - flag.StringVar(&cloudConfig.Cluster, "gke-cluster", "", "GKE name of cluster being used, if applicable") - flag.StringVar(&cloudConfig.NodeInstanceGroup, "node-instance-group", "", "Name of the managed instance group for nodes. Valid only for gce, gke or aws. If there is more than one group: comma separated list of groups.") - flag.StringVar(&cloudConfig.Network, "network", "e2e", "The cloud provider network for this e2e cluster.") - flag.IntVar(&cloudConfig.NumNodes, "num-nodes", DefaultNumNodes, fmt.Sprintf("Number of nodes in the cluster. If the default value of '%q' is used the number of schedulable nodes is auto-detected.", DefaultNumNodes)) - flag.StringVar(&cloudConfig.ClusterIPRange, "cluster-ip-range", "10.64.0.0/14", "A CIDR notation IP range from which to assign IPs in the cluster.") - flag.StringVar(&cloudConfig.NodeTag, "node-tag", "", "Network tags used on node instances. Valid only for gce, gke") - flag.StringVar(&cloudConfig.MasterTag, "master-tag", "", "Network tags used on master instances. Valid only for gce, gke") + flags.StringVar(&cloudConfig.MasterName, "kube-master", "", "Name of the kubernetes master. Only required if provider is gce or gke") + flags.StringVar(&cloudConfig.APIEndpoint, "gce-api-endpoint", "", "The GCE APIEndpoint being used, if applicable") + flags.StringVar(&cloudConfig.ProjectID, "gce-project", "", "The GCE project being used, if applicable") + flags.StringVar(&cloudConfig.Zone, "gce-zone", "", "GCE zone being used, if applicable") + flags.StringVar(&cloudConfig.Region, "gce-region", "", "GCE region being used, if applicable") + flags.BoolVar(&cloudConfig.MultiZone, "gce-multizone", false, "If true, start GCE cloud provider with multizone support.") + flags.BoolVar(&cloudConfig.MultiMaster, "gce-multimaster", false, "If true, the underlying GCE/GKE cluster is assumed to be multi-master.") + flags.StringVar(&cloudConfig.Cluster, "gke-cluster", "", "GKE name of cluster being used, if applicable") + flags.StringVar(&cloudConfig.NodeInstanceGroup, "node-instance-group", "", "Name of the managed instance group for nodes. Valid only for gce, gke or aws. If there is more than one group: comma separated list of groups.") + flags.StringVar(&cloudConfig.Network, "network", "e2e", "The cloud provider network for this e2e cluster.") + flags.IntVar(&cloudConfig.NumNodes, "num-nodes", DefaultNumNodes, fmt.Sprintf("Number of nodes in the cluster. If the default value of '%q' is used the number of schedulable nodes is auto-detected.", DefaultNumNodes)) + flags.StringVar(&cloudConfig.ClusterIPRange, "cluster-ip-range", "10.64.0.0/14", "A CIDR notation IP range from which to assign IPs in the cluster.") + flags.StringVar(&cloudConfig.NodeTag, "node-tag", "", "Network tags used on node instances. Valid only for gce, gke") + flags.StringVar(&cloudConfig.MasterTag, "master-tag", "", "Network tags used on master instances. Valid only for gce, gke") - flag.StringVar(&cloudConfig.ClusterTag, "cluster-tag", "", "Tag used to identify resources. Only required if provider is aws.") - flag.StringVar(&cloudConfig.ConfigFile, "cloud-config-file", "", "Cloud config file. Only required if provider is azure.") - flag.IntVar(&TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used.") - flag.DurationVar(&TestContext.SystemPodsStartupTimeout, "system-pods-startup-timeout", 10*time.Minute, "Timeout for waiting for all system pods to be running before starting tests.") - flag.DurationVar(&TestContext.NodeSchedulableTimeout, "node-schedulable-timeout", 30*time.Minute, "Timeout for waiting for all nodes to be schedulable.") - flag.DurationVar(&TestContext.SystemDaemonsetStartupTimeout, "system-daemonsets-startup-timeout", 5*time.Minute, "Timeout for waiting for all system daemonsets to be ready.") - flag.StringVar(&TestContext.EtcdUpgradeStorage, "etcd-upgrade-storage", "", "The storage version to upgrade to (either 'etcdv2' or 'etcdv3') if doing an etcd upgrade test.") - flag.StringVar(&TestContext.EtcdUpgradeVersion, "etcd-upgrade-version", "", "The etcd binary version to upgrade to (e.g., '3.0.14', '2.3.7') if doing an etcd upgrade test.") - flag.StringVar(&TestContext.GCEUpgradeScript, "gce-upgrade-script", "", "Script to use to upgrade a GCE cluster.") - flag.BoolVar(&TestContext.CleanStart, "clean-start", false, "If true, purge all namespaces except default and system before running tests. This serves to Cleanup test namespaces from failed/interrupted e2e runs in a long-lived cluster.") + flags.StringVar(&cloudConfig.ClusterTag, "cluster-tag", "", "Tag used to identify resources. Only required if provider is aws.") + flags.StringVar(&cloudConfig.ConfigFile, "cloud-config-file", "", "Cloud config file. Only required if provider is azure.") + flags.IntVar(&TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used.") + flags.DurationVar(&TestContext.SystemPodsStartupTimeout, "system-pods-startup-timeout", 10*time.Minute, "Timeout for waiting for all system pods to be running before starting tests.") + flags.DurationVar(&TestContext.NodeSchedulableTimeout, "node-schedulable-timeout", 30*time.Minute, "Timeout for waiting for all nodes to be schedulable.") + flags.DurationVar(&TestContext.SystemDaemonsetStartupTimeout, "system-daemonsets-startup-timeout", 5*time.Minute, "Timeout for waiting for all system daemonsets to be ready.") + flags.StringVar(&TestContext.EtcdUpgradeStorage, "etcd-upgrade-storage", "", "The storage version to upgrade to (either 'etcdv2' or 'etcdv3') if doing an etcd upgrade test.") + flags.StringVar(&TestContext.EtcdUpgradeVersion, "etcd-upgrade-version", "", "The etcd binary version to upgrade to (e.g., '3.0.14', '2.3.7') if doing an etcd upgrade test.") + flags.StringVar(&TestContext.GCEUpgradeScript, "gce-upgrade-script", "", "Script to use to upgrade a GCE cluster.") + flags.BoolVar(&TestContext.CleanStart, "clean-start", false, "If true, purge all namespaces except default and system before running tests. This serves to Cleanup test namespaces from failed/interrupted e2e runs in a long-lived cluster.") nodeKiller := &TestContext.NodeKiller - flag.BoolVar(&nodeKiller.Enabled, "node-killer", false, "Whether NodeKiller should kill any nodes.") - flag.Float64Var(&nodeKiller.FailureRatio, "node-killer-failure-ratio", 0.01, "Percentage of nodes to be killed") - flag.DurationVar(&nodeKiller.Interval, "node-killer-interval", 1*time.Minute, "Time between node failures.") - flag.Float64Var(&nodeKiller.JitterFactor, "node-killer-jitter-factor", 60, "Factor used to jitter node failures.") - flag.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation") + flags.BoolVar(&nodeKiller.Enabled, "node-killer", false, "Whether NodeKiller should kill any nodes.") + flags.Float64Var(&nodeKiller.FailureRatio, "node-killer-failure-ratio", 0.01, "Percentage of nodes to be killed") + flags.DurationVar(&nodeKiller.Interval, "node-killer-interval", 1*time.Minute, "Time between node failures.") + flags.Float64Var(&nodeKiller.JitterFactor, "node-killer-jitter-factor", 60, "Factor used to jitter node failures.") + flags.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation") } // RegisterNodeFlags registers flags specific to the node e2e test suite. -func RegisterNodeFlags() { +func RegisterNodeFlags(flags *flag.FlagSet) { // Mark the test as node e2e when node flags are api.Registry. TestContext.NodeE2E = true - flag.StringVar(&TestContext.NodeName, "node-name", "", "Name of the node to run tests on.") + flags.StringVar(&TestContext.NodeName, "node-name", "", "Name of the node to run tests on.") // TODO(random-liu): Move kubelet start logic out of the test. // TODO(random-liu): Move log fetch logic out of the test. // There are different ways to start kubelet (systemd, initd, docker, manually started etc.) // and manage logs (journald, upstart etc.). // For different situation we need to mount different things into the container, run different commands. // It is hard and unnecessary to deal with the complexity inside the test suite. - flag.BoolVar(&TestContext.NodeConformance, "conformance", false, "If true, the test suite will not start kubelet, and fetch system log (kernel, docker, kubelet log etc.) to the report directory.") - flag.BoolVar(&TestContext.PrepullImages, "prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.") - flag.StringVar(&TestContext.ImageDescription, "image-description", "", "The description of the image which the test will be running on.") - flag.StringVar(&TestContext.SystemSpecName, "system-spec-name", "", "The name of the system spec (e.g., gke) that's used in the node e2e test. The system specs are in test/e2e_node/system/specs/. This is used by the test framework to determine which tests to run for validating the system requirements.") - flag.Var(cliflag.NewMapStringString(&TestContext.ExtraEnvs), "extra-envs", "The extra environment variables needed for node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2") + flags.BoolVar(&TestContext.NodeConformance, "conformance", false, "If true, the test suite will not start kubelet, and fetch system log (kernel, docker, kubelet log etc.) to the report directory.") + flags.BoolVar(&TestContext.PrepullImages, "prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.") + flags.StringVar(&TestContext.ImageDescription, "image-description", "", "The description of the image which the test will be running on.") + flags.StringVar(&TestContext.SystemSpecName, "system-spec-name", "", "The name of the system spec (e.g., gke) that's used in the node e2e test. The system specs are in test/e2e_node/system/specs/. This is used by the test framework to determine which tests to run for validating the system requirements.") + flags.Var(cliflag.NewMapStringString(&TestContext.ExtraEnvs), "extra-envs", "The extra environment variables needed for node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2") } // HandleFlags sets up all flags and parses the command line. func HandleFlags() { - RegisterCommonFlags() - RegisterClusterFlags() + e2econfig.CopyFlags(e2econfig.Flags, flag.CommandLine) + RegisterCommonFlags(flag.CommandLine) + RegisterClusterFlags(flag.CommandLine) flag.Parse() } diff --git a/test/e2e/framework/viperconfig/viperconfig.go b/test/e2e/framework/viperconfig/viperconfig.go index 0b68174d2cf..b42ae73d9b3 100644 --- a/test/e2e/framework/viperconfig/viperconfig.go +++ b/test/e2e/framework/viperconfig/viperconfig.go @@ -25,8 +25,9 @@ import ( "github.com/spf13/viper" ) -// ViperizeFlags checks whether a configuration file was specified, reads it, and updates -// the configuration variables accordingly. Must be called after framework.HandleFlags() +// ViperizeFlags checks whether a configuration file was specified, +// reads it, and updates the configuration variables in the specified +// flag set accordingly. Must be called after framework.HandleFlags() // and before framework.AfterReadingAllFlags(). // // The logic is so that a required configuration file must be present. If empty, @@ -34,7 +35,7 @@ import ( // // Files can be specified with just a base name ("e2e", matches "e2e.json/yaml/..." in // the current directory) or with path and suffix. -func ViperizeFlags(requiredConfig, optionalConfig string) error { +func ViperizeFlags(requiredConfig, optionalConfig string, flags *flag.FlagSet) error { viperConfig := optionalConfig required := false if requiredConfig != "" { @@ -99,24 +100,24 @@ func ViperizeFlags(requiredConfig, optionalConfig string) error { // something like viper.Unmarshal(&TestContext) because we // want to support all values, regardless where they are // stored. - return wrapError(viperUnmarshal()) + return wrapError(viperUnmarshal(flags)) } -// viperUnmarshall updates all command line flags with the corresponding values found +// viperUnmarshall updates all flags with the corresponding values found // via Viper, regardless whether the flag value is stored in TestContext, some other // context or a local variable. -func viperUnmarshal() error { +func viperUnmarshal(flags *flag.FlagSet) error { var result error set := make(map[string]bool) // Determine which values were already set explicitly via // flags. Those we don't overwrite because command line // flags have a higher priority. - flag.Visit(func(f *flag.Flag) { + flags.Visit(func(f *flag.Flag) { set[f.Name] = true }) - flag.VisitAll(func(f *flag.Flag) { + flags.VisitAll(func(f *flag.Flag) { if result != nil || set[f.Name] || !viper.IsSet(f.Name) { diff --git a/test/e2e/framework/viperconfig/viperconfig_test.go b/test/e2e/framework/viperconfig/viperconfig_test.go new file mode 100644 index 00000000000..7afa2bfe403 --- /dev/null +++ b/test/e2e/framework/viperconfig/viperconfig_test.go @@ -0,0 +1,72 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package viperconfig + +import ( + "flag" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + "k8s.io/kubernetes/test/e2e/framework/config" +) + +func TestViperConfig(t *testing.T) { + flags := flag.NewFlagSet("test", 0) + type Context struct { + Bool bool `default:"true"` + Duration time.Duration `default:"1ms"` + Float64 float64 `default:"1.23456789"` + String string `default:"hello world"` + Int int `default:"-1" usage:"some number"` + Int64 int64 `default:"-1234567890123456789"` + Uint uint `default:"1"` + Uint64 uint64 `default:"1234567890123456789"` + } + var context Context + require.NotPanics(t, func() { + config.AddOptionsToSet(flags, &context, "") + }) + + config := ` +bool: false +duration: 1s +float64: -1.23456789 +string: pong +int: -2 +int64: -9123456789012345678 +uint: 2 +uint64: 9123456789012345678 +` + tmpfile, err := ioutil.TempFile("", "viperconfig-*.yaml") + require.NoError(t, err, "temp file") + defer os.Remove(tmpfile.Name()) + if _, err := tmpfile.Write([]byte(config)); err != nil { + require.NoError(t, err, "write config") + } + require.NoError(t, tmpfile.Close(), "close temp file") + + require.NoError(t, ViperizeFlags(tmpfile.Name(), "", flags), "read config file") + require.Equal(t, + Context{false, time.Second, -1.23456789, "pong", + -2, -9123456789012345678, 2, 9123456789012345678, + }, + context, + "values from viper must match") +} diff --git a/test/e2e/lifecycle/cluster_upgrade.go b/test/e2e/lifecycle/cluster_upgrade.go index ee5dc3929ba..29dafd741d7 100644 --- a/test/e2e/lifecycle/cluster_upgrade.go +++ b/test/e2e/lifecycle/cluster_upgrade.go @@ -18,7 +18,6 @@ package lifecycle import ( "encoding/xml" - "flag" "fmt" "os" "path/filepath" @@ -31,6 +30,7 @@ import ( "k8s.io/client-go/discovery" "k8s.io/kubernetes/test/e2e/chaosmonkey" "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/framework/config" "k8s.io/kubernetes/test/e2e/framework/ginkgowrapper" e2elifecycle "k8s.io/kubernetes/test/e2e/framework/lifecycle" "k8s.io/kubernetes/test/e2e/upgrades" @@ -42,8 +42,8 @@ import ( ) var ( - upgradeTarget = flag.String("upgrade-target", "ci/latest", "Version to upgrade to (e.g. 'release/stable', 'release/latest', 'ci/latest', '0.19.1', '0.19.1-669-gabac8c8') if doing an upgrade test.") - upgradeImage = flag.String("upgrade-image", "", "Image to upgrade to (e.g. 'container_vm' or 'gci') if doing an upgrade test.") + upgradeTarget = config.Flags.String("upgrade-target", "ci/latest", "Version to upgrade to (e.g. 'release/stable', 'release/latest', 'ci/latest', '0.19.1', '0.19.1-669-gabac8c8') if doing an upgrade test.") + upgradeImage = config.Flags.String("upgrade-image", "", "Image to upgrade to (e.g. 'container_vm' or 'gci') if doing an upgrade test.") ) var upgradeTests = []upgrades.Test{ diff --git a/test/e2e/storage/drivers/csi.go b/test/e2e/storage/drivers/csi.go index 06b57b4dfec..e7a0dbb669d 100644 --- a/test/e2e/storage/drivers/csi.go +++ b/test/e2e/storage/drivers/csi.go @@ -144,8 +144,6 @@ func (h *hostpathCSIDriver) PrepareTest(f *framework.Framework) (*testsuites.Per ClientNodeName: nodeName, } - // TODO (?): the storage.csi.image.version and storage.csi.image.registry - // settings are ignored for this test. We could patch the image definitions. o := utils.PatchCSIOptions{ OldDriverName: h.driverInfo.Name, NewDriverName: config.GetUniqueDriverName(), @@ -288,8 +286,6 @@ func (m *mockCSIDriver) PrepareTest(f *framework.Framework) (*testsuites.PerTest containerArgs = append(containerArgs, "--node-expand-required=true") } - // TODO (?): the storage.csi.image.version and storage.csi.image.registry - // settings are ignored for this test. We could patch the image definitions. o := utils.PatchCSIOptions{ OldDriverName: "csi-mock", NewDriverName: "csi-mock-" + f.UniqueName, diff --git a/test/e2e/storage/external/external.go b/test/e2e/storage/external/external.go index 3b712dd252a..616c6433638 100644 --- a/test/e2e/storage/external/external.go +++ b/test/e2e/storage/external/external.go @@ -30,6 +30,7 @@ import ( "k8s.io/apiserver/pkg/storage/names" "k8s.io/client-go/kubernetes/scheme" "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/framework/config" "k8s.io/kubernetes/test/e2e/storage/testpatterns" "k8s.io/kubernetes/test/e2e/storage/testsuites" @@ -49,7 +50,7 @@ var csiTestSuites = []func() testsuites.TestSuite{ } func init() { - flag.Var(testDriverParameter{}, "storage.testdriver", "name of a .yaml or .json file that defines a driver for storage testing, can be used more than once") + config.Flags.Var(testDriverParameter{}, "storage.testdriver", "name of a .yaml or .json file that defines a driver for storage testing, can be used more than once") } // testDriverParameter is used to hook loading of the driver diff --git a/test/e2e/storage/utils/deployment.go b/test/e2e/storage/utils/deployment.go index c14ba2f7976..b1a3aed5af5 100644 --- a/test/e2e/storage/utils/deployment.go +++ b/test/e2e/storage/utils/deployment.go @@ -49,10 +49,6 @@ import ( // // Driver deployments that are different will have to do the patching // without this function, or skip patching entirely. -// -// TODO (?): the storage.csi.image.version and storage.csi.image.registry -// settings are ignored. We could patch the image definitions or deprecate -// those options. func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interface{}) error { rename := o.OldDriverName != "" && o.NewDriverName != "" && o.OldDriverName != o.NewDriverName diff --git a/test/e2e_kubeadm/e2e_kubeadm_suite_test.go b/test/e2e_kubeadm/e2e_kubeadm_suite_test.go index 6d1817bbca4..9a508138f94 100644 --- a/test/e2e_kubeadm/e2e_kubeadm_suite_test.go +++ b/test/e2e_kubeadm/e2e_kubeadm_suite_test.go @@ -30,11 +30,13 @@ import ( morereporters "github.com/onsi/ginkgo/reporters" "k8s.io/kubernetes/test/e2e/framework" + e2econfig "k8s.io/kubernetes/test/e2e/framework/config" ) func init() { - framework.RegisterCommonFlags() - framework.RegisterClusterFlags() + e2econfig.CopyFlags(e2econfig.Flags, flag.CommandLine) + framework.RegisterCommonFlags(flag.CommandLine) + framework.RegisterClusterFlags(flag.CommandLine) pflag.CommandLine.AddGoFlagSet(flag.CommandLine) } diff --git a/test/e2e_node/e2e_node_suite_test.go b/test/e2e_node/e2e_node_suite_test.go index bf920672ba2..409d5286f0d 100644 --- a/test/e2e_node/e2e_node_suite_test.go +++ b/test/e2e_node/e2e_node_suite_test.go @@ -41,6 +41,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/util/system" commontest "k8s.io/kubernetes/test/e2e/common" "k8s.io/kubernetes/test/e2e/framework" + e2econfig "k8s.io/kubernetes/test/e2e/framework/config" "k8s.io/kubernetes/test/e2e/framework/testfiles" "k8s.io/kubernetes/test/e2e/generated" "k8s.io/kubernetes/test/e2e_node/services" @@ -63,8 +64,9 @@ var systemValidateMode = flag.Bool("system-validate-mode", false, "If true, only var systemSpecFile = flag.String("system-spec-file", "", "The name of the system spec file that will be used for node conformance test. If it's unspecified or empty, the default system spec (system.DefaultSysSpec) will be used.") func init() { - framework.RegisterCommonFlags() - framework.RegisterNodeFlags() + e2econfig.CopyFlags(e2econfig.Flags, flag.CommandLine) + framework.RegisterCommonFlags(flag.CommandLine) + framework.RegisterNodeFlags(flag.CommandLine) pflag.CommandLine.AddGoFlagSet(flag.CommandLine) // Mark the run-services-mode flag as hidden to prevent user from using it. pflag.CommandLine.MarkHidden("run-services-mode")