k8s.io/kubernetes@v1.29.3/test/e2e/framework/skipper/skipper.go (about)

     1  /*
     2  Copyright 2014 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 skipper
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/onsi/ginkgo/v2"
    24  
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/labels"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	utilversion "k8s.io/apimachinery/pkg/util/version"
    30  	"k8s.io/client-go/discovery"
    31  	"k8s.io/client-go/dynamic"
    32  	clientset "k8s.io/client-go/kubernetes"
    33  	"k8s.io/component-base/featuregate"
    34  	"k8s.io/kubernetes/test/e2e/framework"
    35  	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
    36  	e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
    37  )
    38  
    39  func skipInternalf(caller int, format string, args ...interface{}) {
    40  	msg := fmt.Sprintf(format, args...)
    41  	ginkgo.Skip(msg, caller+1)
    42  	panic("unreachable")
    43  }
    44  
    45  // Skipf skips with information about why the test is being skipped.
    46  // The direct caller is recorded in the callstack.
    47  func Skipf(format string, args ...interface{}) {
    48  	skipInternalf(1, format, args...)
    49  	panic("unreachable")
    50  }
    51  
    52  // SkipUnlessAtLeast skips if the value is less than the minValue.
    53  func SkipUnlessAtLeast(value int, minValue int, message string) {
    54  	if value < minValue {
    55  		skipInternalf(1, message)
    56  	}
    57  }
    58  
    59  var featureGate featuregate.FeatureGate
    60  
    61  // InitFeatureGates must be called in test suites that have a --feature-gates parameter.
    62  // If not called, SkipUnlessFeatureGateEnabled and SkipIfFeatureGateEnabled will
    63  // record a test failure.
    64  func InitFeatureGates(defaults featuregate.FeatureGate, overrides map[string]bool) error {
    65  	clone := defaults.DeepCopy()
    66  	if err := clone.SetFromMap(overrides); err != nil {
    67  		return err
    68  	}
    69  	featureGate = clone
    70  	return nil
    71  }
    72  
    73  // SkipUnlessFeatureGateEnabled skips if the feature is disabled.
    74  //
    75  // Beware that this only works in test suites that have a --feature-gate
    76  // parameter and call InitFeatureGates. In test/e2e, the `Feature: XYZ` tag
    77  // has to be used instead and invocations have to make sure that they
    78  // only run tests that work with the given test cluster.
    79  func SkipUnlessFeatureGateEnabled(gate featuregate.Feature) {
    80  	if featureGate == nil {
    81  		framework.Failf("Feature gate checking is not enabled, don't use SkipUnlessFeatureGateEnabled(%v). Instead use the Feature tag.", gate)
    82  	}
    83  	if !featureGate.Enabled(gate) {
    84  		skipInternalf(1, "Only supported when %v feature is enabled", gate)
    85  	}
    86  }
    87  
    88  // SkipIfFeatureGateEnabled skips if the feature is enabled.
    89  //
    90  // Beware that this only works in test suites that have a --feature-gate
    91  // parameter and call InitFeatureGates. In test/e2e, the `Feature: XYZ` tag
    92  // has to be used instead and invocations have to make sure that they
    93  // only run tests that work with the given test cluster.
    94  func SkipIfFeatureGateEnabled(gate featuregate.Feature) {
    95  	if featureGate == nil {
    96  		framework.Failf("Feature gate checking is not enabled, don't use SkipFeatureGateEnabled(%v). Instead use the Feature tag.", gate)
    97  	}
    98  	if featureGate.Enabled(gate) {
    99  		skipInternalf(1, "Only supported when %v feature is disabled", gate)
   100  	}
   101  }
   102  
   103  // SkipIfMissingResource skips if the gvr resource is missing.
   104  func SkipIfMissingResource(ctx context.Context, dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
   105  	resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
   106  	_, err := resourceClient.List(ctx, metav1.ListOptions{})
   107  	if err != nil {
   108  		// not all resources support list, so we ignore those
   109  		if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
   110  			skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
   111  		}
   112  		framework.Failf("Unexpected error getting %v: %v", gvr, err)
   113  	}
   114  }
   115  
   116  // SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
   117  func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
   118  	if framework.TestContext.CloudConfig.NumNodes < minNodeCount {
   119  		skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, framework.TestContext.CloudConfig.NumNodes)
   120  	}
   121  }
   122  
   123  // SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
   124  func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
   125  	if framework.TestContext.CloudConfig.NumNodes > maxNodeCount {
   126  		skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, framework.TestContext.CloudConfig.NumNodes)
   127  	}
   128  }
   129  
   130  // SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
   131  func SkipIfProviderIs(unsupportedProviders ...string) {
   132  	if framework.ProviderIs(unsupportedProviders...) {
   133  		skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, framework.TestContext.Provider)
   134  	}
   135  }
   136  
   137  // SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
   138  func SkipUnlessProviderIs(supportedProviders ...string) {
   139  	if !framework.ProviderIs(supportedProviders...) {
   140  		skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, framework.TestContext.Provider)
   141  	}
   142  }
   143  
   144  // SkipUnlessMultizone skips if the cluster does not have multizone.
   145  func SkipUnlessMultizone(ctx context.Context, c clientset.Interface) {
   146  	zones, err := e2enode.GetClusterZones(ctx, c)
   147  	if err != nil {
   148  		skipInternalf(1, "Error listing cluster zones")
   149  	}
   150  	if zones.Len() <= 1 {
   151  		skipInternalf(1, "Requires more than one zone")
   152  	}
   153  }
   154  
   155  // SkipIfMultizone skips if the cluster has multizone.
   156  func SkipIfMultizone(ctx context.Context, c clientset.Interface) {
   157  	zones, err := e2enode.GetClusterZones(ctx, c)
   158  	if err != nil {
   159  		skipInternalf(1, "Error listing cluster zones")
   160  	}
   161  	if zones.Len() > 1 {
   162  		skipInternalf(1, "Requires at most one zone")
   163  	}
   164  }
   165  
   166  // SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
   167  func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
   168  	if !framework.MasterOSDistroIs(supportedMasterOsDistros...) {
   169  		skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, framework.TestContext.MasterOSDistro)
   170  	}
   171  }
   172  
   173  // SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
   174  func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
   175  	if !framework.NodeOSDistroIs(supportedNodeOsDistros...) {
   176  		skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, framework.TestContext.NodeOSDistro)
   177  	}
   178  }
   179  
   180  // SkipUnlessNodeOSArchIs skips if the node OS distro is not included in the supportedNodeOsArchs.
   181  func SkipUnlessNodeOSArchIs(supportedNodeOsArchs ...string) {
   182  	if !framework.NodeOSArchIs(supportedNodeOsArchs...) {
   183  		skipInternalf(1, "Only supported for node OS arch %v (not %s)", supportedNodeOsArchs, framework.TestContext.NodeOSArch)
   184  	}
   185  }
   186  
   187  // SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
   188  func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
   189  	if framework.NodeOSDistroIs(unsupportedNodeOsDistros...) {
   190  		skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, framework.TestContext.NodeOSDistro)
   191  	}
   192  }
   193  
   194  // SkipUnlessServerVersionGTE skips if the server version is less than v.
   195  func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
   196  	gte, err := serverVersionGTE(v, c)
   197  	if err != nil {
   198  		framework.Failf("Failed to get server version: %v", err)
   199  	}
   200  	if !gte {
   201  		skipInternalf(1, "Not supported for server versions before %q", v)
   202  	}
   203  }
   204  
   205  // SkipUnlessSSHKeyPresent skips if no SSH key is found.
   206  func SkipUnlessSSHKeyPresent() {
   207  	if _, err := e2essh.GetSigner(framework.TestContext.Provider); err != nil {
   208  		skipInternalf(1, "No SSH Key for provider %s: '%v'", framework.TestContext.Provider, err)
   209  	}
   210  }
   211  
   212  // serverVersionGTE returns true if v is greater than or equal to the server version.
   213  func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
   214  	serverVersion, err := c.ServerVersion()
   215  	if err != nil {
   216  		return false, fmt.Errorf("Unable to get server version: %w", err)
   217  	}
   218  	sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
   219  	if err != nil {
   220  		return false, fmt.Errorf("Unable to parse server version %q: %w", serverVersion.GitVersion, err)
   221  	}
   222  	return sv.AtLeast(v), nil
   223  }
   224  
   225  // AppArmorDistros are distros with AppArmor support
   226  var AppArmorDistros = []string{"gci", "ubuntu"}
   227  
   228  // SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
   229  func SkipIfAppArmorNotSupported() {
   230  	SkipUnlessNodeOSDistroIs(AppArmorDistros...)
   231  }
   232  
   233  // RunIfSystemSpecNameIs runs if the system spec name is included in the names.
   234  func RunIfSystemSpecNameIs(names ...string) {
   235  	for _, name := range names {
   236  		if name == framework.TestContext.SystemSpecName {
   237  			return
   238  		}
   239  	}
   240  	skipInternalf(1, "Skipped because system spec name %q is not in %v", framework.TestContext.SystemSpecName, names)
   241  }
   242  
   243  // SkipUnlessComponentRunsAsPodsAndClientCanDeleteThem run if the component run as pods and client can delete them
   244  func SkipUnlessComponentRunsAsPodsAndClientCanDeleteThem(ctx context.Context, componentName string, c clientset.Interface, ns string, labelSet labels.Set) {
   245  	// verify if component run as pod
   246  	label := labels.SelectorFromSet(labelSet)
   247  	listOpts := metav1.ListOptions{LabelSelector: label.String()}
   248  	pods, err := c.CoreV1().Pods(ns).List(ctx, listOpts)
   249  	framework.Logf("SkipUnlessComponentRunsAsPodsAndClientCanDeleteThem: %v, %v", pods, err)
   250  	if err != nil {
   251  		skipInternalf(1, "Skipped because client failed to get component:%s pod err:%v", componentName, err)
   252  	}
   253  
   254  	if len(pods.Items) == 0 {
   255  		skipInternalf(1, "Skipped because component:%s is not running as pod.", componentName)
   256  	}
   257  
   258  	// verify if client can delete pod
   259  	pod := pods.Items[0]
   260  	if err := c.CoreV1().Pods(ns).Delete(ctx, pod.Name, metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}); err != nil {
   261  		skipInternalf(1, "Skipped because client failed to delete component:%s pod, err:%v", componentName, err)
   262  	}
   263  }
   264  
   265  // SkipIfIPv6 skips if the cluster IP family is IPv6 and the provider is included in the unsupportedProviders.
   266  func SkipIfIPv6(unsupportedProviders ...string) {
   267  	if framework.TestContext.ClusterIsIPv6() && framework.ProviderIs(unsupportedProviders...) {
   268  		skipInternalf(1, "Not supported for IPv6 clusters and providers %v (found %s)", unsupportedProviders, framework.TestContext.Provider)
   269  	}
   270  }