Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions test/extended/util/compat_otp/client.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package compat_otp

import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"strings"
"time"

g "github.com/onsi/ginkgo/v2"

Expand Down Expand Up @@ -35,6 +39,14 @@ func NewCLIForKubeOpenShift(basename string) *exutil.CLI {
if os.Getenv(EnvIsKubernetesCluster) == "true" {
return NewCLIForKube(basename)
}

// Check if it's HyperShift environment with Kubernetes management cluster
// In this case, we use exutil.NewCLIWithoutNamespace to avoid OpenShift-specific
// initialization (like clusterversion checks) that would fail on pure Kubernetes
if isHyperShiftWithKubernetesManagement() {
return exutil.NewCLIWithoutNamespace(basename)
}

return exutil.NewCLI(basename)
}

Expand Down Expand Up @@ -118,3 +130,64 @@ func GetPodLogs(oc *exutil.CLI, pod, container, since string) (string, error) {
}
return oc.Run("get").Args(args...).Output()
}

// isHyperShiftWithKubernetesManagement checks if this is a HyperShift environment
// where the current KUBECONFIG points to a Kubernetes management cluster (not OpenShift).
// This is typical for HyperShift on AKS, EKS, or GKE where the management cluster
// is a pure Kubernetes cluster.
func isHyperShiftWithKubernetesManagement() bool {
// Check 1: Is HYPERSHIFT environment variable set?
if os.Getenv("HYPERSHIFT") != "true" {
return false
}

// Check 2: Does the cluster have clusterversion API?
// If it doesn't exist, it's likely a Kubernetes cluster (not OpenShift)
return !hasClusterVersionAPI()
}

// hasClusterVersionAPI checks if the cluster has the OpenShift clusterversion API.
// Returns true if the API exists (OpenShift cluster), false otherwise (Kubernetes cluster).
func hasClusterVersionAPI() bool {
// Create context with timeout to prevent hanging
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// Try to list API resources in the config.openshift.io group
cmd := exec.CommandContext(ctx, "oc", "api-resources", "--api-group=config.openshift.io", "-o=name")

// Use KUBECONFIG from environment if set
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
}

output, err := cmd.CombinedOutput()
if err != nil {
// Check for critical errors that should not be silently ignored
if errors.Is(err, exec.ErrNotFound) {
// oc binary not found - this is a real failure but treat as no API
// since we can't determine the cluster type
return false
}
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
// Command timed out - treat as no API available
return false
}

// For other errors, check if it's an expected "API not found" pattern
outputStr := string(output)
// When the API group doesn't exist, oc returns error with no output or specific messages
if outputStr == "" ||
strings.Contains(outputStr, "the server doesn't have a resource type") ||
strings.Contains(outputStr, "no resources found") {
return false
}

// Unexpected error - log it but return false to be safe
// We can't determine definitively, so assume no OpenShift API
return false
}

// Check if clusterversions resource exists in the output
return strings.Contains(string(output), "clusterversions")
}