Repository: kiali/kiali

Issue:
[CI] Add Perses cypress tests
### What do you want to improve?
Add Perses cypress tests.
Needs to install Perses using helm charts and include provisioning Istio Dashboards.

Ref. https://github.com/kiali/kiali/issues/8578

Hints from issue comments:
@nrfox: @josunect is there a helm chart for Perses we can use instead? Less resources than an operator.

I think we can just install this as part of the `frontend` suite? Unless we need to test with multi-cluster?@josunect: > [@josunect](https://github.com/josunect) is there a helm chart for Perses we can use instead? Less resources than an operator.
> 
> I think we can just install this as part of the `frontend` suite? Unless we need to test with multi-cluster?

Yes, I will edit the description. It can be part as the frontend suite, no need to include it in other, I think

Solution patch:
diff --git a/business/namespaces.go b/business/namespaces.go
index abf413806..f6174157b 100644
--- a/business/namespaces.go
+++ b/business/namespaces.go
@@ -21,7 +21,6 @@ import (
 type NamespaceService struct {
 	conf                  *config.Config
 	discovery             istio.MeshDiscovery
-	hasProjects           map[string]bool
 	homeClusterUserClient kubernetes.UserClientInterface
 	kialiCache            cache.KialiCache
 	kialiSAClients        map[string]kubernetes.ClientInterface
@@ -49,15 +48,10 @@ func NewNamespaceService(
 	userClients map[string]kubernetes.UserClientInterface,
 ) NamespaceService {
 	homeClusterName := conf.KubernetesConfig.ClusterName
-	hasProjects := make(map[string]bool)
-	for cluster, client := range kialiSAClients {
-		hasProjects[cluster] = client.IsOpenShift()
-	}
 
 	return NamespaceService{
 		conf:                  conf,
 		discovery:             discovery,
-		hasProjects:           hasProjects,
 		homeClusterUserClient: userClients[homeClusterName],
 		kialiCache:            cache,
 		kialiSAClients:        kialiSAClients,
@@ -65,10 +59,6 @@ func NewNamespaceService(
 	}
 }
 
-func (in *NamespaceService) clusterIsOpenShift(cluster string) bool {
-	return in.hasProjects[cluster]
-}
-
 // GetClusterList Returns a list of cluster names based on the user clients
 func (in *NamespaceService) GetClusterList() []string {
 	var clusterList []string
@@ -163,58 +153,50 @@ func (in *NamespaceService) GetNamespaces(ctx context.Context) ([]models.Namespa
 func (in *NamespaceService) getNamespacesByCluster(ctx context.Context, cluster string) ([]models.Namespace, error) {
 	var namespaces []models.Namespace
 
-	// If we are running in OpenShift, we will use the project names since these are the list of accessible namespaces
-	if in.clusterIsOpenShift(cluster) {
-		projects, err := in.userClients[cluster].GetProjects(ctx, "")
-		if err != nil {
-			return nil, err
-		}
-		namespaces = models.CastProjectCollection(projects, cluster)
-	} else {
-		// Note that cluster-wide-access mode requires cluster role permission to list all namespaces.
-		if in.conf.Deployment.ClusterWideAccess {
+	// Note that cluster-wide-access mode requires cluster role permission to list all namespaces.
+	if in.conf.Deployment.ClusterWideAccess {
 
-			nss, err := in.userClients[cluster].GetNamespaces("")
-			if err != nil {
-				// Fallback to using the Kiali service account, if needed
-				if errors.IsForbidden(err) {
-					if nss, err = in.getNamespacesUsingKialiSA(cluster, "", err); err != nil {
-						return nil, err
-					}
-				} else {
+		nss, err := in.userClients[cluster].GetNamespaces("")
+		if err != nil {
+			// Fallback to using the Kiali service account, if needed
+			if errors.IsForbidden(err) {
+				if nss, err = in.getNamespacesUsingKialiSA(cluster, "", err); err != nil {
 					return nil, err
 				}
+			} else {
+				return nil, err
 			}
+		}
 
-			namespaces = models.CastNamespaceCollection(nss, cluster)
-		} else {
-			// We do not have cluster wide access, so we do not have permission to list namespaces.
-			// Therefore, we assume we can extract the list of accessible namespaces from the discovery selectors configuration.
-			// That list of accessible namespaces will be used as our base list which we then filter with discovery selectors down below.
-			// Note if this is a remote cluster, that remote cluster must have the same namespaces as those in our own local
-			// cluster's accessible namespaces. This is one reason why we suggest enabling CWA for multi-cluster environments.
-			accessibleNamespaces := in.conf.Deployment.AccessibleNamespaces
-			k8sNamespaces := make([]core_v1.Namespace, 0)
-			for _, ans := range accessibleNamespaces {
-				k8sNs, err := in.userClients[cluster].GetNamespace(ans)
-				if err != nil {
-					if errors.IsNotFound(err) {
-						// If a namespace is not found, then we skip it from the list of namespaces
-						log.Warningf("Kiali has an accessible namespace [%s] which doesn't exist", ans)
-					} else if errors.IsForbidden(err) {
-						// Also, if namespace isn't readable, skip it.
-						log.Warningf("Kiali has an accessible namespace [%s] which is forbidden", ans)
-					} else {
-						// On any other error, abort and return the error.
-						return nil, err
-					}
+		namespaces = models.CastNamespaceCollection(nss, cluster)
+	} else {
+		// We do not have cluster wide access, so we do not have permission to list namespaces.
+		// Therefore, we assume we can extract the list of accessible namespaces from the discovery selectors configuration.
+		// That list of accessible namespaces will be used as our base list which we then filter with discovery selectors down below.
+		// Note if this is a remote cluster, that remote cluster must have the same namespaces as those in our own local
+		// cluster's accessible namespaces. This is one reason why we suggest enabling CWA for multi-cluster environments.
+		accessibleNamespaces := in.conf.Deployment.AccessibleNamespaces
+		k8sNamespaces := make([]core_v1.Namespace, 0)
+		for _, ans := range accessibleNamespaces {
+			k8sNs, err := in.userClients[cluster].GetNamespace(ans)
+			if err != nil {
+				if errors.IsNotFound(err) {
+					// If a namespace is not found, then we skip it from the list of namespaces
+					log.Warningf("Kiali has an accessible namespace [%s] which doesn't exist", ans)
+				} else if errors.IsForbidden(err) {
+					// Also, if namespace isn't readable, skip it.
+					log.Warningf("Kiali has an accessible namespace [%s] which is forbidden", ans)
 				} else {
-					k8sNamespaces = append(k8sNamespaces, *k8sNs)
+					// On any other error, abort and return the error.
+					return nil, err
 				}
+			} else {
+				k8sNamespaces = append(k8sNamespaces, *k8sNs)
 			}
-			namespaces = models.CastNamespaceCollection(k8sNamespaces, cluster)
 		}
+		namespaces = models.CastNamespaceCollection(k8sNamespaces, cluster)
 	}
+
 	// here is called GetControlPlaneNamespaces instead of IsControlPlane for performance reasons
 	cpnList := in.discovery.GetControlPlaneNamespaces(ctx, cluster)
 	cpnSet := make(map[string]struct{}, len(cpnList))
@@ -286,20 +268,11 @@ func (in *NamespaceService) GetClusterNamespace(ctx context.Context, namespace s
 		return &ns, nil
 	}
 
-	var result models.Namespace
-	if in.clusterIsOpenShift(cluster) {
-		project, err := client.GetProject(ctx, namespace)
-		if err != nil {
-			return nil, err
-		}
-		result = models.CastProject(*project, cluster)
-	} else {
-		ns, err := client.GetNamespace(namespace)
-		if err != nil {
-			return nil, err
-		}
-		result = models.CastNamespace(*ns, cluster)
+	ns, err := client.GetNamespace(namespace)
+	if err != nil {
+		return nil, err
 	}
+	result := models.CastNamespace(*ns, cluster)
 
 	if !in.isAccessibleNamespace(ctx, result) {
 		return nil, &AccessibleNamespaceError{msg: "Namespace [" + namespace + "] in cluster [" + cluster + "] is not accessible to Kiali"}
diff --git a/frontend/cypress/integration/common/kiali_about.ts b/frontend/cypress/integration/common/kiali_about.ts
index 646defc00..b881443c0 100644
--- a/frontend/cypress/integration/common/kiali_about.ts
+++ b/frontend/cypress/integration/common/kiali_about.ts
@@ -15,3 +15,31 @@ Then(`user see Kiali brand`, () => {
   cy.get('[href="https://www.kiali.io"]').should('have.attr', 'href');
   cy.get('[href="https://github.com/kiali"]').should('have.attr', 'href');
 });
+
+Then(`user see valid version information`, () => {
+  // Test Kiali server version using data-test attribute
+  cy.get('[data-test="kiali-version"]')
+    .should('be.visible')
+    .should('not.contain', 'undefined')
+    .should('not.be.empty')
+    .invoke('text')
+    .then(text => {
+      expect(text.trim()).to.not.equal('');
+      expect(text.trim()).to.not.equal('unknown');
+      expect(text.trim()).to.not.equal('null');
+      expect(text.trim()).to.have.length.greaterThan(0);
+    });
+
+  // Test Kiali container version using data-test attribute
+  cy.get('[data-test="kiali-container-version"]')
+    .should('be.visible')
+    .should('not.contain', 'undefined')
+    .should('not.be.empty')
+    .invoke('text')
+    .then(text => {
+      expect(text.trim()).to.not.equal('');
+      expect(text.trim()).to.not.equal('unknown');
+      expect(text.trim()).to.not.equal('null');
+      expect(text.trim()).to.have.length.greaterThan(0);
+    });
+});
diff --git a/frontend/cypress/integration/common/overview.ts b/frontend/cypress/integration/common/overview.ts
index 1415527eb..1280af1dc 100644
--- a/frontend/cypress/integration/common/overview.ts
+++ b/frontend/cypress/integration/common/overview.ts
@@ -269,6 +269,10 @@ Then('Istio config should not be available for the {string} {string}', (cluster:
   cy.get(`[data-test="CardItem_${ns}_${cluster}"]`).contains('Istio config').siblings().contains('N/A');
 });
 
+Then('Istio config should be available for the {string} {string}', (cluster: string, ns: string) => {
+  cy.get(`[data-test="CardItem_${ns}_${cluster}"]`).contains('Istio config').siblings().should('not.contain', 'N/A');
+});
+
 Then(
   'health should be different for {string} and {string} {string}',
   (cluster1: string, cluster2: string, ns: string) => {
diff --git a/frontend/cypress/integration/common/workloads_details.ts b/frontend/cypress/integration/common/workloads_details.ts
index aaec89bd8..c19d0ed6e 100644
--- a/frontend/cypress/integration/common/workloads_details.ts
+++ b/frontend/cypress/integration/common/workloads_details.ts
@@ -66,6 +66,24 @@ Then('user sees workload outbound metrics information', () => {
     });
 });
 
+Then('user sees Perses link in the Inbound Metrics tab', () => {
+  openTab('Inbound Metrics');
+  cy.waitForReact();
+
+  // Check that the Perses link exists within the card body
+  cy.get('.pf-v5-c-card__body').within(() => {
+    cy.get('#perses_link_0')
+      .should('be.visible')
+      .and('have.attr', 'title', 'Istio Mesh Dashboard')
+      .and('have.attr', 'target', '_blank')
+      .and('have.attr', 'rel', 'noopener noreferrer')
+      .and('contain', 'View in Perses');
+
+    // Validate the href contains istio-mesh-dashboard
+    cy.get('#perses_link_0').should('have.attr', 'href').and('include', 'istio-mesh-dashboard');
+  });
+});
+
 When('user can filter spans by workload {string}', (workload: string) => {
   cy.get('button#filter_select_type-toggle').click();
   cy.get('button#Workload').click();
diff --git a/frontend/cypress/integration/featureFiles/kiali_about.feature b/frontend/cypress/integration/featureFiles/kiali_about.feature
index 1b4dcd2e2..28653cdb4 100644
--- a/frontend/cypress/integration/featureFiles/kiali_about.feature
+++ b/frontend/cypress/integration/featureFiles/kiali_about.feature
@@ -12,3 +12,10 @@ Feature: Kiali help about verify
     And user clicks on Help Button
     And user clicks on About Button
     Then user see Kiali brand
+
+  @smoke
+  @core
+  Scenario: Verify version information is displayed correctly
+    And user clicks on Help Button
+    And user clicks on About Button
+    Then user see valid version information
diff --git a/frontend/cypress/integration/featureFiles/mesh.feature b/frontend/cypress/integration/featureFiles/mesh.feature
index 32a2847e3..cc91d7e04 100644
--- a/frontend/cypress/integration/featureFiles/mesh.feature
+++ b/frontend/cypress/integration/featureFiles/mesh.feature
@@ -38,6 +38,11 @@ Feature: Kiali Mesh page
     When user selects mesh node with label "Grafana"
     Then user sees "Grafana" node side panel
 
+  @perses
+  Scenario: Perses Infra
+    When user selects mesh node with label "Perses"
+    Then user sees "Perses" node side panel
+
   @core
   Scenario: Tracing Infra
     When user selects tracing mesh node
diff --git a/frontend/cypress/integration/featureFiles/overview.feature b/frontend/cypress/integration/featureFiles/overview.feature
index 0ab9a5b67..cfd86154a 100644
--- a/frontend/cypress/integration/featureFiles/overview.feature
+++ b/frontend/cypress/integration/featureFiles/overview.feature
@@ -137,7 +137,7 @@ Feature: Kiali Overview page
     And user sees the "istio-system" namespace card in cluster "west"
     And user sees the "Control plane" label in both "istio-system" namespace cards
     And the toggle on the right side of both "istio-system" namespace cards exists
-  
+
   @multi-cluster
   Scenario: Istio panel for east cluster should be visible and have the control plane label
     Then user sees the "istio-system" namespace card in cluster "east"
@@ -151,7 +151,7 @@ Feature: Kiali Overview page
   Scenario: See "bookinfo" in "east" and "west" clusters
     Then user sees the "bookinfo" namespace card in cluster "east"
     And user sees the "bookinfo" namespace card in cluster "west"
-    And Istio config should not be available for the "west" "bookinfo"
+    And Istio config should be available for the "west" "bookinfo"
     And health should be different for "east" and "west" "bookinfo"
 
   @multi-cluster
diff --git a/frontend/cypress/integration/featureFiles/waypoint.feature b/frontend/cypress/integration/featureFiles/waypoint.feature
index 0dbe45620..9093ef230 100644
--- a/frontend/cypress/integration/featureFiles/waypoint.feature
+++ b/frontend/cypress/integration/featureFiles/waypoint.feature
@@ -246,7 +246,6 @@ Feature: Kiali Waypoint related features
     And user "disables" "http" traffic option
     Then 2 edges appear in the graph
 
-  @skip-istio-1-23
   Scenario: [Traffic] Waypoint for workload
     Given user is at the "graph" page
     When user graphs "waypoint-forworkload" namespaces
@@ -261,7 +260,6 @@ Feature: Kiali Waypoint related features
     And the "unknown" service "does" exists
     And the "curl-client" node "does" exists
 
-  @skip-istio-1-23
   Scenario: [Traffic] Waypoint for workload with waypoints
     Given user is at the "graph" page
     When user graphs "waypoint-forworkload" namespaces
@@ -387,7 +385,6 @@ Feature: Kiali Waypoint related features
     When the user goes to the "Logs" tab
     Then the user updates the log level to "Debug"
 
-  @skip-istio-1-23
   Scenario: [Traffic] Sidecar Ambient traffic
     Given user is at the "graph" page
     When user graphs "test-ambient,test-sidecar" namespaces
@@ -411,7 +408,6 @@ Feature: Kiali Waypoint related features
     Then 4 edges appear in the graph
     Then user "closes" traffic menu
 
-  @selected
   Scenario: [Overview] Add to Ambient in the test-sidecar namespace
     Given user is at administrator perspective
     Given user is at the "overview" page
diff --git a/frontend/cypress/integration/featureFiles/workloads_details.feature b/frontend/cypress/integration/featureFiles/workloads_details.feature
index d74f6aaa5..de40c8736 100644
--- a/frontend/cypress/integration/featureFiles/workloads_details.feature
+++ b/frontend/cypress/integration/featureFiles/workloads_details.feature
@@ -34,6 +34,10 @@ Feature: Kiali Workload Details page
   Scenario: See workload Outbound Metrics
     Then user sees workload outbound metrics information
 
+  @perses
+  Scenario: See workload Perses link
+    Then user sees Perses link in the Inbound Metrics tab
+
   @bookinfo-app
   @tracing
   @waypoint-tracing
diff --git a/frontend/package.json b/frontend/package.json
index 625bc4bac..733056d86 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -38,7 +38,7 @@
     "build:dev": "sh -ac '. ./.env.upstream; npm run lint && npm run build:kiali'",
     "build:kiali": "npm run i18n && REACT_APP_VERSION=$npm_package_version REACT_APP_NAME=$npm_package_name GENERATE_SOURCEMAP=false EXTEND_ESLINT=true react-scripts build --profile",
     "build:prod": "sh -ac '. ./.env.downstream; npm run build:kiali'",
-    "cypress": "cypress open -e TAGS=\"@core or @crd-validation\"",
+    "cypress": "cypress open -e TAGS=\"@core or @crd-validation or @perses\"",
     "cypress:ambient": "cypress open -e TAGS=\"@ambient\"",
     "cypress:external-kiali": "cypress open -e TAGS=\"@external-kiali\"",
     "cypress:combine:reports": "jrm cypress/results/combined-report.xml \"cypress/results/*.xml\"",
@@ -49,7 +49,7 @@
     "cypress:selected": "cypress open -e TAGS=\"@selected\"",
     "cypress:tracing": "cypress open -e TAGS=\"@tracing\"",
     "cypress:waypoint": "cypress open -e TAGS=\"@waypoint or @waypoint-tracing\"",
-    "cypress:run": "cypress run -e TAGS=\"@core\" && cypress run -e TAGS=\"@crd-validation\"",
+    "cypress:run": "cypress run -e TAGS=\"@core\" && cypress run -e TAGS=\"@crd-validation\" && cypress run -e TAGS=\"@perses\"",
     "cypress:run:ambient": "cypress run -e TAGS=\"@ambient\" && cypress run -e TAGS=\"@waypoint\" && cypress run -e TAGS=\"@waypoint-tracing\"",
     "cypress:run:ambient:junit": "cypress run --reporter cypress-multi-reporters --reporter-options configFile=reporter-config.json -e TAGS=\"@ambient\" && cypress run --reporter cypress-multi-reporters --reporter-options configFile=reporter-config.json -e TAGS=\"@waypoint\" && cypress run --reporter cypress-multi-reporters --reporter-options configFile=reporter-config.json -e TAGS=\"@waypoint-tracing\"",
     "cypress:run:ambient123": "cypress run -e TAGS=\"@ambient\" && cypress run -e TAGS=\"@waypoint and not @skip-istio-1-23\" && cypress run -e TAGS=\"@waypoint-tracing\"",
diff --git a/frontend/src/components/About/AboutUIModal.tsx b/frontend/src/components/About/AboutUIModal.tsx
index 7705953cf..e146d9aff 100644
--- a/frontend/src/components/About/AboutUIModal.tsx
+++ b/frontend/src/components/About/AboutUIModal.tsx
@@ -135,13 +135,13 @@ export const AboutUIModal: React.FC<AboutUIModalProps> = (props: AboutUIModalPro
           <TextListItem key="kiali-name" component="dt">
             Kiali
           </TextListItem>
-          <TextListItem key="kiali-version" component="dd">
+          <TextListItem key="kiali-version" component="dd" data-test="kiali-version">
             {coreVersion!}
           </TextListItem>
           <TextListItem key="kiali-container-name" component="dt">
             Kiali Container
           </TextListItem>
-          <TextListItem key="kiali-container-version" component="dd">
+          <TextListItem key="kiali-container-version" component="dd" data-test="kiali-container-version">
             {containerVersion!}
           </TextListItem>
         </TextList>
diff --git a/hack/istio/functions.sh b/hack/istio/functions.sh
index 16a641e59..361528a47 100644
--- a/hack/istio/functions.sh
+++ b/hack/istio/functions.sh
@@ -41,29 +41,3 @@ is_istio_version_eq_greater_than() {
   fi
 
 }
-
-# Returns 0 if the istio version is greater than specified, 0 otherwise, using two arguments
-is_istio_version_eq_greater_than_expected() {
-  local expected_version=$1
-  local istio_version=$2
-
-  istio_expected_version=$(echo "$expected_version" | cut -d'-' -f1)
-
-  IFS='.' read -r major minor patch <<< "$istio_version"
-  IFS='.' read -r major_expected minor_expected patch_expected <<< "$istio_expected_version"
-  IFS=' '
-  if [ "${major}" -lt "${major_expected}" ]; then
-    return 1
-  else
-    if [ "${major}" -eq "${major_expected}" ]; then
-      if [ "${minor}" -lt "${minor_expected}" ]; then
-        return 0
-      else
-        return 1
-      fi
-    else
-      return 0
-    fi
-  fi
-
-}
\ No newline at end of file
diff --git a/hack/istio/perses/dashboard.yaml b/hack/istio/perses/dashboard.yaml
new file mode 100644
index 000000000..5c06652d8
--- /dev/null
+++ b/hack/istio/perses/dashboard.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: perses-provisioning
+  namespace: istio-system
+  labels:
+    perses.dev/resource: "true"
+data:
+  dashboard-control-plane.json: |
+    {"kind":"Dashboard","metadata":{"name":"istio-control-plane","version":1,"project":"istio"},"spec":{"display":{"name":"Istio Control Plane Dashboard"},"panels":{"PushSize":{"kind":"Panel","spec":{"display":{"name":"Push Size","description":"Size of each xDS push."},"plugin":{"kind":"TimeSeriesChart","spec":{}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum(rate(pilot_xds_config_size_bytes_bucket{}[1m])) by (le)","seriesNameFormat":"{{le}}"}}}}]}},"PushTime":{"kind":"Panel","spec":{"display":{"name":"Push Time","description":"Count of active and pending proxies managed by each instance. Pending is expected to converge to zero."},"plugin":{"kind":"TimeSeriesChart","spec":{}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum(rate(pilot_xds_push_time_bucket{}[1m])) by (le)","seriesNameFormat":"{{le}}"}}}}]}},"connections":{"kind":"Panel","spec":{"display":{"name":"Connections","description":"Total number of XDS connections\n"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})","seriesNameFormat":"Connections (client reported)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum (pilot_xds)","seriesNameFormat":"Connections (server reported)"}}}}]}},"cpuusage":{"kind":"Panel","spec":{"display":{"name":"CPU Usage","description":"CPU usage of each running instance"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (irate(container_cpu_usage_seconds_total{container=\"discovery\",pod=~\"istiod-.*\"}[$__rate_interval]))","seriesNameFormat":"Container ({{pod}})"}}}}]}},"events":{"kind":"Panel","spec":{"display":{"name":"Events","description":"Size of each xDS push.\n"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (type,event) (rate(pilot_k8s_reg_events[$__rate_interval]))","seriesNameFormat":"{{event}} {{type}}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum by (type,event) (rate(pilot_k8s_cfg_events[$__rate_interval]))","seriesNameFormat":"{{event}} {{type}}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (type) (rate(pilot_push_triggers[$__rate_interval]))","seriesNameFormat":"Push {{type}}"}}}}]}},"goroutines":{"kind":"Panel","spec":{"display":{"name":"Goroutines","description":"Goroutine count for each running instance"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (go_goroutines{app=\"istiod\"})","seriesNameFormat":"Goroutines ({{pod}})"}}}}]}},"memoryallocations":{"kind":"Panel","spec":{"display":{"name":"Memory Allocations","description":"Details about memory allocations"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes/sec"}}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (rate(go_memstats_alloc_bytes_total{app=\"istiod\"}[$__rate_interval]))","seriesNameFormat":"Bytes ({{pod}})"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum by (pod) (rate(go_memstats_mallocs_total{app=\"istiod\"}[$__rate_interval]))","seriesNameFormat":"Objects ({{pod}})"}}}}]}},"memoryusage":{"kind":"Panel","spec":{"display":{"name":"Memory Usage","description":"Memory usage of each running instance"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes"}}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum by (pod) (container_memory_working_set_bytes{container=\"discovery\",pod=~\"istiod-.*\"})","seriesNameFormat":"Container ({{pod}})"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (go_memstats_stack_inuse_bytes{app=\"istiod\"})","seriesNameFormat":"Stack ({{pod}})"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (go_memstats_heap_inuse_bytes{app=\"istiod\"})","seriesNameFormat":"Heap (In Use) ({{pod}})"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (pod) (go_memstats_heap_alloc_bytes{app=\"istiod\"})","seriesNameFormat":"Heap (Allocated) ({{pod}})"}}}}]}},"pilotversions":{"kind":"Panel","spec":{"display":{"name":"Pilot Versions","description":"Version number of each running instance"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (tag) (istio_build{component=\"pilot\"})","seriesNameFormat":"Version ({{tag}})"}}}}]}},"pusherrors":{"kind":"Panel","spec":{"display":{"name":"Push Errors","description":"Number of push errors. Many of these are at least potentional fatal and should be explored in-depth via Istiod logs.\nNote: metrics here do not use rate() to avoid missing transition from \"No series\"; series are not reported if there are no errors at all.\n"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"table","position":"bottom","values":["last","max"]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum by (type) (pilot_total_xds_rejects)","seriesNameFormat":"Rejected Config ({{type}})"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"pilot_total_xds_internal_errors","seriesNameFormat":"Internal Errors"}}}}]}},"sizexdspush":{"kind":"Panel","spec":{"display":{"name":"Injection","description":"Size of each xDS push.\n"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum (rate(sidecar_injection_success_total[$__rate_interval]))","seriesNameFormat":"Success"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum (rate(sidecar_injection_failure_total[$__rate_interval]))","seriesNameFormat":"Failure"}}}}]}},"validation":{"kind":"Panel","spec":{"display":{"name":"Validation","description":"Rate of XDS push operations, by type. This is incremented on a per-proxy basis.\n"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum (rate(galley_validation_passed[$__rate_interval]))","seriesNameFormat":"Success"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"query":"sum (rate(galley_validation_failed[$__rate_interval]))","seriesNameFormat":"Failure"}}}}]}},"xdspushes":{"kind":"Panel","spec":{"display":{"name":"XDS Pushes"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":1,"connectNulls":false,"display":"bar","lineWidth":1,"stack":"all"}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum by (type) (irate(pilot_xds_pushes[$__rate_interval]))","seriesNameFormat":"{{type}}"}}}}]}}},"layouts":[{"kind":"Grid","spec":{"display":{"title":"Deployed Versions","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":5,"content":{"$ref":"#/spec/panels/pilotversions"}}]}},{"kind":"Grid","spec":{"display":{"title":"Resource Usage","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":6,"height":10,"content":{"$ref":"#/spec/panels/memoryusage"}},{"x":6,"y":0,"width":6,"height":10,"content":{"$ref":"#/spec/panels/memoryallocations"}},{"x":12,"y":0,"width":6,"height":10,"content":{"$ref":"#/spec/panels/cpuusage"}},{"x":18,"y":0,"width":6,"height":10,"content":{"$ref":"#/spec/panels/goroutines"}}]}},{"kind":"Grid","spec":{"display":{"title":"Push Information","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":8,"height":10,"content":{"$ref":"#/spec/panels/xdspushes"}},{"x":8,"y":0,"width":8,"height":10,"content":{"$ref":"#/spec/panels/events"}},{"x":16,"y":0,"width":8,"height":10,"content":{"$ref":"#/spec/panels/connections"}},{"x":0,"y":10,"width":8,"height":10,"content":{"$ref":"#/spec/panels/pusherrors"}},{"x":8,"y":10,"width":8,"height":10,"content":{"$ref":"#/spec/panels/PushTime"}},{"x":16,"y":10,"width":8,"height":10,"content":{"$ref":"#/spec/panels/PushSize"}}]}},{"kind":"Grid","spec":{"display":{"title":"Webhooks","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":12,"height":8,"content":{"$ref":"#/spec/panels/validation"}},{"x":12,"y":0,"width":12,"height":8,"content":{"$ref":"#/spec/panels/sizexdspush"}}]}}],"variables":[],"duration":"1h","refreshInterval":"0s"}}
+  dashboard-mesh.json: |
+    {"kind":"Dashboard","metadata":{"name":"istio-mesh-dashboard","createdAt":"2025-07-10T13:20:44.194148813Z","updatedAt":"2025-07-10T13:20:44.394597152Z","version":1,"project":"istio"},"spec":{"display":{"name":"Istio Mesh Dashboard"},"panels":{"httpgrpcworkloads":{"kind":"Panel","spec":{"display":{"name":"HTTP/gRPC Workloads","description":"Request information for HTTP services"},"plugin":{"kind":"Table","spec":{"columnSettings":[{"header":"Requests","name":"Value #requests"},{"header":"P50 Latency","name":"Value #p50"},{"header":"P90 Latency","name":"Value #p90"},{"header":"P99 Latency","name":"Value #p99"},{"header":"Success Rate","name":"Value #success"},{"header":"Workload","name":"destination_workload_var"},{"header":"Service","name":"destination_service"},{"name":"destination_workload_namespace"},{"name":"destination_workload"},{"name":"timestamp"}],"density":"compact","transforms":[{"kind":"MergeSeries","spec":{}}]}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(sum by (destination_workload,destination_workload_namespace,destination_service) (rate(istio_requests_total{reporter=~\"source|waypoint\"}[$__rate_interval])), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(histogram_quantile(0.5, sum by (le,destination_workload,destination_workload_namespace) (rate(istio_request_duration_milliseconds_bucket{reporter=~\"source|waypoint\"}[$__rate_interval]))), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(histogram_quantile(0.9, sum by (le,destination_workload,destination_workload_namespace) (rate(istio_request_duration_milliseconds_bucket{reporter=~\"source|waypoint\"}[$__rate_interval]))), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(histogram_quantile(0.99, sum by (le,destination_workload,destination_workload_namespace) (rate(istio_request_duration_milliseconds_bucket{reporter=~\"source|waypoint\"}[$__rate_interval]))), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(sum by (destination_workload,destination_workload_namespace) (rate(istio_requests_total{reporter=~\"source|waypoint\",response_code!~\"5..\"}[$__rate_interval]))/sum by (destination_workload,destination_workload_namespace) (rate(istio_requests_total{reporter=~\"source|waypoint\"}[$__rate_interval])), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}}]}},"istio_component_versions":{"kind":"Panel","spec":{"display":{"name":"Istio Component Versions","description":"Version number of each running instance"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum by (component,tag) (istio_build)","seriesNameFormat":"{{component}} ({{tag}})"}}}}]}},"requests4xx":{"kind":"Panel","spec":{"display":{"name":"4xxs","description":"Total 4xx requests in in the cluster"},"plugin":{"kind":"StatChart","spec":{"calculation":"last-number","metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum (rate(istio_requests_total{reporter=~\"source|waypoint\",response_code=~\"4..\"}[$__rate_interval])), 0.01)or vector(0)"}}}}]}},"requests5xx":{"kind":"Panel","spec":{"display":{"name":"5xxs","description":"Total 5xx requests in in the cluster"},"plugin":{"kind":"StatChart","spec":{"calculation":"last-number","metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum (rate(istio_requests_total{reporter=~\"source|waypoint\",response_code=~\"5..\"}[$__rate_interval])), 0.01)or vector(0)"}}}}]}},"successrate":{"kind":"Panel","spec":{"display":{"name":"Success Rate","description":"Total success rate of requests in the cluster"},"plugin":{"kind":"StatChart","spec":{"calculation":"last-number","format":{"unit":"percent-decimal"},"metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum (rate(istio_requests_total{reporter=~\"source|waypoint\",response_code!~\"5..\"}[$__rate_interval])) / sum (rate(istio_requests_total{reporter=~\"source|waypoint\"}[$__rate_interval]))"}}}}]}},"tcpworkloads":{"kind":"Panel","spec":{"display":{"name":"TCP Workloads","description":"Bytes sent and recieived information for TCP services"},"plugin":{"kind":"Table","spec":{"columnSettings":[{"header":"Bytes Received","name":"Value #recv"},{"header":"Bytes Sent","name":"Value #sent"},{"header":"Workload","name":"destination_workload_var"},{"header":"Service","name":"destination_service"},{"name":"destination_workload_namespace"},{"name":"destination_workload"},{"name":"timestamp"}],"density":"compact","transforms":[{"kind":"MergeSeries","spec":{}}]}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(sum by (destination_workload,destination_workload_namespace,destination_service) (rate(istio_tcp_received_bytes_total{reporter=~\"source|waypoint\"}[$__rate_interval])), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"label_join(sum by (destination_workload,destination_workload_namespace,destination_service) (rate(istio_tcp_sent_bytes_total{reporter=~\"source|waypoint\"}[$__rate_interval])), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","seriesNameFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}"}}}}]}},"trafficvolume":{"kind":"Panel","spec":{"display":{"name":"Traffic Volume","description":"Total requests in the cluster"},"plugin":{"kind":"StatChart","spec":{"calculation":"last-number","metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum (rate(istio_requests_total{reporter=~\"source|waypoint\"}[$__rate_interval])), 0.01)"}}}}]}}},"layouts":[{"kind":"Grid","spec":{"display":{"title":"Global Traffic","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":6,"height":5,"content":{"$ref":"#/spec/panels/trafficvolume"}},{"x":6,"y":0,"width":6,"height":5,"content":{"$ref":"#/spec/panels/successrate"}},{"x":12,"y":0,"width":6,"height":5,"content":{"$ref":"#/spec/panels/requests4xx"}},{"x":18,"y":0,"width":6,"height":5,"content":{"$ref":"#/spec/panels/requests5xx"}}]}},{"kind":"Grid","spec":{"display":{"title":"Global Traffic","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":16,"content":{"$ref":"#/spec/panels/httpgrpcworkloads"}},{"x":0,"y":16,"width":24,"height":16,"content":{"$ref":"#/spec/panels/tcpworkloads"}}]}},{"kind":"Grid","spec":{"display":{"title":"Istio Component Versions","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":8,"content":{"$ref":"#/spec/panels/istio_component_versions"}}]}}],"variables":[],"duration":"1h","refreshInterval":"0s"}}
+  dashboard-workload.json: |
+    {"kind":"Dashboard","metadata":{"name":"istio-workload-dashboard","createdAt":"2025-07-10T13:20:44.56971587Z","updatedAt":"2025-07-10T13:20:45.043819803Z","version":1,"project":"istio"},"spec":{"display":{"name":"Istio Workload Dashboard"},"panels":{"inboundrequestduration":{"kind":"Panel","spec":{"display":{"name":"Incoming Request Duration By Source"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"seconds"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P99"}}}}]}},"inboundrequests":{"kind":"Panel","spec":{"display":{"name":"Incoming Requests By Source And Response Code"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=~\"$qrep\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=~\"$qrep\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}"}}}}]}},"inboundrequestsize":{"kind":"Panel","spec":{"display":{"name":"Incoming Request Size By Source"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}}  P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}}  P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P99"}}}}]}},"inboundresponsesize":{"kind":"Panel","spec":{"display":{"name":"Response Size By Source"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}}  P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}}  P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))","seriesNameFormat":"{{source_workload}}.{{source_workload_namespace}} P99"}}}}]}},"inboundsuccessrate":{"kind":"Panel","spec":{"display":{"name":"Incoming Success Rate (non-5xx responses) By Source"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"percent-decimal"},"max":1.01,"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_requests_total{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_requests_total{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace }}"}}}}]}},"inboundtcpbytesreceived":{"kind":"Panel","spec":{"display":{"name":"Bytes Received from Incoming TCP Connection"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes/sec"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\"$qrep\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[$__rate_interval])) by (source_workload, source_workload_namespace), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\"$qrep\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[$__rate_interval])) by (source_workload, source_workload_namespace), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace}}"}}}}]}},"inboundtcpbytessent":{"kind":"Panel","spec":{"display":{"name":"Bytes Sent to Incoming TCP Connection"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes/sec"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=~\"$qrep\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[$__rate_interval])) by (source_workload, source_workload_namespace), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=~\"$qrep\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[$__rate_interval])) by (source_workload, source_workload_namespace), 0.001)","seriesNameFormat":"{{ source_workload }}.{{ source_workload_namespace}}"}}}}]}},"inboundworkloads":{"kind":"Panel","spec":{"display":{"name":"INBOUND WORKLOADS"},"plugin":{"kind":"Markdown","spec":{"text":"<div class=\"dashboard-header text-center\">\n<span>INBOUND WORKLOADS</span>\n</div>"}}}},"outboundrequestduration":{"kind":"Panel","spec":{"display":{"name":"Outgoing Request Duration By Destination"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"seconds"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P99"}}}}]}},"outboundrequests":{"kind":"Panel","spec":{"display":{"name":"Outgoing Requests By Destination And Response Code"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_requests_total{destination_principal=~\"spiffe.*\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)","seriesNameFormat":"{{ destination_service }} : {{ response_code }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_requests_total{destination_principal!~\"spiffe.*\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)","seriesNameFormat":"{{ destination_service }} : {{ response_code }}"}}}}]}},"outboundrequestsize":{"kind":"Panel","spec":{"display":{"name":"Outgoing Request Size By Destination"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P99"}}}}]}},"outboundresponsesize":{"kind":"Panel","spec":{"display":{"name":"Response Size By Destination"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }}  P99 (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P95"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))","seriesNameFormat":"{{ destination_service }} P99"}}}}]}},"outboundservices":{"kind":"Panel","spec":{"display":{"name":"OUTBOUND SERVICES"},"plugin":{"kind":"Markdown","spec":{"text":"<div class=\"dashboard-header text-center\">\n<span>OUTBOUND SERVICES</span>\n</div>"}}}},"outboundsuccessrate":{"kind":"Panel","spec":{"display":{"name":"Outgoing Success Rate (non-5xx responses) By Destination"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"percent-decimal"},"max":1.01,"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)","seriesNameFormat":"{{ destination_service }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)","seriesNameFormat":"{{ destination_service }}"}}}}]}},"outboundtcpbytesreceived":{"kind":"Panel","spec":{"display":{"name":"Bytes Received from Outgoing TCP Connection"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes/sec"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[$__rate_interval])) by (destination_service), 0.001)","seriesNameFormat":"{{ destination_service }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[$__rate_interval])) by (destination_service), 0.001)","seriesNameFormat":"{{ destination_service }}"}}}}]}},"outboundtcpbytessent":{"kind":"Panel","spec":{"display":{"name":"Bytes Sent on Outgoing TCP Connection"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"bottom","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"bytes/sec"},"min":0}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[$__rate_interval])) by (destination_service), 0.001)","seriesNameFormat":"{{ destination_service }} (🔐mTLS)"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[$__rate_interval])) by (destination_service), 0.001)","seriesNameFormat":"{{ destination_service }}"}}}}]}},"requestduration":{"kind":"Panel","spec":{"display":{"name":"Request Duration"},"plugin":{"kind":"TimeSeriesChart","spec":{"legend":{"mode":"list","position":"right","values":[]},"visual":{"areaOpacity":0.1,"connectNulls":false,"display":"line","lineWidth":1},"yAxis":{"format":{"unit":"seconds"}}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"minStep":"","query":"(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))","seriesNameFormat":"P50"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))","seriesNameFormat":"P90"}}}},{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\"$qrep\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))","seriesNameFormat":"P99"}}}}]}},"statchart":{"kind":"Panel","spec":{"display":{"name":"Incoming Request Volume"},"plugin":{"kind":"StatChart","spec":{"calculation":"last-number","mappings":[{"kind":"Misc","spec":{"result":{"value":"N/A"},"value":"null"}}],"metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"round(sum(irate(istio_requests_total{reporter=~\"$qrep\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)"}}}}]}},"successrate":{"kind":"Panel","spec":{"display":{"name":"Incoming Success Rate (non-5xx responses)"},"plugin":{"kind":"StatChart","spec":{"calculation":"mean","format":{"unit":"percent-decimal"},"mappings":[{"kind":"Misc","spec":{"result":{"value":"N/A"},"value":"null"}}],"metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"rgba(50, 172, 45, 0.97)","value":0},{"color":"rgba(237, 129, 40, 0.89)","value":95},{"color":"rgba(245, 54, 54, 0.9)","value":99}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_requests_total{reporter=~\"$qrep\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=~\"$qrep\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))"}}}}]}},"tcpclienttraffic":{"kind":"Panel","spec":{"display":{"name":"TCP Client Traffic"},"plugin":{"kind":"StatChart","spec":{"calculation":"mean","format":{"unit":"bytes/sec"},"mappings":[{"kind":"Misc","spec":{"result":{"value":"N/A"},"value":"null"}}],"metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_tcp_sent_bytes_total{reporter=~\"$qrep\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[$__rate_interval])) + sum(irate(istio_tcp_received_bytes_total{reporter=~\"$qrep\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[$__rate_interval]))","seriesNameFormat":""}}}}]}},"tcpservertraffic":{"kind":"Panel","spec":{"display":{"name":"TCP Server Traffic"},"plugin":{"kind":"StatChart","spec":{"calculation":"mean","format":{"unit":"bytes/sec"},"mappings":[{"kind":"Misc","spec":{"result":{"value":"N/A"},"value":"null"}}],"metricLabel":"","sparkline":{},"thresholds":{"steps":[{"color":"green","value":0},{"color":"red","value":80}]}}},"queries":[{"kind":"TimeSeriesQuery","spec":{"plugin":{"kind":"PrometheusTimeSeriesQuery","spec":{"datasource":{"kind":"PrometheusDatasource","name":"prometheus"},"query":"sum(irate(istio_tcp_sent_bytes_total{reporter=~\"$qrep\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[$__rate_interval])) + sum(irate(istio_tcp_received_bytes_total{reporter=~\"$qrep\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[$__rate_interval]))","seriesNameFormat":""}}}}]}},"workload":{"kind":"Panel","spec":{"display":{"name":"WORKLOAD"},"plugin":{"kind":"Markdown","spec":{"text":"<div class=\"dashboard-header text-center\">\n<span>WORKLOAD: $workload.$namespace</span>\n</div>"}}}}},"layouts":[{"kind":"Grid","spec":{"display":{"title":"General","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":3,"content":{"$ref":"#/spec/panels/workload"}},{"x":0,"y":3,"width":8,"height":4,"content":{"$ref":"#/spec/panels/statchart"}},{"x":8,"y":3,"width":8,"height":4,"content":{"$ref":"#/spec/panels/successrate"}},{"x":16,"y":3,"width":8,"height":4,"content":{"$ref":"#/spec/panels/requestduration"}}]}},{"kind":"Grid","spec":{"display":{"title":"General (II)","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":12,"height":4,"content":{"$ref":"#/spec/panels/tcpservertraffic"}},{"x":12,"y":0,"width":12,"height":4,"content":{"$ref":"#/spec/panels/tcpclienttraffic"}}]}},{"kind":"Grid","spec":{"display":{"title":"Inbound Workloads","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":3,"content":{"$ref":"#/spec/panels/inboundworkloads"}},{"x":0,"y":3,"width":12,"height":6,"content":{"$ref":"#/spec/panels/inboundrequests"}},{"x":12,"y":3,"width":12,"height":6,"content":{"$ref":"#/spec/panels/inboundsuccessrate"}}]}},{"kind":"Grid","spec":{"display":{"title":"Inbound Workloads (II)","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/inboundrequestduration"}},{"x":8,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/inboundrequestsize"}},{"x":16,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/inboundresponsesize"}}]}},{"kind":"Grid","spec":{"display":{"title":"Inbound Workloads (III)","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":12,"height":6,"content":{"$ref":"#/spec/panels/inboundtcpbytesreceived"}},{"x":12,"y":0,"width":12,"height":6,"content":{"$ref":"#/spec/panels/inboundtcpbytessent"}}]}},{"kind":"Grid","spec":{"display":{"title":"Outbound Services","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":24,"height":3,"content":{"$ref":"#/spec/panels/outboundservices"}},{"x":0,"y":3,"width":12,"height":6,"content":{"$ref":"#/spec/panels/outboundrequests"}},{"x":12,"y":3,"width":12,"height":6,"content":{"$ref":"#/spec/panels/outboundsuccessrate"}}]}},{"kind":"Grid","spec":{"display":{"title":"Outbound Services (II)","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/outboundrequestduration"}},{"x":8,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/outboundrequestsize"}},{"x":16,"y":0,"width":8,"height":6,"content":{"$ref":"#/spec/panels/outboundresponsesize"}}]}},{"kind":"Grid","spec":{"display":{"title":"Outbound Services (III)","collapse":{"open":true}},"items":[{"x":0,"y":0,"width":12,"height":6,"content":{"$ref":"#/spec/panels/outboundtcpbytessent"}},{"x":12,"y":0,"width":12,"height":6,"content":{"$ref":"#/spec/panels/outboundtcpbytesreceived"}}]}}],"variables":[{"kind":"ListVariable","spec":{"display":{"name":"Namespace","hidden":false},"defaultValue":"bookinfo","allowAllValue":false,"allowMultiple":false,"plugin":{"kind":"PrometheusPromQLVariable","spec":{"expr":"sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace)","labelName":"destination_workload_namespace"}},"name":"namespace"}},{"kind":"ListVariable","spec":{"display":{"name":"Workload","hidden":false},"defaultValue":"details-v1","allowAllValue":false,"allowMultiple":false,"sort":"alphabetical-asc","plugin":{"kind":"PrometheusPromQLVariable","spec":{"expr":"(sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload))","labelName":"source_workload"}},"name":"workload"}},{"kind":"ListVariable","spec":{"display":{"name":"Reporter","hidden":false},"defaultValue":["destination"],"allowAllValue":false,"allowMultiple":true,"plugin":{"kind":"StaticListVariable","spec":{"values":["source","destination"]}},"name":"qrep"}},{"kind":"ListVariable","spec":{"display":{"name":"Inbound Workload Namespace","hidden":false},"defaultValue":"$__all","allowAllValue":true,"allowMultiple":true,"sort":"alphabetical-desc","plugin":{"kind":"PrometheusPromQLVariable","spec":{"expr":"sum(istio_requests_total{reporter=~\"$qrep\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=~\"$qrep\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace)","labelName":"source_workload_namespace"}},"name":"srcns"}},{"kind":"ListVariable","spec":{"display":{"name":"Inbound Workload","hidden":false},"defaultValue":"$__all","allowAllValue":true,"allowMultiple":true,"sort":"numerical-asc","plugin":{"kind":"PrometheusPromQLVariable","spec":{"expr":"sum(istio_requests_total{reporter=~\"$qrep\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=~\"$qrep\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload)","labelName":"source_workload"}},"name":"srcwl"}},{"kind":"ListVariable","spec":{"display":{"name":"Destination Service","hidden":false},"defaultValue":"$__all","allowAllValue":true,"allowMultiple":true,"sort":"numerical-desc","plugin":{"kind":"PrometheusPromQLVariable","spec":{"expr":"sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service)","labelName":"destination_service"}},"name":"dstsvc"}}],"duration":"1h","refreshInterval":"0s"}}
diff --git a/hack/istio/perses/datasource.yaml b/hack/istio/perses/datasource.yaml
new file mode 100644
index 000000000..60799fbb5
--- /dev/null
+++ b/hack/istio/perses/datasource.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: perses-provisioning-dsh
+  namespace: istio-system
+  labels:
+    perses.dev/resource: "true"
+data:
+  datasources.yaml: |
+    apiVersion: perses.dev/v1alpha1
+    kind: Datasource
+    metadata:
+      name: prometheus
+      project: istio
+    spec:
+      default: true
+      plugin:
+        kind: PrometheusDatasource
+        spec:
+          proxy:
+            kind: HTTPProxy
+            spec:
+              url: 'http://prometheus.istio-system:9090'
diff --git a/hack/istio/perses/project.yaml b/hack/istio/perses/project.yaml
new file mode 100644
index 000000000..e536c44ff
--- /dev/null
+++ b/hack/istio/perses/project.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: perses-provisioning-py
+  namespace: istio-system
+  labels:
+    perses.dev/resource: "true"
+data:
+  project.yaml: |
+    apiVersion: perses.dev/v1alpha1
+    kind: Project
+    metadata:
+      name: istio
+    spec: {}
diff --git a/hack/istio/perses/values.yaml b/hack/istio/perses/values.yaml
new file mode 100644
index 000000000..5d50020ea
--- /dev/null
+++ b/hack/istio/perses/values.yaml
@@ -0,0 +1,6 @@
+sidecar:
+  enabled: true
+logLevel: "debug"
+config:
+  provisioning:
+    interval: 1m
diff --git a/hack/run-integration-tests.sh b/hack/run-integration-tests.sh
index da18059ff..53c8d9bad 100755
--- a/hack/run-integration-tests.sh
+++ b/hack/run-integration-tests.sh
@@ -175,7 +175,6 @@ fi
 
 # Determine where this script is and make it the cwd
 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
-source ${SCRIPT_DIR}/istio/functions.sh
 
 # This is used in multiple places and you need to call 'setKialiURL' first.
 KIALI_URL=""
@@ -390,7 +389,7 @@ elif [ "${TEST_SUITE}" == "${FRONTEND}" ]; then
   ensureCypressInstalled
   
   if [ "${TESTS_ONLY}" == "false" ]; then
-    "${SCRIPT_DIR}"/setup-kind-in-ci.sh --auth-strategy token --sail true ${ISTIO_VERSION_ARG} ${HELM_CHARTS_DIR_ARG}
+    "${SCRIPT_DIR}"/setup-kind-in-ci.sh --auth-strategy token --sail true ${ISTIO_VERSION_ARG} ${HELM_CHARTS_DIR_ARG} --install-perses "true"
 
     # Install demo apps
     "${SCRIPT_DIR}"/istio/install-testing-demos.sh -c "kubectl"
@@ -411,7 +410,6 @@ elif [ "${TEST_SUITE}" == "${FRONTEND}" ]; then
   yarn run cypress:run
   detectRaceConditions
 elif [ "${TEST_SUITE}" == "${FRONTEND_AMBIENT}" ]; then
-
   ensureCypressInstalled
   ensureKialiTracesReady "true"
 
@@ -435,25 +433,8 @@ elif [ "${TEST_SUITE}" == "${FRONTEND_AMBIENT}" ]; then
   fi
 
   cd "${SCRIPT_DIR}"/../frontend
-
-  # TODO: Remove when no support for Istio 1.23 is required
-  # Replace by "yarn run cypress:run:ambient"
-  if [ "${ISTIO_VERSION}" != "" ]; then
-    set +e
-    is_istio_version_eq_greater_than_expected "1.24.0" "${ISTIO_VERSION}"
-    status=$?
-    if [ "$status" -eq 0 ]; then
-      yarn run cypress:run:ambient123
-    else
-      yarn run cypress:run:ambient
-    fi
-    set -e
-  else
-    yarn run cypress:run:ambient
-  fi
-
+  yarn run cypress:run:ambient
   detectRaceConditions
-
 elif [ "${TEST_SUITE}" == "${FRONTEND_PRIMARY_REMOTE}" ]; then
   ensureCypressInstalled
   
diff --git a/hack/setup-kind-in-ci.sh b/hack/setup-kind-in-ci.sh
index 3c6b33d42..ad56d7f66 100755
--- a/hack/setup-kind-in-ci.sh
+++ b/hack/setup-kind-in-ci.sh
@@ -12,6 +12,7 @@ PRIMARY_REMOTE="primary-remote"
 KEYCLOAK_LIMIT_MEMORY=""
 KEYCLOAK_REQUESTS_MEMORY=""
 
+INSTALL_PERSES="false"
 
 infomsg() {
   echo "[INFO] ${1}"
@@ -36,6 +37,10 @@ Options:
 -hcd|--helm-charts-dir
     Directory where the Kiali helm charts are located.
     If one is not supplied a /tmp dir will be created and used.
+-ip|--install-perses <true|false>
+    Whether to deploy Perses as part of the setup.
+    Helm charts will be installed.
+    Default: false
 -iv|--istio-version <#.#.#>
     The version of Istio you want to install.
     If you want to run with a dev build of Istio, the value must be something like "#.#-dev".
@@ -75,6 +80,7 @@ while [[ $# -gt 0 ]]; do
     -dorp|--docker-or-podman)     DORP="$2";                  shift;shift; ;;
     -h|--help)                    helpmsg;                    exit 1       ;;
     -hcd|--helm-charts-dir)       HELM_CHARTS_DIR="$2";       shift;shift; ;;
+    -ip|--install-perses)         INSTALL_PERSES="$2";        shift;shift; ;;
     -iv|--istio-version)          ISTIO_VERSION="$2";         shift;shift; ;;
     -klm|--keycloak-limit-memory) KEYCLOAK_LIMIT_MEMORY="$2"; shift;shift; ;;
     -krm|--keycloak-requests-memory) KEYCLOAK_REQUESTS_MEMORY="$2"; shift;shift; ;;
