123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package skipper
- import (
- "bufio"
- "bytes"
- "fmt"
- "github.com/onsi/ginkgo"
- "regexp"
- "runtime"
- "runtime/debug"
- "strings"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- utilversion "k8s.io/apimachinery/pkg/util/version"
- utilfeature "k8s.io/apiserver/pkg/util/feature"
- "k8s.io/client-go/discovery"
- "k8s.io/client-go/dynamic"
- clientset "k8s.io/client-go/kubernetes"
- "k8s.io/kubernetes/pkg/features"
- "k8s.io/kubernetes/test/e2e/framework"
- e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
- )
- // TestContext should be used by all tests to access common context data.
- var TestContext framework.TestContextType
- func skipInternalf(caller int, format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- framework.Logf("INFO", msg)
- skip(msg, caller+1)
- }
- // SkipPanic is the value that will be panicked from Skip.
- type SkipPanic struct {
- Message string // The failure message passed to Fail
- Filename string // The filename that is the source of the failure
- Line int // The line number of the filename that is the source of the failure
- FullStackTrace string // A full stack trace starting at the source of the failure
- }
- // String makes SkipPanic look like the old Ginkgo panic when printed.
- func (SkipPanic) String() string { return ginkgo.GINKGO_PANIC }
- // Skip wraps ginkgo.Skip so that it panics with more useful
- // information about why the test is being skipped. This function will
- // panic with a SkipPanic.
- func skip(message string, callerSkip ...int) {
- skip := 1
- if len(callerSkip) > 0 {
- skip += callerSkip[0]
- }
- _, file, line, _ := runtime.Caller(skip)
- sp := SkipPanic{
- Message: message,
- Filename: file,
- Line: line,
- FullStackTrace: pruneStack(skip),
- }
- defer func() {
- e := recover()
- if e != nil {
- panic(sp)
- }
- }()
- ginkgo.Skip(message, skip)
- }
- // ginkgo adds a lot of test running infrastructure to the stack, so
- // we filter those out
- var stackSkipPattern = regexp.MustCompile(`onsi/ginkgo`)
- func pruneStack(skip int) string {
- skip += 2 // one for pruneStack and one for debug.Stack
- stack := debug.Stack()
- scanner := bufio.NewScanner(bytes.NewBuffer(stack))
- var prunedStack []string
- // skip the top of the stack
- for i := 0; i < 2*skip+1; i++ {
- scanner.Scan()
- }
- for scanner.Scan() {
- if stackSkipPattern.Match(scanner.Bytes()) {
- scanner.Scan() // these come in pairs
- } else {
- prunedStack = append(prunedStack, scanner.Text())
- scanner.Scan() // these come in pairs
- prunedStack = append(prunedStack, scanner.Text())
- }
- }
- return strings.Join(prunedStack, "\n")
- }
- // Skipf skips with information about why the test is being skipped.
- func Skipf(format string, args ...interface{}) {
- skipInternalf(1, format, args...)
- }
- // SkipUnlessAtLeast skips if the value is less than the minValue.
- func SkipUnlessAtLeast(value int, minValue int, message string) {
- if value < minValue {
- skipInternalf(1, message)
- }
- }
- // SkipUnlessLocalEphemeralStorageEnabled skips if the LocalStorageCapacityIsolation is not enabled.
- func SkipUnlessLocalEphemeralStorageEnabled() {
- if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
- skipInternalf(1, "Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation)
- }
- }
- // SkipIfMissingResource skips if the gvr resource is missing.
- func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
- resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
- _, err := resourceClient.List(metav1.ListOptions{})
- if err != nil {
- // not all resources support list, so we ignore those
- if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
- skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
- }
- framework.Failf("Unexpected error getting %v: %v", gvr, err)
- }
- }
- // SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
- func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
- if TestContext.CloudConfig.NumNodes < minNodeCount {
- skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, TestContext.CloudConfig.NumNodes)
- }
- }
- // SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
- func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
- if TestContext.CloudConfig.NumNodes > maxNodeCount {
- skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, TestContext.CloudConfig.NumNodes)
- }
- }
- // SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
- func SkipIfProviderIs(unsupportedProviders ...string) {
- if framework.ProviderIs(unsupportedProviders...) {
- skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, TestContext.Provider)
- }
- }
- // SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
- func SkipUnlessProviderIs(supportedProviders ...string) {
- if !framework.ProviderIs(supportedProviders...) {
- skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, TestContext.Provider)
- }
- }
- // SkipUnlessMultizone skips if the cluster does not have multizone.
- func SkipUnlessMultizone(c clientset.Interface) {
- zones, err := framework.GetClusterZones(c)
- if err != nil {
- skipInternalf(1, "Error listing cluster zones")
- }
- if zones.Len() <= 1 {
- skipInternalf(1, "Requires more than one zone")
- }
- }
- // SkipIfMultizone skips if the cluster has multizone.
- func SkipIfMultizone(c clientset.Interface) {
- zones, err := framework.GetClusterZones(c)
- if err != nil {
- skipInternalf(1, "Error listing cluster zones")
- }
- if zones.Len() > 1 {
- skipInternalf(1, "Requires at most one zone")
- }
- }
- // SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
- func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
- if !framework.MasterOSDistroIs(supportedMasterOsDistros...) {
- skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, TestContext.MasterOSDistro)
- }
- }
- // SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
- func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
- if !framework.NodeOSDistroIs(supportedNodeOsDistros...) {
- skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, TestContext.NodeOSDistro)
- }
- }
- // SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
- func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
- if framework.NodeOSDistroIs(unsupportedNodeOsDistros...) {
- skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, TestContext.NodeOSDistro)
- }
- }
- // SkipUnlessServerVersionGTE skips if the server version is less than v.
- func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
- gte, err := serverVersionGTE(v, c)
- if err != nil {
- framework.Failf("Failed to get server version: %v", err)
- }
- if !gte {
- skipInternalf(1, "Not supported for server versions before %q", v)
- }
- }
- // SkipUnlessSSHKeyPresent skips if no SSH key is found.
- func SkipUnlessSSHKeyPresent() {
- if _, err := e2essh.GetSigner(TestContext.Provider); err != nil {
- skipInternalf(1, "No SSH Key for provider %s: '%v'", TestContext.Provider, err)
- }
- }
- // serverVersionGTE returns true if v is greater than or equal to the server version.
- func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
- serverVersion, err := c.ServerVersion()
- if err != nil {
- return false, fmt.Errorf("Unable to get server version: %v", err)
- }
- sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
- if err != nil {
- return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err)
- }
- return sv.AtLeast(v), nil
- }
- // AppArmorDistros are distros with AppArmor support
- var AppArmorDistros = []string{"gci", "ubuntu"}
- // SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
- func SkipIfAppArmorNotSupported() {
- SkipUnlessNodeOSDistroIs(AppArmorDistros...)
- }
- // RunIfContainerRuntimeIs runs if the container runtime is included in the runtimes.
- func RunIfContainerRuntimeIs(runtimes ...string) {
- for _, containerRuntime := range runtimes {
- if containerRuntime == TestContext.ContainerRuntime {
- return
- }
- }
- skipInternalf(1, "Skipped because container runtime %q is not in %s", TestContext.ContainerRuntime, runtimes)
- }
- // RunIfSystemSpecNameIs runs if the system spec name is included in the names.
- func RunIfSystemSpecNameIs(names ...string) {
- for _, name := range names {
- if name == TestContext.SystemSpecName {
- return
- }
- }
- skipInternalf(1, "Skipped because system spec name %q is not in %v", TestContext.SystemSpecName, names)
- }
|