Repository: kiali/kiali
Pull request #8466 (2025-05-28 12:02:27)

Add partial selector match for ztunnel
### Describe the change

Include a partial match field in FilterDaemonSetsBySelector so the selector can be a superset of the filter.
The motivation is to match ztunnel even if it includes more selectors than just the label app=ztunnel 

### Steps to test the PR

- Verify Istio Ambient is enabled by just installing Istio Ambient
- Verify Istio Ambient is enabled by adding a new selector to ztunnel*
- Verify Istio Ambient is disabled when Istio is installed in the default profile.

*Followed the steps: 
`k get daemonset ztunnel -n istio-system -o yaml > ztunnel.yaml`
edit ztunnel.yaml to add additional selectors
`k delete daemonset ztunnel -n istio-system`
`k apply -f ztunnel.yaml -n istio-system`

### Automation testing

CI should pass

### Issue reference

Fixes https://github.com/kiali/kiali/issues/8464



Patch:
diff --git a/business/workloads.go b/business/workloads.go
index dbc47acc0..3faaa433e 100644
--- a/business/workloads.go
+++ b/business/workloads.go
@@ -2713,8 +2713,10 @@ func (in *WorkloadService) StreamPodLogs(ctx context.Context, cluster, namespace
 		for _, pod := range pods {
 			names = append(names, pod.Name)
 		}
-		// They should be all in the same ns
-		return in.streamParsedLogs(cluster, pods[0].Namespace, names, opts, w)
+		if len(pods) > 0 {
+			// They should be all in the same ns
+			return in.streamParsedLogs(cluster, pods[0].Namespace, names, opts, w)
+		}
 	}
 	if opts.LogType == models.LogTypeWaypoint {
 		wk, err := in.GetWorkload(ctx, WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: workload, IncludeServices: false})
diff --git a/cache/cache.go b/cache/cache.go
index 9db9d91fe..f25845122 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -285,22 +285,17 @@ func (in *kialiCacheImpl) IsAmbientEnabled(cluster string) bool {
 		}
 
 		daemonSetList := &appsv1.DaemonSetList{}
-		if err := kubeCache.List(context.TODO(), daemonSetList); err != nil {
-			// Don't set the check so we will check again the next time since this error may be transient.
-			in.zl.Debug().Msgf("Error checking for ztunnel in Kiali accessible namespaces in cluster '%s': %s", cluster, err.Error())
-			return false
-		}
 		selector := map[string]string{
-			config.IstioAppLabel: config.Ztunnel,
+			config.KubernetesAppLabel: config.Ztunnel,
 		}