@@ -333,6 +339,26 @@ setup_kind_singlecluster() {
     "${SCRIPT_DIR}"/istio/install-istio-via-istioctl.sh --reduce-resources true --client-exe-path "$(which kubectl)" -cn "cluster-default" -mid "mesh-default" -net "network-default" -gae true ${hub_arg:-}
   fi
 
+  PERSES_ARGS=()
+  if [ "${INSTALL_PERSES}" == "true" ]; then
+    infomsg "Installing Perses"
+    kubectl apply -f "${SCRIPT_DIR}"/istio/perses/project.yaml
+    kubectl apply -f "${SCRIPT_DIR}"/istio/perses/datasource.yaml
+    kubectl apply -f "${SCRIPT_DIR}"/istio/perses/dashboard.yaml
+
+    ${HELM} repo add perses https://perses.github.io/helm-charts
+    ${HELM} install perses perses/perses -n istio-system -f "${SCRIPT_DIR}"/istio/perses/values.yaml
+          PERSES_ARGS=(
+        "--set" "external_services.perses.enabled=true"
+        "--set" "external_services.perses.internal_url=http://perses.istio-system:8080"
+        "--set" "external_services.perses.external_url=http://localhost:4000"
+        "--set" "external_services.perses.dashboards[0].name=Istio Mesh Dashboard"
+        "--set" "external_services.perses.dashboards[0].variables.namespace=var-namespace"
+        "--set" "external_services.perses.dashboards[0].variables.workload=var-workload"
+        "--set" "external_services.perses.dashboards[0].variables.datasource=var-datasource"
+      )
+  fi
+
   if [ "${DEPLOY_KIALI}" != "true" ]; then
     infomsg "Skipping Kiali deployment as requested"
     return
@@ -362,6 +388,7 @@ setup_kind_singlecluster() {
     --set deployment.service_type="LoadBalancer" \
     --set external_services.grafana.external_url="http://grafana.istio-system:3000" \
     --set external_services.grafana.dashboards[0].name="Istio Mesh Dashboard" \
+    "${PERSES_ARGS[@]}" \
     --set external_services.tracing.enabled="true" \
     --set external_services.tracing.external_url="http://tracing.istio-system:16685/jaeger" \
     --set external_services.istio.validation_reconcile_interval="5s" \
diff --git a/kubernetes/kubernetes.go b/kubernetes/kubernetes.go
index b6a2e1c8a..5c63fca2b 100644
--- a/kubernetes/kubernetes.go
+++ b/kubernetes/kubernetes.go
@@ -15,7 +15,6 @@ import (
 
 	osapps_v1 "github.com/openshift/api/apps/v1"
 	osoauth_v1 "github.com/openshift/api/oauth/v1"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	osroutes_v1 "github.com/openshift/api/route/v1"
 	osuser_v1 "github.com/openshift/api/user/v1"
 	"go.opentelemetry.io/otel"
@@ -76,15 +75,12 @@ type OSClientInterface interface {
 	GetDeploymentConfig(ctx context.Context, namespace string, name string) (*osapps_v1.DeploymentConfig, error)
 	GetDeploymentConfigs(ctx context.Context, namespace string) ([]osapps_v1.DeploymentConfig, error)
 	GetOAuthClient(ctx context.Context, name string) (*osoauth_v1.OAuthClient, error)
-	GetProject(ctx context.Context, project string) (*osproject_v1.Project, error)
-	GetProjects(ctx context.Context, labelSelector string) ([]osproject_v1.Project, error)
 	GetRoute(ctx context.Context, namespace string, name string) (*osroutes_v1.Route, error)
 	GetUser(ctx context.Context, name string) (*osuser_v1.User, error)
 }
 
 type OSUserClientInterface interface {
 	OSClientInterface
-	UpdateProject(ctx context.Context, project string, jsonPatch string) (*osproject_v1.Project, error)
 }
 
 func (in *K8SClient) ForwardGetRequest(namespace, podName string, destinationPort int, path string) ([]byte, error) {
@@ -178,22 +174,6 @@ func (in *K8SClient) GetNamespaces(labelSelector string) ([]core_v1.Namespace, e
 	return namespaces.Items, nil
 }
 
-// GetProject fetches and returns the definition of the project with
-// the specified name by querying the cluster API. GetProject will fail
-// if the underlying cluster is not Openshift.
-func (in *K8SClient) GetProject(ctx context.Context, name string) (*osproject_v1.Project, error) {
-	return in.projectClient.ProjectV1().Projects().Get(ctx, name, emptyGetOptions)
-}
-
-func (in *K8SClient) GetProjects(ctx context.Context, labelSelector string) ([]osproject_v1.Project, error) {
-	projects, err := in.projectClient.ProjectV1().Projects().List(ctx, meta_v1.ListOptions{LabelSelector: labelSelector})
-	if err != nil {
-		return nil, err
-	}
-
-	return projects.Items, nil
-}
-
 func (in *K8SClient) GetDeploymentConfig(ctx context.Context, namespace string, name string) (*osapps_v1.DeploymentConfig, error) {
 	return in.osAppsClient.AppsV1().DeploymentConfigs(namespace).Get(ctx, name, emptyGetOptions)
 }
@@ -219,10 +199,6 @@ func (in *K8SClient) DeleteOAuthToken(ctx context.Context, token string) error {
 	return in.oAuthClient.OauthV1().OAuthAccessTokens().Delete(ctx, token, meta_v1.DeleteOptions{})
 }
 
-func (in *K8SClient) UpdateProject(ctx context.Context, project string, jsonPatch string) (*osproject_v1.Project, error) {
-	return in.projectClient.ProjectV1().Projects().Patch(ctx, project, types.MergePatchType, []byte(jsonPatch), meta_v1.PatchOptions{})
-}
-
 func (in *K8SClient) GetRoute(ctx context.Context, namespace string, name string) (*osroutes_v1.Route, error) {
 	return in.routeClient.RouteV1().Routes(namespace).Get(ctx, name, emptyGetOptions)
 }
diff --git a/make/Makefile.build.mk b/make/Makefile.build.mk
index 162a5c623..76297d3e9 100644
--- a/make/Makefile.build.mk
+++ b/make/Makefile.build.mk
@@ -59,14 +59,14 @@ build-linux-multi-arch: go-check
 	@for arch in ${TARGET_ARCHS}; do \
 		echo "Building for architecture [$${arch}]"; \
 		${GO_BUILD_ENVVARS} GOOS=linux GOARCH=$${arch} ${GO} build \
-			-o ${GOPATH}/bin/kiali-$${arch} -ldflags "-X main.version=${VERSION} -X main.commitHash=${COMMIT_HASH} -X main.goVersion=${GO_ACTUAL_VERSION}" ${GO_BUILD_FLAGS}; \
+			-o ${GOPATH}/bin/kiali-$${arch} -ldflags "-X github.com/kiali/kiali/cmd.version=${VERSION} -X github.com/kiali/kiali/cmd.commitHash=${COMMIT_HASH} -X github.com/kiali/kiali/cmd.goVersion=${GO_ACTUAL_VERSION}" ${GO_BUILD_FLAGS}; \
 	done
 
 ## install: Install missing dependencies. Runs `go install` internally
 install: go-check
 	@echo Installing...
 	${GO_BUILD_ENVVARS} ${GO} install \
-		-ldflags "-X main.version=${VERSION} -X main.commitHash=${COMMIT_HASH} -X main.goVersion=${GO_ACTUAL_VERSION}"
+		-ldflags "-X github.com/kiali/kiali/cmd.version=${VERSION} -X github.com/kiali/kiali/cmd.commitHash=${COMMIT_HASH} -X github.com/kiali/kiali/cmd.goVersion=${GO_ACTUAL_VERSION}"
 
 ## format: Format all the files excluding vendor. Runs `gofmt` and `goimports` internally
 format:
@@ -80,7 +80,7 @@ format:
 build-system-test: go-check
 	@echo Building executable for system tests with code coverage enabled
 	${GO} test -c -covermode=count -coverpkg $(shell ${GO} list ./... | grep -v test |  awk -vORS=, "{ print $$1 }" | sed "s/,$$//") \
-	  -o ${GOPATH}/bin/kiali -ldflags "-X main.version=${VERSION} -X main.commitHash=${COMMIT_HASH} -X main.goVersion=${GO_ACTUAL_VERSION}"
+	  -o ${GOPATH}/bin/kiali -ldflags "-X github.com/kiali/kiali/cmd.version=${VERSION} -X github.com/kiali/kiali/cmd.commitHash=${COMMIT_HASH} -X github.com/kiali/kiali/cmd.goVersion=${GO_ACTUAL_VERSION}"
 
 ## test: Run tests, excluding third party tests under vendor and frontend. Runs `go test` internally
 test: .ensure-envtest-bin-dir-exists
diff --git a/models/namespace.go b/models/namespace.go
index ce57303d0..22adcf498 100644
--- a/models/namespace.go
+++ b/models/namespace.go
@@ -3,7 +3,6 @@ package models
 import (
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	core_v1 "k8s.io/api/core/v1"
 
 	"github.com/kiali/kiali/config"
@@ -99,29 +98,6 @@ func CastNamespace(ns core_v1.Namespace, cluster string) Namespace {
 	return namespace
 }
 
-func CastProjectCollection(ps []osproject_v1.Project, cluster string) []Namespace {
-	namespaces := make([]Namespace, len(ps))
-	for i, project := range ps {
-		namespaces[i] = CastProject(project, cluster)
-	}
-
-	return namespaces
-}
-
-func CastProject(p osproject_v1.Project, cluster string) Namespace {
-	istioLabels := config.Get().IstioLabels
-	namespace := Namespace{}
-	namespace.Name = p.Name
-	namespace.Cluster = cluster
-	namespace.CreationTimestamp = p.CreationTimestamp.Time
-	namespace.Labels = p.Labels
-	namespace.Annotations = p.Annotations
-	if p.Labels[istioLabels.AmbientNamespaceLabel] == istioLabels.AmbientNamespaceLabelValue {
-		namespace.IsAmbient = true
-	}
-	return namespace
-}
-
 func (nss Namespaces) Includes(namespace string) bool {
 	for _, ns := range nss {
 		if ns.Name == namespace {



Test patch:
diff --git a/business/apps_test.go b/business/apps_test.go
index e6401c950..16bfd9055 100644
--- a/business/apps_test.go
+++ b/business/apps_test.go
@@ -5,9 +5,9 @@ import (
 	"strings"
 	"testing"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	core_v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 
@@ -36,7 +36,6 @@ func TestGetAppListFromDeployments(t *testing.T) {
 	// Auxiliar fake* tests defined in workload_test.go
 	objects := []runtime.Object{
 		kubetest.FakeNamespace("Namespace"),
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeployments(*conf) {
 		o := obj
@@ -71,7 +70,6 @@ func TestGetAppListFromWorkloadGroups(t *testing.T) {
 	// Auxiliar fake* tests defined in workload_test.go
 	kubeObjs := []runtime.Object{
 		kubetest.FakeNamespace("Namespace"),
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range data.CreateWorkloadGroups(*conf) {
 		o := obj
@@ -119,7 +117,7 @@ func TestGetAppFromDeployments(t *testing.T) {
 
 	// Setup mocks
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+		&core_v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeployments(*conf) {
 		o := obj
@@ -159,7 +157,7 @@ func TestGetAppFromDeploymentsNoAppVerLabelNames(t *testing.T) {
 
 	// Setup mocks
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+		&core_v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeployments(*conf) {
 		o := obj
@@ -201,7 +199,7 @@ func TestGetAppFromWorkloadGroups(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+		&core_v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range data.CreateWorkloadGroups(*conf) {
 		o := obj
@@ -243,7 +241,7 @@ func TestGetAppListFromReplicaSets(t *testing.T) {
 	// Setup mocks
 	// Auxiliar fake* tests defined in workload_test.go
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+		&core_v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeReplicaSets(*conf) {
 		o := obj
@@ -276,7 +274,7 @@ func TestGetAppFromReplicaSets(t *testing.T) {
 
 	// Setup mocks
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+		&core_v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeReplicaSets(*conf) {
 		o := obj
diff --git a/business/health_test.go b/business/health_test.go
index 22a2664ec..255d27b21 100644
--- a/business/health_test.go
+++ b/business/health_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/prometheus/common/model"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
@@ -31,7 +30,7 @@ func TestGetServiceHealth(t *testing.T) {
 	config.Set(conf)
 
 	k8s := kubetest.NewFakeK8sClient(
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 	)
 	k8s.OpenShift = true
@@ -68,7 +67,7 @@ func TestGetAppHealth(t *testing.T) {
 	conf := config.NewConfig()
 	config.Set(conf)
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 	}
 	for _, obj := range fakeDeploymentsHealthReview() {
@@ -123,7 +122,7 @@ func TestGetWorkloadHealth(t *testing.T) {
 	conf := config.NewConfig()
 	config.Set(conf)
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 		&fakeDeploymentsHealthReview()[0],
 	}
@@ -171,7 +170,7 @@ func TestGetAppHealthWithoutIstio(t *testing.T) {
 	conf := config.NewConfig()
 
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 	}
 	for _, obj := range fakeDeploymentsHealthReview() {
@@ -204,7 +203,7 @@ func TestGetWorkloadHealthWithoutIstio(t *testing.T) {
 	conf := config.NewConfig()
 	config.Set(conf)
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 		&fakeDeploymentsHealthReview()[0],
 	}
@@ -237,7 +236,7 @@ func TestGetNamespaceAppHealthWithoutIstio(t *testing.T) {
 	config.Set(conf)
 
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 	}
 	for _, obj := range fakeDeploymentsHealthReview() {
@@ -270,8 +269,8 @@ func TestGetNamespaceServiceHealthWithNA(t *testing.T) {
 	reviews := kubetest.FakeService("tutorial", "reviews")
 	httpbin := kubetest.FakeService("tutorial", "httpbin")
 	k8s := kubetest.NewFakeK8sClient(
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}},
 		&core_v1.Service{ObjectMeta: meta_v1.ObjectMeta{Name: "httpbin", Namespace: "ns"}},
 		&reviews,
 		&httpbin,
diff --git a/business/istio_config_test.go b/business/istio_config_test.go
index 081988c9f..0c34ce1e2 100644
--- a/business/istio_config_test.go
+++ b/business/istio_config_test.go
@@ -6,12 +6,12 @@ import (
 	"time"
 
 	"github.com/golang/protobuf/ptypes/wrappers"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	api_networking_v1 "istio.io/api/networking/v1"
 	networking_v1 "istio.io/client-go/pkg/apis/networking/v1"
 	auth_v1 "k8s.io/api/authorization/v1"
+	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 
@@ -212,7 +212,7 @@ func TestCheckMulticlusterPermissions(t *testing.T) {
 }
 
 func mockGetIstioConfigList(t *testing.T) IstioConfigService {
-	fakeIstioObjects := []runtime.Object{&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}}}
+	fakeIstioObjects := []runtime.Object{&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}}}
 	for _, g := range fakeGetGateways() {
 		fakeIstioObjects = append(fakeIstioObjects, g.DeepCopyObject())
 	}
@@ -405,7 +405,7 @@ func mockGetIstioConfigDetails(t *testing.T) IstioConfigService {
 		fakeGetVirtualServices()[0],
 		fakeGetDestinationRules()[0],
 		fakeGetServiceEntries()[0],
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}},
 	}
 	k8s := kubetest.NewFakeK8sClient(fakeIstioObjects...)
 	k8s.OpenShift = true
@@ -421,7 +421,7 @@ func mockGetIstioConfigDetailsMulticluster(t *testing.T) IstioConfigService {
 		fakeGetVirtualServices()[0],
 		fakeGetDestinationRules()[0],
 		fakeGetServiceEntries()[0],
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "test"}},
 	}
 	k8s := kubetest.NewFakeK8sClient(fakeIstioObjects...)
 	k8s.OpenShift = true
diff --git a/business/istio_status_test.go b/business/istio_status_test.go
index fbb55364b..4c420bad7 100644
--- a/business/istio_status_test.go
+++ b/business/istio_status_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	apps_v1 "k8s.io/api/apps/v1"
 	v1 "k8s.io/api/core/v1"
@@ -127,7 +126,7 @@ func mockAddOnsCalls(t *testing.T, objects []runtime.Object, _ bool, overrideAdd
 	// Prepare the Call counts for each Addon
 	grafanaCalls, persesCalls, prometheusCalls := 0, 0, 0
 
-	objects = append(objects, &osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "istio-system"}})
+	objects = append(objects, &v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "istio-system"}})
 
 	k8s := kubetest.NewFakeK8sClient(objects...)
 	k8s.OpenShift = true
@@ -263,7 +262,7 @@ func TestGrafanaNotWorking(t *testing.T) {
 				UnavailableReplicas: 0,
 			}),
 	}
-	objects = append(objects, &osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "istio-system"}})
+	objects = append(objects, &v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "istio-system"}})
 	addOnsStetup := defaultAddOnCalls(&grafanaCalls, &persesCalls, &prometheusCalls)
 	addOnsStetup["grafana"] = addOnsSetup{
 		Url:        "/grafana/mock",
diff --git a/business/namespaces_test.go b/business/namespaces_test.go
index 4bb3c745e..10cf8bd6f 100644
--- a/business/namespaces_test.go
+++ b/business/namespaces_test.go
@@ -7,7 +7,6 @@ import (
 	"slices"
 	"testing"
 
-	v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	core_v1 "k8s.io/api/core/v1"
@@ -80,9 +79,9 @@ func setupAmbientProjectWithNs() kubernetes.UserClientInterface {
 	}
 	// config needs to be set by other services since those rely on the global.
 	objects := []runtime.Object{
-		&v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "bookinfo", Labels: labels}},
-		&v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "alpha"}},
-		&v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "beta"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "bookinfo", Labels: labels}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "alpha"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "beta"}},
 	}
 	for _, obj := range fakeNamespaces() {
 		o := obj
@@ -381,14 +380,13 @@ func TestMixedClustersNoError(t *testing.T) {
 
 	openshift := kubetest.NewFakeK8sClient(
 		kubetest.FakeNamespace("alpha"),
-		&v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "alpha"}},
 	)
 	openshift.OpenShift = true
 	vanilla := kubetest.NewFakeK8sClient(
 		kubetest.FakeNamespace("beta"),
 	)
-	vanilla.ProjectFake.PrependReactor("get", "projects", func(action kubeclienttesting.Action) (bool, runtime.Object, error) {
-		return true, nil, errors.NewForbidden(v1.Resource("projects"), "beta", fmt.Errorf("forbidden"))
+	vanilla.ProjectFake.PrependReactor("get", "namespaces", func(action kubeclienttesting.Action) (bool, runtime.Object, error) {
+		return true, nil, errors.NewForbidden(core_v1.Resource("namespaces"), "beta", fmt.Errorf("forbidden"))
 	})
 
 	clients := map[string]kubernetes.UserClientInterface{
diff --git a/business/tls_test.go b/business/tls_test.go
index 489f7c527..4dcc43d46 100644
--- a/business/tls_test.go
+++ b/business/tls_test.go
@@ -4,13 +4,13 @@ import (
 	"context"
 	"testing"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 	api_security_v1 "istio.io/api/security/v1"
 	api_security_v1beta1 "istio.io/api/security/v1beta1"
 	networking_v1 "istio.io/client-go/pkg/apis/networking/v1"
 	security_v1 "istio.io/client-go/pkg/apis/security/v1"
+	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 
@@ -356,7 +356,7 @@ func TestNamespaceHasDestinationRuleEnabledDifferentNs(t *testing.T) {
 	var objs []runtime.Object
 	objs = append(objs, kubernetes.ToRuntimeObjects(ps)...)
 	objs = append(objs, kubernetes.ToRuntimeObjects(drs)...)
-	objs = append(objs, kubernetes.ToRuntimeObjects(fakeProjects())...)
+	objs = append(objs, kubernetes.ToRuntimeObjects(fakeTestNamespaces())...)
 	k8s := kubetest.NewFakeK8sClient(objs...)
 	k8s.OpenShift = true
 	conf := config.NewConfig()
@@ -392,13 +392,10 @@ func testNamespaceScenario(exStatus string, drs []*networking_v1.DestinationRule
 	conf.Deployment.ClusterWideAccess = true
 	kubernetes.SetConfig(t, *conf)
 
-	objs := []runtime.Object{
-		kubetest.FakeNamespaceWithLabels("bookinfo", injectionEnabledLabel),
-		kubetest.FakeNamespaceWithLabels("foo", injectionEnabledLabel),
-	}
+	objs := []runtime.Object{}
 	objs = append(objs, kubernetes.ToRuntimeObjects(ps)...)
 	objs = append(objs, kubernetes.ToRuntimeObjects(drs)...)
-	objs = append(objs, kubernetes.ToRuntimeObjects(fakeProjects())...)
+	objs = append(objs, kubernetes.ToRuntimeObjects(fakeTestNamespaces())...)
 	k8s := kubetest.NewFakeK8sClient(objs...)
 	k8s.OpenShift = true
 
@@ -429,8 +426,8 @@ func testNamespaceScenario(exStatus string, drs []*networking_v1.DestinationRule
 	}
 }
 
-func fakeProjects() []*osproject_v1.Project {
-	return []*osproject_v1.Project{
+func fakeTestNamespaces() []*core_v1.Namespace {
+	return []*core_v1.Namespace{
 		{
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:   "bookinfo",
diff --git a/business/workloads_test.go b/business/workloads_test.go
index e6a84129b..dbaa75bcd 100644
--- a/business/workloads_test.go
+++ b/business/workloads_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	apps_v1 "k8s.io/api/apps/v1"
@@ -61,7 +60,7 @@ func TestGetWorkloadListFromDeployments(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeployments(*conf) {
 		o := obj
@@ -101,7 +100,7 @@ func TestGetWorkloadListFromDeploymentsNoAppVerLabelNames(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeployments(*conf) {
 		o := obj
@@ -143,7 +142,7 @@ func TestGetWorkloadListFromWorkloadGroups(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range data.CreateWorkloadGroups(*conf) {
 		o := obj
@@ -204,7 +203,7 @@ func TestGetWorkloadListFromReplicaSets(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeReplicaSets(*conf) {
 		o := obj
@@ -245,7 +244,7 @@ func TestGetWorkloadListFromReplicationControllers(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeReplicationControllers(conf) {
 		o := obj
@@ -287,7 +286,7 @@ func TestGetWorkloadListFromDeploymentConfigs(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDeploymentConfigs(conf) {
 		o := obj
@@ -329,7 +328,7 @@ func TestGetWorkloadListFromStatefulSets(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeStatefulSets(conf) {
 		o := obj
@@ -371,7 +370,7 @@ func TestGetWorkloadListFromDaemonSets(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDaemonSets(conf) {
 		o := obj
@@ -413,7 +412,7 @@ func TestGetWorkloadListFromDepRCPod(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDepSyncedWithRS(conf) {
 		o := obj
@@ -454,7 +453,7 @@ func TestGetWorkloadListFromPod(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakePodsNoController(conf) {
 		o := obj
@@ -487,7 +486,7 @@ func TestGetWorkloadListFromPods(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeCustomControllerRSSyncedWithPods(conf) {
 		o := obj
@@ -527,7 +526,7 @@ func TestGetWorkloadFromDeployment(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 		&FakeDepSyncedWithRS(conf)[0],
 	}
 	for _, o := range FakeRSSyncedWithPods(conf) {
@@ -563,7 +562,7 @@ func TestGetWorkloadFromWorkloadGroup(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range data.CreateWorkloadGroups(*conf) {
 		o := obj
@@ -622,7 +621,7 @@ func TestGetWorkloadWithInvalidWorkloadType(t *testing.T) {
 	// Setup mocks
 	kubeObjs := []runtime.Object{
 		&FakeDepSyncedWithRS(conf)[0],
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeRSSyncedWithPods(conf) {
 		o := obj
@@ -660,7 +659,7 @@ func TestGetWorkloadFromPods(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeCustomControllerRSSyncedWithPods(conf) {
 		o := obj
@@ -691,7 +690,7 @@ func TestGetPod(t *testing.T) {
 	require := require.New(t)
 
 	conf := config.NewConfig()
-	k8s := kubetest.NewFakeK8sClient(FakePodSyncedWithDeployments(conf), &osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}})
+	k8s := kubetest.NewFakeK8sClient(FakePodSyncedWithDeployments(conf), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}})
 	svc := setupWorkloadService(t, k8s, conf)
 
 	pod, err := svc.GetPod(conf.KubernetesConfig.ClusterName, "Namespace", "details-v1-3618568057-dnkjp")
@@ -716,7 +715,7 @@ func TestGetPodLogs(t *testing.T) {
 
 	k8s := &logStreamer{
 		logs:                FakePodLogsSyncedWithDeployments().Logs,
-		UserClientInterface: kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
+		UserClientInterface: kubetest.NewFakeK8sClient(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
 	}
 
 	svc := setupWorkloadService(t, k8s, config.NewConfig())
@@ -751,7 +750,7 @@ func TestGetPodLogsMaxLines(t *testing.T) {
 
 	k8s := &logStreamer{
 		logs:                FakePodLogsSyncedWithDeployments().Logs,
-		UserClientInterface: kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
+		UserClientInterface: kubetest.NewFakeK8sClient(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
 	}
 
 	svc := setupWorkloadService(t, k8s, config.NewConfig())
@@ -770,7 +769,7 @@ func TestGetPodLogsDuration(t *testing.T) {
 	require := require.New(t)
 	conf := config.NewConfig()
 
-	proj := &osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
+	proj := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
 	k8s := &logStreamer{
 		logs:                FakePodLogsSyncedWithDeployments().Logs,
 		UserClientInterface: kubetest.NewFakeK8sClient(proj),
@@ -816,7 +815,7 @@ func TestGetPodLogsMaxLinesAndDurations(t *testing.T) {
 	conf := config.NewConfig()
 
 	// Setup mocks
-	proj := &osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
+	proj := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
 	k8s := &logStreamer{
 		logs:                FakePodLogsSyncedWithDeployments().Logs,
 		UserClientInterface: kubetest.NewFakeK8sClient(proj),
@@ -854,7 +853,7 @@ func TestGetPodLogsProxy(t *testing.T) {
 	conf := config.NewConfig()
 
 	// Setup mocks
-	proj := &osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
+	proj := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}
 	k8s := &logStreamer{
 		logs:                FakePodLogsProxy().Logs,
 		UserClientInterface: kubetest.NewFakeK8sClient(proj),
@@ -886,7 +885,7 @@ func TestGetZtunnelPodLogsProxy(t *testing.T) {
 	// Setup mocks
 	kubeObjs := []runtime.Object{
 		FakePodSyncedWithDeployments(conf),
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "bookinfo"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "bookinfo"}},
 	}
 	for _, obj := range FakeZtunnelDaemonSet(conf) {
 		o := obj
@@ -944,7 +943,7 @@ func TestGetWaypointPodLogsProxy(t *testing.T) {
 	// Setup mocks
 	kubeObjs := []runtime.Object{
 		FakePodWithWaypointAndDeployments(),
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeWaypointPod() {
 		o := obj
@@ -1028,7 +1027,7 @@ func TestDuplicatedControllers(t *testing.T) {
 	// Setup mocks
 	kubeObjs := []runtime.Object{
 		FakePodSyncedWithDeployments(conf),
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range FakeDuplicatedDeployments() {
 		o := obj
@@ -1088,7 +1087,7 @@ func TestGetWorkloadListFromGenericPodController(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range pods {
 		o := obj
@@ -1134,7 +1133,7 @@ func TestGetWorkloadListKindsWithSameName(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range rs {
 		o := obj
@@ -1182,7 +1181,7 @@ func TestGetWorkloadListRSWithoutPrefix(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range rs {
 		o := obj
@@ -1237,7 +1236,7 @@ func TestGetWorkloadListRSOwnedByCustom(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, obj := range replicaSets {
 		o := obj
@@ -1281,7 +1280,7 @@ func TestGetPodLogsWithoutAccessLogs(t *testing.T) {
 2021-10-05T00:32:40.309457Z     ':scheme', 'http'`
 	k8s := &logStreamer{
 		logs:                logs,
-		UserClientInterface: kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
+		UserClientInterface: kubetest.NewFakeK8sClient(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}}),
 	}
 	conf := config.NewConfig()
 	config.Set(conf)
@@ -1362,7 +1361,7 @@ func TestValidateWaypoint(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 
 	for _, obj := range FakeWaypointPod() {
@@ -1445,7 +1444,7 @@ func TestValidateWaypointNS(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace", Labels: map[string]string{waypointLabel: "waypoint"}}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace", Labels: map[string]string{waypointLabel: "waypoint"}}},
 	}
 
 	for _, obj := range FakeWaypointPod() {
@@ -1529,7 +1528,7 @@ func TestValidateWaypointService(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 
 	for _, obj := range FakeWaypointPod() {
@@ -1620,7 +1619,7 @@ func TestGetWaypointWorkloads(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace", Labels: map[string]string{"istio.io/use-waypoint": "waypoint"}}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace", Labels: map[string]string{"istio.io/use-waypoint": "waypoint"}}},
 	}
 
 	for _, obj := range FakeWaypointPod() {
@@ -1710,7 +1709,7 @@ func TestValidateWaypointProxyStatus(t *testing.T) {
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 
 	for _, obj := range FakeWaypointPod() {
@@ -1847,7 +1846,7 @@ func TestGetWorkloadListWithCustomKindThatMatchesCoreKind(t *testing.T) {
 	conf := config.NewConfig()
 
 	kubeObjs := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
+		&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "Namespace"}},
 	}
 	for _, pod := range FakePodsFromCustomController(conf) {
 		p := pod
diff --git a/graph/telemetry/istio/appender/health_test.go b/graph/telemetry/istio/appender/health_test.go
index c6ea27ac6..5d36445c1 100644
--- a/graph/telemetry/istio/appender/health_test.go
+++ b/graph/telemetry/istio/appender/health_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/prometheus/common/model"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -475,7 +474,6 @@ func TestErrorCausesPanic(t *testing.T) {
 
 	trafficMap := buildAppTrafficMap()
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "testNamespace"}},
 		kubetest.FakeNamespace("testNamespace"),
 	}
 	for _, obj := range buildFakeWorkloadDeploymentsHealth(rateDefinition) {
@@ -525,7 +523,6 @@ func TestMultiClusterHealthConfig(t *testing.T) {
 	westNode, _ := graph.NewNode("west", "testNamespace", "", "testNamespace", graph.Unknown, "myTest", graph.Unknown, graph.GraphTypeVersionedApp)
 	trafficMap[westNode.ID] = westNode
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "testNamespace"}},
 		kubetest.FakeNamespace("testNamespace"),
 	}
 	westClient := kubetest.NewFakeK8sClient(objects...)
@@ -603,7 +600,6 @@ func buildFakePodsHealth(rate string) []core_v1.Pod {
 
 func setupHealthConfig(t *testing.T, services []core_v1.Service, deployments []apps_v1.Deployment, pods []core_v1.Pod) *business.Layer {
 	objects := []runtime.Object{
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "testNamespace"}},
 		kubetest.FakeNamespace("testNamespace"),
 	}
 	for _, obj := range services {
diff --git a/handlers/apps_test.go b/handlers/apps_test.go
index ba1c08da1..2c05810e8 100644
--- a/handlers/apps_test.go
+++ b/handlers/apps_test.go
@@ -11,13 +11,11 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 	"github.com/stretchr/testify/require"
 	core_v1 "k8s.io/api/core/v1"
-	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 
 	"github.com/kiali/kiali/business"
@@ -200,14 +198,6 @@ func setupAppListEndpoint(t *testing.T, k8s kubernetes.UserClientInterface, conf
 	return ts
 }
 
-func newProject() *osproject_v1.Project {
-	return &osproject_v1.Project{
-		ObjectMeta: meta_v1.ObjectMeta{
-			Name: "ns",
-		},
-	}
-}
-
 func TestAppsEndpoint(t *testing.T) {
 	assert := assert.New(t)
 
@@ -216,9 +206,7 @@ func TestAppsEndpoint(t *testing.T) {
 	config.Set(cfg)
 
 	mockClock()
-	proj := newProject()
-	proj.Name = "Namespace"
-	kubeObjects := []runtime.Object{proj}
+	kubeObjects := []runtime.Object{kubetest.FakeNamespace("Namespace")}
 	for _, obj := range business.FakeDeployments(*cfg) {
 		o := obj
 		kubeObjects = append(kubeObjects, &o)
@@ -253,9 +241,7 @@ func TestAppDetailsEndpoint(t *testing.T) {
 	kubernetes.SetConfig(t, *conf)
 
 	mockClock()
-	proj := newProject()
-	proj.Name = "Namespace"
-	kubeObjects := []runtime.Object{proj}
+	kubeObjects := []runtime.Object{kubetest.FakeNamespace("Namespace")}
 	for _, obj := range business.FakeDeployments(*conf) {
 		o := obj
 		kubeObjects = append(kubeObjects, &o)
diff --git a/handlers/authentication/openid_auth_controller_test.go b/handlers/authentication/openid_auth_controller_test.go
index 31c3417ed..48612e074 100644
--- a/handlers/authentication/openid_auth_controller_test.go
+++ b/handlers/authentication/openid_auth_controller_test.go
@@ -15,9 +15,9 @@ import (
 	"time"
 
 	"github.com/go-jose/go-jose/v4"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/kiali/kiali/cache"
@@ -236,7 +236,7 @@ QwIDAQAB
 	// Returning some namespace when a cluster API call is made should have the result of
 	// a successful authentication.
 	k8s := kubetest.NewFakeK8sClient(
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "Foo"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "Foo"}},
 	)
 	k8s.OpenShift = true
 	mockClientFactory := kubetest.NewK8SClientFactoryMock(k8s)
@@ -312,7 +312,7 @@ func TestOpenIdAuthControllerRejectsImplicitFlow(t *testing.T) {
 	// Returning some namespace when a cluster API call is made should have the result of
 	// a successful authentication.
 	k8s := kubetest.NewFakeK8sClient(
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "Foo"}},
+		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "Foo"}},
 	)
 	k8s.OpenShift = true
 	mockClientFactory := kubetest.NewK8SClientFactoryMock(k8s)
diff --git a/handlers/authentication_test.go b/handlers/authentication_test.go
index 9ebf8e198..3c6f0cd1f 100644
--- a/handlers/authentication_test.go
+++ b/handlers/authentication_test.go
@@ -1,7 +1,6 @@
 package handlers
 
 import (
-	"context"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -12,9 +11,9 @@ import (
 	"testing"
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/clientcmd/api"
 
@@ -37,7 +36,7 @@ func TestStrategyTokenAuthentication(t *testing.T) {
 	cfg.LoginToken.SigningKey = util.RandomString(16)
 	config.Set(cfg)
 
-	k8s := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
+	k8s := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
 	k8s.OpenShift = true
 	mockClientFactory := kubetest.NewK8SClientFactoryMock(k8s)
 	cache := cache.NewTestingCacheWithFactory(t, mockClientFactory, *cfg)
@@ -78,7 +77,7 @@ func TestStrategyTokenFails(t *testing.T) {
 	cfg.LoginToken.SigningKey = util.RandomString(16)
 	config.Set(cfg)
 
-	k8s := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
+	k8s := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
 	k8s.OpenShift = true
 	rejectClient := &rejectClient{k8s}
 	mockClientFactory := kubetest.NewK8SClientFactoryMock(rejectClient)
@@ -176,7 +175,7 @@ func TestStrategyHeaderOidcAuthentication(t *testing.T) {
 	clockTime := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
 	util.Clock = util.ClockMock{Time: clockTime}
 
-	k8s := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
+	k8s := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
 	k8s.OpenShift = true
 	authController, err := authentication.NewHeaderAuthController(cfg, k8s)
 	require.NoError(err)
@@ -219,7 +218,7 @@ func TestStrategyHeaderAuthentication(t *testing.T) {
 	clockTime := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
 	util.Clock = util.ClockMock{Time: clockTime}
 
-	k8s := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
+	k8s := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
 	k8s.OpenShift = true
 	authController, err := authentication.NewHeaderAuthController(cfg, k8s)
 	require.NoError(err)
@@ -262,7 +261,7 @@ func TestStrategyHeaderOidcWithImpersonationAuthentication(t *testing.T) {
 	clockTime := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
 	util.Clock = util.ClockMock{Time: clockTime}
 
-	k8s := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
+	k8s := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}})
 	k8s.OpenShift = true
 	authController, err := authentication.NewHeaderAuthController(cfg, k8s)
 	require.NoError(err)
@@ -456,6 +455,6 @@ func TestAuthenticationInfo(t *testing.T) {
 
 type rejectClient struct{ kubernetes.UserClientInterface }
 
-func (r *rejectClient) GetProjects(ctx context.Context, labelSelector string) ([]osproject_v1.Project, error) {
+func (r *rejectClient) GetNamespaces(labelSelector string) ([]core_v1.Namespace, error) {
 	return nil, fmt.Errorf("Rejecting")
 }
diff --git a/handlers/health_test.go b/handlers/health_test.go
index 90c2650d9..f2f08294f 100644
--- a/handlers/health_test.go
+++ b/handlers/health_test.go
@@ -8,7 +8,6 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/prometheus/common/model"
 	"github.com/stretchr/testify/assert"
 	core_v1 "k8s.io/api/core/v1"
@@ -106,9 +105,9 @@ func setupClustersHealthEndpoint(t *testing.T, k8s *kubetest.FakeK8sClient) (*ht
 	return ts, prom
 }
 
-func setupMockData() *osproject_v1.Project {
+func setupMockData() *core_v1.Namespace {
 	mockClock()
-	return &osproject_v1.Project{
+	return &core_v1.Namespace{
 		ObjectMeta: meta_v1.ObjectMeta{
 			Name:              "ns",
 			CreationTimestamp: meta_v1.NewTime(util.Clock.Now().Add(-17 * time.Second)),
diff --git a/handlers/metrics_test.go b/handlers/metrics_test.go
index fadb2858e..5d4afd3f7 100644
--- a/handlers/metrics_test.go
+++ b/handlers/metrics_test.go
@@ -11,7 +11,6 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
@@ -248,7 +247,7 @@ func TestAggregateMetricsWithParams(t *testing.T) {
 }
 
 func TestAggregateMetricsInaccessibleNamespace(t *testing.T) {
-	k := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
+	k := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
 	k.OpenShift = true
 
 	ts, _ := setupAggregateMetricsEndpointWithClient(t, &noPrivClient{k})
@@ -321,7 +320,7 @@ func TestAggregateMetricsBadReporter(t *testing.T) {
 func setupAggregateMetricsEndpoint(t *testing.T) (*httptest.Server, *prometheustest.PromAPIMock) {
 	conf := config.NewConfig()
 	xapi := new(prometheustest.PromAPIMock)
-	k := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
+	k := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
 	k.OpenShift = true
 	prom, err := prometheus.NewClient(*config.NewConfig(), k.GetToken())
 	if err != nil {
@@ -972,9 +971,6 @@ func setupMocked(t *testing.T) (*prometheus.Client, *prometheustest.PromAPIMock,
 		kubetest.FakeNamespace("bookinfo"),
 		kubetest.FakeNamespace("tutorial"),
 		kubetest.FakeNamespace("ns"),
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "bookinfo"}},
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}},
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 	)
 	k.OpenShift = true
 
diff --git a/handlers/namespaces_test.go b/handlers/namespaces_test.go
index 4c44625ef..262f688ab 100644
--- a/handlers/namespaces_test.go
+++ b/handlers/namespaces_test.go
@@ -7,9 +7,7 @@ import (
 	"testing"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	"github.com/stretchr/testify/assert"
-	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/kiali/kiali/cache"
 	"github.com/kiali/kiali/config"
@@ -60,9 +58,6 @@ func setupMocked(t *testing.T) (*prometheus.Client, *prometheustest.PromAPIMock,
 		kubetest.FakeNamespace("bookinfo"),
 		kubetest.FakeNamespace("tutorial"),
 		kubetest.FakeNamespace("ns"),
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "bookinfo"}},
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "tutorial"}},
-		&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
 	)
 	k.OpenShift = true
 
diff --git a/handlers/services_test.go b/handlers/services_test.go
index 4d9e8826b..0f1ca25c6 100644
--- a/handlers/services_test.go
+++ b/handlers/services_test.go
@@ -10,10 +10,10 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
+	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/kiali/kiali/cache"
@@ -309,7 +309,7 @@ func TestServiceMetricsBadRateFunc(t *testing.T) {
 }
 
 func TestServiceMetricsInaccessibleNamespace(t *testing.T) {
-	k := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
+	k := kubetest.NewFakeK8sClient(&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}})
 	k.OpenShift = true
 	ts, _ := setupServiceMetricsEndpointWithClient(t, &noPrivClient{UserClientInterface: k})
 
@@ -325,7 +325,7 @@ func TestServiceMetricsInaccessibleNamespace(t *testing.T) {
 
 func setupServiceMetricsEndpoint(t *testing.T) (*httptest.Server, *prometheustest.PromAPIMock) {
 	conf := config.NewConfig()
-	k := kubetest.NewFakeK8sClient(&osproject_v1.Project{ObjectMeta: meta_v1.ObjectMeta{Name: "ns"}},
+	k := kubetest.NewFakeK8sClient(
 		kubetest.FakeNamespace("my_namespace"),
 		kubetest.FakeNamespace("ns"))
 	k.OpenShift = true
diff --git a/handlers/testing.go b/handlers/testing.go
index bb47beaf4..7cf1f1970 100644
--- a/handlers/testing.go
+++ b/handlers/testing.go
@@ -5,12 +5,10 @@
 package handlers
 
 import (
-	"context"
 	"fmt"
 	"net/http"
 	"time"
 
-	osproject_v1 "github.com/openshift/api/project/v1"
 	core_v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,14 +29,6 @@ type noPrivClient struct {
 	kubernetes.UserClientInterface
 }
 
-func (n *noPrivClient) GetProjects(ctx context.Context, labelSelector string) ([]osproject_v1.Project, error) {
-	return nil, errors.NewForbidden(schema.GroupResource{Group: osproject_v1.GroupName, Resource: "projects"}, "", fmt.Errorf("Rejecting"))
-}
-
-func (n *noPrivClient) GetProject(ctx context.Context, name string) (*osproject_v1.Project, error) {
-	return nil, errors.NewForbidden(schema.GroupResource{Group: osproject_v1.GroupName, Resource: "projects"}, name, fmt.Errorf("Rejecting"))
-}
-
 func (n *noPrivClient) GetNamespace(namespace string) (*core_v1.Namespace, error) {
 	return nil, errors.NewForbidden(schema.GroupResource{Group: core_v1.GroupName, Resource: "namespaces"}, "namespace", fmt.Errorf("Rejecting"))
 }
diff --git a/kubernetes/kubetest/mock_openshift.go b/kubernetes/kubetest/mock_openshift.go
index bf4157b16..21f6c42e3 100644
--- a/kubernetes/kubetest/mock_openshift.go
+++ b/kubernetes/kubetest/mock_openshift.go
@@ -5,7 +5,6 @@ import (
 
 	osapps_v1 "github.com/openshift/api/apps/v1"
 	osoauth_v1 "github.com/openshift/api/oauth/v1"
-	osproject_v1 "github.com/openshift/api/project/v1"
 	osroutes_v1 "github.com/openshift/api/route/v1"
 	osuser_v1 "github.com/openshift/api/user/v1"
 )
@@ -25,21 +24,6 @@ func (o *K8SClientMock) GetDeploymentConfigs(ctx context.Context, namespace stri
 	return args.Get(0).([]osapps_v1.DeploymentConfig), args.Error(1)
 }
 
-func (o *K8SClientMock) GetProject(ctx context.Context, project string) (*osproject_v1.Project, error) {
-	args := o.Called(project)
-	return args.Get(0).(*osproject_v1.Project), args.Error(1)
-}
-
-func (o *K8SClientMock) GetProjects(ctx context.Context, labelSelector string) ([]osproject_v1.Project, error) {
-	args := o.Called(labelSelector)
-	return args.Get(0).([]osproject_v1.Project), args.Error(1)
-}
-
-func (o *K8SClientMock) UpdateProject(ctx context.Context, project string, jsonPatch string) (*osproject_v1.Project, error) {
-	args := o.Called(project)
-	return args.Get(0).(*osproject_v1.Project), args.Error(1)
-}
-
 func (o *K8SClientMock) DeleteOAuthToken(ctx context.Context, token string) error {
 	args := o.Called(ctx, token)
 	return args.Error(0)