1
16
17 package framework
18
19 import (
20 "context"
21 "crypto/rand"
22 "encoding/base64"
23 "errors"
24 "flag"
25 "fmt"
26 "io"
27 "math"
28 "os"
29 "path"
30 "path/filepath"
31 "sort"
32 "strings"
33 "time"
34
35 "github.com/onsi/ginkgo/v2"
36 "github.com/onsi/ginkgo/v2/reporters"
37 "github.com/onsi/ginkgo/v2/types"
38 "github.com/onsi/gomega"
39 gomegaformat "github.com/onsi/gomega/format"
40
41 "k8s.io/apimachinery/pkg/util/sets"
42 restclient "k8s.io/client-go/rest"
43 "k8s.io/client-go/tools/clientcmd"
44 cliflag "k8s.io/component-base/cli/flag"
45 "k8s.io/klog/v2"
46
47 "k8s.io/kubernetes/test/e2e/framework/internal/junit"
48 "k8s.io/kubernetes/test/utils/image"
49 "k8s.io/kubernetes/test/utils/kubeconfig"
50 )
51
52 const (
53 defaultHost = "https://127.0.0.1:6443"
54
55
56 DefaultNumNodes = -1
57 )
58
59 var (
60
61
62 Output io.Writer = os.Stdout
63
64
65
66 Exit = os.Exit
67
68
69
70 CheckForBugs = true
71 )
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 type TestContextType struct {
102 KubeConfig string
103 KubeContext string
104 KubeAPIContentType string
105 KubeletRootDir string
106 KubeletConfigDropinDir string
107 CertDir string
108 Host string
109 BearerToken string `datapolicy:"token"`
110
111 RepoRoot string
112
113 ListImages bool
114
115 listTests, listLabels bool
116
117
118 ListConformanceTests bool
119
120
121 Provider string
122
123
124 Tooling string
125
126
127
128
129
130
131 timeouts TimeoutContext
132
133 CloudConfig CloudConfig
134 KubectlPath string
135 OutputDir string
136 ReportDir string
137 ReportPrefix string
138 ReportCompleteGinkgo bool
139 ReportCompleteJUnit bool
140 Prefix string
141 MinStartupPods int
142 EtcdUpgradeStorage string
143 EtcdUpgradeVersion string
144 GCEUpgradeScript string
145 ContainerRuntimeEndpoint string
146 ContainerRuntimeProcessName string
147 ContainerRuntimePidFile string
148
149
150 SystemdServices string
151
152 DumpSystemdJournal bool
153 ImageServiceEndpoint string
154 MasterOSDistro string
155 NodeOSDistro string
156 NodeOSArch string
157 VerifyServiceAccount bool
158 DeleteNamespace bool
159 DeleteNamespaceOnFailure bool
160 AllowedNotReadyNodes int
161 CleanStart bool
162
163
164
165 GatherKubeSystemResourceUsageData string
166 GatherLogsSizes bool
167 GatherMetricsAfterTest string
168 GatherSuiteMetricsAfterTest bool
169 MaxNodesToGather int
170
171 IncludeClusterAutoscalerMetrics bool
172
173 OutputPrintType string
174
175
176
177 CreateTestingNS CreateTestingNSFn
178
179 DumpLogsOnFailure bool
180
181 DisableLogDump bool
182
183 LogexporterGCSPath string
184
185 NodeTestContextType
186
187
188 ClusterDNSDomain string
189
190
191 NodeKiller NodeKillerConfig
192
193
194 IPFamily string
195
196
197 NonblockingTaints string
198
199
200 ProgressReportURL string
201
202
203 SriovdpConfigMapFile string
204
205
206 SpecSummaryOutput string
207
208
209 DockerConfigFile string
210
211
212
213 E2EDockerConfigFile string
214
215
216 KubeTestRepoList string
217
218
219 SnapshotControllerPodName string
220
221
222 SnapshotControllerHTTPPort int
223
224
225
226 RequireDevices bool
227
228
229 EnabledVolumeDrivers []string
230 }
231
232
233
234
235
236
237 type NodeKillerConfig struct {
238
239
240 Enabled bool
241
242 FailureRatio float64
243
244 Interval time.Duration
245
246
247 JitterFactor float64
248
249 SimulatedDowntime time.Duration
250
251 NodeKillerStopCtx context.Context
252
253 NodeKillerStop func()
254 }
255
256
257 type NodeTestContextType struct {
258
259 NodeE2E bool
260
261 NodeName string
262
263 NodeConformance bool
264
265 PrepullImages bool
266
267 ImageDescription string
268
269 RuntimeConfig map[string]string
270
271
272
273 SystemSpecName string
274
275 RestartKubelet bool
276
277 ExtraEnvs map[string]string
278
279 StandaloneMode bool
280 }
281
282
283 type CloudConfig struct {
284 APIEndpoint string
285 ProjectID string
286 Zone string
287 Zones []string
288 Region string
289 MultiZone bool
290 MultiMaster bool
291 Cluster string
292 MasterName string
293 NodeInstanceGroup string
294 NumNodes int
295 ClusterIPRange string
296 ClusterTag string
297 Network string
298 ConfigFile string
299 NodeTag string
300 MasterTag string
301
302 Provider ProviderInterface
303 }
304
305
306 var TestContext = TestContextType{
307 timeouts: defaultTimeouts,
308 }
309
310
311 type stringArrayValue struct {
312 stringArray *[]string
313 }
314
315 func (v stringArrayValue) String() string {
316 if v.stringArray != nil {
317 return strings.Join(*v.stringArray, ",")
318 }
319 return ""
320 }
321
322 func (v stringArrayValue) Set(s string) error {
323 if len(s) == 0 {
324 *v.stringArray = []string{}
325 } else {
326 *v.stringArray = strings.Split(s, ",")
327 }
328 return nil
329 }
330
331
332 func (tc TestContextType) ClusterIsIPv6() bool {
333 return tc.IPFamily == "ipv6"
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347 func RegisterCommonFlags(flags *flag.FlagSet) {
348
349 flags.IntVar(&gomegaformat.MaxLength, "gomega-max-length", 8000, "Sets the maximum size for the gomega formatter (= gomega.MaxLength). Use 0 to disable truncation.")
350
351 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.")
352 flags.BoolVar(&TestContext.GatherLogsSizes, "gather-logs-sizes", false, "If set to true framework will be monitoring logs sizes on all machines running e2e tests.")
353 flags.IntVar(&TestContext.MaxNodesToGather, "max-nodes-to-gather-from", 20, "The maximum number of nodes to gather extended info from on test failure.")
354 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.")
355 flags.BoolVar(&TestContext.GatherSuiteMetricsAfterTest, "gather-suite-metrics-at-teardown", false, "If set to true framework will gather metrics from all components after the whole test suite completes.")
356 flags.BoolVar(&TestContext.IncludeClusterAutoscalerMetrics, "include-cluster-autoscaler", false, "If set to true, framework will include Cluster Autoscaler when gathering metrics.")
357 flags.StringVar(&TestContext.OutputPrintType, "output-print-type", "json", "Format in which summaries should be printed: 'hr' for human readable, 'json' for JSON ones.")
358 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.")
359 flags.BoolVar(&TestContext.DisableLogDump, "disable-log-dump", false, "If set to true, logs from master and nodes won't be gathered after test run.")
360 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.")
361 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.")
362 flags.BoolVar(&TestContext.DeleteNamespaceOnFailure, "delete-namespace-on-failure", true, "If true, framework will delete test namespace on failure. Used only during test debugging.")
363 flags.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If greater than zero, framework will allow for that many non-ready nodes when checking for all ready nodes. If -1, no waiting will be performed for ready nodes or daemonset pods.")
364
365 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))
366 flags.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.")
367 flags.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the simplified JUnit XML reports and other tests results should be saved. Default is empty, which doesn't generate these reports. If ginkgo's -junit-report parameter is used, that parameter instead of -report-dir determines the location of a single JUnit report.")
368 flags.BoolVar(&TestContext.ReportCompleteGinkgo, "report-complete-ginkgo", false, "Enables writing a complete test report as Ginkgo JSON to <report dir>/ginkgo/report.json. Ignored if --report-dir is not set.")
369 flags.BoolVar(&TestContext.ReportCompleteJUnit, "report-complete-junit", false, "Enables writing a complete test report as JUnit XML to <report dir>/ginkgo/report.json. Ignored if --report-dir is not set.")
370 flags.StringVar(&TestContext.ContainerRuntimeEndpoint, "container-runtime-endpoint", "unix:///run/containerd/containerd.sock", "The container runtime endpoint of cluster VM instances.")
371 flags.StringVar(&TestContext.ContainerRuntimeProcessName, "container-runtime-process-name", "containerd", "The name of the container runtime process.")
372 flags.StringVar(&TestContext.ContainerRuntimePidFile, "container-runtime-pid-file", "/run/containerd/containerd.pid", "The pid file of the container runtime.")
373 flags.StringVar(&TestContext.SystemdServices, "systemd-services", "containerd*", "The comma separated list of systemd services the framework will dump logs for.")
374 flags.BoolVar(&TestContext.DumpSystemdJournal, "dump-systemd-journal", false, "Whether to dump the full systemd journal.")
375 flags.StringVar(&TestContext.ImageServiceEndpoint, "image-service-endpoint", "", "The image service endpoint of cluster VM instances.")
376 flags.StringVar(&TestContext.NonblockingTaints, "non-blocking-taints", `node-role.kubernetes.io/control-plane`, "Nodes with taints in this comma-delimited list will not block the test framework from starting tests.")
377
378 flags.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for running tests.")
379 flags.BoolVar(&TestContext.listLabels, "list-labels", false, "If true, will show the list of labels that can be used to select tests via -ginkgo.label-filter.")
380 flags.BoolVar(&TestContext.listTests, "list-tests", false, "If true, will show the full names of all tests (aka specs) that can be used to select test via -ginkgo.focus/skip.")
381 flags.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.")
382
383 flags.StringVar(&TestContext.ProgressReportURL, "progress-report-url", "", "The URL to POST progress updates to as the suite runs to assist in aiding integrations. If empty, no messages sent.")
384 flags.StringVar(&TestContext.SpecSummaryOutput, "spec-dump", "", "The file to dump all ginkgo.SpecSummary to after tests run. If empty, no objects are saved/printed.")
385 flags.StringVar(&TestContext.DockerConfigFile, "docker-config-file", "", "A docker credential file which contains authorization token that is used to perform image pull tests from an authenticated registry. For more details regarding the content of the file refer https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#log-in-to-docker-hub")
386
387 flags.StringVar(&TestContext.E2EDockerConfigFile, "e2e-docker-config-file", "", "A docker credentials configuration file used which contains authorization token that can be used to pull images from certain private registries provided by the users. For more details refer https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#log-in-to-docker-hub")
388 flags.StringVar(&TestContext.KubeTestRepoList, "kube-test-repo-list", "", "A yaml file used for overriding registries for test images. Alternatively, the KUBE_TEST_REPO_LIST env variable can be set.")
389
390 flags.StringVar(&TestContext.SnapshotControllerPodName, "snapshot-controller-pod-name", "", "The pod name to use for identifying the snapshot controller in the kube-system namespace.")
391 flags.IntVar(&TestContext.SnapshotControllerHTTPPort, "snapshot-controller-http-port", 0, "The port to use for snapshot controller HTTP communication.")
392
393 flags.Var(&stringArrayValue{&TestContext.EnabledVolumeDrivers}, "enabled-volume-drivers", "Comma-separated list of in-tree volume drivers to enable for testing. This is only needed for in-tree drivers disabled by default. An example is gcepd; see test/e2e/storage/in_tree_volumes.go for full details.")
394 }
395
396 func CreateGinkgoConfig() (types.SuiteConfig, types.ReporterConfig) {
397
398 suiteConfig, reporterConfig := ginkgo.GinkgoConfiguration()
399
400 suiteConfig.RandomizeAllSpecs = true
401
402 if len(suiteConfig.FocusStrings) == 0 && len(suiteConfig.SkipStrings) == 0 {
403 suiteConfig.SkipStrings = []string{`\[Flaky\]|\[Feature:.+\]`}
404 }
405 return suiteConfig, reporterConfig
406 }
407
408
409 func RegisterClusterFlags(flags *flag.FlagSet) {
410 flags.BoolVar(&TestContext.VerifyServiceAccount, "e2e-verify-service-account", true, "If true tests will verify the service account before running.")
411 flags.StringVar(&TestContext.KubeConfig, clientcmd.RecommendedConfigPathFlag, os.Getenv(clientcmd.RecommendedConfigPathEnvVar), "Path to kubeconfig containing embedded authinfo.")
412 flags.StringVar(&TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'")
413 flags.StringVar(&TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver")
414
415 flags.StringVar(&TestContext.KubeletRootDir, "kubelet-root-dir", "/var/lib/kubelet", "The data directory of kubelet. Some tests (for example, CSI storage tests) deploy DaemonSets which need to know this value and cannot query it. Such tests only work in clusters where the data directory is the same on all nodes.")
416 flags.StringVar(&TestContext.KubeletRootDir, "volume-dir", "/var/lib/kubelet", "An alias for --kubelet-root-dir, kept for backwards compatibility.")
417 flags.StringVar(&TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.")
418 flags.StringVar(&TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.")
419
420
421 flags.BoolVar(&TestContext.PrepullImages, "prepull-images", false, "If true, prepull images so image pull failures do not cause test failures.")
422 flags.StringVar(&TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)")
423 flags.StringVar(&TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)")
424 flags.StringVar(&TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.")
425 flags.StringVar(&TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.")
426 flags.StringVar(&TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).")
427 flags.StringVar(&TestContext.NodeOSDistro, "node-os-distro", "debian", "The OS distribution of cluster VM instances (debian, ubuntu, gci, coreos, windows, or custom), which determines how specific tests are implemented.")
428 flags.StringVar(&TestContext.NodeOSArch, "node-os-arch", "amd64", "The OS architecture of cluster VM instances (amd64, arm64, or custom).")
429 flags.StringVar(&TestContext.ClusterDNSDomain, "dns-domain", "cluster.local", "The DNS Domain of the cluster.")
430
431
432 cloudConfig := &TestContext.CloudConfig
433 flags.StringVar(&cloudConfig.MasterName, "kube-master", "", "Name of the kubernetes master. Only required if provider is gce or gke")
434 flags.StringVar(&cloudConfig.APIEndpoint, "gce-api-endpoint", "", "The GCE APIEndpoint being used, if applicable")
435 flags.StringVar(&cloudConfig.ProjectID, "gce-project", "", "The GCE project being used, if applicable")
436 flags.StringVar(&cloudConfig.Zone, "gce-zone", "", "GCE zone being used, if applicable")
437 flags.Var(cliflag.NewStringSlice(&cloudConfig.Zones), "gce-zones", "The set of zones to use in a multi-zone test instead of querying the cloud provider.")
438 flags.StringVar(&cloudConfig.Region, "gce-region", "", "GCE region being used, if applicable")
439 flags.BoolVar(&cloudConfig.MultiZone, "gce-multizone", false, "If true, start GCE cloud provider with multizone support.")
440 flags.BoolVar(&cloudConfig.MultiMaster, "gce-multimaster", false, "If true, the underlying GCE/GKE cluster is assumed to be multi-master.")
441 flags.StringVar(&cloudConfig.Cluster, "gke-cluster", "", "GKE name of cluster being used, if applicable")
442 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.")
443 flags.StringVar(&cloudConfig.Network, "network", "e2e", "The cloud provider network for this e2e cluster.")
444 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))
445 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.")
446 flags.StringVar(&cloudConfig.NodeTag, "node-tag", "", "Network tags used on node instances. Valid only for gce, gke")
447 flags.StringVar(&cloudConfig.MasterTag, "master-tag", "", "Network tags used on master instances. Valid only for gce, gke")
448
449 flags.StringVar(&cloudConfig.ClusterTag, "cluster-tag", "", "Tag used to identify resources. Only required if provider is aws.")
450 flags.StringVar(&cloudConfig.ConfigFile, "cloud-config-file", "", "Cloud config file. Only required if provider is azure or vsphere.")
451 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. If set to -1, no pods are checked and tests run straight away.")
452 flags.DurationVar(&TestContext.timeouts.SystemPodsStartup, "system-pods-startup-timeout", TestContext.timeouts.SystemPodsStartup, "Timeout for waiting for all system pods to be running before starting tests.")
453 flags.DurationVar(&TestContext.timeouts.NodeSchedulable, "node-schedulable-timeout", TestContext.timeouts.NodeSchedulable, "Timeout for waiting for all nodes to be schedulable.")
454 flags.DurationVar(&TestContext.timeouts.SystemDaemonsetStartup, "system-daemonsets-startup-timeout", TestContext.timeouts.SystemDaemonsetStartup, "Timeout for waiting for all system daemonsets to be ready.")
455 flags.StringVar(&TestContext.EtcdUpgradeStorage, "etcd-upgrade-storage", "", "The storage version to upgrade to (either 'etcdv2' or 'etcdv3') if doing an etcd upgrade test.")
456 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.")
457 flags.StringVar(&TestContext.GCEUpgradeScript, "gce-upgrade-script", "", "Script to use to upgrade a GCE cluster.")
458 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.")
459
460 nodeKiller := &TestContext.NodeKiller
461 flags.BoolVar(&nodeKiller.Enabled, "node-killer", false, "Whether NodeKiller should kill any nodes.")
462 flags.Float64Var(&nodeKiller.FailureRatio, "node-killer-failure-ratio", 0.01, "Percentage of nodes to be killed")
463 flags.DurationVar(&nodeKiller.Interval, "node-killer-interval", 1*time.Minute, "Time between node failures.")
464 flags.Float64Var(&nodeKiller.JitterFactor, "node-killer-jitter-factor", 60, "Factor used to jitter node failures.")
465 flags.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation")
466 }
467
468
469
470
471 func generateSecureToken(tokenLen int) (string, error) {
472
473 tokenSize := math.Ceil(float64(tokenLen) * 6 / 8)
474 rawToken := make([]byte, int(tokenSize))
475 if _, err := rand.Read(rawToken); err != nil {
476 return "", err
477 }
478 encoded := base64.RawURLEncoding.EncodeToString(rawToken)
479 token := encoded[:tokenLen]
480 return token, nil
481 }
482
483
484
485 func AfterReadingAllFlags(t *TestContextType) {
486
487
488
489
490
491
492 if t.KubeTestRepoList != "" {
493 image.Init(t.KubeTestRepoList)
494 }
495
496 if t.ListImages {
497 for _, v := range image.GetImageConfigs() {
498 fmt.Println(v.GetE2EImage())
499 }
500 Exit(0)
501 }
502
503
504
505
506
507 gomega.SetDefaultEventuallyPollingInterval(t.timeouts.Poll)
508 gomega.SetDefaultConsistentlyPollingInterval(t.timeouts.Poll)
509 gomega.SetDefaultEventuallyTimeout(t.timeouts.PodStart)
510 gomega.SetDefaultConsistentlyDuration(t.timeouts.PodStartShort)
511
512
513 report := ginkgo.PreviewSpecs("Kubernetes e2e test statistics")
514 validateSpecs(report.SpecReports)
515 if err := FormatBugs(); CheckForBugs && err != nil {
516
517 fmt.Fprint(Output, "ERROR: E2E suite initialization was faulty, these errors must be fixed:")
518 fmt.Fprint(Output, "\n"+err.Error())
519 Exit(1)
520 }
521 if t.listLabels || t.listTests {
522 listTestInformation(report)
523 Exit(0)
524 }
525
526
527 if len(t.Host) == 0 && len(t.KubeConfig) == 0 {
528
529 if clusterConfig, err := restclient.InClusterConfig(); err == nil {
530 if tempFile, err := os.CreateTemp(os.TempDir(), "kubeconfig-"); err == nil {
531 kubeConfig := kubeconfig.CreateKubeConfig(clusterConfig)
532 clientcmd.WriteToFile(*kubeConfig, tempFile.Name())
533 t.KubeConfig = tempFile.Name()
534 klog.V(4).Infof("Using a temporary kubeconfig file from in-cluster config : %s", tempFile.Name())
535 }
536 }
537 if len(t.KubeConfig) == 0 {
538 klog.Warningf("Unable to find in-cluster config, using default host : %s", defaultHost)
539 t.Host = defaultHost
540 }
541 }
542 if len(t.BearerToken) == 0 {
543 var err error
544 t.BearerToken, err = generateSecureToken(16)
545 ExpectNoError(err, "Failed to generate bearer token")
546 }
547
548
549 if t.AllowedNotReadyNodes == 0 {
550 t.AllowedNotReadyNodes = t.CloudConfig.NumNodes / 100
551 }
552
553 klog.V(4).Infof("Tolerating taints %q when considering if nodes are ready", TestContext.NonblockingTaints)
554
555
556
557
558 if TestContext.Provider == "" {
559
560
561 Logf("The --provider flag is not set. Continuing as if --provider=skeleton had been used.")
562 TestContext.Provider = "skeleton"
563 }
564
565 var err error
566 TestContext.CloudConfig.Provider, err = SetupProviderConfig(TestContext.Provider)
567 if err != nil {
568 if os.IsNotExist(errors.Unwrap(err)) {
569
570 var providers []string
571 for _, name := range GetProviders() {
572
573 if name == "" {
574 name = `""`
575 }
576 providers = append(providers, name)
577 }
578 sort.Strings(providers)
579 klog.Errorf("Unknown provider %q. The following providers are known: %v", TestContext.Provider, strings.Join(providers, " "))
580 } else {
581 klog.Errorf("Failed to setup provider config for %q: %v", TestContext.Provider, err)
582 }
583 Exit(1)
584 }
585
586 if TestContext.ReportDir != "" {
587
588
589
590
591 if err := os.MkdirAll(TestContext.ReportDir, 0777); err != nil && !os.IsExist(err) {
592 klog.Errorf("Create report dir: %v", err)
593 Exit(1)
594 }
595 ginkgoDir := path.Join(TestContext.ReportDir, "ginkgo")
596 if TestContext.ReportCompleteGinkgo || TestContext.ReportCompleteJUnit {
597 if err := os.MkdirAll(ginkgoDir, 0777); err != nil && !os.IsExist(err) {
598 klog.Errorf("Create <report-dir>/ginkgo: %v", err)
599 Exit(1)
600 }
601 }
602
603 if TestContext.ReportCompleteGinkgo {
604 ginkgo.ReportAfterSuite("Ginkgo JSON report", func(report ginkgo.Report) {
605 ExpectNoError(reporters.GenerateJSONReport(report, path.Join(ginkgoDir, "report.json")))
606 })
607 ginkgo.ReportAfterSuite("JUnit XML report", func(report ginkgo.Report) {
608 ExpectNoError(reporters.GenerateJUnitReport(report, path.Join(ginkgoDir, "report.xml")))
609 })
610 }
611
612 ginkgo.ReportAfterSuite("Kubernetes e2e JUnit report", func(report ginkgo.Report) {
613
614
615
616
617
618 junitReport := path.Join(TestContext.ReportDir, "junit_"+TestContext.ReportPrefix+"01.xml")
619
620
621
622
623
624
625
626 ExpectNoError(junit.WriteJUnitReport(report, junitReport))
627 })
628 }
629 }
630
631 func listTestInformation(report ginkgo.Report) {
632 indent := strings.Repeat(" ", 4)
633
634 if TestContext.listLabels {
635 labels := sets.New[string]()
636 for _, spec := range report.SpecReports {
637 if spec.LeafNodeType == types.NodeTypeIt {
638 labels.Insert(spec.Labels()...)
639 }
640 }
641 fmt.Fprintf(Output, "The following labels can be used with 'ginkgo run --label-filter':\n%s%s\n\n", indent, strings.Join(sets.List(labels), "\n"+indent))
642 }
643 if TestContext.listTests {
644 leafs := make([][]string, 0, len(report.SpecReports))
645 wd, _ := os.Getwd()
646 for _, spec := range report.SpecReports {
647 if spec.LeafNodeType == types.NodeTypeIt {
648 leafs = append(leafs, []string{fmt.Sprintf("%s:%d: ", relativePath(wd, spec.LeafNodeLocation.FileName), spec.LeafNodeLocation.LineNumber), spec.FullText()})
649 }
650 }
651
652
653 sort.Slice(leafs, func(i, j int) bool {
654 return leafs[i][1] < leafs[j][1]
655 })
656 fmt.Fprint(Output, "The following spec names can be used with 'ginkgo run --focus/skip':\n")
657 for _, leaf := range leafs {
658 fmt.Fprintf(Output, "%s%s%s\n", indent, leaf[0], leaf[1])
659 }
660 fmt.Fprint(Output, "\n")
661 }
662 }
663
664 func relativePath(wd, path string) string {
665 if wd == "" {
666 return path
667 }
668 relpath, err := filepath.Rel(wd, path)
669 if err != nil {
670 return path
671 }
672 return relpath
673 }
674
View as plain text