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