From aa2170626bcd38482defb3c0adde866fa0cc29ce Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Wed, 5 Feb 2025 16:40:53 +0100 Subject: [PATCH 1/7] Add CRD validation cypress tests --- .../openshift/common/istio_config.ts | 92 +++++ .../openshift/common/istio_resources.ts | 20 +- .../openshift/common/sidebar_navigation.ts | 8 +- .../featureFiles/istio_config.feature | 335 +++++++++++++++++- plugin/cypress/support/commands.ts | 2 +- 5 files changed, 446 insertions(+), 11 deletions(-) diff --git a/plugin/cypress/integration/openshift/common/istio_config.ts b/plugin/cypress/integration/openshift/common/istio_config.ts index 6231ef50..5be7871e 100644 --- a/plugin/cypress/integration/openshift/common/istio_config.ts +++ b/plugin/cypress/integration/openshift/common/istio_config.ts @@ -2,6 +2,7 @@ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'; import { getColWithRowText } from './table'; import { istioResources, referenceFor } from './istio_resources'; import { K8sGroupVersionKind } from '@openshift-console/dynamic-plugin-sdk'; +import { ensureOSSMCFinishedLoading } from './sidebar_navigation'; Given('user is at the istio config list page', () => { // Forcing "Pause" to not cause unhandled promises from the browser when cypress is testing @@ -80,3 +81,94 @@ Then('the user can create a {string} K8s Istio object in ossmc', (object: string } }); }); + +Then('the AuthorizationPolicy should have a {string} in ossmc', function (healthStatus: string) { + waitUntilConfigIsVisible( + 3, + this.targetAuthorizationPolicy, + 'AuthorizationPolicy', + this.targetNamespace, + healthStatus + ); +}); + +const hexToRgb = (hex: string): string => { + const rValue = parseInt(hex.substring(0, 2), 16); + const gValue = parseInt(hex.substring(2, 4), 16); + const bValue = parseInt(hex.substring(4), 16); + + return `rgb(${rValue}, ${gValue}, ${bValue})`; +}; + +function waitUntilConfigIsVisible( + attempt: number, + crdInstanceName: string, + crdName: string, + namespace: string, + healthStatus: string +): void { + if (attempt === 0) { + throw new Error(`Condition not met after retries`); + } + + cy.reload(true); + ensureOSSMCFinishedLoading(); + + let found = false; + // Get the link of the item name to distinguish each row + cy.get('td a') + .each($link => { + const hRefAttr = $link[0].attributes.getNamedItem('href'); + + // Get the row to check the configuration icon + cy.wrap($link) + .parent() + .parent() + .then($row => { + const hasNA = $row[0].innerText.includes('N/A'); + + if (hRefAttr !== null) { + const istioResource = istioResources.find(item => item.id.toLowerCase() === crdName.toLowerCase()); + + if ( + istioResource && + hRefAttr.value === + `/k8s/ns/${namespace}/${referenceFor( + istioResource as K8sGroupVersionKind + )}/${crdInstanceName}/ossmconsole` && + !hasNA + ) { + cy.wrap($row) + .find('span.pf-v5-c-icon') + .should('be.visible') + .then(icon => { + const colorVar = `--pf-v5-global--${healthStatus}-color--100`; + const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); + + cy.wrap(icon[0]) + .invoke('css', 'color') + .then(iconColor => { + // Convert the status color to RGB format to compare it with the icon color + if (iconColor.toString() === hexToRgb(statusColor)) { + found = true; + } + }); + }); + } + } + }); + }) + .then(() => { + if (!found) { + cy.wait(10000); + waitUntilConfigIsVisible(attempt - 1, crdInstanceName, crdName, namespace, healthStatus); + } + }); +} + +Then( + 'the {string} {string} of the {string} namespace should have a {string} in ossmc', + (crdInstanceName: string, crdName: string, namespace: string, healthStatus: string) => { + waitUntilConfigIsVisible(3, crdInstanceName, crdName, namespace, healthStatus); + } +); diff --git a/plugin/cypress/integration/openshift/common/istio_resources.ts b/plugin/cypress/integration/openshift/common/istio_resources.ts index 8df85da8..79c7d961 100644 --- a/plugin/cypress/integration/openshift/common/istio_resources.ts +++ b/plugin/cypress/integration/openshift/common/istio_resources.ts @@ -131,12 +131,18 @@ export const referenceFor = (groupVersionKind: K8sGroupVersionKind): string => { return `${groupVersionKind.group}~${groupVersionKind.version}~${groupVersionKind.kind}`; }; -export const refForKialiIstio = (objectType: string, details: string): string => { - const kialiIstioResource = istioResources.find(item => objectType === item.objectType); +// This helper would translate Istio Kiali format +// i.e. /istio/networking.istio.io/v1/DestinationRule/reviews +// Into the regular format used for resources in OpenShift +// i.e. /networking.istio.io~v1~DestinationRule/reviews +export const refForKialiIstio = (kialiIstioUrl: string): string => { + const kialiIstioResource = kialiIstioUrl.split('/'); - if (kialiIstioResource) { - return `/${referenceFor(kialiIstioResource)}${details}`; - } + const groupVersionKind = { + group: kialiIstioResource[2], + version: kialiIstioResource[3], + kind: kialiIstioResource[4] + }; - return ''; -}; + return `/${referenceFor(groupVersionKind)}/${kialiIstioResource[5]}`; +}; \ No newline at end of file diff --git a/plugin/cypress/integration/openshift/common/sidebar_navigation.ts b/plugin/cypress/integration/openshift/common/sidebar_navigation.ts index d6344021..29da4217 100644 --- a/plugin/cypress/integration/openshift/common/sidebar_navigation.ts +++ b/plugin/cypress/integration/openshift/common/sidebar_navigation.ts @@ -1,5 +1,9 @@ import { Then, When } from '@badeball/cypress-cucumber-preprocessor'; +export const ensureOSSMCFinishedLoading = () => { + cy.waitForReact(5000, '#app', 'node_modules/resq/dist/index.js'); // Manually passing in the resq module path +}; + When('user is at the dashboard page', () => { cy.visit({ url: `/` }); }); @@ -21,7 +25,7 @@ When('cypress intercept hooks for sidebar are registered', () => { }); Then('buttons for Overview, Graph and Istio Config are displayed', () => { - cy.waitForReact(5000, '#app', 'node_modules/resq/dist/index.js'); // Manually passing in the resq module path + ensureOSSMCFinishedLoading(); cy.reload(true); // force reload to make sure OSSMC is loaded cy.get('a[data-test="nav"][class*="pf-v5-c-nav__link"]').contains('Overview'); cy.get('a[data-test="nav"][class*="pf-v5-c-nav__link"]').contains('Graph'); @@ -91,7 +95,7 @@ Then(`user sees the {string} graph summary`, (ns: string) => { Then('user sees the mesh side panel', () => { cy.wait('@meshRequest').then(interception => { - cy.get('#loading_kiali_spinner').should('not.exist'); + ensureOSSMCFinishedLoading(); cy.get('#target-panel-mesh') .should('be.visible') .within(() => { diff --git a/plugin/cypress/integration/openshift/featureFiles/istio_config.feature b/plugin/cypress/integration/openshift/featureFiles/istio_config.feature index 1ffad8fc..89ca035d 100644 --- a/plugin/cypress/integration/openshift/featureFiles/istio_config.feature +++ b/plugin/cypress/integration/openshift/featureFiles/istio_config.feature @@ -49,4 +49,337 @@ Feature: Kiali Istio Config page Then the user can create a "serviceEntry" Istio object in ossmc Scenario: Ability to create a Sidecar object - Then the user can create a "sidecar" Istio object in ossmc \ No newline at end of file + Then the user can create a "sidecar" Istio object in ossmc + + @crd-validation + @bookinfo-app + Scenario: KIA0101 validation + Given a "foo" AuthorizationPolicy in the "bookinfo" namespace + And the AuthorizationPolicy has a from-source rule for "bar" namespace + When user selects the "bookinfo" project + Then the AuthorizationPolicy should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + Scenario: KIA0102 validation + Given a "enable-mtls" DestinationRule in the "bookinfo" namespace for "*.bookinfo.svc.cluster.local" host + And a "foo" AuthorizationPolicy in the "bookinfo" namespace + And the AuthorizationPolicy has a to-operation rule with "non-fully-qualified-grpc" method + When user selects the "bookinfo" project + Then the AuthorizationPolicy should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + Scenario: KIA0104 validation + Given there is not a "bookinfo" "VirtualService" in the "bookinfo" namespace + Given a "foo" AuthorizationPolicy in the "bookinfo" namespace + And the AuthorizationPolicy has a to-operation rule with "missing.hostname" host + When user selects the "bookinfo" project + Then the AuthorizationPolicy should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + Scenario: KIA0106 validation + Given a "foo" AuthorizationPolicy in the "bookinfo" namespace + And the AuthorizationPolicy has a from-source rule for "cluster.local/ns/bookinfo/sa/sleep" principal + When user selects the "bookinfo" project + Then the AuthorizationPolicy should have a "danger" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0201 validation + Given a "foo" DestinationRule in the "sleep" namespace for "sleep" host + And the DestinationRule has a "mysubset" subset for "version=v1" labels + And a "bar" DestinationRule in the "sleep" namespace for "sleep" host + And the DestinationRule has a "mysubset" subset for "version=v1" labels + When user selects the "sleep" project + Then the "foo" "DestinationRule" of the "sleep" namespace should have a "warning" in ossmc + And the "bar" "DestinationRule" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" "DestinationRule" in the "sleep" namespace + And there is not a "bar" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0202 validation + Given a "foo" DestinationRule in the "sleep" namespace for "nonexistent" host + When user selects the "sleep" project + Then the "foo" "DestinationRule" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0203 validation + Given a "foo" DestinationRule in the "sleep" namespace for "sleep" host + And the DestinationRule has a "v1" subset for "version=v1" labels + And there is a "foo-route" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" and subset "v1" + When user selects the "sleep" project + Then the "foo" "DestinationRule" of the "sleep" namespace should have a "danger" in ossmc + And there is not a "foo" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0207 validation + Given a "disable-mtls" DestinationRule in the "sleep" namespace for "*.sleep.svc.cluster.local" host + And the DestinationRule disables mTLS + And there is a "default" PeerAuthentication in the "sleep" namespace + And the PeerAuthentication has "STRICT" mtls mode + When user selects the "sleep" project + Then the "disable-mtls" "DestinationRule" of the "sleep" namespace should have a "danger" in ossmc + And there is not a "disable-mtls" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + @clean-istio-namespace-resources-after + Scenario: KIA0208 validation + Given a "disable-mtls" DestinationRule in the "sleep" namespace for "*.sleep.svc.cluster.local" host + And the DestinationRule disables mTLS + And there is a "default" PeerAuthentication in the "istio-system" namespace + And the PeerAuthentication has "STRICT" mtls mode + When user selects the "sleep" project + Then the "disable-mtls" "DestinationRule" of the "sleep" namespace should have a "danger" in ossmc + And there is not a "disable-mtls" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0209 validation + Given a "foo" DestinationRule in the "sleep" namespace for "*.sleep.svc.cluster.local" host + And the DestinationRule has a "v1" subset for "" labels + When user selects the "sleep" project + Then the "foo" "DestinationRule" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0301 wildcard validation + Given there is a "foo" Gateway on "bookinfo" namespace for "productpage.local" hosts on HTTP port 80 with "app=productpage" labels selector + And there is a "foo" Gateway on "sleep" namespace for "*" hosts on HTTP port 80 with "app=productpage" labels selector + When user selects the "bookinfo" project + Then the "foo" "Gateway" of the "bookinfo" namespace should have a "warning" in ossmc + When user selects the "sleep" project + Then the "foo" "Gateway" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" Gateway in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0301 validation + Given there is a "foo" Gateway on "bookinfo" namespace for "productpage.local" hosts on HTTP port 80 with "app=productpage" labels selector + And there is a "foo" Gateway on "sleep" namespace for "productpage.local" hosts on HTTP port 80 with "app=productpage" labels selector + When user selects the "bookinfo" project + Then the "foo" "Gateway" of the "bookinfo" namespace should have a "warning" in ossmc + When user selects the "sleep" project + Then the "foo" "Gateway" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" Gateway in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0302 validation + Given there is a "foo" Gateway on "sleep" namespace for "foo.local" hosts on HTTP port 80 with "app=foo" labels selector + When user selects the "sleep" project + Then the "foo" "Gateway" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" Gateway in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA0505 validation + Given a "enable-mtls" DestinationRule in the "sleep" namespace for "*.sleep.svc.cluster.local" host + And the DestinationRule enables mTLS + And there is a "default" PeerAuthentication in the "sleep" namespace + And the PeerAuthentication has "DISABLE" mtls mode + When user selects the "sleep" project + Then the "default" "PeerAuthentication" of the "sleep" namespace should have a "danger" in ossmc + And there is not a "enable-mtls" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + @clean-istio-namespace-resources-after + Scenario: KIA0506 validation + Given a "enable-mtls" DestinationRule in the "sleep" namespace for "*.local" host + And the DestinationRule enables mTLS + And there is a "default" PeerAuthentication in the "istio-system" namespace + And the PeerAuthentication has "DISABLE" mtls mode + When user selects the "istio-system" project + Then the "default" "PeerAuthentication" of the "istio-system" namespace should have a "danger" in ossmc + And there is not a "enable-mtls" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1004 validation + Given there is a "foo" Sidecar resource in the "sleep" namespace that captures egress traffic for hosts "sleep/foo.sleep.svc.cluster.local" + And the Sidecar is applied to workloads with "app=sleep" labels + When user selects the "sleep" project + Then the "foo" "Sidecar" of the "sleep" namespace should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + @clean-istio-namespace-resources-after + Scenario: KIA1006 validation + Given there is a "default" Sidecar resource in the "istio-system" namespace that captures egress traffic for hosts "default/sleep.sleep.svc.cluster.local" + And the Sidecar is applied to workloads with "app=grafana" labels + When user selects the "istio-system" project + Then the "default" "Sidecar" of the "istio-system" namespace should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1101 validation + Given there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "foo" + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1102 validation + Given there is not a "foo" Gateway in the "sleep" namespace + And there is not a "foo" "DestinationRule" in the "sleep" namespace + And there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" + And the VirtualService applies to "sleep" hosts + And the VirtualService references "foo" gateways + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "danger" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: VirtualService references to Gateway + Given there is a "foo" Gateway on "bookinfo" namespace for "productpage.local" hosts on HTTP port 80 with "app=productpage" labels selector + And there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" + And the VirtualService applies to "sleep" hosts + And the VirtualService references "bookinfo/foo" gateways + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "success" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1104 validation + Given there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" + And the route of the VirtualService has weight 10 + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1105 validation + Given there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" and subset "v1" + And the route of the VirtualService has weight 50 + And the http-route of the VirtualService also has a destination to host "sleep" and subset "v1" with weight 50 + And a "foo" DestinationRule in the "sleep" namespace for "sleep" host + And the DestinationRule has a "v1" subset for "version=v1" labels + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + And there is not a "foo" "DestinationRule" in the "sleep" namespace + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1106 validation + Given there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" + And the VirtualService applies to "sleep" hosts + Given there is a "bar" VirtualService in the "sleep" namespace with a "bar-route" http-route to host "sleep" + And the VirtualService applies to "sleep" hosts + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + And the "bar" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + + @crd-validation + @bookinfo-app + @sleep-app + Scenario: KIA1107 validation + Given there is a "foo" VirtualService in the "sleep" namespace with a "foo-route" http-route to host "sleep" and subset "v1" + And there is not a "foo" "DestinationRule" in the "sleep" namespace + And there is not a "foo" Gateway in the "sleep" namespace + When user selects the "sleep" project + Then the "foo" "VirtualService" of the "sleep" namespace should have a "warning" in ossmc + + # KIA1501 is tested through GUI in wizard_istio_config.feature + @crd-validation + @bookinfo-app + @gateway-api + Scenario: KIA1502 validation + Given user deletes k8sgateway named "foo" and the resource is no longer available + And user deletes k8sgateway named "bar" and the resource is no longer available + When there is a "foo" K8sGateway in the "bookinfo" namespace for "google.com" host using "HTTP" protocol on port "80" and "istio" gatewayClassName + And there is a "bar" K8sGateway in the "bookinfo" namespace for "secondary.com" host using "HTTP" protocol on port "9080" and "istio" gatewayClassName + And the "foo" K8sGateway in the "bookinfo" namespace has an address with a "Hostname" type and a "example.com" value + And the "bar" K8sGateway in the "bookinfo" namespace has an address with a "Hostname" type and a "example.com" value + When user selects the "bookinfo" project + Then the "foo" "K8sGateway" of the "bookinfo" namespace should have a "warning" in ossmc + And the "bar" "K8sGateway" of the "bookinfo" namespace should have a "warning" in ossmc + + # KIA1503 validation is not tested, as it is not possible to create a K8sGateway with duplicate listeners + + @crd-validation + @bookinfo-app + @gateway-api + Scenario: KIA1504 validation + Given user deletes k8sgateway named "foo" and the resource is no longer available + When there is a "foo" K8sGateway in the "bookinfo" namespace for "google.com" host using "HTTP" protocol on port "80" and "nonexistentname" gatewayClassName + And the user refreshes the page + And user selects the "bookinfo" project + Then the "foo" "K8sGateway" of the "bookinfo" namespace should have a "danger" in ossmc + + @crd-validation + @bookinfo-app + @gateway-api + Scenario: KIA1601 validation + Given user deletes k8sreferencegrant named "foo" and the resource is no longer available + When there is a "foo" K8sReferenceGrant in the "bookinfo" namespace pointing from "nonexistent" namespace + And the user refreshes the page + And user selects the "bookinfo" project + Then the "foo" "K8sReferenceGrant" of the "bookinfo" namespace should have a "danger" in ossmc + +# TODO: KIA06xx and KIA07xx does not appear in Istio Config list page. They appear in Svc/workload lists. +# Thus, these validations do not belong to this feature file. + +# TODO: Apparently, Kiali does not trigger: +# KIA0204, KIA0205, KIA0206, KIA0401, KIA0501 +# It is possible that under the current mTLS defaults these +# validations may became obsolete and may never happen anymore. +# Below, there are some Scenarios that were prepared to teset some of these chekers, +# but they are "red", because of the non-triggering validation. +# Also, KIA1108 is not triggering for some unknown reason. +# +# @crd-validation +# Scenario: KIA0204 validation +# Given a "default" DestinationRule in the "istio-system" namespace for "*.local" host +# And the DestinationRule enables mTLS +# And a "default" DestinationRule in the "sleep" namespace for "default" host +# And the DestinationRule has a "mysubset" subset for "app=sleep" labels +# When user selects the "sleep" project +# Then the "default" DestinationRule should have a "warning" in ossmc +# And the "default" DestinationRule should have a "warning" in ossmc +# +# @crd-validation +# Scenario: KIA0401 validation +# Given there is a "default" PeerAuthentication in the "istio-system" namespace +# And the PeerAuthentication has "STRICT" mtls mode +# When user selects the "istio-system" project +# Then the "default" "PeerAuthentication" of the "istio-system" namespace should have a "danger" in ossmc +# +# @crd-validation +# Scenario: KIA0501 validation +# Given there is a "default" PeerAuthentication in the "sleep" namespace +# And the PeerAuthentication has "STRICT" mtls mode +# When user selects the "sleep" project +# Then the "default" "PeerAuthentication" of the "sleep" namespace should have a "danger" in ossmc +# +# @crd-validation +# Scenario: KIA1108 validation +# Given there is a "foo" VirtualService in the "bookinfo" namespace with a "foo-route" http-route to host "reviews" +# And the VirtualService applies to "reviews" hosts +# And the VirtualService references "bookinfo-gateway.bookinfo.svc.cluster.local" gateways +# Then the "foo" "VirtualService" of the "bookinfo" namespace should have a "warning" in ossmc diff --git a/plugin/cypress/support/commands.ts b/plugin/cypress/support/commands.ts index d36dbf34..431d6f44 100644 --- a/plugin/cypress/support/commands.ts +++ b/plugin/cypress/support/commands.ts @@ -166,7 +166,7 @@ Cypress.Commands.overwrite('visit', (originalFn, visitUrl) => { } else if (type === 'services') { visitUrl.url = `/k8s/ns/${namespace}/services/${details}/ossmconsole${webParams}`; } else if (type === 'istio') { - const istioUrl = refForKialiIstio(targetPage, details); + const istioUrl = refForKialiIstio(details); visitUrl.url = `/k8s/ns/${namespace}${istioUrl}/ossmconsole${webParams}`; } From 2cabad90382f489be1a5fc4b4f0211be43bbabce Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Wed, 5 Feb 2025 20:03:04 +0100 Subject: [PATCH 2/7] Fix some cypress tests --- .../integration/openshift/featureFiles/istio_config.feature | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin/cypress/integration/openshift/featureFiles/istio_config.feature b/plugin/cypress/integration/openshift/featureFiles/istio_config.feature index 89ca035d..853c30a4 100644 --- a/plugin/cypress/integration/openshift/featureFiles/istio_config.feature +++ b/plugin/cypress/integration/openshift/featureFiles/istio_config.feature @@ -328,7 +328,6 @@ Feature: Kiali Istio Config page Scenario: KIA1504 validation Given user deletes k8sgateway named "foo" and the resource is no longer available When there is a "foo" K8sGateway in the "bookinfo" namespace for "google.com" host using "HTTP" protocol on port "80" and "nonexistentname" gatewayClassName - And the user refreshes the page And user selects the "bookinfo" project Then the "foo" "K8sGateway" of the "bookinfo" namespace should have a "danger" in ossmc @@ -338,7 +337,6 @@ Feature: Kiali Istio Config page Scenario: KIA1601 validation Given user deletes k8sreferencegrant named "foo" and the resource is no longer available When there is a "foo" K8sReferenceGrant in the "bookinfo" namespace pointing from "nonexistent" namespace - And the user refreshes the page And user selects the "bookinfo" project Then the "foo" "K8sReferenceGrant" of the "bookinfo" namespace should have a "danger" in ossmc From 22811d50432ec11bbdc453200be4d75ff74f3129 Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Thu, 6 Feb 2025 08:30:21 +0100 Subject: [PATCH 3/7] Filter only name column --- plugin/cypress/integration/openshift/common/istio_config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/cypress/integration/openshift/common/istio_config.ts b/plugin/cypress/integration/openshift/common/istio_config.ts index 5be7871e..bcdc759d 100644 --- a/plugin/cypress/integration/openshift/common/istio_config.ts +++ b/plugin/cypress/integration/openshift/common/istio_config.ts @@ -116,7 +116,7 @@ function waitUntilConfigIsVisible( let found = false; // Get the link of the item name to distinguish each row - cy.get('td a') + cy.get('td#name a') .each($link => { const hRefAttr = $link[0].attributes.getNamedItem('href'); From d64ae3a914b850aac560ba7f256947bbb3399f48 Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Thu, 6 Feb 2025 10:15:53 +0100 Subject: [PATCH 4/7] Get the row after validation --- .../openshift/common/istio_config.ts | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/plugin/cypress/integration/openshift/common/istio_config.ts b/plugin/cypress/integration/openshift/common/istio_config.ts index bcdc759d..618eef54 100644 --- a/plugin/cypress/integration/openshift/common/istio_config.ts +++ b/plugin/cypress/integration/openshift/common/istio_config.ts @@ -120,43 +120,42 @@ function waitUntilConfigIsVisible( .each($link => { const hRefAttr = $link[0].attributes.getNamedItem('href'); - // Get the row to check the configuration icon - cy.wrap($link) - .parent() - .parent() - .then($row => { - const hasNA = $row[0].innerText.includes('N/A'); - - if (hRefAttr !== null) { - const istioResource = istioResources.find(item => item.id.toLowerCase() === crdName.toLowerCase()); - - if ( - istioResource && - hRefAttr.value === - `/k8s/ns/${namespace}/${referenceFor( - istioResource as K8sGroupVersionKind - )}/${crdInstanceName}/ossmconsole` && - !hasNA - ) { - cy.wrap($row) - .find('span.pf-v5-c-icon') - .should('be.visible') - .then(icon => { - const colorVar = `--pf-v5-global--${healthStatus}-color--100`; - const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); - - cy.wrap(icon[0]) - .invoke('css', 'color') - .then(iconColor => { - // Convert the status color to RGB format to compare it with the icon color - if (iconColor.toString() === hexToRgb(statusColor)) { - found = true; - } - }); - }); - } - } - }); + if (hRefAttr !== null) { + const istioResource = istioResources.find(item => item.id.toLowerCase() === crdName.toLowerCase()); + + if ( + istioResource && + hRefAttr.value === + `/k8s/ns/${namespace}/${referenceFor(istioResource as K8sGroupVersionKind)}/${crdInstanceName}/ossmconsole` + ) { + // Get the row to check the configuration icon + cy.wrap($link) + .parent() + .parent() + .then($row => { + const hasNA = $row[0].innerText.includes('N/A'); + + if (!hasNA) { + cy.wrap($row) + .find('span.pf-v5-c-icon') + .should('be.visible') + .then(icon => { + const colorVar = `--pf-v5-global--${healthStatus}-color--100`; + const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); + + cy.wrap(icon[0]) + .invoke('css', 'color') + .then(iconColor => { + // Convert the status color to RGB format to compare it with the icon color + if (iconColor.toString() === hexToRgb(statusColor)) { + found = true; + } + }); + }); + } + }); + } + } }) .then(() => { if (!found) { From e4ab48d302700cf09ee959f9c808e9f7c244219e Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Thu, 6 Feb 2025 17:10:21 +0100 Subject: [PATCH 5/7] Copy of Kiali frontend source code Kiali frontend source originated from: * git ref: master * git commit: dd432afc0e140b872c445cf4eacd1052d4886417 * GitHub URL: https://github.com/kiali/kiali/tree/dd432afc0e140b872c445cf4eacd1052d4886417/frontend/src Signed-off-by: Fernando Hoyos --- .../integration/kiali/common/istio_config.ts | 24 ++++- .../cypress/integration/kiali/common/mesh.ts | 48 +++++++-- .../kiali/featureFiles/mesh.feature | 6 +- .../featureFiles/service_details.feature | 3 +- .../kiali/featureFiles/waypoint.feature | 13 --- plugin/src/kiali/README.md | 6 +- plugin/src/kiali/app/History.tsx | 1 + .../kiali/components/Envoy/AccessLogModal.tsx | 10 +- plugin/src/kiali/components/Pf/PfBadges.tsx | 4 +- plugin/src/kiali/components/Pf/PfColors.tsx | 3 + .../pages/Graph/GraphToolbar/GraphTraffic.tsx | 2 +- .../WorkloadDetails/WorkloadDetailsPage.tsx | 2 + .../pages/WorkloadDetails/WorkloadPodLogs.tsx | 99 +++++++++++++++++-- plugin/src/kiali/services/Api.ts | 10 ++ plugin/src/kiali/types/IstioConfigList.ts | 2 +- plugin/src/kiali/types/IstioObjects.ts | 2 + 16 files changed, 187 insertions(+), 48 deletions(-) diff --git a/plugin/cypress/integration/kiali/common/istio_config.ts b/plugin/cypress/integration/kiali/common/istio_config.ts index 80a61ab4..b6ee31f3 100644 --- a/plugin/cypress/integration/kiali/common/istio_config.ts +++ b/plugin/cypress/integration/kiali/common/istio_config.ts @@ -613,6 +613,14 @@ Then('the AuthorizationPolicy should have a {string}', function (healthStatus: s ); }); +const hexToRgb = (hex: string): string => { + const rValue = parseInt(hex.substring(0, 2), 16); + const gValue = parseInt(hex.substring(2, 4), 16); + const bValue = parseInt(hex.substring(4), 16); + + return `rgb(${rValue}, ${gValue}, ${bValue})`; +}; + function waitUntilConfigIsVisible( attempt: number, crdInstanceName: string, @@ -626,11 +634,13 @@ function waitUntilConfigIsVisible( cy.request({ method: 'GET', url: `${Cypress.config('baseUrl')}/api/istio/config?refresh=0` }); cy.get('[data-test="refresh-button"]').click(); ensureKialiFinishedLoading(); + let found = false; cy.get('tr') .each($row => { const dataTestAttr = $row[0].attributes.getNamedItem('data-test'); const hasNA = $row[0].innerText.includes('N/A'); + if (dataTestAttr !== null) { if (dataTestAttr.value === `VirtualItem_Ns${namespace}_${crdName}_${crdInstanceName}` && !hasNA) { // Check if the health status icon is correct @@ -638,10 +648,16 @@ function waitUntilConfigIsVisible( .should('be.visible') .then(icon => { const colorVar = `--pf-v5-global--${healthStatus}-color--100`; - const color = getComputedStyle(icon[0]).getPropertyValue(colorVar); - if (color) { - found = true; - } + const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); + + cy.wrap(icon[0]) + .invoke('css', 'color') + .then(iconColor => { + // Convert the status color to RGB format to compare it with the icon color + if (iconColor.toString() === hexToRgb(statusColor)) { + found = true; + } + }); }); } } diff --git a/plugin/cypress/integration/kiali/common/mesh.ts b/plugin/cypress/integration/kiali/common/mesh.ts index e950b7d9..366624dd 100644 --- a/plugin/cypress/integration/kiali/common/mesh.ts +++ b/plugin/cypress/integration/kiali/common/mesh.ts @@ -45,7 +45,27 @@ When('user selects mesh node with label {string}', (label: string) => { assert.isTrue(controller.hasGraph()); const { nodes } = elems(controller); - const node = nodes.find(n => n.getLabel() === label); + const node = nodes.find(n => n.getLabel().toLowerCase() === label.toLowerCase()); + assert.exists(node); + + const setSelectedIds = state.meshRefs.setSelectedIds as (values: string[]) => void; + setSelectedIds([node!.getId()]); + }); +}); + +When('user selects tracing mesh node', () => { + cy.waitForReact(); + cy.get('#loading_kiali_spinner').should('not.exist'); + cy.getReact('MeshPageComponent', { state: { isReady: true } }) + .should('have.length', 1) + .then($graph => { + const { state } = $graph[0]; + + const controller = state.meshRefs.getController() as Visualization; + assert.isTrue(controller.hasGraph()); + + const { nodes } = elems(controller); + const node = nodes.find(n => n.getLabel().toLowerCase() === 'jaeger' || n.getLabel().toLowerCase() === 'tempo'); assert.exists(node); const setSelectedIds = state.meshRefs.setSelectedIds as (values: string[]) => void; @@ -130,17 +150,17 @@ Then('user sees expected mesh infra', () => { assert.isTrue(controller.hasGraph()); const { nodes, edges } = elems(controller); - const nodeNames = nodes.map(n => n.getLabel()); - const nodesLength = nodeNames.some(n => n === 'External Deployments') ? 9 : 8; + const nodeNames = nodes.map(n => n.getLabel().toLowerCase()); + const minNodesLength = nodeNames.some(n => n === 'external deployments') ? 9 : 8; - assert.equal(nodes.length, nodesLength, 'Unexpected number of infra nodes'); - assert.equal(edges.length, 5, 'Unexpected number of infra edges'); - assert.isTrue(nodeNames.some(n => n === 'Data Plane')); - assert.isTrue(nodeNames.some(n => n === 'Grafana')); + assert.isAtLeast(nodes.length, minNodesLength, 'Unexpected number of infra nodes'); + assert.isAtLeast(edges.length, 5, 'Unexpected number of infra edges'); + assert.isTrue(nodeNames.some(n => n === 'data plane')); + assert.isTrue(nodeNames.some(n => n === 'grafana')); assert.isTrue(nodeNames.some(n => n.startsWith('istiod'))); - assert.isTrue(nodeNames.some(n => n === 'jaeger' || n === 'Tempo')); + assert.isTrue(nodeNames.some(n => n === 'jaeger' || n === 'tempo')); assert.isTrue(nodeNames.some(n => n === 'kiali')); - assert.isTrue(nodeNames.some(n => n === 'Prometheus')); + assert.isTrue(nodeNames.some(n => n === 'prometheus')); }); }); @@ -220,3 +240,13 @@ Then('user sees {string} node side panel', (name: string) => { cy.contains(name); }); }); + +Then('user sees tracing node side panel', () => { + cy.waitForReact(); + cy.get('#loading_kiali_spinner').should('not.exist'); + cy.get('#target-panel-node') + .should('be.visible') + .within(() => { + cy.contains(new RegExp('jaeger|Jaeger|tempo|Tempo', 'g')); + }); +}); diff --git a/plugin/cypress/integration/kiali/featureFiles/mesh.feature b/plugin/cypress/integration/kiali/featureFiles/mesh.feature index e8f9980c..32082e6c 100644 --- a/plugin/cypress/integration/kiali/featureFiles/mesh.feature +++ b/plugin/cypress/integration/kiali/featureFiles/mesh.feature @@ -33,9 +33,9 @@ Feature: Kiali Mesh page When user selects mesh node with label "Grafana" Then user sees "Grafana" node side panel - Scenario: Jaeger Infra - When user selects mesh node with label "jaeger" - Then user sees "jaeger" node side panel + Scenario: Tracing Infra + When user selects tracing mesh node + Then user sees tracing node side panel Scenario: Prometheus Infra When user selects mesh node with label "Prometheus" diff --git a/plugin/cypress/integration/kiali/featureFiles/service_details.feature b/plugin/cypress/integration/kiali/featureFiles/service_details.feature index 92d1a7a5..b16ba002 100644 --- a/plugin/cypress/integration/kiali/featureFiles/service_details.feature +++ b/plugin/cypress/integration/kiali/featureFiles/service_details.feature @@ -59,7 +59,8 @@ Feature: Kiali Service Details page Then user sees trace details @bookinfo-app - @tracing-tracing + @tracing + @waypoint-tracing Scenario: See span info after selecting service span And user sees trace information When user selects a trace diff --git a/plugin/cypress/integration/kiali/featureFiles/waypoint.feature b/plugin/cypress/integration/kiali/featureFiles/waypoint.feature index b2cb39e9..e3756e5d 100644 --- a/plugin/cypress/integration/kiali/featureFiles/waypoint.feature +++ b/plugin/cypress/integration/kiali/featureFiles/waypoint.feature @@ -10,12 +10,10 @@ Feature: Kiali Waypoint related features Background: Given user is at administrator perspective - @waypoint Scenario: [Setup] namespace is labeled with waypoint label Then "bookinfo" namespace is labeled with the waypoint label And the graph page has enough data - @waypoint Scenario: [Workload list] See the workload list of bookinfo with the correct info Given user is at the "workloads" list page When user selects the "bookinfo" namespace @@ -27,7 +25,6 @@ Feature: Kiali Waypoint related features And the "Details" column on the "waypoint" row has the text "Waypoint Proxy" And the "Details" column on the "waypoint" row has a link ending in "bookinfo/istio/gateway.networking.k8s.io/v1/Gateway/waypoint" - @waypoint Scenario: [Workload details - productpage] The workload productpage is enrolled in waypoint Given user is at the details page for the "workload" "bookinfo/productpage-v1" located in the "" cluster Then user sees "ambient" badge @@ -38,7 +35,6 @@ Feature: Kiali Waypoint related features And the user sees the L7 "waypoint" link And the link for the waypoint "waypoint" should redirect to a valid workload details - @waypoint Scenario: [Workload details - waypoint] The workload details for a waypoint are valid Given user is at the details page for the "workload" "bookinfo/waypoint" located in the "" cluster Then the user sees the "L7" badge @@ -56,14 +52,12 @@ Feature: Kiali Waypoint related features Then user goes to the waypoint "Info" subtab And validates waypoint Info data - @waypoint Scenario: [Workload details - ztunnel] The workload details for a ztunnel are valid Given user is at the details page for the "workload" "istio-system/ztunnel" located in the "" cluster Then the user cannot see the "missing-sidecar" badge for "ztunnel" workload in "istio-system" namespace And the proxy status is "healthy" And the user validates the Ztunnel tab - @waypoint Scenario: [Traffic Graph] User sees ztunnel traffic Given user is at the "graphpf" page When user graphs "bookinfo" namespaces @@ -72,7 +66,6 @@ Feature: Kiali Waypoint related features And user "enables" "ambientZtunnel" traffic option Then 7 edges appear in the graph - @waypoint Scenario: [Traffic Graph] User sees no Ambient traffic Given user is at the "graphpf" page When user graphs "bookinfo" namespaces @@ -81,7 +74,6 @@ Feature: Kiali Waypoint related features And user "disables" "ambient" traffic option Then 2 edges appear in the graph - @waypoint Scenario: [Traffic Graph] User sees all Ambient traffic Given user is at the "graphpf" page When user graphs "bookinfo" namespaces @@ -91,11 +83,9 @@ Feature: Kiali Waypoint related features And user "enables" "ambient" traffic option Then 16 edges appear in the graph - @waypoint Scenario: [Traffic Graph] User doesn't see waypoint proxy And the "waypoint" node "doesn't" exists - @waypoint Scenario: [Traffic Graph] User sees waypoint proxy When user opens display menu Then the display menu opens @@ -105,7 +95,6 @@ Feature: Kiali Waypoint related features Then 16 edges appear in the graph And the "waypoint" node "does" exists - @waypoint Scenario: [Traffic Graph] User sees waypoint traffic Given user is at the "graphpf" page When user graphs "bookinfo" namespaces @@ -114,13 +103,11 @@ Feature: Kiali Waypoint related features And user "enables" "ambientWaypoint" traffic option Then 11 edges appear in the graph - @waypoint Scenario: [Istio Config] Waypoint should not have validation errors Given user is at the "istio" page And user selects the "bookinfo" namespace Then the "K8sGateway" object in "bookinfo" namespace with "waypoint" name Istio Config is valid - @waypoint Scenario: [Overview] Namespace is labeled with the waypoint labels Given user is at the "overview" page When user clicks in the "LIST" view diff --git a/plugin/src/kiali/README.md b/plugin/src/kiali/README.md index f913283c..0048b3fc 100644 --- a/plugin/src/kiali/README.md +++ b/plugin/src/kiali/README.md @@ -2,6 +2,6 @@ Copy of Kiali frontend source code Kiali frontend source originated from: -* git ref: v2.5 -* git commit: 05703c34a990e828ad8db06604314612cffe25ac -* GitHub URL: https://github.com/kiali/kiali/tree/05703c34a990e828ad8db06604314612cffe25ac/frontend/src +* git ref: master +* git commit: dd432afc0e140b872c445cf4eacd1052d4886417 +* GitHub URL: https://github.com/kiali/kiali/tree/dd432afc0e140b872c445cf4eacd1052d4886417/frontend/src diff --git a/plugin/src/kiali/app/History.tsx b/plugin/src/kiali/app/History.tsx index 8cb70ffa..75f2ef6b 100644 --- a/plugin/src/kiali/app/History.tsx +++ b/plugin/src/kiali/app/History.tsx @@ -95,6 +95,7 @@ export enum URLParam { SHOW_AVERAGE = 'avg', SHOW_SPANS = 'spans', SHOW_TRENDLINES = 'trendlines', + SHOW_WAYPOINT = 'waypoint', SHOW_ZTUNNEL = 'ztunnel', SORT = 'sort', TO = 'to', diff --git a/plugin/src/kiali/components/Envoy/AccessLogModal.tsx b/plugin/src/kiali/components/Envoy/AccessLogModal.tsx index c09c3775..24156602 100644 --- a/plugin/src/kiali/components/Envoy/AccessLogModal.tsx +++ b/plugin/src/kiali/components/Envoy/AccessLogModal.tsx @@ -10,6 +10,7 @@ export interface AccessLogModalProps { accessLog: AccessLog; accessLogMessage: string; className?: string; + isWaypoint: boolean; isZtunnel: boolean; onClose?: () => void; } @@ -835,12 +836,17 @@ export const AccessLogModal: React.FC = (props: AccessLogMo return <>No documentation available; } }; - return ( diff --git a/plugin/src/kiali/components/Pf/PfBadges.tsx b/plugin/src/kiali/components/Pf/PfBadges.tsx index 0ad853a8..94ba7099 100644 --- a/plugin/src/kiali/components/Pf/PfBadges.tsx +++ b/plugin/src/kiali/components/Pf/PfBadges.tsx @@ -88,11 +88,11 @@ export const PFBadges: { [key: string]: PFBadgeType } = Object.freeze({ TraceStore: { badge: 'TS', tt: 'Trace Store' } as PFBadgeType, Unknown: { badge: 'U', tt: 'Unknown' } as PFBadgeType, VirtualService: { badge: 'VS', tt: 'Virtual Service' } as PFBadgeType, - Waypoint: { badge: 'L7', tt: 'Waypoint proxy' } as PFBadgeType, + Waypoint: { badge: 'L7', tt: 'Waypoint proxy', style: { backgroundColor: PFColors.Gold500 } } as PFBadgeType, Workload: { badge: 'W', tt: 'Workload', style: { backgroundColor: PFColors.Blue500 } } as PFBadgeType, WorkloadEntry: { badge: 'WE', tt: 'Workload Entry' } as PFBadgeType, WorkloadGroup: { badge: 'WG', tt: 'Workload Group' } as PFBadgeType, - Ztunnel: { badge: 'L4', tt: 'ztunnel' } as PFBadgeType + Ztunnel: { badge: 'L4', tt: 'ztunnel', style: { backgroundColor: PFColors.Gold300 } } as PFBadgeType }); // This is styled for consistency with OpenShift Console. See console: public/components/_resource.scss diff --git a/plugin/src/kiali/components/Pf/PfColors.tsx b/plugin/src/kiali/components/Pf/PfColors.tsx index 56e8767f..35e12d4f 100644 --- a/plugin/src/kiali/components/Pf/PfColors.tsx +++ b/plugin/src/kiali/components/Pf/PfColors.tsx @@ -22,13 +22,16 @@ export enum PFColors { Black900 = 'var(--pf-v5-global--palette--black-900)', Black1000 = 'var(--pf-v5-global--palette--black-1000)', Blue50 = 'var(--pf-v5-global--palette--blue-50)', + Blue100 = 'var(--pf-v5-global--palette--blue-100)', Blue200 = 'var(--pf-v5-global--palette--blue-200)', Blue300 = 'var(--pf-v5-global--palette--blue-300)', Blue400 = 'var(--pf-v5-global--palette--blue-400)', Blue500 = 'var(--pf-v5-global--palette--blue-500)', Blue600 = 'var(--pf-v5-global--palette--blue-600)', Cyan300 = 'var(--pf-v5-global--palette--cyan-300)', + Gold300 = 'var(--pf-v5-global--palette--gold-300)', Gold400 = 'var(--pf-v5-global--palette--gold-400)', + Gold500 = 'var(--pf-v5-global--palette--gold-500)', Green300 = 'var(--pf-v5-global--palette--green-300)', Green400 = 'var(--pf-v5-global--palette--green-400)', Green500 = 'var(--pf-v5-global--palette--green-500)', diff --git a/plugin/src/kiali/pages/Graph/GraphToolbar/GraphTraffic.tsx b/plugin/src/kiali/pages/Graph/GraphToolbar/GraphTraffic.tsx index 051a28b4..c38b795d 100644 --- a/plugin/src/kiali/pages/Graph/GraphToolbar/GraphTraffic.tsx +++ b/plugin/src/kiali/pages/Graph/GraphToolbar/GraphTraffic.tsx @@ -127,7 +127,7 @@ const GraphTrafficComponent: React.FC = (props: GraphTrafficP }, { id: TrafficRate.AMBIENT_ZTUNNEL, - labelText: 'ZTunnel', + labelText: 'Ztunnel', isChecked: trafficRates.includes(TrafficRate.AMBIENT_ZTUNNEL), tooltip: (
diff --git a/plugin/src/kiali/pages/WorkloadDetails/WorkloadDetailsPage.tsx b/plugin/src/kiali/pages/WorkloadDetails/WorkloadDetailsPage.tsx index 63467247..1fd0531b 100644 --- a/plugin/src/kiali/pages/WorkloadDetails/WorkloadDetailsPage.tsx +++ b/plugin/src/kiali/pages/WorkloadDetails/WorkloadDetailsPage.tsx @@ -184,11 +184,13 @@ class WorkloadDetailsPageComponent extends React.Component {hasPods ? ( ) : ( diff --git a/plugin/src/kiali/pages/WorkloadDetails/WorkloadPodLogs.tsx b/plugin/src/kiali/pages/WorkloadDetails/WorkloadPodLogs.tsx index 9bd1e63f..f2688e2d 100644 --- a/plugin/src/kiali/pages/WorkloadDetails/WorkloadPodLogs.tsx +++ b/plugin/src/kiali/pages/WorkloadDetails/WorkloadPodLogs.tsx @@ -58,9 +58,11 @@ import { isParentKiosk, kioskContextMenuAction } from 'components/Kiosk/KioskAct import { TRACE_LIMIT_DEFAULT } from 'components/Metrics/TraceLimit'; import { TraceSpansLimit } from 'components/Metrics/TraceSpansLimit'; import { infoStyle } from 'styles/IconStyle'; +import { WaypointInfo } from '../../types/Workload'; -const appContainerColors = [PFColors.Blue300, PFColors.Green300, PFColors.Purple300, PFColors.Orange300]; -const proxyContainerColor = PFColors.Gold400; +const appContainerColors = [PFColors.Blue200, PFColors.Blue300, PFColors.Blue400, PFColors.Blue100]; +const proxyContainerColor = PFColors.Gold300; +const waypointContainerColor = PFColors.Gold500; const spanColor = PFColors.Cyan300; type ReduxProps = { @@ -70,10 +72,12 @@ type ReduxProps = { }; export type WorkloadPodLogsProps = ReduxProps & { + app?: string; cluster?: string; lastRefreshAt: TimeInMilliseconds; namespace: string; pods: Pod[]; + waypoints?: WaypointInfo[]; workload: string; }; @@ -116,6 +120,7 @@ interface WorkloadPodLogsState { showSpansLimit: number; showTimestamps: boolean; showToolbar: boolean; + showWaypoint: boolean; showZtunnel: boolean; useRegex: boolean; } @@ -192,6 +197,11 @@ const checkboxStyle = kialiStyle({ marginRight: '1rem' }); +const checkboxMarginStyle = kialiStyle({ + marginLeft: '1rem', + marginRight: '1rem' +}); + const logListStyle = kialiStyle({ overflow: 'auto !important', paddingTop: '0.375rem', @@ -260,6 +270,7 @@ export class WorkloadPodLogsComponent extends React.Component this.setState({ fullscreen: !this.state.fullscreen })); - if (this.state.containerOptions) { const pod = this.props.pods[this.state.podValue!]; this.fetchEntries( @@ -321,6 +332,7 @@ export class WorkloadPodLogsComponent extends React.Component this.toggleSelected(c)} /> - {c.isAmbient && ( + {c.isAmbient && i + 1 === this.state.containerOptions?.length && ( <> + {this.props.waypoints && ( + <> + + waypoint + + } + onChange={() => this.toggleWaypoint()} + /> + + + + + )} )} @@ -602,6 +647,14 @@ export class WorkloadPodLogsComponent extends React.Component { + const urlParams = new URLSearchParams(location.getSearch()); + urlParams.set(URLParam.SHOW_WAYPOINT, String(!this.state.showWaypoint)); + router.navigate(`${location.getPathname()}?${urlParams.toString()}`, { replace: true }); + + this.setState({ showWaypoint: !this.state.showWaypoint }); + }; + private toggleTimeOptionsVisibility = (): void => { this.setState(prevState => ({ isTimeOptionsOpen: !prevState.isTimeOptionsOpen })); }; @@ -868,7 +921,8 @@ export class WorkloadPodLogsComponent extends React.Component this.removeAccessLogModal(k)} - isZtunnel={this.state.showZtunnel} + isZtunnel={this.state.showZtunnel && v.upstream_cluster.includes('spiffe')} + isWaypoint={this.state.showWaypoint && !v.upstream_cluster.includes('spiffe')} /> ); }); @@ -1087,10 +1141,8 @@ export class WorkloadPodLogsComponent extends React.Component>[] = selectedContainers.map(c => { return getPodLogs( namespace, podName, + this.props.workload, + this.props.app, c.name, maxLines, sinceTime, @@ -1159,9 +1226,23 @@ export class WorkloadPodLogsComponent extends React.Component { - promises.push(getPodLogs(namespace, podName, c.name, maxLines, sinceTime, duration, LogType.ZTUNNEL, cluster)); + const containerType = c.displayName === 'ztunnel' ? LogType.ZTUNNEL : LogType.WAYPOINT; + promises.push( + getPodLogs( + namespace, + podName, + this.props.workload, + this.props.app, + c.name, + maxLines, + sinceTime, + duration, + containerType, + cluster + ) + ); }); } diff --git a/plugin/src/kiali/services/Api.ts b/plugin/src/kiali/services/Api.ts index ffe2dca4..9e0a35f8 100644 --- a/plugin/src/kiali/services/Api.ts +++ b/plugin/src/kiali/services/Api.ts @@ -1068,6 +1068,8 @@ export const getPod = (namespace: string, name: string): Promise(HTTP_VERBS.GET, urls.podLogs(namespace, name), params, {}); }; diff --git a/plugin/src/kiali/types/IstioConfigList.ts b/plugin/src/kiali/types/IstioConfigList.ts index a1ac9170..ce81538d 100644 --- a/plugin/src/kiali/types/IstioConfigList.ts +++ b/plugin/src/kiali/types/IstioConfigList.ts @@ -103,7 +103,7 @@ export const dicTypeToGVK: { [key in gvkType]: GroupVersionKind } = { [gvkType.K8sGatewayClass]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GatewayClass' }, [gvkType.K8sGRPCRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GRPCRoute' }, [gvkType.K8sHTTPRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'HTTPRoute' }, - [gvkType.K8sReferenceGrant]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'ReferenceGrant' }, + [gvkType.K8sReferenceGrant]: { Group: 'gateway.networking.k8s.io', Version: 'v1beta1', Kind: 'ReferenceGrant' }, [gvkType.K8sTCPRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TCPRoute' }, [gvkType.K8sTLSRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TLSRoute' }, diff --git a/plugin/src/kiali/types/IstioObjects.ts b/plugin/src/kiali/types/IstioObjects.ts index 1a3203b6..799e0fb1 100644 --- a/plugin/src/kiali/types/IstioObjects.ts +++ b/plugin/src/kiali/types/IstioObjects.ts @@ -278,11 +278,13 @@ export enum LogType { } export interface PodLogsQuery { + app?: string; container?: string; duration?: string; logType?: LogType; maxLines?: number; sinceTime?: number; + workload?: string; } export interface LogLevelQuery { From 16a4c3af4ac1b641eba8e4325df0b4c35d8fbfcb Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Thu, 6 Feb 2025 17:28:51 +0100 Subject: [PATCH 6/7] Validate icon color in a different way --- .../integration/openshift/common/istio_config.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/plugin/cypress/integration/openshift/common/istio_config.ts b/plugin/cypress/integration/openshift/common/istio_config.ts index 618eef54..969d9bbf 100644 --- a/plugin/cypress/integration/openshift/common/istio_config.ts +++ b/plugin/cypress/integration/openshift/common/istio_config.ts @@ -143,14 +143,9 @@ function waitUntilConfigIsVisible( const colorVar = `--pf-v5-global--${healthStatus}-color--100`; const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); - cy.wrap(icon[0]) - .invoke('css', 'color') - .then(iconColor => { - // Convert the status color to RGB format to compare it with the icon color - if (iconColor.toString() === hexToRgb(statusColor)) { - found = true; - } - }); + cy.wrap(icon[0]).should('have.css', 'background-color', hexToRgb(statusColor)); + + found = true; }); } }); From 84d9a54ec44ac8d1419a9b717115c40574ff20cc Mon Sep 17 00:00:00 2001 From: Fernando Hoyos Date: Fri, 7 Feb 2025 12:55:21 +0100 Subject: [PATCH 7/7] Fix color typo --- plugin/cypress/integration/openshift/common/istio_config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/cypress/integration/openshift/common/istio_config.ts b/plugin/cypress/integration/openshift/common/istio_config.ts index 969d9bbf..be1fd072 100644 --- a/plugin/cypress/integration/openshift/common/istio_config.ts +++ b/plugin/cypress/integration/openshift/common/istio_config.ts @@ -143,7 +143,7 @@ function waitUntilConfigIsVisible( const colorVar = `--pf-v5-global--${healthStatus}-color--100`; const statusColor = getComputedStyle(icon[0]).getPropertyValue(colorVar).replace('#', ''); - cy.wrap(icon[0]).should('have.css', 'background-color', hexToRgb(statusColor)); + cy.wrap(icon[0]).should('have.css', 'color', hexToRgb(statusColor)); found = true; });