-
Notifications
You must be signed in to change notification settings - Fork 128
Add wrapper which will allow running o/k tests as external binary in origin #1485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3df01c
6040b96
1399bb6
f7b7abc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "flag" | ||
| "fmt" | ||
| "math/rand" | ||
| "os" | ||
| "sort" | ||
| "time" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| "github.com/spf13/pflag" | ||
|
|
||
| utilflag "k8s.io/component-base/cli/flag" | ||
| "k8s.io/component-base/logs" | ||
| "k8s.io/kubernetes/test/e2e/framework" | ||
|
|
||
| // initialize framework extensions | ||
| _ "k8s.io/kubernetes/test/e2e/framework/debug/init" | ||
| _ "k8s.io/kubernetes/test/e2e/framework/metrics/init" | ||
| ) | ||
|
|
||
| func main() { | ||
| logs.InitLogs() | ||
| defer logs.FlushLogs() | ||
|
|
||
| rand.Seed(time.Now().UTC().UnixNano()) | ||
|
|
||
| pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) | ||
|
|
||
| root := &cobra.Command{ | ||
| Long: "OpenShift Tests compatible wrapper", | ||
| } | ||
|
|
||
| root.AddCommand( | ||
| newRunTestCommand(), | ||
| newListTestsCommand(), | ||
| ) | ||
|
|
||
| f := flag.CommandLine.Lookup("v") | ||
| root.PersistentFlags().AddGoFlag(f) | ||
| pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError) | ||
| flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError) | ||
| framework.RegisterCommonFlags(flag.CommandLine) | ||
| framework.RegisterClusterFlags(flag.CommandLine) | ||
|
|
||
| if err := func() error { | ||
| return root.Execute() | ||
| }(); err != nil { | ||
| if ex, ok := err.(ExitError); ok { | ||
| fmt.Fprintf(os.Stderr, "Ginkgo exit error %d: %v\n", ex.Code, err) | ||
| os.Exit(ex.Code) | ||
| } | ||
| fmt.Fprintf(os.Stderr, "error: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
| } | ||
|
|
||
| func newRunTestCommand() *cobra.Command { | ||
| testOpt := NewTestOptions(os.Stdout, os.Stderr) | ||
|
|
||
| cmd := &cobra.Command{ | ||
| Use: "run-test NAME", | ||
| Short: "Run a single test by name", | ||
| Long: "Execute a single test.", | ||
| SilenceUsage: true, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| if err := initializeTestFramework(os.Getenv("TEST_PROVIDER")); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return testOpt.Run(args) | ||
| }, | ||
| } | ||
| return cmd | ||
| } | ||
|
|
||
| func newListTestsCommand() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "list", | ||
| Short: "List available tests", | ||
| Long: "List the available tests in this binary.", | ||
| SilenceUsage: true, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| tests := testsForSuite() | ||
| sort.Slice(tests, func(i, j int) bool { return tests[i].Name < tests[j].Name }) | ||
| data, err := json.Marshal(tests) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| fmt.Fprintf(os.Stdout, "%s\n", data) | ||
| return nil | ||
| }, | ||
| } | ||
|
|
||
| return cmd | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
|
|
||
| "github.com/onsi/ginkgo/v2" | ||
| "github.com/onsi/gomega" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
| kclientset "k8s.io/client-go/kubernetes" | ||
| "k8s.io/client-go/tools/clientcmd" | ||
| "k8s.io/kubernetes/openshift-hack/e2e" | ||
| conformancetestdata "k8s.io/kubernetes/test/conformance/testdata" | ||
| "k8s.io/kubernetes/test/e2e/framework" | ||
| "k8s.io/kubernetes/test/e2e/framework/testfiles" | ||
| "k8s.io/kubernetes/test/e2e/storage/external" | ||
| e2etestingmanifests "k8s.io/kubernetes/test/e2e/testing-manifests" | ||
| testfixtures "k8s.io/kubernetes/test/fixtures" | ||
|
|
||
| // this appears to inexplicably auto-register global flags. | ||
| _ "k8s.io/kubernetes/test/e2e/storage/drivers" | ||
|
|
||
| // these are loading important global flags that we need to get and set | ||
| _ "k8s.io/kubernetes/test/e2e" | ||
| _ "k8s.io/kubernetes/test/e2e/lifecycle" | ||
| ) | ||
|
|
||
| // copied directly from github.com/openshift/origin/cmd/openshift-tests/provider.go | ||
| // and github.com/openshift/origin/test/extended/util/test.go | ||
| func initializeTestFramework(provider string) error { | ||
| providerInfo := &ClusterConfiguration{} | ||
| if err := json.Unmarshal([]byte(provider), &providerInfo); err != nil { | ||
| return fmt.Errorf("provider must be a JSON object with the 'type' key at a minimum: %v", err) | ||
| } | ||
| if len(providerInfo.ProviderName) == 0 { | ||
| return fmt.Errorf("provider must be a JSON object with the 'type' key") | ||
| } | ||
| config := &ClusterConfiguration{} | ||
| if err := json.Unmarshal([]byte(provider), config); err != nil { | ||
| return fmt.Errorf("provider must decode into the ClusterConfig object: %v", err) | ||
| } | ||
|
|
||
| // update context with loaded config | ||
| context := &framework.TestContext | ||
| context.Provider = config.ProviderName | ||
| context.CloudConfig = framework.CloudConfig{ | ||
| ProjectID: config.ProjectID, | ||
| Region: config.Region, | ||
| Zone: config.Zone, | ||
| Zones: config.Zones, | ||
| NumNodes: config.NumNodes, | ||
| MultiMaster: config.MultiMaster, | ||
| MultiZone: config.MultiZone, | ||
| ConfigFile: config.ConfigFile, | ||
| } | ||
| context.AllowedNotReadyNodes = -1 | ||
| context.MinStartupPods = -1 | ||
| context.MaxNodesToGather = 0 | ||
| context.KubeConfig = os.Getenv("KUBECONFIG") | ||
|
|
||
| // allow the CSI tests to access test data, but only briefly | ||
| // TODO: ideally CSI would not use any of these test methods | ||
| // var err error | ||
| // exutil.WithCleanup(func() { err = initCSITests(dryRun) }) | ||
| // TODO: for now I'm only initializing CSI directly, but we probably need that | ||
| // WithCleanup here as well | ||
| if err := initCSITests(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if ad := os.Getenv("ARTIFACT_DIR"); len(strings.TrimSpace(ad)) == 0 { | ||
| os.Setenv("ARTIFACT_DIR", filepath.Join(os.TempDir(), "artifacts")) | ||
| } | ||
|
|
||
| context.DeleteNamespace = os.Getenv("DELETE_NAMESPACE") != "false" | ||
| context.VerifyServiceAccount = true | ||
| testfiles.AddFileSource(e2etestingmanifests.GetE2ETestingManifestsFS()) | ||
|
||
| testfiles.AddFileSource(testfixtures.GetTestFixturesFS()) | ||
| testfiles.AddFileSource(conformancetestdata.GetConformanceTestdataFS()) | ||
| context.KubectlPath = "kubectl" | ||
| // context.KubeConfig = KubeConfigPath() | ||
| context.KubeConfig = os.Getenv("KUBECONFIG") | ||
|
|
||
| // "debian" is used when not set. At least GlusterFS tests need "custom". | ||
| // (There is no option for "rhel" or "centos".) | ||
| context.NodeOSDistro = "custom" | ||
| context.MasterOSDistro = "custom" | ||
|
|
||
| // load and set the host variable for kubectl | ||
| clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&clientcmd.ClientConfigLoadingRules{ExplicitPath: context.KubeConfig}, &clientcmd.ConfigOverrides{}) | ||
| cfg, err := clientConfig.ClientConfig() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| context.Host = cfg.Host | ||
|
|
||
| // Ensure that Kube tests run privileged (like they do upstream) | ||
| context.CreateTestingNS = func(baseName string, c kclientset.Interface, labels map[string]string) (*corev1.Namespace, error) { | ||
| return e2e.CreateTestingNS(baseName, c, labels, true) | ||
| } | ||
|
|
||
| gomega.RegisterFailHandler(ginkgo.Fail) | ||
|
|
||
| framework.AfterReadingAllFlags(context) | ||
| context.DumpLogsOnFailure = true | ||
|
|
||
| // these constants are taken from kube e2e and used by tests | ||
| context.IPFamily = "ipv4" | ||
| if config.HasIPv6 && !config.HasIPv4 { | ||
| context.IPFamily = "ipv6" | ||
| } | ||
|
|
||
| context.ReportDir = os.Getenv("TEST_JUNIT_DIR") | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| const ( | ||
| manifestEnvVar = "TEST_CSI_DRIVER_FILES" | ||
| ) | ||
|
|
||
| // copied directly from github.com/openshift/origin/cmd/openshift-tests/csi.go | ||
| // Initialize openshift/csi suite, i.e. define CSI tests from TEST_CSI_DRIVER_FILES. | ||
| func initCSITests() error { | ||
| manifestList := os.Getenv(manifestEnvVar) | ||
| if manifestList != "" { | ||
| manifests := strings.Split(manifestList, ",") | ||
| for _, manifest := range manifests { | ||
| if err := external.AddDriverDefinition(manifest); err != nil { | ||
| return fmt.Errorf("failed to load manifest from %q: %s", manifest, err) | ||
| } | ||
| // Register the base dir of the manifest file as a file source. | ||
| // With this we can reference the CSI driver's storageClass | ||
| // in the manifest file (FromFile field). | ||
| testfiles.AddFileSource(testfiles.RootFileSource{ | ||
| Root: filepath.Dir(manifest), | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of unmarshaling into
&providerInfo? I.e. reference toproviderInfoinstead of justproviderInfo?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
providerInfo in origin is populated here: https://github.com/openshift/origin/blob/bfcc30fde82a91fab1c881a836e4ad8e63c72fb5/cmd/openshift-tests/provider.go#L78, so it's done on every test invocation.
tl;dr
When you invoke
openshift-tests run openshift/conformance/parallelit creates a list of tests and runs one by one invokingopenshift-tests run-test. The abovedecodeProvideris responsible to read what the cluster looks like during thatrun-testinvocation. Since we don't want to rely on that mechanism in here, we need to inject that value through env variable, and then decode it and use it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm updating openshift/enhancements#1291 I'll add more details how this works there.