Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
fix(disruption): Using correct internal LB of apiserver for monitor t…
…est on ARO and Baremetal Hypershift
  • Loading branch information
wangke19 committed Oct 15, 2025
commit db5e78dbb9729b0c44b9a86b41f4c28193ad2f8e
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"

"github.com/openshift/origin/pkg/monitortestlibrary/disruptionlibrary"
"github.com/openshift/origin/pkg/test/extensions"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"

Expand Down Expand Up @@ -76,6 +77,9 @@ type InvariantInClusterDisruption struct {
replicas int32
controlPlaneNodes int32

isHypershift bool
isAROHCPCluster bool
isBareMetalHypershift bool
adminRESTConfig *rest.Config
kubeClient kubernetes.Interface
}
Expand All @@ -86,6 +90,68 @@ func NewInvariantInClusterDisruption(info monitortestframework.MonitorTestInitia
}
}

// parseAdminRESTConfigHost parses the adminRESTConfig.Host URL and returns hostname and port
func (i *InvariantInClusterDisruption) parseAdminRESTConfigHost() (hostname, port string, err error) {
parsedURL, err := url.Parse(i.adminRESTConfig.Host)
if err != nil {
return "", "", fmt.Errorf("failed to parse adminRESTConfig.Host %q: %v", i.adminRESTConfig.Host, err)
}

hostname = parsedURL.Hostname()
if hostname == "" {
return "", "", fmt.Errorf("no hostname found in adminRESTConfig.Host %q", i.adminRESTConfig.Host)
}

port = parsedURL.Port()
if port == "" {
port = "6443" // default port
}

return hostname, port, nil
}

// setKubernetesServiceEnvVars sets the KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT environment variables
// based on the cluster type (ARO HCP, bare metal HyperShift, or standard)
func (i *InvariantInClusterDisruption) setKubernetesServiceEnvVars(envVars []corev1.EnvVar, apiIntHost, apiIntPort string) []corev1.EnvVar {
// Parse adminRESTConfig.Host once for bare metal HyperShift
var bareMetalHost, bareMetalPort string
var bareMetalErr error
if i.isHypershift && i.isBareMetalHypershift {
bareMetalHost, bareMetalPort, bareMetalErr = i.parseAdminRESTConfigHost()
if bareMetalErr != nil {
logrus.WithError(bareMetalErr).Errorf("Failed to parse adminRESTConfig.Host for bare metal HyperShift")
}
}

for j, env := range envVars {
switch env.Name {
case "KUBERNETES_SERVICE_HOST":
if i.isHypershift && i.isBareMetalHypershift {
if bareMetalErr != nil {
envVars[j].Value = apiIntHost
} else {
envVars[j].Value = bareMetalHost
}
} else {
envVars[j].Value = apiIntHost
}
case "KUBERNETES_SERVICE_PORT":
if i.isHypershift && i.isAROHCPCluster {
envVars[j].Value = "7443"
} else if i.isHypershift && i.isBareMetalHypershift {
if bareMetalErr != nil {
envVars[j].Value = apiIntPort
} else {
envVars[j].Value = bareMetalPort
}
} else {
envVars[j].Value = apiIntPort
}
}
}
return envVars
}

