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 }