From 679604c1d55ce733bd35121e3509080fc26f8b38 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 14 Dec 2021 14:10:27 -0500 Subject: [PATCH] Fix crash on NetworkPolicy when matchLabels is missing (#4500) --- .../__tests__/network-policy-details.test.tsx | 15 +++++ .../network-policy-details.module.css | 9 +++ .../network-policy-details.tsx | 57 ++++++++++++++++--- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx b/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx index ff6adb8cefa27..2b6684300f687 100644 --- a/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx +++ b/src/renderer/components/+network-policies/__tests__/network-policy-details.test.tsx @@ -53,4 +53,19 @@ describe("NetworkPolicyDetails", () => { expect(await findByTestId(container, "egress-0")).toBeInstanceOf(HTMLElement); expect(await findByText(container, "foo: bar")).toBeInstanceOf(HTMLElement); }); + + it("should not crash if egress nodeSelector doesn't have matchLabels", async () => { + const spec: NetworkPolicySpec = { + egress: [{ + to: [{ + namespaceSelector: {}, + }], + }], + podSelector: {}, + }; + const policy = new NetworkPolicy({ metadata: {} as any, spec } as any); + const { container } = render(); + + expect(container).toBeInstanceOf(HTMLElement); + }); }); diff --git a/src/renderer/components/+network-policies/network-policy-details.module.css b/src/renderer/components/+network-policies/network-policy-details.module.css index 50be1a602466c..a3c06f8616a90 100644 --- a/src/renderer/components/+network-policies/network-policy-details.module.css +++ b/src/renderer/components/+network-policies/network-policy-details.module.css @@ -29,4 +29,13 @@ padding-bottom: 16px; } } + + ul.policySelectorList { + list-style: disc; + } + + .policySelectorList ul { + list-style: circle; + list-style-position: inside; + } } diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index e5632ec30d075..ff870bc2cccb7 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -23,13 +23,15 @@ import styles from "./network-policy-details.module.css"; import React from "react"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { IPolicyIpBlock, IPolicySelector, NetworkPolicy, NetworkPolicyPeer, NetworkPolicyPort } from "../../../common/k8s-api/endpoints/network-policy.api"; +import { IPolicyIpBlock, NetworkPolicy, NetworkPolicyPeer, NetworkPolicyPort } from "../../../common/k8s-api/endpoints/network-policy.api"; import { Badge } from "../badge"; import { SubTitle } from "../layout/sub-title"; import { observer } from "mobx-react"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { KubeObjectMeta } from "../kube-object-meta"; import logger from "../../../common/logger"; +import type { LabelMatchExpression, LabelSelector } from "../../../common/k8s-api/kube-object"; +import { isEmpty } from "lodash"; interface Props extends KubeObjectDetailsProps { } @@ -60,20 +62,57 @@ export class NetworkPolicyDetails extends React.Component { ); } - renderIPolicySelector(name: string, selector: IPolicySelector | undefined) { + renderMatchLabels(matchLabels: Record | undefined) { + if (!matchLabels) { + return null; + } + + return Object.entries(matchLabels) + .map(([key, value]) =>
  • {key}: {value}
  • ); + } + + renderMatchExpressions(matchExpressions: LabelMatchExpression[] | undefined) { + if (!matchExpressions) { + return null; + } + + return matchExpressions.map(expr => { + switch (expr.operator) { + case "DoesNotExist": + case "Exists": + return
  • {expr.key} ({expr.operator})
  • ; + case "In": + case "NotIn": + return ( +
  • + {expr.key}({expr.operator}) +
      + {expr.values.map((value, index) =>
    • {value}
    • )} +
    +
  • + ); + } + }); + } + + renderIPolicySelector(name: string, selector: LabelSelector | undefined) { if (!selector) { return null; } + const { matchLabels, matchExpressions } = selector; + return ( - { - Object - .entries(selector.matchLabels) - .map(data => data.join(": ")) - .join(", ") - || "(empty)" - } +
      + {this.renderMatchLabels(matchLabels)} + {this.renderMatchExpressions(matchExpressions)} + { + (isEmpty(matchLabels) && isEmpty(matchExpressions)) && ( +
    • (empty)
    • + ) + } +
    ); }