diff --git a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb index cb13c8112d..763649f4f1 100644 --- a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb +++ b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb @@ -39,7 +39,7 @@ spec: serviceAccountName: kube-state-metrics containers: - name: kube-state-metrics - image: quay.io/coreos/kube-state-metrics:v1.9.5 + image: quay.io/coreos/kube-state-metrics:v1.9.7 ports: - name: metrics containerPort: 8080 diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index e29a9156bd..886cabe6dd 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -26,7 +26,7 @@ export interface MetricsConfiguration { export class MetricsFeature extends ClusterFeature.Feature { name = "metrics"; - latestVersion = "v2.17.2-lens1"; + latestVersion = "v2.17.2-lens2"; templateContext: MetricsConfiguration = { persistence: { diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 5770429a7e..e4f6ab4a34 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -120,6 +120,14 @@ export class LensProxy { protected createProxy(): httpProxy { const proxy = httpProxy.createProxyServer(); + proxy.on("proxyRes", (proxyRes, req) => { + const retryCounterId = this.getRequestId(req); + + if (this.retryCounters.has(retryCounterId)) { + this.retryCounters.delete(retryCounterId); + } + }); + proxy.on("error", (error, req, res, target) => { if (this.closed) { return; diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index 6610fb4b56..412293eee1 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -13,6 +13,7 @@ import { crdStore } from "./crd.store"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Input } from "../input"; import { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import { parseJsonPath } from "../../utils/jsonPath"; interface Props extends KubeObjectDetailsProps { } @@ -46,7 +47,7 @@ export class CrdResourceDetails extends React.Component { renderAdditionalColumns(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { return columns.map(({ name, jsonPath: jp }) => ( - {convertSpecValue(jsonPath.value(crd, jp.slice(1)))} + {convertSpecValue(jsonPath.value(crd, parseJsonPath(jp.slice(1))))} )); } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index cca7ac7015..72209c80f7 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -12,6 +12,7 @@ import { autorun, computed } from "mobx"; import { crdStore } from "./crd.store"; import { TableSortCallback } from "../table"; import { apiManager } from "../../api/api-manager"; +import { parseJsonPath } from "../../utils/jsonPath"; interface Props extends RouteComponentProps { } @@ -61,7 +62,7 @@ export class CrdResources extends React.Component { }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)); + sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); }); return ( @@ -91,10 +92,18 @@ export class CrdResources extends React.Component { renderTableContents={(crdInstance: KubeObject) => [ crdInstance.getName(), isNamespaced && crdInstance.getNs(), - ...extraColumns.map(column => ({ - renderBoolean: true, - children: JSON.stringify(jsonPath.value(crdInstance, column.jsonPath.slice(1))), - })), + ...extraColumns.map((column) => { + let value = jsonPath.value(crdInstance, parseJsonPath(column.jsonPath.slice(1))); + + if (Array.isArray(value) || typeof value === "object") { + value = JSON.stringify(value); + } + + return { + renderBoolean: true, + children: value, + }; + }), crdInstance.getAge(), ]} /> diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 21c3e454a0..ad02dd137c 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -51,10 +51,10 @@ export class NamespaceStore extends KubeObjectStore { } subscribe(apis = [this.api]) { - const { allowedNamespaces } = getHostedCluster(); + const { accessibleNamespaces } = getHostedCluster(); // if user has given static list of namespaces let's not start watches because watch adds stuff that's not wanted - if (allowedNamespaces.length > 0) { + if (accessibleNamespaces.length > 0) { return Function; // no-op } diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index da0e9e8c4c..32885a4c66 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -134,7 +134,7 @@ export class Nodes extends React.Component { { + test("should convert \\. to use indexed notation", () => { + const res = parseJsonPath(".metadata.labels.kubesphere\\.io/alias-name"); + + expect(res).toBe(".metadata.labels['kubesphere.io/alias-name']"); + }); + + test("should convert keys with escpaped charatecrs to use indexed notation", () => { + const res = parseJsonPath(".metadata.labels.kubesphere\\\"io/alias-name"); + + expect(res).toBe(".metadata.labels['kubesphere\"io/alias-name']"); + }); + + test("should convert '-' to use indexed notation", () => { + const res = parseJsonPath(".metadata.labels.alias-name"); + + expect(res).toBe(".metadata.labels['alias-name']"); + }); + + test("should handle scenario when both \\. and indexed notation are present", () => { + const rest = parseJsonPath(".metadata.labels\\.serving['some.other.item']"); + + expect(rest).toBe(".metadata['labels.serving']['some.other.item']"); + }); + + + test("should not touch given jsonPath if no invalid characters present", () => { + const res = parseJsonPath(".status.conditions[?(@.type=='Ready')].status"); + + expect(res).toBe(".status.conditions[?(@.type=='Ready')].status"); + }); + + test("strips '\\' away from the result", () => { + const res = parseJsonPath(".metadata.labels['serving\\.knative\\.dev/configuration']"); + + expect(res).toBe(".metadata.labels['serving.knative.dev/configuration']"); + }); + +}); diff --git a/src/renderer/utils/jsonPath.ts b/src/renderer/utils/jsonPath.ts new file mode 100644 index 0000000000..ea31ffa80e --- /dev/null +++ b/src/renderer/utils/jsonPath.ts @@ -0,0 +1,35 @@ +// Helper to convert strings used for jsonPath where \. or - is present to use indexed notation, +// for example: .metadata.labels.kubesphere\.io/alias-name -> .metadata.labels['kubesphere\.io/alias-name'] + +export function parseJsonPath(jsonPath: string) { + let pathExpression = jsonPath; + + if (jsonPath.match(/[\\-]/g)) { // search for '\' and '-' + const [first, ...rest] = jsonPath.split(/(?<=\w)\./); // split jsonPath by '.' (\. cases are ignored) + + pathExpression = `${convertToIndexNotation(first, true)}${rest.map(value => convertToIndexNotation(value)).join("")}`; + } + + // strip '\' characters from the result + return pathExpression.replace(/\\/g, ""); +} + +function convertToIndexNotation(key: string, firstItem = false) { + if (key.match(/[\\-]/g)) { // check if found '\' and '-' in key + if (key.includes("[")) { // handle cases where key contains [...] + const keyToConvert = key.match(/^.*(?=\[)/g); // get the text from the key before '[' + + if (keyToConvert && keyToConvert[0].match(/[\\-]/g)) { // check if that part contains illegal characters + return key.replace(keyToConvert[0], `['${keyToConvert[0]}']`); // surround key with '[' and ']' + } else { + return `.${key}`; // otherwise return as is with leading '.' + } + } + + return `['${key}']`; + } else { // no illegal chracters found, do not touch + const prefix = firstItem ? "" : "."; + + return `${prefix}${key}`; + } +} \ No newline at end of file