func (i *InvariantInClusterDisruption) createDeploymentAndWaitToRollout(ctx context.Context, deploymentObj *appsv1.Deployment) error {
deploymentID := uuid.New().String()
deploymentObj = disruptionlibrary.UpdateDeploymentENVs(deploymentObj, deploymentID, "")
Expand Down Expand Up @@ -117,12 +183,14 @@ func (i *InvariantInClusterDisruption) createDeploymentAndWaitToRollout(ctx cont
func (i *InvariantInClusterDisruption) createInternalLBDeployment(ctx context.Context, apiIntHost string) error {
deploymentObj := resourceread.ReadDeploymentV1OrDie(internalLBDeploymentYaml)
deploymentObj.SetNamespace(i.namespaceName)
deploymentObj.Spec.Template.Spec.Containers[0].Env[0].Value = apiIntHost
// set amount of deployment replicas to make sure it runs on all nodes
deploymentObj.Spec.Replicas = &i.replicas
// we need to use the openshift-tests image of the destination during an upgrade.
deploymentObj.Spec.Template.Spec.Containers[0].Image = i.openshiftTestsImagePullSpec

// Set the correct host and port for internal API server based on cluster type
deploymentObj.Spec.Template.Spec.Containers[0].Env = i.setKubernetesServiceEnvVars(
deploymentObj.Spec.Template.Spec.Containers[0].Env, apiIntHost, apiIntPort)
err := i.createDeploymentAndWaitToRollout(ctx, deploymentObj)
if err != nil {
return err
Expand Down Expand Up @@ -332,8 +400,30 @@ func (i *InvariantInClusterDisruption) StartCollection(ctx context.Context, admi
managementOC := exutil.NewHypershiftManagementCLI(hcpNamespace)
if isAROHCPcluster, err = exutil.IsAroHCP(ctx, hcpNamespace, managementOC.AdminKubeClient()); err != nil {
logrus.WithError(err).Warning("Failed to check if ARO HCP, assuming it's not")
i.isAROHCPCluster = false // Assume not ARO HCP on error
} else if isAROHCPcluster {
i.notSupportedReason = "platform Hypershift - ARO HCP not supported"
i.isAROHCPCluster = true
} else {
i.isAROHCPCluster = false
}

// Check if this is a bare metal HyperShift cluster
i.isBareMetalHypershift, err = exutil.IsBareMetalHyperShiftCluster(ctx, managementOC)
if err != nil {
logrus.WithError(err).Warning("Failed to check if bare metal HyperShift, assuming it's not")
i.isBareMetalHypershift = false // Assume not bare metal HyperShift on error
}
}

if len(i.payloadImagePullSpec) == 0 {
i.payloadImagePullSpec, err = extensions.DetermineReleasePayloadImage()
if err != nil {
return err
}

if len(i.payloadImagePullSpec) == 0 {
log.Info("unable to determine payloadImagePullSpec")
i.notSupportedReason = "no image pull spec specified."
return nil
}
}
Expand Down Expand Up @@ -379,11 +469,25 @@ func (i *InvariantInClusterDisruption) StartCollection(ctx context.Context, admi
return fmt.Errorf("error getting openshift infrastructure: %v", err)
}

internalAPI, err := url.Parse(infra.Status.APIServerInternalURL)
if err != nil {
return fmt.Errorf("error parsing api int url: %v", err)
var apiIntHost string
var apiIntPort string
if i.isHypershift {
apiIntHost, apiIntPort, err = i.parseAdminRESTConfigHost()
if err != nil {
return fmt.Errorf("failed to parse adminRESTConfig.Host: %v", err)
}
} else {
internalAPI, err := url.Parse(infra.Status.APIServerInternalURL)
if err != nil {
return fmt.Errorf("error parsing api int url: %v", err)
}
apiIntHost = internalAPI.Hostname()
if internalAPI.Port() != "" {
apiIntPort = internalAPI.Port()
} else {
apiIntPort = "6443" // default port
}
}
apiIntHost := internalAPI.Hostname()

allNodes, err := i.kubeClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
if err != nil {
Expand Down
38 changes: 38 additions & 0 deletions test/extended/util/managed_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package util

import (
"context"
"fmt"
"strings"

"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -95,3 +97,39 @@ func IsAroHCP(ctx context.Context, namespace string, kubeClient kubernetes.Inter
logrus.Infof("No deployment found with control-plane-operator container in namespace %s", namespace)
return false, nil
}

// IsBareMetalHyperShiftCluster checks if the HyperShift cluster is running on bare metal
// by checking the platform type of the hosted cluster. It uses kubectl commands to query
// the hosted cluster's platform type and returns true if it's "None" or "Agent".
func IsBareMetalHyperShiftCluster(ctx context.Context, managementOC *CLI) (bool, error) {
// Get the hosted cluster namespace
_, hcpNamespace, err := GetHypershiftManagementClusterConfigAndNamespace()
if err != nil {
return false, fmt.Errorf("failed to get hypershift management cluster config and namespace: %v", err)
}

// Get the first hosted cluster name
clusterNames, err := managementOC.AsAdmin().WithoutNamespace().Run("get").Args(
"-n", hcpNamespace, "hostedclusters", "-o=jsonpath={.items[*].metadata.name}").Output()
if err != nil {
return false, fmt.Errorf("failed to get hosted cluster names: %v", err)
}

if len(clusterNames) == 0 {
return false, fmt.Errorf("no hosted clusters found")
}

// Get the first hosted cluster name
clusterName := strings.Split(strings.TrimSpace(clusterNames), " ")[0]

// Get the platform type of the hosted cluster
platformType, err := managementOC.AsAdmin().WithoutNamespace().Run("get").Args(
"hostedcluster", clusterName, "-n", hcpNamespace, `-ojsonpath={.spec.platform.type}`).Output()
if err != nil {
return false, fmt.Errorf("failed to get hosted cluster platform type: %v", err)
}

// Check if it's bare metal (None or Agent platform)
platformTypeStr := strings.TrimSpace(platformType)
return platformTypeStr == "None" || platformTypeStr == "Agent", nil
}