Repository: kiali/kiali

Issue:
CI Fail in Primary-Remote cypress
In masthead.feature

```
  Kiali masthead cluster components status
    1) Cluster components healthy
    ✓ Istio components unhealthy (27566ms)


  1 passing (1m)
  1 failing

  1) Kiali masthead cluster components status
       Cluster components healthy:
     AssertionError: Timed out retrying after 40000ms: Expected to find content: 'west' within the element: <div#pf-tooltip-89.pf-v5-c-tooltip.pf-m-bottom> but never did.
      at Context.eval (http://172.18.255.72/__cypress/tests?p=cypress/integration/featureFiles/masthead.feature:118882:29)

```

Hints from issue comments:
@jshaughn: The problem seems to be server-side, based on some debug logging.  still looking...

...looks like somehow we ask for "west" status but get back "east"
2025-04-04T16:58:45Z INF **** ISTIO STATUS merge status for cluster=[west] ics=[east:Healthy]
2025-04-04T16:58:45Z INF **** ISTIO STATUS merge status for cluster=[west] ics=[east:Healthy]
2025-04-04T16:58:45Z INF **** ISTIO STATUS merge status for cluster=[west] ics=[east:Healthy]

Solution patch:
diff --git a/business/istio_status.go b/business/istio_status.go
index 5db386b92..d00612c61 100644
--- a/business/istio_status.go
+++ b/business/istio_status.go
@@ -14,6 +14,7 @@ import (
 	"github.com/kiali/kiali/models"
 	"github.com/kiali/kiali/observability"
 	"github.com/kiali/kiali/util/httputil"
+	"github.com/kiali/kiali/util/sliceutil"
 )
 
 func NewIstioStatusService(
@@ -123,19 +124,22 @@ func (iss *IstioStatusService) getIstioComponentStatus(ctx context.Context, clus
 	}
 
 	// Autodiscover gateways.
-	gateways, err := iss.workloads.GetAllGateways(ctx, cluster, "")
+	allGateways, err := iss.workloads.GetGateways(ctx)
 	if err != nil {
 		// Don't error on gateways since they are non-essential.
 		log.Debugf("Unable to get gateway workloads when building istio component status. Cluster: %s. Err: %s", cluster, err)
 		return istiodStatus, nil
 	}
+	gateways := sliceutil.Filter(allGateways, func(gw *models.Workload) bool {
+		return gw.Cluster == cluster
+	})
 
-	for _, workload := range gateways {
+	for _, gateway := range gateways {
 		istiodStatus = append(istiodStatus, kubernetes.ComponentStatus{
-			Cluster:   workload.Cluster,
-			Name:      workload.Name,
-			Namespace: workload.Namespace,
-			Status:    GetWorkloadStatus(*workload),
+			Cluster:   gateway.Cluster,
+			Name:      gateway.Name,
+			Namespace: gateway.Namespace,
+			Status:    GetWorkloadStatus(*gateway),
 			IsCore:    false,
 		})
 	}
diff --git a/business/workloads.go b/business/workloads.go
index 84719c26a..461ce8f87 100644
--- a/business/workloads.go
+++ b/business/workloads.go
@@ -185,23 +185,28 @@ func (in *WorkloadService) GetAllWorkloads(ctx context.Context, cluster string,
 	return workloads, nil
 }
 
-// GetAllGateways fetches all gateway workloads across every namespace in the cluster.
-func (in *WorkloadService) GetAllGateways(ctx context.Context, cluster string, labelSelector string) (models.Workloads, error) {
+// GetGateways fetches all gateway workloads across all clusters and namespaces.
+func (in *WorkloadService) GetGateways(ctx context.Context) (models.Workloads, error) {
 	if gateways, ok := in.cache.GetGateways(); ok {
-		log.Tracef("GetAllGateways: Returning list from cache")
+		log.Tracef("GetGateways: Returning list from cache")
 		return gateways, nil
 	}
 
-	workloads, err := in.GetAllWorkloads(ctx, cluster, labelSelector)
-	if err != nil {
-		return nil, err
+	gateways := models.Workloads{}
+	for cluster := range in.userClients {
+		workloads, err := in.GetAllWorkloads(ctx, cluster, "")
+		if err != nil {
+			log.Debugf("GetGateways: Error fetching workloads for cluster=[%s]: %s", cluster, err.Error())
+			continue
+		}
+
+		clusterGateways := sliceutil.Filter(workloads, func(w *models.Workload) bool {
+			return w.IsGateway()
+		})
+		gateways = append(gateways, clusterGateways...)
 	}
 
-	gateways := sliceutil.Filter(workloads, func(w *models.Workload) bool {
-		return w.IsGateway()
-	})
 	in.cache.SetGateways(gateways)
-
 	return gateways, nil
 }
 



Test patch:
diff --git a/business/workloads_test.go b/business/workloads_test.go
index b56c84739..402e4c1cf 100644
--- a/business/workloads_test.go
+++ b/business/workloads_test.go
@@ -27,6 +27,7 @@ import (
 	"github.com/kiali/kiali/models"
 	"github.com/kiali/kiali/prometheus/prometheustest"
 	"github.com/kiali/kiali/tests/data"
+	"github.com/kiali/kiali/util/sliceutil"
 )
 
 func setupWorkloadService(k8s kubernetes.ClientInterface, conf *config.Config) WorkloadService {
@@ -1889,11 +1890,14 @@ func TestGetAllGateways(t *testing.T) {
 	SetupBusinessLayer(t, k8s, *conf)
 	svc := setupWorkloadService(k8s, conf)
 
-	workloads, err := svc.GetAllGateways(context.Background(), conf.KubernetesConfig.ClusterName, "")
+	gateways, err := svc.GetGateways(context.Background())
 	require.NoError(err)
+	gateways = sliceutil.Filter(gateways, func(gw *models.Workload) bool {
+		return gw.Cluster == conf.KubernetesConfig.ClusterName
+	})
 
-	require.Len(workloads, 1)
-	require.True(workloads[0].IsGateway(), "Expected IsGateway to be True but it was false")
+	require.Len(gateways, 1)
+	require.True(gateways[0].IsGateway(), "Expected IsGateway to be True but it was false")
 }
 
 func TestGetWorkloadListWithCustomKindThatMatchesCoreKind(t *testing.T) {