-		daemonsets, err := kubernetes.FilterDaemonSetsBySelector(daemonSetList.Items, selector)
-		if err != nil {
+		listOpts := []client.ListOption{client.MatchingLabels(selector)}
+		if err := kubeCache.List(context.TODO(), daemonSetList, listOpts...); err != nil {
 			// Don't set the check so we will check again the next time since this error may be transient.
 			in.zl.Debug().Msgf("Error checking for ztunnel in Kiali accessible namespaces in cluster '%s': %s", cluster, err.Error())
 			return false
 		}
 
-		if len(daemonsets) == 0 {
+		if len(daemonSetList.Items) == 0 {
 			in.zl.Debug().Msgf("No ztunnel daemonsets found in Kiali accessible namespaces in cluster '%s'", cluster)
 			in.ambientChecksPerCluster.Set(cluster, false)
 			return false
@@ -322,28 +317,23 @@ func (in *kialiCacheImpl) GetZtunnelPods(cluster string) []v1.Pod {
 	}
 
 	daemonSetList := &appsv1.DaemonSetList{}
-	if err := kubeCache.List(context.TODO(), daemonSetList); err != nil {
-		// Don't set the check so we will check again the next time since this error may be transient.
-		in.zl.Debug().Msgf("Error checking for ztunnel in Kiali accessible namespaces in cluster '%s': %s", cluster, err.Error())
-		return nil
-	}
-
 	selector := map[string]string{
-		config.IstioAppLabel: config.Ztunnel,
+		config.KubernetesAppLabel: config.Ztunnel,
 	}
-	daemonsets, err := kubernetes.FilterDaemonSetsBySelector(daemonSetList.Items, selector)
-	if err != nil {
+	listOpts := []client.ListOption{client.MatchingLabels(selector)}
+	if err := kubeCache.List(context.TODO(), daemonSetList, listOpts...); err != nil {
+		// Don't set the check so we will check again the next time since this error may be transient.
 		in.zl.Debug().Msgf("Error checking for ztunnel in Kiali accessible namespaces in cluster '%s': %s", cluster, err.Error())
 		return nil
 	}
 
-	if len(daemonsets) == 0 {
+	if len(daemonSetList.Items) == 0 {
 		in.zl.Debug().Msgf("No ztunnel daemonsets found in Kiali accessible namespaces in cluster '%s'", cluster)
 		return nil
 	}
 
 	podList := &v1.PodList{}
-	if err := kubeCache.List(context.TODO(), podList, client.InNamespace(daemonsets[0].Namespace), client.MatchingLabels{"app": config.Ztunnel}); err != nil {
+	if err := kubeCache.List(context.TODO(), podList, client.InNamespace(daemonSetList.Items[0].Namespace), client.MatchingLabels{"app": config.Ztunnel}); err != nil {
 		in.zl.Error().Msgf("Unable to get ztunnel pods: %s", err)
 		return nil
 	}
diff --git a/config/config.go b/config/config.go
index e04a41792..159c16060 100644
--- a/config/config.go
+++ b/config/config.go
@@ -80,6 +80,7 @@ const (
 	IstioAppLabel             = "app"                                    // we can assume istio components are labeled with "app"
 	IstioRevisionLabel        = "istio.io/rev"                           // the standard label key used to identify the istio revision.
 	IstioVersionLabel         = "version"                                // we can assume istio components are labeled with "version", if versioned
+	KubernetesAppLabel        = "app.kubernetes.io/name"
 	Waypoint                  = "waypoint"
 	WaypointFor               = "istio.io/waypoint-for"
 	WaypointForAll            = "all"
@@ -390,6 +391,8 @@ type IstioLabels struct {
 	AppLabelName                string `yaml:"app_label_name,omitempty" json:"appLabelName"`
 	InjectionLabelName          string `yaml:"injection_label_name,omitempty" json:"injectionLabelName"`
 	InjectionLabelRev           string `yaml:"injection_label_rev,omitempty" json:"injectionLabelRev"`
+	ServiceCanonicalName        string `yaml:"service_canonical_name,omitempty" json:"serviceCanonicalName"`
+	ServiceCanonicalRevision    string `yaml:"service_canonical_revision,omitempty" json:"serviceCanonicalRevision"`
 	VersionLabelName            string `yaml:"version_label_name,omitempty" json:"versionLabelName"`
 }
 
@@ -837,6 +840,8 @@ func NewConfig() (c *Config) {
 			AppLabelName:                "",
 			InjectionLabelName:          "istio-injection",
 			InjectionLabelRev:           IstioRevisionLabel,
+			ServiceCanonicalName:        "service.istio.io/canonical-name",
+			ServiceCanonicalRevision:    "service.istio.io/canonical-revision",
 			VersionLabelName:            "",
 		},
 		KialiFeatureFlags: KialiFeatureFlags{
@@ -1061,8 +1066,8 @@ func Set(conf *Config) {
 			appLabelNames = []string{conf.IstioLabels.AppLabelName}
 			versionLabelNames = []string{conf.IstioLabels.VersionLabelName}
 		} else {
-			appLabelNames = []string{"service.istio.io/canonical-name", "app.kubernetes.io/name", "app"}
-			versionLabelNames = []string{"service.istio.io/canonical-revision", "app.kubernetes.io/version", "version"}
+			appLabelNames = []string{conf.IstioLabels.ServiceCanonicalName, "app.kubernetes.io/name", "app"}
+			versionLabelNames = []string{conf.IstioLabels.ServiceCanonicalRevision, "app.kubernetes.io/version", "version"}
 		}
 	}
 }
diff --git a/frontend/src/components/MTls/MeshMTLSStatus.tsx b/frontend/src/components/MTls/MeshMTLSStatus.tsx
index 053f22d50..326267a96 100644
--- a/frontend/src/components/MTls/MeshMTLSStatus.tsx
+++ b/frontend/src/components/MTls/MeshMTLSStatus.tsx
@@ -98,7 +98,6 @@ class MeshMTLSStatusComponent extends React.Component<Props> {
     // leaving empty cluster param here, home cluster will be used by default
     API.getMeshTls(this.props.cluster, this.props.revision)
       .then(response => {
-        console.log(response);
         return this.props.setMeshTlsStatus(response.data);
       })
       .catch(error => {
diff --git a/frontend/src/pages/Graph/GraphElems.tsx b/frontend/src/pages/Graph/GraphElems.tsx
index a9966a5eb..66feccd8c 100644
--- a/frontend/src/pages/Graph/GraphElems.tsx
+++ b/frontend/src/pages/Graph/GraphElems.tsx
@@ -273,7 +273,10 @@ export const setNodeLabel = (
       data.labelIcon = <span className={`${badgeMap.get('RO')?.className} ${rootIconStyle}`}></span>;
     }
   } else {
-    if (data.isGateway?.egressInfo?.hostnames?.length !== undefined) {
+    if (
+      data.isGateway?.egressInfo?.hostnames?.length !== undefined ||
+      data.isGateway?.gatewayAPIInfo?.hostnames?.length !== undefined
+    ) {
       data.labelIcon = <span className={`${badgeMap.get('GW')?.className} ${gatewayIconStyle}`}></span>;
     }
     // A Waypoint should be mutually exclusive with being a traffic source
diff --git a/graph/telemetry/istio/appender/istio_details.go b/graph/telemetry/istio/appender/istio_details.go
index 39979520d..f5c316f5c 100644
--- a/graph/telemetry/istio/appender/istio_details.go
+++ b/graph/telemetry/istio/appender/istio_details.go
@@ -267,8 +267,8 @@ func decorateMatchingAPIGateways(cluster string, gwCrd *k8s_networking_v1.Gatewa
 		if gw.Cluster != cluster {
 			continue
 		}
-
-		if gwSelector.Matches(labels.Set(gw.Labels)) {
+		// If the selector is empty, try to match with the crd name and the GW label
+		if (!gwSelector.Empty() && gwSelector.Matches(labels.Set(gw.Labels))) || (gwSelector.Empty() && gwCrd.Name == gw.Labels[config.GatewayLabel]) {
 			// If we are here, the GatewayCrd selects the GatewayAPI workload.
 			// So, all node graphs associated with the GW API workload should be listening
 			// requests for the hostnames listed in the GatewayAPI CRD.
@@ -283,7 +283,10 @@ func decorateMatchingAPIGateways(cluster string, gwCrd *k8s_networking_v1.Gatewa
 						hostnames = append(hostnames, string(*gwListener.Hostname))
 					}
 				}
-
+				// Hostnames are not required. Adding * to be processed by the frontend (Indicates the kind of GW).
+				if len(hostnames) == 0 {
+					hostnames = append(hostnames, "*")
+				}
 				// Metadata format: { gatewayName => array of hostnames }
 				node.Metadata[nodeMetadataKey].(graph.GatewaysMetadata)[gwCrd.Name] = hostnames
 			}
@@ -301,7 +304,7 @@ func resolveGatewayNodeMapping(gatewayWorkloads map[string][]models.WorkloadList
 			for _, node := range trafficMap {
 				if _, ok := node.Metadata[nodeMetadataKey]; !ok {
 					appLabelName, _ := gi.Conf.GetAppLabelName(gw.Labels)
-					if (node.NodeType == graph.NodeTypeApp || node.NodeType == graph.NodeTypeWorkload) && node.App == gw.Labels[appLabelName] && node.Cluster == gwCluster && node.Namespace == gwNs {
+					if (node.NodeType == graph.NodeTypeApp || node.NodeType == graph.NodeTypeWorkload) && node.App != "" && node.App == gw.Labels[appLabelName] && node.Cluster == gwCluster && node.Namespace == gwNs {
 						node.Metadata[nodeMetadataKey] = graph.GatewaysMetadata{}
 						gatewayNodeMapping[&gw] = append(gatewayNodeMapping[&gw], node)
 					}
@@ -391,7 +394,7 @@ func (a IstioAppender) getGatewayAPIWorkloads(ctx context.Context, globalInfo *g
 		// Find Istio managed Gateway API deployments
 		for _, workload := range wList.Workloads {
 			if workload.WorkloadGVK == kubernetes.Deployments {
-				if _, ok := workload.Labels["istio.io/gateway-name"]; ok {
+				if workload.IsGateway {
 					managedWorkloads[key] = append(managedWorkloads[key], workload)
 				}
 			}
diff --git a/hack/istio/multicluster/verify-kiali-permissions.sh b/hack/istio/multicluster/verify-kiali-permissions.sh
new file mode 100755
index 000000000..3cfb4582b
--- /dev/null
+++ b/hack/istio/multicluster/verify-kiali-permissions.sh
@@ -0,0 +1,222 @@
+#!/usr/bin/env bash
+
+##############################################################################
+# This script checks the permissions of a given kubeconfig to ensure it
+# has the necessary permissions so Kiali can use it to access a remote
+# cluster.
+#
+# The kubeconfig must be provided as either a kubeconfig file or
+# found within a secret (thus you can generate a Kiali remote cluster secret
+# and use this script to confirm its validity). See the options
+# --kubeconfig-file and --kubeconfig-secret.
+#
+# You must tell the script what version of Kiali you want to test with.
+# See the option --kiali-version.
+#
+# This script will perform auth can-i checks on resources
+# that the kubeconfig should provide permissions for.
+#
+# You must have `helm` and `yq` installed in order to use this script.
+#
+# If you are connected to a cluster with a kubeconfig that you think can be
+# used as a Kiali remote cluster config, you can store it as a secret and
+# then test that to see if it is a valid Kiali remote cluster secret:
+#
+# 1. Save your current kubeconfig context to a file:
+#    kubectl config view --minify --raw > ./active-context-kubeconfig.yaml
+#
+# 2. Create a secret with that kubeconfig file:
+#    kubectl create secret generic mycluster-secret \
+#      --namespace default \
+#      --from-file=mycluster=./active-context-kubeconfig.yaml
+#
+# 3. Use this test script to verify the permissions are correct:
+#    ./verify-kiali-permissions.sh \
+#      --kubeconfig-secret default:mycluster-secret:mycluster \
+#      --kiali-version v2.9.0
+#
+# 4. Once testing is complete, remove the kubeconfig file and delete the secret:
+#    rm ./active-context-kubeconfig.yaml
+#    kubectl delete secret --namespace default mycluster-secret
+##############################################################################
+
+set -euo pipefail
+
+print_help() {
+  cat <<EOF
+Usage: $0 [OPTIONS]
+
+Options:
+  --kubeconfig-file FILE
+        Path to a kubeconfig file.
+  --kubeconfig-secret NS:NAME:KEY
+        Specify kubeconfig as a Kubernetes secret with namespace, secret name, and secret key.
+        Format: --kubeconfig-secret <namespace>:<secretName>:<secretKey>
+  --kiali-version vX.Y.Z
+        Kiali version whose needed permissions will be checked (e.g. v2.9.0).
+        Required.
+  --help
+        Show this help message and exit.
+
+Notes:
+  Exactly one of --kubeconfig-file or --kubeconfig-secret must be specified.
+EOF
+}
+
+KUBECONFIG_FILE=""
+KUBECONFIG_SECRET_SPEC=""
+KIALI_VERSION=""
+
+if [[ $# -eq 0 ]]; then
+  print_help
+  exit 1
+fi
+
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+    --kubeconfig-file)
+      if [[ $# -lt 2 ]]; then
+        echo "Error: --kubeconfig-file requires a file path argument"
+        exit 1
+      fi
+      KUBECONFIG_FILE="$2"
+      shift 2
+      ;;
+    --kubeconfig-secret)
+      if [[ $# -lt 2 ]]; then
+        echo "Error: --kubeconfig-secret requires a secret spec argument"
+        exit 1
+      fi
+      KUBECONFIG_SECRET_SPEC="$2"
+      shift 2
+      ;;
+    --kiali-version)
+      if [[ $# -lt 2 ]]; then
+        echo "Error: --kiali-version requires a version argument"
+        exit 1
+      fi
+      KIALI_VERSION="$2"
+      # Validate version format: must be X.Y.Z or vX.Y.Z
+      if [[ ! "$KIALI_VERSION" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+        echo "Error: --kiali-version must be in the form X.Y.Z (optionally prefixed with 'v')"
+        exit 1
+      fi
+      shift 2
+      ;;
+    --help)
+      print_help
+      exit 0
+      ;;
+    *)
+      echo "Unknown option: $1"
+      print_help
+      exit 1
+      ;;
+  esac
+done
+
+# Validate required --kiali-version
+if [[ -z "$KIALI_VERSION" ]]; then
+  echo "Error: --kiali-version is required"
+  print_help
+  exit 1
+fi
+
+# Validate exclusive kubeconfig input
+if [[ -n "$KUBECONFIG_FILE" && -n "$KUBECONFIG_SECRET_SPEC" ]]; then
+  echo "Error: Cannot specify both --kubeconfig-file and --kubeconfig-secret"
+  exit 1
+fi
+
+if [[ -z "$KUBECONFIG_FILE" && -z "$KUBECONFIG_SECRET_SPEC" ]]; then
+  echo "Error: Must specify exactly one of --kubeconfig-file or --kubeconfig-secret"
+  exit 1
+fi
+
+# Parse secret spec if provided
+if [[ -n "$KUBECONFIG_SECRET_SPEC" ]]; then
+  if ! [[ "$KUBECONFIG_SECRET_SPEC" =~ ^[^:]+:[^:]+:[^:]+$ ]]; then
+    echo "Error: --kubeconfig-secret must be in format <namespace>:<secretName>:<secretKey>"
+    exit 1
+  fi
+  IFS=':' read -r KUBECONFIG_SECRET_NS KUBECONFIG_SECRET_NAME KUBECONFIG_SECRET_KEY <<< "$KUBECONFIG_SECRET_SPEC"
+
+  TMP_KUBECONFIG="$(mktemp)"
+  trap 'rm -f "$TMP_KUBECONFIG"' EXIT
+  kubectl get secret "$KUBECONFIG_SECRET_NAME" -n "$KUBECONFIG_SECRET_NS" -o "jsonpath={.data.${KUBECONFIG_SECRET_KEY}}" | base64 -d > "$TMP_KUBECONFIG"
+  KUBECONFIG_FILE="$TMP_KUBECONFIG"
+fi
+
+# Normalize KIALI_VERSION to have "v" prefix
+if [[ "$KIALI_VERSION" != v* ]]; then
+  KIALI_VERSION="v$KIALI_VERSION"
+fi
+
+if [ ! -f "$KUBECONFIG_FILE" ]; then
+  echo "Kubeconfig file [$KUBECONFIG_FILE] does not exist."
+  exit 1
+fi
+
+echo "=== SETTINGS ==="
+echo "KUBECONFIG_FILE=$KUBECONFIG_FILE"
+echo "KUBECONFIG_SECRET_SPEC=${KUBECONFIG_SECRET_SPEC:-<not set>}"
+echo "KIALI_VERSION=$KIALI_VERSION"
+echo "================"
+
+if ! command -v helm &>/dev/null; then
+  echo "Error: 'helm' is required but not found in PATH."
+  exit 1
+fi
+
+if ! command -v yq &>/dev/null; then
+  echo "Error: 'yq' is required but not found in PATH."
+  exit 1
+fi
+
+# Ensure Kiali Helm repo is added and updated
+helm repo add kiali https://kiali.org/helm-charts --force-update
+
+ROLE_YAML=$(helm template kiali-server kiali/kiali-server --version "$KIALI_VERSION" --set auth.strategy=anonymous --show-only templates/role.yaml)
+
+# Extract all resources from ClusterRole rules
+mapfile -t RESOURCES_ARR < <(echo "$ROLE_YAML" | yq eval-all '. | select(.kind == "ClusterRole") | .rules[].resources[]' - | sort -u)
+
+# Initialize an array to hold final resource list
+declare -a RESOURCES_FINAL=()
+
+for resource in "${RESOURCES_ARR[@]}"; do
+  if [[ "$resource" == "*" ]]; then
+    # If resource is "*", get all resource kinds from API server via kubectl
+    # This gets all resource kinds (including CRDs) available
+    mapfile -t all_resources < <(kubectl --kubeconfig="$KUBECONFIG_FILE" api-resources -o name)
+    RESOURCES_FINAL+=("${all_resources[@]}")
+  else
+    RESOURCES_FINAL+=("$resource")
+  fi
+done
+
+# Remove duplicates from final resource list
+IFS=$'\n' RESOURCES=($(sort -u <<<"${RESOURCES_FINAL[*]}"))
+unset IFS
+
+if [[ ${#RESOURCES[@]} -eq 0 ]]; then
+  echo "Error: Could not retrieve resource list from ClusterRole"
+  exit 1
+fi
+
+echo
+echo "Resources to check:"
+printf '%s\n' "${RESOURCES[@]}"
+
+for verb in get list watch; do
+  echo
+  echo "🔍 Checking permission: $verb"
+  for res in "${RESOURCES[@]}"; do
+    echo -n "  Can $verb $res: "
+    if output="$(kubectl --kubeconfig="$KUBECONFIG_FILE" auth can-i "$verb" "$res" --all-namespaces 2>&1 | tr '\n' ' ')"; then
+      echo "$output ✅"
+    else
+      echo "$output ❌"
+    fi
+  done
+done
diff --git a/handlers/graph.go b/handlers/graph.go
index f701b49fc..23e84292a 100644
--- a/handlers/graph.go
+++ b/handlers/graph.go
@@ -63,9 +63,6 @@ func GraphNamespaces(
 	return func(w http.ResponseWriter, r *http.Request) {
 		defer handlePanic(r.Context(), w)
 
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.GraphLogName)
-
 		// TODO: getLayer and its downstream call chain has our logger in the request context now; it just needs to extract and use it (which it does not today)
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		graph.CheckError(err)
@@ -91,9 +88,6 @@ func GraphNode(
 	return func(w http.ResponseWriter, r *http.Request) {
 		defer handlePanic(r.Context(), w)
 
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.GraphLogName)
-
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		graph.CheckError(err)
 
diff --git a/handlers/istio_config.go b/handlers/istio_config.go
index 76206b758..d16534a07 100644
--- a/handlers/istio_config.go
+++ b/handlers/istio_config.go
@@ -32,8 +32,6 @@ func IstioConfigList(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		params := mux.Vars(r)
 		namespace := params["namespace"]
@@ -118,8 +116,6 @@ func IstioConfigDetails(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		params := mux.Vars(r)
 		namespace := params["namespace"]
@@ -235,8 +231,6 @@ func IstioConfigDelete(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		params := mux.Vars(r)
 		namespace := params["namespace"]
@@ -286,8 +280,6 @@ func IstioConfigUpdate(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		params := mux.Vars(r)
 		namespace := params["namespace"]
@@ -343,8 +335,6 @@ func IstioConfigCreate(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		// Feels kinda replicated for multiple functions..
 		params := mux.Vars(r)
@@ -417,8 +407,6 @@ func IstioConfigPermissions(
 	grafana *grafana.Service,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.IstioConfigLogName)
 
 		// query params
 		params := r.URL.Query()
@@ -458,9 +446,6 @@ func IstioConfigValidationSummary(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		// note we put this in the "validations" group log name since it is more about validations that just istio config
-		r = log.AddGroupToLoggerInRequestContext(r, log.ValidationLogName)
 
 		params := r.URL.Query()
 		namespaces := params.Get("namespaces") // csl of namespaces
diff --git a/handlers/namespaces.go b/handlers/namespaces.go
index 604e7c26f..d446d8ee5 100644
--- a/handlers/namespaces.go
+++ b/handlers/namespaces.go
@@ -77,8 +77,6 @@ func NamespaceValidationSummary(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.ValidationLogName)
 
 		query := r.URL.Query()
 		vars := mux.Vars(r)
diff --git a/handlers/tracing.go b/handlers/tracing.go
index 97668df04..b5e1fe61b 100644
--- a/handlers/tracing.go
+++ b/handlers/tracing.go
@@ -16,7 +16,6 @@ import (
 	"github.com/kiali/kiali/grafana"
 	"github.com/kiali/kiali/istio"
 	"github.com/kiali/kiali/kubernetes"
-	"github.com/kiali/kiali/log"
 	"github.com/kiali/kiali/models"
 	"github.com/kiali/kiali/prometheus"
 	"github.com/kiali/kiali/tracing"
@@ -61,8 +60,6 @@ func AppTraces(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -101,8 +98,6 @@ func ServiceTraces(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -137,8 +132,6 @@ func WorkloadTraces(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -174,8 +167,6 @@ func ErrorTraces(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -212,8 +203,6 @@ func TraceDetails(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -248,8 +237,6 @@ func AppSpans(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -288,8 +275,6 @@ func ServiceSpans(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
@@ -328,8 +313,6 @@ func WorkloadSpans(
 	discovery *istio.Discovery,
 ) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-		// prepare the logger in a context, and replace the request context with ours that has our logger in it
-		r = log.AddGroupToLoggerInRequestContext(r, log.TracingLogName)
 
 		business, err := getLayer(r, conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery)
 		if err != nil {
diff --git a/kubernetes/filters.go b/kubernetes/filters.go
index 427c8be48..f2ff7b0da 100644
--- a/kubernetes/filters.go
+++ b/kubernetes/filters.go
@@ -688,26 +688,6 @@ func FilterByNamespace[T runtime.Object](objects []T, namespace string) []T {
 	return filtered
 }
 
-func FilterDaemonSetsBySelector(daemonSets []appsv1.DaemonSet, l map[string]string) ([]appsv1.DaemonSet, error) {
-	selector := labels.Set(l)
-	retDS := []appsv1.DaemonSet{}
-	for _, ds := range daemonSets {
-		// TODO: Can we eliminate error?
-		labelMap, err := metav1.LabelSelectorAsMap(ds.Spec.Selector)
-		if err != nil {
-			return nil, err
-		}
-		labelSet := labels.Set(labelMap)
-
-		svcSelector := labelSet.AsSelector()
-		// selector match is done after listing all daemonSets, similar to registry reading
-		if selector.AsSelector().Empty() || (!svcSelector.Empty() && svcSelector.Matches(selector)) {
-			retDS = append(retDS, ds)
-		}
-	}
-	return retDS, nil
-}
-
 func FilterServicesBySelector(services []core_v1.Service, l map[string]string) []core_v1.Service {
 	selector := labels.Set(l)
 	retSvc := []core_v1.Service{}
diff --git a/log/log.go b/log/log.go
index 2a04f4165..29ca72530 100644
--- a/log/log.go
+++ b/log/log.go
@@ -81,17 +81,10 @@ func setLogFormat(l zerolog.Logger) zerolog.Logger {
 // WithGroup is a simple convienence function that provides a zerolog logger that will log messages associated with a group name in the log context
 // Use this to obtain a logger that has only group name associated with it - there will be no associated data.
 func WithGroup(group string) *zerolog.Logger {
-	zl := log.With().Str("group", group).Logger()
+	zl := log.With().Str(GroupLogName, group).Logger()
 	return &zl
 }
 
-// AddGroup is a convienence function that adds to the logger context a group name.
-// Use this to retain the original logger context (and all its data) - you are simply adding a group to it.
-func AddGroup(zl *zerolog.Logger, group string) *zerolog.Logger {
-	newLogger := zl.With().Str("group", group).Logger()
-	return &newLogger
-}
-
 // FromRequest is a convienence wrapper around zerolog's FromRequest thus helping callers avoid having to explicitly import hlog
 func FromRequest(r *http.Request) *zerolog.Logger {
 	return hlog.FromRequest(r)
@@ -110,13 +103,6 @@ func ToContext(ctx context.Context, zl *zerolog.Logger) context.Context {
 	return zl.WithContext(ctx)
 }
 
-// AddGroupToLoggerInRequestContext will add a group log name to the logger found in the given request.
-// That logger will be added back into the request's context. The caller must use the returned request in lieu
-// of the given request in order to be able to use the new logger.
-func AddGroupToLoggerInRequestContext(r *http.Request, group string) *http.Request {
-	return r.WithContext(ToContext(r.Context(), AddGroup(FromContext(r.Context()), group)))
-}
-
 // Info logs a message via the global logger
 func Info(args ...interface{}) {
 	log.Info().Msgf("%s", args...)
diff --git a/log/log_names.go b/log/log_names.go
index 14cce8f29..083f26313 100644
--- a/log/log_names.go
+++ b/log/log_names.go
@@ -1,14 +1,28 @@
 package log
 
-// these are variables used to define logger group names or other names of structured data fields used when logging messages
+// these are variables used to define logger group names
 // see log.WithGroup for when these are typically used
+var (
+	AuthenticateLogName = "authenticate"
+	ClustersLogName     = "clusters"
+	ConfigLogName       = "config"
+	GraphLogName        = "graph"
+	IstioConfigLogName  = "istioConfig"
+	KialiCacheLogName   = "kialiCache"
+	MeshLogName         = "mesh"
+	MetricsLogName      = "metrics"
+	PromCacheLogName    = "promCache"
+	PrometheusLogName   = "prometheus"
+	ResourcesLogName    = "resources"
+	StatusLogName       = "status"
+	TracingLogName      = "tracing"
+	ValidationLogName   = "validation"
+)
+
+// these are structured attribute key names for log messages
 var (
 	GraphAppenderLogName = "appender"
-	GraphLogName         = "graph"
-	IstioConfigLogName   = "istioConfig"
-	KialiCacheLogName    = "kialiCache"
-	PromCacheLogName     = "promCache"
-	PrometheusLogName    = "prometheus"
-	TracingLogName       = "tracing"
-	ValidationLogName    = "validation"
+	GroupLogName         = "group"
+	RouteLogName         = "route"
+	RoutePatternLogName  = "route-pattern"
 )
diff --git a/routing/router.go b/routing/router.go
index 2e4e91fb5..c4f2457ad 100644
--- a/routing/router.go
+++ b/routing/router.go
@@ -378,13 +378,18 @@ func (a alice) then(h http.Handler) http.Handler {
 
 func buildHttpHandlerLogger(route Route, handlerFunction http.Handler) http.Handler {
 
-	zlc := zerolog.With().Str("route", route.Name)
+	// prepare the request's logger
+	zlc := zerolog.With().Str(log.RouteLogName, route.Name)
 	if log.IsTrace() {
-		zlc = zlc.Str("route-pattern", route.Pattern)
+		zlc = zlc.Str(log.RoutePatternLogName, route.Pattern)
 	}
+	if route.LogGroupName != "" {
+		zlc = zlc.Str(log.GroupLogName, route.LogGroupName)
+	}
+	zl := zlc.Logger()
 
 	c := alice{}
-	c = c.append(hlog.NewHandler(zlc.Logger()))
+	c = c.append(hlog.NewHandler(zl))
 
 	// TODO: commenting out but leaving these here in case we want to look into including them at a future date
 	// c = c.append(hlog.HostHandler("host", true))
diff --git a/routing/routes.go b/routing/routes.go
index 7e2a5123c..44b45ce11 100644
--- a/routing/routes.go
+++ b/routing/routes.go
@@ -13,6 +13,7 @@ import (
 	"github.com/kiali/kiali/handlers/authentication"
 	"github.com/kiali/kiali/istio"
 	"github.com/kiali/kiali/kubernetes"
+	"github.com/kiali/kiali/log"
 	"github.com/kiali/kiali/prometheus"
 	"github.com/kiali/kiali/tracing"
 )
@@ -20,6 +21,7 @@ import (
 // Route describes a single route
 type Route struct {
 	Name          string
+	LogGroupName  string
 	Method        string
 	Pattern       string
 	HandlerFunc   http.HandlerFunc
@@ -60,6 +62,7 @@ func NewRoutes(
 		//		200
 		{
 			"Healthz",
+			log.StatusLogName,
 			"GET",
 			"/healthz",
 			handlers.Healthz,
@@ -78,6 +81,7 @@ func NewRoutes(
 		//      200: statusInfo
 		{
 			"Root",
+			log.StatusLogName,
 			"GET",
 			"/api",
 			handlers.Root(conf, clientFactory, kialiCache, grafana),
@@ -100,6 +104,7 @@ func NewRoutes(
 		//      200: userSessionData
 		{
 			"Authenticate",
+			log.AuthenticateLogName,
 			"GET",
 			"/api/authenticate",
 			handlers.Authenticate(conf, authController),
@@ -119,6 +124,7 @@ func NewRoutes(
 		//      200: userSessionData
 		{
 			"OpenshiftCheckToken",
+			log.AuthenticateLogName,
 			"POST",
 			"/api/authenticate",
 			handlers.Authenticate(conf, authController),
@@ -134,6 +140,7 @@ func NewRoutes(
 		//      204: noContent
 		{
 			"Logout",
+			log.AuthenticateLogName,
 			"GET",
 			"/api/logout",
 			handlers.Logout(conf, authController),
@@ -157,6 +164,7 @@ func NewRoutes(
 		//      200: authenticationInfo
 		{
 			"AuthenticationInfo",
+			log.AuthenticateLogName,
 			"GET",
 			"/api/auth/info",
 			handlers.AuthenticationInfo(conf, authController, maps.Keys(clientFactory.GetSAClients())),
@@ -176,6 +184,7 @@ func NewRoutes(
 		//      200: statusInfo
 		{
 			"Status",
+			log.StatusLogName,
 			"GET",
 			"/api/status",
 			handlers.Root(conf, clientFactory, kialiCache, grafana),
@@ -195,6 +204,7 @@ func NewRoutes(
 		//      200: statusInfo
 		{
 			"Config",
+			log.ConfigLogName,
 			"GET",
 			"/api/config",
 			handlers.Config(conf, kialiCache, discovery, clientFactory, prom),
@@ -214,6 +224,7 @@ func NewRoutes(
 		//      200: statusInfo
 		{
 			"Crippled",
+			log.ConfigLogName,
 			"GET",
 			"/api/crippled",
 			handlers.CrippledFeatures(prom),
@@ -233,6 +244,7 @@ func NewRoutes(
 		//      200: istioConfigPermissions
 		{
 			"IstioConfigPermissions",
+			log.IstioConfigLogName,
 			"GET",
 			"/api/istio/permissions",
 			handlers.IstioConfigPermissions(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -253,6 +265,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigList",
+			log.IstioConfigLogName,
 			"GET",
 			"/api/namespaces/{namespace}/istio",
 			handlers.IstioConfigList(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -273,6 +286,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigListAll",
+			log.IstioConfigLogName,
 			"GET",
 			"/api/istio/config",
 			handlers.IstioConfigList(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -295,6 +309,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigDetails",
+			log.IstioConfigLogName,
 			"GET",
 			"/api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}",
 			handlers.IstioConfigDetails(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -316,6 +331,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigDelete",
+			log.IstioConfigLogName,
 			"DELETE",
 			"/api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}",
 			handlers.IstioConfigDelete(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -341,6 +357,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigUpdate",
+			log.IstioConfigLogName,
 			"PATCH",
 			"/api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}",
 			handlers.IstioConfigUpdate(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -364,6 +381,7 @@ func NewRoutes(
 		//
 		{
 			"IstioConfigCreate",
+			log.IstioConfigLogName,
 			"POST",
 			"/api/namespaces/{namespace}/istio/{group}/{version}/{kind}",
 			handlers.IstioConfigCreate(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -384,6 +402,7 @@ func NewRoutes(
 		//
 		{
 			"ClustersServices",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/services",
 			handlers.ClustersServices,
@@ -405,6 +424,7 @@ func NewRoutes(
 		//
 		{
 			"ServiceDetails",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}",
 			handlers.ServiceDetails,
@@ -430,6 +450,7 @@ func NewRoutes(
 		//
 		{
 			"ServiceUpdate",
+			log.ResourcesLogName,
 			"PATCH",
 			"/api/namespaces/{namespace}/services/{service}",
 			handlers.ServiceUpdate,
@@ -449,6 +470,7 @@ func NewRoutes(
 		//		200: spansResponse
 		{
 			"AppSpans",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}/spans",
 			handlers.AppSpans(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -468,6 +490,7 @@ func NewRoutes(
 		//		200: spansResponse
 		{
 			"WorkloadSpans",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}/spans",
 			handlers.WorkloadSpans(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -487,6 +510,7 @@ func NewRoutes(
 		//		200: spansResponse
 		{
 			"ServiceSpans",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}/spans",
 			handlers.ServiceSpans(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -508,6 +532,7 @@ func NewRoutes(
 		//
 		{
 			"AppTraces",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}/traces",
 			handlers.AppTraces(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -529,6 +554,7 @@ func NewRoutes(
 		//
 		{
 			"ServiceTraces",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}/traces",
 			handlers.ServiceTraces(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -550,6 +576,7 @@ func NewRoutes(
 		//
 		{
 			"WorkloadTraces",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}/traces",
 			handlers.WorkloadTraces(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -571,6 +598,7 @@ func NewRoutes(
 		//
 		{
 			"ErrorTraces",
+			log.TracingLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}/errortraces",
 			handlers.ErrorTraces(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -592,6 +620,7 @@ func NewRoutes(
 		//
 		{
 			"TracesDetails",
+			log.TracingLogName,
 			"GET",
 			"/api/traces/{traceID}",
 			handlers.TraceDetails(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -612,6 +641,7 @@ func NewRoutes(
 		//
 		{
 			"ClusterWorkloads",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/workloads",
 			handlers.ClusterWorkloads(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -633,6 +663,7 @@ func NewRoutes(
 		//
 		{
 			"WorkloadDetails",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}",
 			handlers.WorkloadDetails(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -658,6 +689,7 @@ func NewRoutes(
 		//
 		{
 			"WorkloadUpdate",
+			log.ResourcesLogName,
 			"PATCH",
 			"/api/namespaces/{namespace}/workloads/{workload}",
 			handlers.WorkloadUpdate(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -678,6 +710,7 @@ func NewRoutes(
 		//
 		{
 			"ClustersApps",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/apps",
 			handlers.ClusterApps(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -699,6 +732,7 @@ func NewRoutes(
 		//
 		{
 			"AppDetails",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}",
 			handlers.AppDetails(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -719,6 +753,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceList",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces",
 			handlers.NamespaceList(conf, kialiCache, clientFactory, discovery),
@@ -744,6 +779,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceUpdate",
+			log.ResourcesLogName,
 			"PATCH",
 			"/api/namespaces/{namespace}",
 			handlers.NamespaceUpdate(conf, kialiCache, clientFactory, discovery),
@@ -764,6 +800,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceInfo",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/info",
 			handlers.NamespaceInfo(conf, kialiCache, clientFactory, discovery),
@@ -785,6 +822,7 @@ func NewRoutes(
 		//
 		{
 			"ServiceMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}/metrics",
 			handlers.ServiceMetrics,
@@ -806,6 +844,7 @@ func NewRoutes(
 		//
 		{
 			"AggregateMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/aggregates/{aggregate}/{aggregateValue}/metrics",
 			handlers.AggregateMetrics,
@@ -827,6 +866,7 @@ func NewRoutes(
 		//
 		{
 			"AppMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}/metrics",
 			handlers.AppMetrics,
@@ -848,6 +888,7 @@ func NewRoutes(
 		//
 		{
 			"WorkloadMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}/metrics",
 			handlers.WorkloadMetrics,
@@ -869,6 +910,7 @@ func NewRoutes(
 		//
 		{
 			"ControlPlaneMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/controlplanes/{controlplane}/metrics",
 			handlers.ControlPlaneMetrics(handlers.DefaultPromClientSupplier),
@@ -890,6 +932,7 @@ func NewRoutes(
 		//
 		{
 			"UsageMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/{app}/usage_metrics",
 			handlers.ResourceUsageMetrics(handlers.DefaultPromClientSupplier),
@@ -911,6 +954,7 @@ func NewRoutes(
 		//
 		{
 			"ServiceDashboard",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}/dashboard",
 			handlers.ServiceDashboard(conf, grafana),
@@ -932,6 +976,7 @@ func NewRoutes(
 		//
 		{
 			"AppDashboard",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/apps/{app}/dashboard",
 			handlers.AppDashboard(conf, grafana),
@@ -953,6 +998,7 @@ func NewRoutes(
 		//
 		{
 			"WorkloadDashboard",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}/dashboard",
 			handlers.WorkloadDashboard(conf, grafana),
@@ -974,6 +1020,7 @@ func NewRoutes(
 		//
 		{
 			"ZtunnelDashboard",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/ztunnel/{workload}/dashboard",
 			handlers.ZtunnelDashboard(handlers.DefaultPromClientSupplier, conf, grafana),
@@ -995,6 +1042,7 @@ func NewRoutes(
 		//
 		{
 			"CustomDashboard",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/customdashboard/{dashboard}",
 			handlers.CustomDashboard(conf, grafana),
@@ -1016,6 +1064,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceMetrics",
+			log.MetricsLogName,
 			"GET",
 			"/api/namespaces/{namespace}/metrics",
 			handlers.NamespaceMetrics(handlers.DefaultPromClientSupplier),
@@ -1037,6 +1086,7 @@ func NewRoutes(
 		//
 		{
 			"ClustersHealth",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/health",
 			handlers.ClustersHealth,
@@ -1058,6 +1108,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceValidationSummary",
+			log.ValidationLogName,
 			"GET",
 			"/api/namespaces/{namespace}/validations",
 			handlers.NamespaceValidationSummary(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1079,6 +1130,7 @@ func NewRoutes(
 		//
 		{
 			"ConfigValidationSummary",
+			log.ValidationLogName,
 			"GET",
 			"/api/istio/validations",
 			handlers.IstioConfigValidationSummary(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1100,6 +1152,7 @@ func NewRoutes(
 		//
 		{
 			"MeshTls",
+			log.StatusLogName,
 			"GET",
 			"/api/mesh/tls",
 			handlers.MeshTls(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1121,6 +1174,7 @@ func NewRoutes(
 		//
 		{
 			"NamespaceTls",
+			log.StatusLogName,
 			"GET",
 			"/api/namespaces/{namespace}/tls",
 			handlers.NamespaceTls(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1142,6 +1196,7 @@ func NewRoutes(
 		//
 		{
 			"ClusterTls",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/tls",
 			handlers.ClustersTls(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1163,6 +1218,7 @@ func NewRoutes(
 		//
 		{
 			"IstioStatus",
+			log.StatusLogName,
 			"GET",
 			"/api/istio/status",
 			handlers.IstioStatus(conf, kialiCache, clientFactory, prom, traceClientLoader, discovery, cpm, grafana),
@@ -1184,6 +1240,7 @@ func NewRoutes(
 		//
 		{
 			"GraphNamespaces",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/graph",
 			handlers.GraphNamespaces(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1205,6 +1262,7 @@ func NewRoutes(
 		//
 		{
 			"GraphAggregate",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/aggregates/{aggregate}/{aggregateValue}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1226,6 +1284,7 @@ func NewRoutes(
 		//
 		{
 			"GraphAggregateByService",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/aggregates/{aggregate}/{aggregateValue}/{service}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1247,6 +1306,7 @@ func NewRoutes(
 		//
 		{
 			"GraphAppVersion",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/applications/{app}/versions/{version}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1268,6 +1328,7 @@ func NewRoutes(
 		//
 		{
 			"GraphApp",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/applications/{app}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1289,6 +1350,7 @@ func NewRoutes(
 		//
 		{
 			"GraphService",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/services/{service}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1310,6 +1372,7 @@ func NewRoutes(
 		//
 		{
 			"GraphWorkload",
+			log.GraphLogName,
 			"GET",
 			"/api/namespaces/{namespace}/workloads/{workload}/graph",
 			handlers.GraphNode(conf, kialiCache, clientFactory, prom, cpm, traceClientLoader, grafana, discovery),
@@ -1331,6 +1394,7 @@ func NewRoutes(
 		//
 		{
 			"MeshGraph",
+			log.GraphLogName,
 			"GET",
 			"/api/mesh/graph",
 			handlers.MeshGraph(conf, clientFactory, kialiCache, grafana, prom, traceClientLoader, discovery, cpm),
@@ -1352,6 +1416,7 @@ func NewRoutes(
 		//
 		{
 			"MeshControlPlanes",
+			log.MeshLogName,
 			"GET",
 			"/api/mesh/controlplanes",
 			handlers.ControlPlanes(kialiCache, clientFactory, conf, discovery),
@@ -1374,6 +1439,7 @@ func NewRoutes(
 		//
 		{
 			"GrafanaURL",
+			log.ConfigLogName,
 			"GET",
 			"/api/grafana",
 			handlers.GetGrafanaInfo(conf, grafana),
@@ -1395,6 +1461,7 @@ func NewRoutes(
 		//
 		{
 			"TracingURL",
+			log.ConfigLogName,
 			"GET",
 			"/api/tracing",
 			handlers.GetTracingInfo(conf),
@@ -1416,6 +1483,7 @@ func NewRoutes(
 		//
 		{
 			"PodDetails",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}",
 			handlers.PodDetails(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -1437,6 +1505,7 @@ func NewRoutes(
 		//
 		{
 			"PodLogs",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}/logs",
 			handlers.PodLogs(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -1458,6 +1527,7 @@ func NewRoutes(
 		//
 		{
 			"PodConfigDump",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}/config_dump",
 			handlers.ConfigDump(conf, kialiCache, clientFactory, discovery),
@@ -1479,6 +1549,7 @@ func NewRoutes(
 		//
 		{
 			"PodProxyResource",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}/config_dump/{resource}",
 			handlers.ConfigDumpResourceEntries(conf, kialiCache, clientFactory, discovery),
@@ -1500,6 +1571,7 @@ func NewRoutes(
 		//
 		{
 			"ZtunnelConfigDump",
+			log.ResourcesLogName,
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}/config_dump_ztunnel",
 			handlers.ConfigDumpZtunnel(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -1522,6 +1594,7 @@ func NewRoutes(
 		//
 		{
 			"PodProxyLogging",
+			log.ResourcesLogName,
 			"POST",
 			"/api/namespaces/{namespace}/pods/{pod}/logging",
 			handlers.LoggingUpdate(conf, kialiCache, clientFactory, cpm, prom, traceClientLoader, grafana, discovery),
@@ -1543,6 +1616,7 @@ func NewRoutes(
 		//
 		{
 			"ClustersMetrics",
+			log.ClustersLogName,
 			"GET",
 			"/api/clusters/metrics",
 			handlers.ClustersMetrics(handlers.DefaultPromClientSupplier),
@@ -1564,6 +1638,7 @@ func NewRoutes(
 		//		200: metricsStatsResponse
 		{
 			Name:          "MetricsStats",
+			LogGroupName:  log.MetricsLogName,
 			Method:        "POST",
 			Pattern:       "/api/stats/metrics",
 			HandlerFunc:   handlers.MetricsStats,


Test patch:
diff --git a/business/test_util.go b/business/test_util.go
index b10a6395d..b568e3cdc 100644
--- a/business/test_util.go
+++ b/business/test_util.go
@@ -1076,6 +1076,7 @@ func FakeZtunnelDaemonSet(conf *config.Config) []apps_v1.DaemonSet {
 	conf.KubernetesConfig.ExcludeWorkloads = []string{}
 
 	appLabel := conf.IstioLabels.AppLabelName
+	kubernetesLabel := config.KubernetesAppLabel
 	t1, _ := time.Parse(time.RFC822Z, "08 Mar 18 17:44 +0300")
 	return []apps_v1.DaemonSet{
 		{
@@ -1087,6 +1088,7 @@ func FakeZtunnelDaemonSet(conf *config.Config) []apps_v1.DaemonSet {
 				Name:              "ztunnel",
 				Namespace:         "istio-system",
 				CreationTimestamp: meta_v1.NewTime(t1),
+				Labels:            map[string]string{kubernetesLabel: "ztunnel"},
 			},
 			Spec: apps_v1.DaemonSetSpec{
 				Template: core_v1.PodTemplateSpec{
diff --git a/cache/cache_test.go b/cache/cache_test.go
index db68f8642..319f73953 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -78,6 +78,7 @@ func ztunnelDaemonSet() *apps_v1.DaemonSet {
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "ztunnel",
 			Namespace: "istio-system",
+			Labels:    map[string]string{"app.kubernetes.io/name": "ztunnel"},
 		},
 		Spec: apps_v1.DaemonSetSpec{
 			Selector: &metav1.LabelSelector{
diff --git a/hack/ci-kind-molecule-tests.sh b/hack/ci-kind-molecule-tests.sh
index 21baf0217..60c065a96 100755
--- a/hack/ci-kind-molecule-tests.sh
+++ b/hack/ci-kind-molecule-tests.sh
@@ -403,7 +403,8 @@ fi
 # if requested, install OLM and the Kiali Operator via OLM
 if [ "${OLM_ENABLED}" == "true" ]; then
   if [ "${OLM_VERSION}" == "latest" ]; then
-    OLM_VERSION="$(curl -s https://api.github.com/repos/operator-framework/operator-lifecycle-manager/releases 2> /dev/null | grep "tag_name" | sed -e 's/.*://' -e 's/ *"//' -e 's/",//' | grep -v "snapshot" | sort -t "." -k 1.2g,1 -k 2g,2 -k 3g | tail -n 1)"
+    for i in {1..60}; do curl_output=$(curl -s https://api.github.com/repos/operator-framework/operator-lifecycle-manager/releases 2> /dev/null) && [ -n "$curl_output" ] && break || { echo "Retry $i/60: Attempting to get the latest OLM version from GitHub, retrying in 60 seconds..."; sleep 60; }; done; if [ -z "$curl_output" ]; then echo "Failed to obtain the latest OLM version from GitHub - curl failed"; exit 1; fi
+    OLM_VERSION="$(echo "$curl_output" | grep "tag_name" | sed -e 's/.*://' -e 's/ *"//' -e 's/",//' | grep -v "snapshot" | sort -t "." -k 1.2g,1 -k 2g,2 -k 3g | tail -n 1)"
     if [ -z "${OLM_VERSION}" ]; then
       infomsg "Failed to obtain the latest OLM version from Github."
       exit 1
@@ -421,13 +422,13 @@ if [ "${OLM_ENABLED}" == "true" ]; then
   export CLIENT_EXE
   export -f kubectl
   curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/${OLM_VERSION}/install.sh | bash -s ${OLM_VERSION}
-  [ "$?" != "0" ] && echo "ERROR: Failed to install OLM" && exit 1
+  [ "$?" != "0" ] && infomsg "ERROR: Failed to install OLM" && exit 1
   unset -f kubectl
 
   infomsg "OLM ${OLM_VERSION} is installed."
 
   infomsg "Installing Kiali Operator via OLM"
-  ${CLIENT_EXE} create -f https://operatorhub.io/install/stable/kiali.yaml
+  for i in {1..60}; do ${CLIENT_EXE} create -f https://operatorhub.io/install/stable/kiali.yaml && break || { [ "$i" -lt 60 ] && infomsg "Retry $i/60: Attempting to install Kiali Operator subscription, retrying in 60 seconds..." && sleep 60; }; done || { infomsg "Error: Cannot install Kiali Operator subscription."; exit 1; }
 
   infomsg -n "Waiting for Kiali CRD to be created."
   timeout 1h bash -c "until ${CLIENT_EXE} get crd kialis.kiali.io >& /dev/null; do echo -n '.' ; sleep 3; done"
diff --git a/mesh/api/testdata/test_mesh_graph.expected b/mesh/api/testdata/test_mesh_graph.expected
index 1f5aeab3a..73989b271 100644
--- a/mesh/api/testdata/test_mesh_graph.expected
+++ b/mesh/api/testdata/test_mesh_graph.expected
@@ -1,616 +1,537 @@
 {
-  "elements": {
-    "nodes": [
-      {
-        "data": {
-          "id": "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
-          "cluster": "_external_",
-          "infraName": "External Deployments",
-          "infraType": "cluster",
-          "namespace": "",
-          "nodeType": "box",
-          "healthData": "Healthy",
-          "isBox": "cluster",
-          "isExternal": true,
-          "isInaccessible": true
-        }
-      },
-      {
-        "data": {
-          "id": "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
-          "cluster": "cluster-primary",
-          "infraName": "cluster-primary",
-          "infraType": "cluster",
-          "namespace": "",
-          "nodeType": "box",
-          "healthData": "Healthy",
-          "infraData": {
-            "apiEndpoint": "http://127.0.0.2:9443",
-            "isKialiHome": true,
-            "kialiInstances": [
-              {
-                "namespace": "istio-system",
-                "operatorResource": "",
-                "serviceName": "kiali",
-                "url": "",
-                "version": ""
-              }
-            ],
-            "name": "cluster-primary",
-            "secretName": "",
-            "accessible": true
+  "elements" : {
+    "nodes" : [ {
+      "data" : {
+        "id" : "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
+        "cluster" : "_external_",
+        "infraName" : "External Deployments",
+        "infraType" : "cluster",
+        "namespace" : "",
+        "nodeType" : "box",
+        "healthData" : "Healthy",
+        "isBox" : "cluster",
+        "isExternal" : true,
+        "isInaccessible" : true
+      }
+    }, {
+      "data" : {
+        "id" : "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
+        "cluster" : "cluster-primary",
+        "infraName" : "cluster-primary",
+        "infraType" : "cluster",
+        "namespace" : "",
+        "nodeType" : "box",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "apiEndpoint" : "http://127.0.0.2:9443",
+          "isKialiHome" : true,
+          "kialiInstances" : [ {
+            "namespace" : "istio-system",
+            "operatorResource" : "",
+            "serviceName" : "kiali",
+            "url" : "",
+            "version" : ""
+          } ],
+          "name" : "cluster-primary",
+          "secretName" : "",
+          "accessible" : true
+        },
+        "isBox" : "cluster",
+        "version" : "Unknown"
+      }
+    }, {
+      "data" : {
+        "id" : "421c6926a61f0f21f1fe0babb48ea9fac6454c1d9a448dea2c559402723ec4da",
+        "cluster" : "cluster-remote",
+        "infraName" : "cluster-remote",
+        "infraType" : "cluster",
+        "namespace" : "",
+        "nodeType" : "box",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "apiEndpoint" : "",
+          "isKialiHome" : false,
+          "kialiInstances" : null,
+          "name" : "cluster-remote",
+          "secretName" : "",
+          "accessible" : true
+        },
+        "isBox" : "cluster"
+      }
+    }, {
+      "data" : {
+        "id" : "5d47c4043773968316f9d71a07212a1c363d76a3d9ffe7c52198f864cde8c5f5",
+        "parent" : "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
+        "cluster" : "cluster-primary",
+        "infraName" : "data-plane-1",
+        "infraType" : "namespace",
+        "namespace" : "data-plane-1",
+        "nodeType" : "box",
+        "healthData" : null,
+        "isBox" : "namespace"
+      }
+    }, {
+      "data" : {
+        "id" : "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
+        "parent" : "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
+        "cluster" : "cluster-primary",
+        "infraName" : "istio-system",
+        "infraType" : "namespace",
+        "namespace" : "istio-system",
+        "nodeType" : "box",
+        "healthData" : null,
+        "isBox" : "namespace"
+      }
+    }, {
+      "data" : {
+        "id" : "33493098cdd63801f773396da680159d0bb57b482ef38a4b208899a2e477e1f0",
+        "parent" : "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
+        "cluster" : "_external_",
+        "infraName" : "Grafana",
+        "infraType" : "grafana",
+        "namespace" : "",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "Auth" : {
+            "CAFile" : "xxx",
+            "InsecureSkipVerify" : false,
+            "Password" : "xxx",
+            "Token" : "xxx",
+            "Type" : "none",
+            "UseKialiToken" : false,
+            "Username" : "xxx"
           },
-          "isBox": "cluster",
-          "version": "Unknown"
-        }
-      },
-      {
-        "data": {
-          "id": "421c6926a61f0f21f1fe0babb48ea9fac6454c1d9a448dea2c559402723ec4da",
-          "cluster": "cluster-remote",
-          "infraName": "cluster-remote",
-          "infraType": "cluster",
-          "namespace": "",
-          "nodeType": "box",
-          "healthData": "Healthy",
-          "infraData": {
-            "apiEndpoint": "",
-            "isKialiHome": false,
-            "kialiInstances": null,
-            "name": "cluster-remote",
-            "secretName": "",
-            "accessible": true
+          "Dashboards" : null,
+          "Enabled" : true,
+          "ExternalURL" : "",
+          "HealthCheckUrl" : "",
+          "InternalURL" : "http://grafana.istio-system:3000",
+          "IsCore" : false
+        },
+        "isExternal" : true,
+        "isInaccessible" : true
+      }
+    }, {
+      "data" : {
+        "id" : "41b50563edf837e2e828b50492b24356bf392be6e0a7a7f21d90eabe551dd686",
+        "parent" : "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
+        "cluster" : "_external_",
+        "infraName" : "Prometheus",
+        "infraType" : "metricStore",
+        "namespace" : "",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "Auth" : {
+            "CAFile" : "xxx",
+            "InsecureSkipVerify" : false,
+            "Password" : "xxx",
+            "Token" : "xxx",
+            "Type" : "none",
+            "UseKialiToken" : false,
+            "Username" : "xxx"
           },
-          "isBox": "cluster"
-        }
-      },
-      {
-        "data": {
-          "id": "5d47c4043773968316f9d71a07212a1c363d76a3d9ffe7c52198f864cde8c5f5",
-          "parent": "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
-          "cluster": "cluster-primary",
-          "infraName": "data-plane-1",
-          "infraType": "namespace",
-          "namespace": "data-plane-1",
-          "nodeType": "box",
-          "healthData": null,
-          "isBox": "namespace"
-        }
-      },
-      {
-        "data": {
-          "id": "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
-          "parent": "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
-          "cluster": "cluster-primary",
-          "infraName": "istio-system",
-          "infraType": "namespace",
-          "namespace": "istio-system",
-          "nodeType": "box",
-          "healthData": null,
-          "isBox": "namespace"
-        }
-      },
-      {
-        "data": {
-          "id": "33493098cdd63801f773396da680159d0bb57b482ef38a4b208899a2e477e1f0",
-          "parent": "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
-          "cluster": "_external_",
-          "infraName": "Grafana",
-          "infraType": "grafana",
-          "namespace": "",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "Auth": {
-              "CAFile": "xxx",
-              "InsecureSkipVerify": false,
-              "Password": "xxx",
-              "Token": "xxx",
-              "Type": "none",
-              "UseKialiToken": false,
-              "Username": "xxx"
-            },
-            "Dashboards": null,
-            "Enabled": true,
-            "ExternalURL": "",
-            "HealthCheckUrl": "",
-            "InternalURL": "http://grafana.istio-system:3000",
-            "IsCore": false
+          "CacheDuration" : 7,
+          "CacheEnabled" : true,
+          "CacheExpiration" : 300,
+          "CustomHeaders" : { },
+          "HealthCheckUrl" : "",
+          "IsCore" : false,
+          "QueryScope" : { },
+          "ThanosProxy" : {
+            "Enabled" : false,
+            "RetentionPeriod" : "7d",
+            "ScrapeInterval" : "30s"
           },
-          "isExternal": true,
-          "isInaccessible": true
-        }
-      },
-      {
-        "data": {
-          "id": "41b50563edf837e2e828b50492b24356bf392be6e0a7a7f21d90eabe551dd686",
-          "parent": "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
-          "cluster": "_external_",
-          "infraName": "Prometheus",
-          "infraType": "metricStore",
-          "namespace": "",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "Auth": {
-              "CAFile": "xxx",
-              "InsecureSkipVerify": false,
-              "Password": "xxx",
-              "Token": "xxx",
-              "Type": "none",
-              "UseKialiToken": false,
-              "Username": "xxx"
-            },
-            "CacheDuration": 7,
-            "CacheEnabled": true,
-            "CacheExpiration": 300,
-            "CustomHeaders": {},
-            "HealthCheckUrl": "",
-            "IsCore": false,
-            "QueryScope": {},
-            "ThanosProxy": {
-              "Enabled": false,
-              "RetentionPeriod": "7d",
-              "ScrapeInterval": "30s"
-            },
-            "URL": "http://prometheus.istio-system:9090"
+          "URL" : "http://prometheus.istio-system:9090"
+        },
+        "isExternal" : true,
+        "isInaccessible" : true
+      }
+    }, {
+      "data" : {
+        "id" : "e0733a58436c292ece7cbcf37db7b77510545c027d03c1798c3d6d8202b93f6f",
+        "parent" : "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
+        "cluster" : "_external_",
+        "infraName" : "jaeger",
+        "infraType" : "traceStore",
+        "namespace" : "",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "Auth" : {
+            "CAFile" : "xxx",
+            "InsecureSkipVerify" : false,
+            "Password" : "xxx",
+            "Token" : "xxx",
+            "Type" : "none",
+            "UseKialiToken" : false,
+            "Username" : "xxx"
           },
-          "isExternal": true,
-          "isInaccessible": true
-        }
-      },
-      {
-        "data": {
-          "id": "e0733a58436c292ece7cbcf37db7b77510545c027d03c1798c3d6d8202b93f6f",
-          "parent": "85774128be9f0db40aeb4c610e9436f63cb0945838e6db0c05ae36b62c6c6c10",
-          "cluster": "_external_",
-          "infraName": "jaeger",
-          "infraType": "traceStore",
-          "namespace": "",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "Auth": {
-              "CAFile": "xxx",
-              "InsecureSkipVerify": false,
-              "Password": "xxx",
-              "Token": "xxx",
-              "Type": "none",
-              "UseKialiToken": false,
-              "Username": "xxx"
-            },
-            "CustomHeaders": {},
-            "DisableVersionCheck": false,
-            "Enabled": true,
-            "ExternalURL": "",
-            "HealthCheckUrl": "",
-            "GrpcPort": 9095,
-            "InternalURL": "http://tracing.istio-system:16685/jaeger",
-            "IsCore": false,
-            "Provider": "jaeger",
-            "TempoConfig": {
-              "cache_capacity": 200,
-              "cache_enabled": true
-            },
-            "NamespaceSelector": true,
-            "QueryScope": {},
-            "QueryTimeout": 5,
-            "UseGRPC": true,
-            "WhiteListIstioSystem": [
-              "jaeger-query",
-              "istio-ingressgateway"
-            ]
+          "CustomHeaders" : { },
+          "DisableVersionCheck" : false,
+          "Enabled" : true,
+          "ExternalURL" : "",
+          "HealthCheckUrl" : "",
+          "GrpcPort" : 9095,
+          "InternalURL" : "http://tracing.istio-system:16685/jaeger",
+          "IsCore" : false,
+          "Provider" : "jaeger",
+          "TempoConfig" : {
+            "cache_capacity" : 200,
+            "cache_enabled" : true
           },
-          "isExternal": true,
-          "isInaccessible": true
-        }
-      },
-      {
-        "data": {
-          "id": "0bb699228f65bc52ec82ed3c72726df27b56e7518b38b7e2021196ea0065233c",
-          "parent": "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
-          "cluster": "cluster-primary",
-          "infraName": "Data Plane",
-          "infraType": "dataplane",
-          "namespace": "",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": [
-            {
-              "name": "data-plane-1",
-              "cluster": "cluster-primary",
-              "isAmbient": false,
-              "labels": {
-                "istio-injection": "enabled",
-                "kubernetes.io/metadata.name": "data-plane-1"
-              },
-              "annotations": null,
-              "revision": "default"
-            },
-            {
-              "name": "data-plane-2",
-              "cluster": "cluster-primary",
-              "isAmbient": false,
-              "labels": {
-                "istio.io/rev": "default",
-                "kubernetes.io/metadata.name": "data-plane-2"
-              },
-              "annotations": null,
-              "revision": "default"
-            }
-          ],
-          "version": "default"
-        }
-      },
-      {
-        "data": {
-          "id": "5d63e313a5acadb4bf9f5bcaa606b69bbaf81a4193a511719a878e9ad8729a5f",
-          "parent": "5d47c4043773968316f9d71a07212a1c363d76a3d9ffe7c52198f864cde8c5f5",
-          "cluster": "cluster-primary",
-          "infraName": "waypoint",
-          "infraType": "waypoint",
-          "namespace": "data-plane-1",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "Annotations": {},
-            "Labels": {
-              "gateway.istio.io/managed": "istio.io-mesh-controller",
-              "gateway.networking.k8s.io/gateway-name": "waypoint"
-            },
-            "TemplateAnnotations": null,
-            "TemplateLabels": {
-              "gateway.istio.io/managed": "istio.io-mesh-controller",
-              "gateway.networking.k8s.io/gateway-name": "waypoint"
-            }
+          "NamespaceSelector" : true,
+          "QueryScope" : { },
+          "QueryTimeout" : 5,
+          "UseGRPC" : true,
+          "WhiteListIstioSystem" : [ "jaeger-query", "istio-ingressgateway" ]
+        },
+        "isExternal" : true,
+        "isInaccessible" : true
+      }
+    }, {
+      "data" : {
+        "id" : "0bb699228f65bc52ec82ed3c72726df27b56e7518b38b7e2021196ea0065233c",
+        "parent" : "52e2139bb2622c3156273a148bb95c794e674e820ffcf433a3e530e31e5fcd36",
+        "cluster" : "cluster-primary",
+        "infraName" : "Data Plane",
+        "infraType" : "dataplane",
+        "namespace" : "",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : [ {
+          "name" : "data-plane-1",
+          "cluster" : "cluster-primary",
+          "isAmbient" : false,
+          "labels" : {
+            "istio-injection" : "enabled",
+            "kubernetes.io/metadata.name" : "data-plane-1"
           },
-          "version": "default"
-        }
-      },
-      {
-        "data": {
-          "id": "1cf59ab6492289f4c7371ad6c0de54505a037f949855c902b5547fa6f15e3674",
-          "parent": "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
-          "cluster": "cluster-primary",
-          "infraName": "ztunnel",
-          "infraType": "ztunnel",
-          "namespace": "istio-system",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "Annotations": null,
-            "Labels": {
-              "app": "ztunnel"
-            },
-            "TemplateAnnotations": null,
-            "TemplateLabels": {
-              "app": "ztunnel"
-            }
+          "annotations" : null,
+          "revision" : "default"
+        }, {
+          "name" : "data-plane-2",
+          "cluster" : "cluster-primary",
+          "isAmbient" : false,
+          "labels" : {
+            "istio.io/rev" : "default",
+            "kubernetes.io/metadata.name" : "data-plane-2"
           },
-          "version": "default"
-        }
-      },
-      {
-        "data": {
-          "id": "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
-          "parent": "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
-          "cluster": "cluster-primary",
-          "infraName": "kiali",
-          "infraType": "kiali",
-          "namespace": "istio-system",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "ComponentStatuses": {
-              "Enabled": true,
-              "Components": []
-            },
-            "ConfigMapName": "",
-            "EnvoyAdminLocalPort": 15000,
-            "GatewayAPIClasses": [],
-            "GatewayAPIClassesLabelSelector": "",
-            "IstioAPIEnabled": true,
-            "IstioIdentityDomain": "svc.cluster.local",
-            "IstioInjectionAnnotation": "sidecar.istio.io/inject",
-            "IstioSidecarInjectorConfigMapName": "",
-            "IstioSidecarAnnotation": "sidecar.istio.io/status",
-            "IstiodDeploymentName": "",
-            "IstiodPodMonitoringPort": 15014,
-            "IstiodPollingIntervalSeconds": 20,
-            "Registry": null,
-            "RootNamespace": "istio-system",
-            "UrlServiceVersion": "",
-            "ValidationChangeDetectionEnabled": true,
-            "ValidationReconcileInterval": 60000000000
+          "annotations" : null,
+          "revision" : "default"
+        } ],
+        "version" : "default"
+      }
+    }, {
+      "data" : {
+        "id" : "5d63e313a5acadb4bf9f5bcaa606b69bbaf81a4193a511719a878e9ad8729a5f",
+        "parent" : "5d47c4043773968316f9d71a07212a1c363d76a3d9ffe7c52198f864cde8c5f5",
+        "cluster" : "cluster-primary",
+        "infraName" : "waypoint",
+        "infraType" : "waypoint",
+        "namespace" : "data-plane-1",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "Annotations" : { },
+          "Labels" : {
+            "gateway.istio.io/managed" : "istio.io-mesh-controller",
+            "gateway.networking.k8s.io/gateway-name" : "waypoint"
+          },
+          "TemplateAnnotations" : null,
+          "TemplateLabels" : {
+            "gateway.istio.io/managed" : "istio.io-mesh-controller",
+            "gateway.networking.k8s.io/gateway-name" : "waypoint"
           }
-        }
-      },
-      {
-        "data": {
-          "id": "4ffd132efe1291fcd70490d6add887f9e160a72c4885a83669432bea09de23f9",
-          "parent": "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
-          "cluster": "cluster-primary",
-          "infraName": "gateway",
-          "infraType": "gateway",
-          "namespace": "istio-system",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "kind": "Gateway",
-            "apiVersion": "networking.istio.io/v1",
-            "metadata": {
-              "name": "gateway",
-              "namespace": "istio-system",
-              "resourceVersion": "999",
-              "creationTimestamp": null
-            },
-            "spec": {
-              "selector": {
-                "istio": "ingressgateway"
-              }
-            },
-            "status": {}
+        },
+        "version" : "default"
+      }
+    }, {
+      "data" : {
+        "id" : "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
+        "parent" : "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
+        "cluster" : "cluster-primary",
+        "infraName" : "kiali",
+        "infraType" : "kiali",
+        "namespace" : "istio-system",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "ComponentStatuses" : {
+            "Enabled" : true,
+            "Components" : [ ]
           },
-          "version": "default"
+          "ConfigMapName" : "",
+          "EnvoyAdminLocalPort" : 15000,
+          "GatewayAPIClasses" : [ ],
+          "GatewayAPIClassesLabelSelector" : "",
+          "IstioAPIEnabled" : true,
+          "IstioIdentityDomain" : "svc.cluster.local",
+          "IstioInjectionAnnotation" : "sidecar.istio.io/inject",
+          "IstioSidecarInjectorConfigMapName" : "",
+          "IstioSidecarAnnotation" : "sidecar.istio.io/status",
+          "IstiodDeploymentName" : "",
+          "IstiodPodMonitoringPort" : 15014,
+          "IstiodPollingIntervalSeconds" : 20,
+          "Registry" : null,
+          "RootNamespace" : "istio-system",
+          "UrlServiceVersion" : "",
+          "ValidationChangeDetectionEnabled" : true,
+          "ValidationReconcileInterval" : 60000000000
         }
-      },
-      {
-        "data": {
-          "id": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "parent": "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
-          "cluster": "cluster-primary",
-          "infraName": "istiod",
-          "infraType": "istiod",
-          "namespace": "istio-system",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": {
-            "cluster": {
-              "apiEndpoint": "http://127.0.0.2:9443",
-              "isKialiHome": true,
-              "kialiInstances": [
-                {
-                  "namespace": "istio-system",
-                  "operatorResource": "",
-                  "serviceName": "kiali",
-                  "url": "",
-                  "version": ""
-                }
-              ],
-              "name": "cluster-primary",
-              "secretName": "",
-              "accessible": true
-            },
-            "config": {
-              "certificates": [
-                {
-                  "dnsNames": null,
-                  "configMapName": "istio-ca-root-cert",
-                  "issuer": "O=cluster.local",
-                  "notBefore": "2021-07-27T14:37:00Z",
-                  "notAfter": "2031-07-25T14:37:00Z",
-                  "error": "",
-                  "accessible": true,
-                  "cluster": ""
-                }
-              ],
-              "effectiveConfig": {
-                "configMap": {
-                  "mesh": {
-                    "accessLogFile": "/dev/stdout",
-                    "enableAutoMtls": true,
-                    "trustDomain": "cluster.local",
-                    "rootNamespace": "istio-system"
-                  }
+      }
+    }, {
+      "data" : {
+        "id" : "4ffd132efe1291fcd70490d6add887f9e160a72c4885a83669432bea09de23f9",
+        "parent" : "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
+        "cluster" : "cluster-primary",
+        "infraName" : "gateway",
+        "infraType" : "gateway",
+        "namespace" : "istio-system",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "kind" : "Gateway",
+          "apiVersion" : "networking.istio.io/v1",
+          "metadata" : {
+            "name" : "gateway",
+            "namespace" : "istio-system",
+            "resourceVersion" : "999",
+            "creationTimestamp" : null
+          },
+          "spec" : {
+            "selector" : {
+              "istio" : "ingressgateway"
+            }
+          },
+          "status" : { }
+        },
+        "version" : "default"
+      }
+    }, {
+      "data" : {
+        "id" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
+        "parent" : "d267c54a08bd79c4a07c88b2e0d93b5c93962da0703c7bfd70d1ead571b067f0",
+        "cluster" : "cluster-primary",
+        "infraName" : "istiod",
+        "infraType" : "istiod",
+        "namespace" : "istio-system",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : {
+          "cluster" : {
+            "apiEndpoint" : "http://127.0.0.2:9443",
+            "isKialiHome" : true,
+            "kialiInstances" : [ {
+              "namespace" : "istio-system",
+              "operatorResource" : "",
+              "serviceName" : "kiali",
+              "url" : "",
+              "version" : ""
+            } ],
+            "name" : "cluster-primary",
+            "secretName" : "",
+            "accessible" : true
+          },
+          "config" : {
+            "certificates" : [ {
+              "dnsNames" : null,
+              "configMapName" : "istio-ca-root-cert",
+              "issuer" : "O=cluster.local",
+              "notBefore" : "2021-07-27T14:37:00Z",
+              "notAfter" : "2031-07-25T14:37:00Z",
+              "error" : "",
+              "accessible" : true,
+              "cluster" : ""
+            } ],
+            "effectiveConfig" : {
+              "configMap" : {
+                "mesh" : {
+                  "accessLogFile" : "/dev/stdout",
+                  "enableAutoMtls" : true,
+                  "trustDomain" : "cluster.local",
+                  "rootNamespace" : "istio-system"
                 }
-              },
-              "network": "kialiNetwork",
-              "standardConfig": {
-              "cluster": "cluster-primary",
-                "configMap": {
-                  "mesh": {
-                    "accessLogFile": "/dev/stdout",
-                    "enableAutoMtls": true,
-                    "trustDomain": "cluster.local",
-                    "rootNamespace": "istio-system"
-                  }
-                },
-                "name": "istio",
-                "namespace": "istio-system"
               }
             },
-            "externalControlPlane": false,
-            "id": "cluster-primary",
-            "istiodName": "istiod",
-            "istiodNamespace": "istio-system",
-            "managedClusters": [
-              {
-                "apiEndpoint": "http://127.0.0.2:9443",
-                "isKialiHome": true,
-                "kialiInstances": [
-                  {
-                    "namespace": "istio-system",
-                    "operatorResource": "",
-                    "serviceName": "kiali",
-                    "url": "",
-                    "version": ""
-                  }
-                ],
-                "name": "cluster-primary",
-                "secretName": "",
-                "accessible": true
-              },
-              {
-                "apiEndpoint": "",
-                "isKialiHome": false,
-                "kialiInstances": null,
-                "name": "cluster-remote",
-                "secretName": "",
-                "accessible": true
-              }
-            ],
-            "managesExternal": true,
-            "managedNamespaces": [
-              {
-                "name": "data-plane-1",
-                "cluster": "cluster-primary",
-                "isAmbient": false,
-                "labels": {
-                  "istio-injection": "enabled",
-                  "kubernetes.io/metadata.name": "data-plane-1"
-                },
-                "annotations": null,
-                "revision": "default"
-              },
-              {
-                "name": "data-plane-2",
-                "cluster": "cluster-primary",
-                "isAmbient": false,
-                "labels": {
-                  "istio.io/rev": "default",
-                  "kubernetes.io/metadata.name": "data-plane-2"
-                },
-                "annotations": null,
-                "revision": "default"
-              },
-              {
-                "name": "data-plane-3",
-                "cluster": "cluster-remote",
-                "isAmbient": false,
-                "labels": {
-                  "istio-injection": "enabled",
-                  "kubernetes.io/metadata.name": "data-plane-3"
-                },
-                "annotations": null,
-                "revision": "default"
+            "network" : "kialiNetwork",
+            "standardConfig" : {
+              "cluster" : "cluster-primary",
+              "configMap" : {
+                "mesh" : {
+                  "accessLogFile" : "/dev/stdout",
+                  "enableAutoMtls" : true,
+                  "trustDomain" : "cluster.local",
+                  "rootNamespace" : "istio-system"
+                }
               },
-              {
-                "name": "data-plane-4",
-                "cluster": "cluster-remote",
-                "isAmbient": false,
-                "labels": {
-                  "istio.io/rev": "default",
-                  "kubernetes.io/metadata.name": "data-plane-4"
-                },
-                "annotations": null,
-                "revision": "default"
-              }
-            ],
-            "resources": {},
-            "revision": "default",
-            "status": "",
-            "thresholds": {
-              "memory": 0,
-              "cpu": 0
+              "name" : "istio",
+              "namespace" : "istio-system"
             }
           },
-          "version": "Unknown"
-        }
-      },
-      {
-        "data": {
-          "id": "5ff0f691c850d727e75813fb484e06f5bad835b005b08caf2a62c0cff7cd5405",
-          "parent": "421c6926a61f0f21f1fe0babb48ea9fac6454c1d9a448dea2c559402723ec4da",
-          "cluster": "cluster-remote",
-          "infraName": "Data Plane",
-          "infraType": "dataplane",
-          "namespace": "",
-          "nodeType": "infra",
-          "healthData": "Healthy",
-          "infraData": [
-            {
-              "name": "data-plane-3",
-              "cluster": "cluster-remote",
-              "isAmbient": false,
-              "labels": {
-                "istio-injection": "enabled",
-                "kubernetes.io/metadata.name": "data-plane-3"
-              },
-              "annotations": null,
-              "revision": "default"
+          "externalControlPlane" : false,
+          "id" : "cluster-primary",
+          "istiodName" : "istiod",
+          "istiodNamespace" : "istio-system",
+          "managedClusters" : [ {
+            "apiEndpoint" : "http://127.0.0.2:9443",
+            "isKialiHome" : true,
+            "kialiInstances" : [ {
+              "namespace" : "istio-system",
+              "operatorResource" : "",
+              "serviceName" : "kiali",
+              "url" : "",
+              "version" : ""
+            } ],
+            "name" : "cluster-primary",
+            "secretName" : "",
+            "accessible" : true
+          }, {
+            "apiEndpoint" : "",
+            "isKialiHome" : false,
+            "kialiInstances" : null,
+            "name" : "cluster-remote",
+            "secretName" : "",
+            "accessible" : true
+          } ],
+          "managesExternal" : true,
+          "managedNamespaces" : [ {
+            "name" : "data-plane-1",
+            "cluster" : "cluster-primary",
+            "isAmbient" : false,
+            "labels" : {
+              "istio-injection" : "enabled",
+              "kubernetes.io/metadata.name" : "data-plane-1"
             },
-            {
-              "name": "data-plane-4",
-              "cluster": "cluster-remote",
-              "isAmbient": false,
-              "labels": {
-                "istio.io/rev": "default",
-                "kubernetes.io/metadata.name": "data-plane-4"
-              },
-              "annotations": null,
-              "revision": "default"
-            }
-          ],
-          "version": "default"
-        }
+            "annotations" : null,
+            "revision" : "default"
+          }, {
+            "name" : "data-plane-2",
+            "cluster" : "cluster-primary",
+            "isAmbient" : false,
+            "labels" : {
+              "istio.io/rev" : "default",
+              "kubernetes.io/metadata.name" : "data-plane-2"
+            },
+            "annotations" : null,
+            "revision" : "default"
+          }, {
+            "name" : "data-plane-3",
+            "cluster" : "cluster-remote",
+            "isAmbient" : false,
+            "labels" : {
+              "istio-injection" : "enabled",
+              "kubernetes.io/metadata.name" : "data-plane-3"
+            },
+            "annotations" : null,
+            "revision" : "default"
+          }, {
+            "name" : "data-plane-4",
+            "cluster" : "cluster-remote",
+            "isAmbient" : false,
+            "labels" : {
+              "istio.io/rev" : "default",
+              "kubernetes.io/metadata.name" : "data-plane-4"
+            },
+            "annotations" : null,
+            "revision" : "default"
+          } ],
+          "resources" : { },
+          "revision" : "default",
+          "status" : "",
+          "thresholds" : {
+            "memory" : 0,
+            "cpu" : 0
+          }
+        },
+        "version" : "Unknown"
       }
-    ],
-    "edges": [
-      {
-        "data": {
-          "id": "3c1e5459c5b6268c2f2452f3e6b620fd1ae0297b4621175c97e376558bea9d58",
-          "source": "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
-          "target": "33493098cdd63801f773396da680159d0bb57b482ef38a4b208899a2e477e1f0"
-        }
-      },
-      {
-        "data": {
-          "id": "3800bf57dd84bfc7bb159fc26de3fd964dc4faa7274b6250dcde483edeba542d",
-          "source": "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
-          "target": "41b50563edf837e2e828b50492b24356bf392be6e0a7a7f21d90eabe551dd686"
-        }
-      },
-      {
-        "data": {
-          "id": "3444b8aee4ed1e0a9d9388de97152e089e723e1efae8db5658d9558b12346ac4",
-          "source": "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
-          "target": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2"
-        }
-      },
-      {
-        "data": {
-          "id": "6fb152c8305cf91514cbb0d86796cc62eb47e275cf803af3fbb26224c9ddf600",
-          "source": "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
-          "target": "e0733a58436c292ece7cbcf37db7b77510545c027d03c1798c3d6d8202b93f6f"
-        }
-      },
-      {
-        "data": {
-          "id": "8213394da06023363e2d5747d26db6f7e23d0beeacc84fcf97119768822e6dc8",
-          "source": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "target": "0bb699228f65bc52ec82ed3c72726df27b56e7518b38b7e2021196ea0065233c"
-        }
-      },
-      {
-        "data": {
-          "id": "7263daad487f2d7fb6e3b4225f94ccc140429de5456489175644410155bdaead",
-          "source": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "target": "1cf59ab6492289f4c7371ad6c0de54505a037f949855c902b5547fa6f15e3674"
-        }
-      },
-      {
-        "data": {
-          "id": "ea8e134859bb70d340128c62d2468a12174517151b37014f82613d6a0957eb8e",
-          "source": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "target": "4ffd132efe1291fcd70490d6add887f9e160a72c4885a83669432bea09de23f9"
-        }
-      },
-      {
-        "data": {
-          "id": "f25288d2a684e5be99e297439adad0d0f65e5893ba592b397f4841a42e3bab68",
-          "source": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "target": "5d63e313a5acadb4bf9f5bcaa606b69bbaf81a4193a511719a878e9ad8729a5f"
-        }
-      },
-      {
-        "data": {
-          "id": "1622664f016a337006cce1427c522c2e24c1b1b39548109f49ad478594f7d8ca",
-          "source": "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
-          "target": "5ff0f691c850d727e75813fb484e06f5bad835b005b08caf2a62c0cff7cd5405"
-        }
+    }, {
+      "data" : {
+        "id" : "5ff0f691c850d727e75813fb484e06f5bad835b005b08caf2a62c0cff7cd5405",
+        "parent" : "421c6926a61f0f21f1fe0babb48ea9fac6454c1d9a448dea2c559402723ec4da",
+        "cluster" : "cluster-remote",
+        "infraName" : "Data Plane",
+        "infraType" : "dataplane",
+        "namespace" : "",
+        "nodeType" : "infra",
+        "healthData" : "Healthy",
+        "infraData" : [ {
+          "name" : "data-plane-3",
+          "cluster" : "cluster-remote",
+          "isAmbient" : false,
+          "labels" : {
+            "istio-injection" : "enabled",
+            "kubernetes.io/metadata.name" : "data-plane-3"
+          },
+          "annotations" : null,
+          "revision" : "default"
+        }, {
+          "name" : "data-plane-4",
+          "cluster" : "cluster-remote",
+          "isAmbient" : false,
+          "labels" : {
+            "istio.io/rev" : "default",
+            "kubernetes.io/metadata.name" : "data-plane-4"
+          },
+          "annotations" : null,
+          "revision" : "default"
+        } ],
+        "version" : "default"
+      }
+    } ],
+    "edges" : [ {
+      "data" : {
+        "id" : "3c1e5459c5b6268c2f2452f3e6b620fd1ae0297b4621175c97e376558bea9d58",
+        "source" : "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
+        "target" : "33493098cdd63801f773396da680159d0bb57b482ef38a4b208899a2e477e1f0"
+      }
+    }, {
+      "data" : {
+        "id" : "3800bf57dd84bfc7bb159fc26de3fd964dc4faa7274b6250dcde483edeba542d",
+        "source" : "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
+        "target" : "41b50563edf837e2e828b50492b24356bf392be6e0a7a7f21d90eabe551dd686"
+      }
+    }, {
+      "data" : {
+        "id" : "3444b8aee4ed1e0a9d9388de97152e089e723e1efae8db5658d9558b12346ac4",
+        "source" : "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
+        "target" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2"
+      }
+    }, {
+      "data" : {
+        "id" : "6fb152c8305cf91514cbb0d86796cc62eb47e275cf803af3fbb26224c9ddf600",
+        "source" : "29c05b5dfa30d15d450e54f0651c03c68a25a78ae4dc8f292c6ceb5ce6be7e6d",
+        "target" : "e0733a58436c292ece7cbcf37db7b77510545c027d03c1798c3d6d8202b93f6f"
+      }
+    }, {
+      "data" : {
+        "id" : "8213394da06023363e2d5747d26db6f7e23d0beeacc84fcf97119768822e6dc8",
+        "source" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
+        "target" : "0bb699228f65bc52ec82ed3c72726df27b56e7518b38b7e2021196ea0065233c"
+      }
+    }, {
+      "data" : {
+        "id" : "ea8e134859bb70d340128c62d2468a12174517151b37014f82613d6a0957eb8e",
+        "source" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
+        "target" : "4ffd132efe1291fcd70490d6add887f9e160a72c4885a83669432bea09de23f9"
+      }
+    }, {
+      "data" : {
+        "id" : "f25288d2a684e5be99e297439adad0d0f65e5893ba592b397f4841a42e3bab68",
+        "source" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
+        "target" : "5d63e313a5acadb4bf9f5bcaa606b69bbaf81a4193a511719a878e9ad8729a5f"
+      }
+    }, {
+      "data" : {
+        "id" : "1622664f016a337006cce1427c522c2e24c1b1b39548109f49ad478594f7d8ca",
+        "source" : "9b5c974b8b5c42157a685413c86f2ff15ee4266f307f0c519d9acc50b6c97bc2",
+        "target" : "5ff0f691c850d727e75813fb484e06f5bad835b005b08caf2a62c0cff7cd5405"
       }
-    ]
+    } ]
   },
-  "meshName": "",
-  "timestamp": 1523364075
-}
\ No newline at end of file
+  "meshName" : "",
+  "timestamp" : 1523364075
+}