@backstage/plugin-kubernetes 0.4.17 → 0.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -3,14 +3,15 @@ import * as React from 'react';
3
3
  import React__default, { Fragment, useState, useEffect, useContext } from 'react';
4
4
  import { useEntity } from '@backstage/plugin-catalog-react';
5
5
  import { Routes, Route } from 'react-router-dom';
6
- import { Typography, Chip, makeStyles, createStyles, Button, Drawer, Grid, IconButton, FormControlLabel, Switch, Accordion, AccordionSummary, AccordionDetails, Divider, Stepper, Step, StepLabel } from '@material-ui/core';
7
- import { WarningPanel, SubvalueCell, StatusError, StatusOK, StatusAborted, Button as Button$1, CodeSnippet, StructuredMetadataTable, Table, InfoCard, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
6
+ import { Typography, Chip, Grid, makeStyles, createStyles, Button, Drawer, IconButton, FormControlLabel, Switch, Accordion, AccordionSummary, AccordionDetails, Divider, Stepper, Step, StepLabel } from '@material-ui/core';
7
+ import { WarningPanel, InfoCard, Table, SubvalueCell, StatusError, StatusOK, StatusAborted, Button as Button$1, CodeSnippet, StructuredMetadataTable, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
8
+ import EmptyStateImage from './assets/emptystate.svg';
8
9
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
9
10
  import Close from '@material-ui/icons/Close';
10
11
  import OpenInNewIcon from '@material-ui/icons/OpenInNew';
11
12
  import { withStyles } from '@material-ui/core/styles';
12
13
  import jsYaml from 'js-yaml';
13
- import EmptyStateImage from './assets/emptystate.svg';
14
+ import { useInterval } from 'react-use';
14
15
  import lodash from 'lodash';
15
16
  import PauseIcon from '@material-ui/icons/Pause';
16
17
  import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
@@ -172,6 +173,123 @@ const ErrorPanel$1 = ({
172
173
  variant: "body2"
173
174
  }, "Errors: ", errorMessage));
174
175
 
176
+ const columns$1 = [
177
+ {
178
+ title: "cluster",
179
+ width: "15%",
180
+ render: (detectedError) => detectedError.cluster
181
+ },
182
+ {
183
+ title: "kind",
184
+ width: "15%",
185
+ render: (detectedError) => detectedError.kind
186
+ },
187
+ {
188
+ title: "name",
189
+ width: "30%",
190
+ render: (detectedError) => {
191
+ const errorCount = detectedError.names.length;
192
+ if (errorCount === 0) {
193
+ return null;
194
+ }
195
+ const displayName = detectedError.names[0];
196
+ const otherErrorCount = errorCount - 1;
197
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, displayName, " ", otherErrorCount > 0 && /* @__PURE__ */ React.createElement(Chip, {
198
+ label: `+ ${otherErrorCount} other${otherErrorCount > 1 ? "s" : ""}`,
199
+ size: "small"
200
+ }));
201
+ }
202
+ },
203
+ {
204
+ title: "messages",
205
+ width: "40%",
206
+ render: (detectedError) => /* @__PURE__ */ React.createElement(React.Fragment, null, detectedError.message.map((m, i) => /* @__PURE__ */ React.createElement("div", {
207
+ key: i
208
+ }, m)))
209
+ }
210
+ ];
211
+ const sortBySeverity = (a, b) => {
212
+ if (a.severity < b.severity) {
213
+ return 1;
214
+ } else if (b.severity < a.severity) {
215
+ return -1;
216
+ }
217
+ return 0;
218
+ };
219
+ const ErrorEmptyState = () => {
220
+ return /* @__PURE__ */ React.createElement(Grid, {
221
+ container: true,
222
+ justifyContent: "space-around",
223
+ direction: "row",
224
+ alignItems: "center",
225
+ spacing: 2
226
+ }, /* @__PURE__ */ React.createElement(Grid, {
227
+ item: true,
228
+ xs: 4
229
+ }, /* @__PURE__ */ React.createElement(Typography, {
230
+ variant: "h5"
231
+ }, "Nice! There are no errors to report!")), /* @__PURE__ */ React.createElement(Grid, {
232
+ item: true,
233
+ xs: 4
234
+ }, /* @__PURE__ */ React.createElement("img", {
235
+ src: EmptyStateImage,
236
+ alt: "EmptyState",
237
+ "data-testid": "emptyStateImg"
238
+ })));
239
+ };
240
+ const ErrorReporting = ({detectedErrors}) => {
241
+ const errors = Array.from(detectedErrors.values()).flat().sort(sortBySeverity);
242
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length === 0 ? /* @__PURE__ */ React.createElement(InfoCard, {
243
+ title: "Error Reporting"
244
+ }, /* @__PURE__ */ React.createElement(ErrorEmptyState, null)) : /* @__PURE__ */ React.createElement(Table, {
245
+ title: "Error Reporting",
246
+ data: errors,
247
+ columns: columns$1,
248
+ options: {paging: true, search: false}
249
+ }));
250
+ };
251
+
252
+ const groupResponses = (fetchResponse) => {
253
+ return fetchResponse.reduce((prev, next) => {
254
+ switch (next.type) {
255
+ case "deployments":
256
+ prev.deployments.push(...next.resources);
257
+ break;
258
+ case "pods":
259
+ prev.pods.push(...next.resources);
260
+ break;
261
+ case "replicasets":
262
+ prev.replicaSets.push(...next.resources);
263
+ break;
264
+ case "services":
265
+ prev.services.push(...next.resources);
266
+ break;
267
+ case "configmaps":
268
+ prev.configMaps.push(...next.resources);
269
+ break;
270
+ case "horizontalpodautoscalers":
271
+ prev.horizontalPodAutoscalers.push(...next.resources);
272
+ break;
273
+ case "ingresses":
274
+ prev.ingresses.push(...next.resources);
275
+ break;
276
+ case "customresources":
277
+ prev.customResources.push(...next.resources);
278
+ break;
279
+ }
280
+ return prev;
281
+ }, {
282
+ pods: [],
283
+ replicaSets: [],
284
+ deployments: [],
285
+ services: [],
286
+ configMaps: [],
287
+ horizontalPodAutoscalers: [],
288
+ ingresses: [],
289
+ customResources: []
290
+ });
291
+ };
292
+
175
293
  const imageChips = (pod) => {
176
294
  var _a, _b;
177
295
  const containerStatuses2 = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
@@ -243,141 +361,307 @@ const renderCondition = (condition) => {
243
361
  return [condition.type, /* @__PURE__ */ React__default.createElement(StatusAborted, null)];
244
362
  };
245
363
 
246
- const useKubernetesObjects = (entity) => {
247
- const kubernetesApi = useApi(kubernetesApiRef);
248
- const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
249
- const [kubernetesObjects, setKubernetesObjects] = useState(void 0);
250
- const [error, setError] = useState(void 0);
251
- useEffect(() => {
252
- (async () => {
253
- let clusters = [];
254
- try {
255
- clusters = await kubernetesApi.getClusters();
256
- } catch (e) {
257
- setError(e.message);
258
- return;
259
- }
260
- const authProviders = [
261
- ...new Set(clusters.map((c) => c.authProvider))
262
- ];
263
- let requestBody = {
264
- entity
265
- };
266
- for (const authProviderStr of authProviders) {
267
- try {
268
- requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(authProviderStr, requestBody);
269
- } catch (e) {
270
- setError(e.message);
271
- return;
364
+ const detectErrorsInObjects = (objects, kind, clusterName, errorMappers) => {
365
+ var _a, _b;
366
+ const errors = new Map();
367
+ for (const object of objects) {
368
+ for (const errorMapper of errorMappers) {
369
+ if (errorMapper.errorExists(object)) {
370
+ const message = errorMapper.messageAccessor(object);
371
+ const dedupKey = message.join("");
372
+ const value = errors.get(dedupKey);
373
+ const name = (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown";
374
+ if (value !== void 0) {
375
+ value.names.push(name);
376
+ errors.set(dedupKey, value);
377
+ } else {
378
+ errors.set(dedupKey, {
379
+ cluster: clusterName,
380
+ kind,
381
+ names: [name],
382
+ message,
383
+ severity: errorMapper.severity
384
+ });
272
385
  }
273
386
  }
274
- try {
275
- setKubernetesObjects(await kubernetesApi.getObjectsByEntity(requestBody));
276
- } catch (e) {
277
- setError(e.message);
278
- return;
279
- }
280
- })();
281
- }, [entity.metadata.name, kubernetesApi, kubernetesAuthProvidersApi]);
282
- return {
283
- kubernetesObjects,
284
- error
285
- };
286
- };
287
-
288
- const PodNamesWithErrorsContext = React__default.createContext(new Set());
289
-
290
- const GroupedResponsesContext = React__default.createContext({
291
- pods: [],
292
- replicaSets: [],
293
- deployments: [],
294
- services: [],
295
- configMaps: [],
296
- horizontalPodAutoscalers: [],
297
- ingresses: [],
298
- customResources: []
299
- });
300
-
301
- const ClusterContext = React__default.createContext({
302
- name: ""
303
- });
304
-
305
- const kindMappings$1 = {
306
- deployment: "deployment",
307
- ingress: "ingress",
308
- service: "service",
309
- horizontalpodautoscaler: "deployment"
310
- };
311
- function standardFormatter(options) {
312
- var _a, _b;
313
- const result = new URL(options.dashboardUrl.href);
314
- const name = (_a = options.object.metadata) == null ? void 0 : _a.name;
315
- const namespace = (_b = options.object.metadata) == null ? void 0 : _b.namespace;
316
- const validKind = kindMappings$1[options.kind.toLocaleLowerCase("en-US")];
317
- if (namespace) {
318
- result.searchParams.set("namespace", namespace);
319
- }
320
- if (validKind && name && namespace) {
321
- result.hash = `/${validKind}/${namespace}/${name}`;
322
- } else if (namespace) {
323
- result.hash = "/workloads";
324
- }
325
- return result;
326
- }
327
-
328
- const kindMappings = {
329
- deployment: "apps.deployment",
330
- ingress: "networking.k8s.io.ingress",
331
- service: "service",
332
- horizontalpodautoscaler: "autoscaling.horizontalpodautoscaler"
333
- };
334
- function rancherFormatter(options) {
335
- var _a, _b;
336
- const result = new URL(options.dashboardUrl.href);
337
- const name = (_a = options.object.metadata) == null ? void 0 : _a.name;
338
- const namespace = (_b = options.object.metadata) == null ? void 0 : _b.namespace;
339
- const validKind = kindMappings[options.kind.toLocaleLowerCase("en-US")];
340
- if (validKind && name && namespace) {
341
- result.pathname += `explorer/${validKind}/${namespace}/${name}`;
342
- } else if (namespace) {
343
- result.pathname += "explorer/workload";
387
+ }
344
388
  }
345
- return result;
346
- }
347
-
348
- function openshiftFormatter(_options) {
349
- throw new Error("OpenShift formatter is not yet implemented. Please, contribute!");
350
- }
351
-
352
- function aksFormatter(_options) {
353
- throw new Error("AKS formatter is not yet implemented. Please, contribute!");
354
- }
355
-
356
- function eksFormatter(_options) {
357
- throw new Error("EKS formatter is not yet implemented. Please, contribute!");
358
- }
359
-
360
- function gkeFormatter(_options) {
361
- throw new Error("GKE formatter is not yet implemented. Please, contribute!");
362
- }
363
-
364
- const clusterLinksFormatters = {
365
- standard: standardFormatter,
366
- rancher: rancherFormatter,
367
- openshift: openshiftFormatter,
368
- aks: aksFormatter,
369
- eks: eksFormatter,
370
- gke: gkeFormatter
389
+ return Array.from(errors.values());
371
390
  };
372
- const defaultFormatterName = "standard";
373
391
 
374
- function formatClusterLink(options) {
375
- if (!options.dashboardUrl) {
376
- return void 0;
377
- }
378
- if (!options.object) {
379
- return options.dashboardUrl;
380
- }
392
+ const podErrorMappers = [
393
+ {
394
+ severity: 5,
395
+ errorExplanation: "status-message",
396
+ errorExists: (pod) => {
397
+ var _a;
398
+ return ((_a = pod.status) == null ? void 0 : _a.message) !== void 0;
399
+ },
400
+ messageAccessor: (pod) => {
401
+ var _a, _b;
402
+ return [(_b = (_a = pod.status) == null ? void 0 : _a.message) != null ? _b : ""];
403
+ }
404
+ },
405
+ {
406
+ severity: 4,
407
+ errorExplanation: "containers-restarting",
408
+ errorExists: (pod) => {
409
+ return totalRestarts(pod) > 3;
410
+ },
411
+ messageAccessor: (pod) => {
412
+ var _a, _b;
413
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => cs.restartCount > 0).map((cs) => `container=${cs.name} restarted ${cs.restartCount} times`);
414
+ }
415
+ },
416
+ {
417
+ severity: 5,
418
+ errorExplanation: "condition-message-present",
419
+ errorExists: (pod) => {
420
+ var _a, _b;
421
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).some((c) => c.message !== void 0);
422
+ },
423
+ messageAccessor: (pod) => {
424
+ var _a, _b;
425
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.message !== void 0).map((c) => {
426
+ var _a2;
427
+ return (_a2 = c.message) != null ? _a2 : "";
428
+ });
429
+ }
430
+ },
431
+ {
432
+ severity: 6,
433
+ errorExplanation: "container-waiting",
434
+ errorExists: (pod) => {
435
+ var _a, _b;
436
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
437
+ var _a2, _b2;
438
+ return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
439
+ });
440
+ },
441
+ messageAccessor: (pod) => {
442
+ var _a, _b;
443
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
444
+ var _a2, _b2;
445
+ return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
446
+ }).map((cs) => {
447
+ var _a2, _b2, _c;
448
+ return (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "";
449
+ });
450
+ }
451
+ },
452
+ {
453
+ severity: 4,
454
+ errorExplanation: "container-last-state-error",
455
+ errorExists: (pod) => {
456
+ var _a, _b;
457
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
458
+ var _a2, _b2, _c;
459
+ return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
460
+ });
461
+ },
462
+ messageAccessor: (pod) => {
463
+ var _a, _b;
464
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
465
+ var _a2, _b2, _c;
466
+ return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
467
+ }).map((cs) => {
468
+ var _a2, _b2;
469
+ return `container=${cs.name} exited with error code (${(_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.exitCode})`;
470
+ });
471
+ }
472
+ }
473
+ ];
474
+ const detectErrorsInPods = (pods, clusterName) => detectErrorsInObjects(pods, "Pod", clusterName, podErrorMappers);
475
+
476
+ const deploymentErrorMappers = [
477
+ {
478
+ severity: 6,
479
+ errorExplanation: "condition-message-present",
480
+ errorExists: (deployment) => {
481
+ var _a, _b;
482
+ return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").some((c) => c.message !== void 0);
483
+ },
484
+ messageAccessor: (deployment) => {
485
+ var _a, _b;
486
+ return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").filter((c) => c.message !== void 0).map((c) => {
487
+ var _a2;
488
+ return (_a2 = c.message) != null ? _a2 : "";
489
+ });
490
+ }
491
+ }
492
+ ];
493
+ const detectErrorsInDeployments = (deployments, clusterName) => detectErrorsInObjects(deployments, "Deployment", clusterName, deploymentErrorMappers);
494
+
495
+ const hpaErrorMappers = [
496
+ {
497
+ severity: 8,
498
+ errorExplanation: "hpa-max-current-replicas",
499
+ errorExists: (hpa) => {
500
+ var _a, _b, _c;
501
+ return ((_b = (_a = hpa.spec) == null ? void 0 : _a.maxReplicas) != null ? _b : -1) === ((_c = hpa.status) == null ? void 0 : _c.currentReplicas);
502
+ },
503
+ messageAccessor: (hpa) => {
504
+ var _a, _b, _c;
505
+ return [
506
+ `Current number of replicas (${(_a = hpa.status) == null ? void 0 : _a.currentReplicas}) is equal to the configured max number of replicas (${(_c = (_b = hpa.spec) == null ? void 0 : _b.maxReplicas) != null ? _c : -1})`
507
+ ];
508
+ }
509
+ }
510
+ ];
511
+ const detectErrorsInHpa = (hpas, clusterName) => detectErrorsInObjects(hpas, "HorizontalPodAutoscaler", clusterName, hpaErrorMappers);
512
+
513
+ const detectErrors = (objects) => {
514
+ const errors = new Map();
515
+ for (const clusterResponse of objects.items) {
516
+ let clusterErrors = [];
517
+ const groupedResponses = groupResponses(clusterResponse.resources);
518
+ clusterErrors = clusterErrors.concat(detectErrorsInPods(groupedResponses.pods, clusterResponse.cluster.name));
519
+ clusterErrors = clusterErrors.concat(detectErrorsInDeployments(groupedResponses.deployments, clusterResponse.cluster.name));
520
+ clusterErrors = clusterErrors.concat(detectErrorsInHpa(groupedResponses.horizontalPodAutoscalers, clusterResponse.cluster.name));
521
+ errors.set(clusterResponse.cluster.name, clusterErrors);
522
+ }
523
+ return errors;
524
+ };
525
+
526
+ const useKubernetesObjects = (entity, intervalMs = 1e4) => {
527
+ const kubernetesApi = useApi(kubernetesApiRef);
528
+ const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
529
+ const [kubernetesObjects, setKubernetesObjects] = useState(void 0);
530
+ const [error, setError] = useState(void 0);
531
+ const getObjects = async () => {
532
+ let clusters = [];
533
+ try {
534
+ clusters = await kubernetesApi.getClusters();
535
+ } catch (e) {
536
+ setError(e.message);
537
+ return;
538
+ }
539
+ const authProviders = [
540
+ ...new Set(clusters.map((c) => c.authProvider))
541
+ ];
542
+ let requestBody = {
543
+ entity
544
+ };
545
+ for (const authProviderStr of authProviders) {
546
+ try {
547
+ requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(authProviderStr, requestBody);
548
+ } catch (e) {
549
+ setError(e.message);
550
+ return;
551
+ }
552
+ }
553
+ try {
554
+ setKubernetesObjects(await kubernetesApi.getObjectsByEntity(requestBody));
555
+ } catch (e) {
556
+ setError(e.message);
557
+ return;
558
+ }
559
+ };
560
+ useEffect(() => {
561
+ getObjects();
562
+ }, [entity.metadata.name, kubernetesApi, kubernetesAuthProvidersApi]);
563
+ useInterval(() => {
564
+ getObjects();
565
+ }, intervalMs);
566
+ return {
567
+ kubernetesObjects,
568
+ error
569
+ };
570
+ };
571
+
572
+ const PodNamesWithErrorsContext = React__default.createContext(new Set());
573
+
574
+ const GroupedResponsesContext = React__default.createContext({
575
+ pods: [],
576
+ replicaSets: [],
577
+ deployments: [],
578
+ services: [],
579
+ configMaps: [],
580
+ horizontalPodAutoscalers: [],
581
+ ingresses: [],
582
+ customResources: []
583
+ });
584
+
585
+ const ClusterContext = React__default.createContext({
586
+ name: ""
587
+ });
588
+
589
+ const kindMappings$1 = {
590
+ deployment: "deployment",
591
+ ingress: "ingress",
592
+ service: "service",
593
+ horizontalpodautoscaler: "deployment"
594
+ };
595
+ function standardFormatter(options) {
596
+ var _a, _b;
597
+ const result = new URL(options.dashboardUrl.href);
598
+ const name = (_a = options.object.metadata) == null ? void 0 : _a.name;
599
+ const namespace = (_b = options.object.metadata) == null ? void 0 : _b.namespace;
600
+ const validKind = kindMappings$1[options.kind.toLocaleLowerCase("en-US")];
601
+ if (namespace) {
602
+ result.searchParams.set("namespace", namespace);
603
+ }
604
+ if (validKind && name && namespace) {
605
+ result.hash = `/${validKind}/${namespace}/${name}`;
606
+ } else if (namespace) {
607
+ result.hash = "/workloads";
608
+ }
609
+ return result;
610
+ }
611
+
612
+ const kindMappings = {
613
+ deployment: "apps.deployment",
614
+ ingress: "networking.k8s.io.ingress",
615
+ service: "service",
616
+ horizontalpodautoscaler: "autoscaling.horizontalpodautoscaler"
617
+ };
618
+ function rancherFormatter(options) {
619
+ var _a, _b;
620
+ const result = new URL(options.dashboardUrl.href);
621
+ const name = (_a = options.object.metadata) == null ? void 0 : _a.name;
622
+ const namespace = (_b = options.object.metadata) == null ? void 0 : _b.namespace;
623
+ const validKind = kindMappings[options.kind.toLocaleLowerCase("en-US")];
624
+ if (validKind && name && namespace) {
625
+ result.pathname += `explorer/${validKind}/${namespace}/${name}`;
626
+ } else if (namespace) {
627
+ result.pathname += "explorer/workload";
628
+ }
629
+ return result;
630
+ }
631
+
632
+ function openshiftFormatter(_options) {
633
+ throw new Error("OpenShift formatter is not yet implemented. Please, contribute!");
634
+ }
635
+
636
+ function aksFormatter(_options) {
637
+ throw new Error("AKS formatter is not yet implemented. Please, contribute!");
638
+ }
639
+
640
+ function eksFormatter(_options) {
641
+ throw new Error("EKS formatter is not yet implemented. Please, contribute!");
642
+ }
643
+
644
+ function gkeFormatter(_options) {
645
+ throw new Error("GKE formatter is not yet implemented. Please, contribute!");
646
+ }
647
+
648
+ const clusterLinksFormatters = {
649
+ standard: standardFormatter,
650
+ rancher: rancherFormatter,
651
+ openshift: openshiftFormatter,
652
+ aks: aksFormatter,
653
+ eks: eksFormatter,
654
+ gke: gkeFormatter
655
+ };
656
+ const defaultFormatterName = "standard";
657
+
658
+ function formatClusterLink(options) {
659
+ if (!options.dashboardUrl) {
660
+ return void 0;
661
+ }
662
+ if (!options.object) {
663
+ return options.dashboardUrl;
664
+ }
381
665
  const app = options.dashboardApp || defaultFormatterName;
382
666
  const formatter = clusterLinksFormatters[app];
383
667
  if (!formatter) {
@@ -590,7 +874,7 @@ const PodDrawer = ({
590
874
  });
591
875
  };
592
876
 
593
- const columns$1 = [
877
+ const columns = [
594
878
  {
595
879
  title: "name",
596
880
  highlight: true,
@@ -600,516 +884,237 @@ const columns$1 = [
600
884
  },
601
885
  {
602
886
  title: "phase",
603
- render: (pod) => {
604
- var _a, _b;
605
- return (_b = (_a = pod.status) == null ? void 0 : _a.phase) != null ? _b : "unknown";
606
- }
607
- },
608
- {
609
- title: "containers ready",
610
- align: "center",
611
- render: containersReady
612
- },
613
- {
614
- title: "total restarts",
615
- align: "center",
616
- render: totalRestarts,
617
- type: "numeric"
618
- },
619
- {
620
- title: "status",
621
- render: containerStatuses
622
- }
623
- ];
624
- const PodsTable = ({pods}) => {
625
- const tableStyle = {
626
- minWidth: "0",
627
- width: "100%"
628
- };
629
- return /* @__PURE__ */ React__default.createElement("div", {
630
- style: tableStyle
631
- }, /* @__PURE__ */ React__default.createElement(Table, {
632
- options: {paging: true, search: false},
633
- data: pods,
634
- columns: columns$1
635
- }));
636
- };
637
-
638
- const DeploymentDrawer = ({
639
- deployment,
640
- expanded
641
- }) => {
642
- var _a, _b, _c;
643
- const namespace = (_a = deployment.metadata) == null ? void 0 : _a.namespace;
644
- return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
645
- object: deployment,
646
- expanded,
647
- kind: "Deployment",
648
- renderObject: (deploymentObj) => {
649
- var _a2, _b2, _c2, _d, _e, _f, _g, _h;
650
- const conditions = ((_b2 = (_a2 = deploymentObj.status) == null ? void 0 : _a2.conditions) != null ? _b2 : []).map(renderCondition).reduce((accum, next) => {
651
- accum[next[0]] = next[1];
652
- return accum;
653
- }, {});
654
- return {
655
- strategy: (_d = (_c2 = deploymentObj.spec) == null ? void 0 : _c2.strategy) != null ? _d : "???",
656
- minReadySeconds: (_f = (_e = deploymentObj.spec) == null ? void 0 : _e.minReadySeconds) != null ? _f : "???",
657
- progressDeadlineSeconds: (_h = (_g = deploymentObj.spec) == null ? void 0 : _g.progressDeadlineSeconds) != null ? _h : "???",
658
- ...conditions
659
- };
660
- }
661
- }, /* @__PURE__ */ React__default.createElement(Grid, {
662
- container: true,
663
- direction: "column",
664
- justifyContent: "flex-start",
665
- alignItems: "flex-start",
666
- spacing: 0
667
- }, /* @__PURE__ */ React__default.createElement(Grid, {
668
- item: true
669
- }, /* @__PURE__ */ React__default.createElement(Typography, {
670
- variant: "h5"
671
- }, (_c = (_b = deployment.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")), /* @__PURE__ */ React__default.createElement(Grid, {
672
- item: true
673
- }, /* @__PURE__ */ React__default.createElement(Typography, {
674
- color: "textSecondary",
675
- variant: "body1"
676
- }, "Deployment")), namespace && /* @__PURE__ */ React__default.createElement(Grid, {
677
- item: true
678
- }, /* @__PURE__ */ React__default.createElement(Chip, {
679
- size: "small",
680
- label: `namespace: ${namespace}`
681
- }))));
682
- };
683
-
684
- const HorizontalPodAutoscalerDrawer = ({
685
- hpa,
686
- expanded,
687
- children
688
- }) => {
689
- return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
690
- kind: "HorizontalPodAutoscaler",
691
- object: hpa,
692
- expanded,
693
- renderObject: (hpaObject) => {
694
- var _a, _b, _c, _d, _e, _f;
695
- return {
696
- targetCPUUtilizationPercentage: (_a = hpaObject.spec) == null ? void 0 : _a.targetCPUUtilizationPercentage,
697
- currentCPUUtilizationPercentage: (_b = hpaObject.status) == null ? void 0 : _b.currentCPUUtilizationPercentage,
698
- minReplicas: (_c = hpaObject.spec) == null ? void 0 : _c.minReplicas,
699
- maxReplicas: (_d = hpaObject.spec) == null ? void 0 : _d.maxReplicas,
700
- currentReplicas: (_e = hpaObject.status) == null ? void 0 : _e.currentReplicas,
701
- desiredReplicas: (_f = hpaObject.status) == null ? void 0 : _f.desiredReplicas
702
- };
703
- }
704
- }, children);
705
- };
706
-
707
- function getOwnedResources(potentialOwner, possiblyOwned) {
708
- return possiblyOwned.filter((p) => {
709
- var _a, _b, _c;
710
- return (_c = (_b = (_a = p.metadata) == null ? void 0 : _a.ownerReferences) == null ? void 0 : _b.some((o) => {
711
- var _a2;
712
- return o.uid === ((_a2 = potentialOwner.metadata) == null ? void 0 : _a2.uid);
713
- })) != null ? _c : false;
714
- });
715
- }
716
- const getOwnedPodsThroughReplicaSets = (potentialOwner, replicaSets, pods) => {
717
- return getOwnedResources(potentialOwner, replicaSets.filter((rs) => rs.status && rs.status.replicas > 0)).reduce((accum, rs) => {
718
- return accum.concat(getOwnedResources(rs, pods));
719
- }, []);
720
- };
721
- const getMatchingHpa = (ownerName, ownerKind, hpas) => {
722
- return hpas.find((hpa) => {
723
- var _a, _b, _c, _d, _e, _f;
724
- return ((_c = (_b = (_a = hpa.spec) == null ? void 0 : _a.scaleTargetRef) == null ? void 0 : _b.kind) != null ? _c : "").toLocaleLowerCase("en-US") === ownerKind.toLocaleLowerCase("en-US") && ((_f = (_e = (_d = hpa.spec) == null ? void 0 : _d.scaleTargetRef) == null ? void 0 : _e.name) != null ? _f : "") === (ownerName != null ? ownerName : "unknown-deployment");
725
- });
726
- };
727
-
728
- const DeploymentSummary = ({
729
- deployment,
730
- numberOfCurrentPods,
731
- numberOfPodsWithErrors,
732
- hpa
733
- }) => {
734
- var _a, _b, _c, _d, _e, _f, _g, _h;
735
- return /* @__PURE__ */ React__default.createElement(Grid, {
736
- container: true,
737
- direction: "row",
738
- justifyContent: "flex-start",
739
- alignItems: "center"
740
- }, /* @__PURE__ */ React__default.createElement(Grid, {
741
- xs: 3,
742
- item: true
743
- }, /* @__PURE__ */ React__default.createElement(DeploymentDrawer, {
744
- deployment
745
- })), /* @__PURE__ */ React__default.createElement(Grid, {
746
- item: true,
747
- xs: 1
748
- }, /* @__PURE__ */ React__default.createElement(Divider, {
749
- style: {height: "5em"},
750
- orientation: "vertical"
751
- })), hpa && /* @__PURE__ */ React__default.createElement(Grid, {
752
- item: true,
753
- xs: 3
754
- }, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, {
755
- hpa
756
- }, /* @__PURE__ */ React__default.createElement(Grid, {
757
- item: true,
758
- container: true,
759
- direction: "column",
760
- justifyContent: "flex-start",
761
- alignItems: "flex-start",
762
- spacing: 0
763
- }, /* @__PURE__ */ React__default.createElement(Grid, {
764
- item: true
765
- }, /* @__PURE__ */ React__default.createElement(Typography, {
766
- variant: "subtitle2"
767
- }, "min replicas ", (_b = (_a = hpa.spec) == null ? void 0 : _a.minReplicas) != null ? _b : "?", " / max replicas", " ", (_d = (_c = hpa.spec) == null ? void 0 : _c.maxReplicas) != null ? _d : "?")), /* @__PURE__ */ React__default.createElement(Grid, {
768
- item: true
769
- }, /* @__PURE__ */ React__default.createElement(Typography, {
770
- variant: "subtitle2"
771
- }, "current CPU usage:", " ", (_f = (_e = hpa.status) == null ? void 0 : _e.currentCPUUtilizationPercentage) != null ? _f : "?", "%")), /* @__PURE__ */ React__default.createElement(Grid, {
772
- item: true
773
- }, /* @__PURE__ */ React__default.createElement(Typography, {
774
- variant: "subtitle2"
775
- }, "target CPU usage:", " ", (_h = (_g = hpa.spec) == null ? void 0 : _g.targetCPUUtilizationPercentage) != null ? _h : "?", "%"))))), /* @__PURE__ */ React__default.createElement(Grid, {
776
- item: true,
777
- container: true,
778
- xs: 3,
779
- direction: "column",
780
- justifyContent: "flex-start",
781
- alignItems: "flex-start"
782
- }, /* @__PURE__ */ React__default.createElement(Grid, {
783
- item: true
784
- }, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")), /* @__PURE__ */ React__default.createElement(Grid, {
785
- item: true
786
- }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pod", numberOfPodsWithErrors > 1 ? "s" : "", " with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))));
787
- };
788
- const DeploymentAccordion = ({
789
- deployment,
790
- ownedPods,
791
- matchingHpa
792
- }) => {
793
- const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
794
- const podsWithErrors = ownedPods.filter((p) => {
795
- var _a, _b;
796
- return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
797
- });
798
- return /* @__PURE__ */ React__default.createElement(Accordion, {
799
- TransitionProps: {unmountOnExit: true}
800
- }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
801
- expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
802
- }, /* @__PURE__ */ React__default.createElement(DeploymentSummary, {
803
- deployment,
804
- numberOfCurrentPods: ownedPods.length,
805
- numberOfPodsWithErrors: podsWithErrors.length,
806
- hpa: matchingHpa
807
- })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(PodsTable, {
808
- pods: ownedPods
809
- })));
810
- };
811
- const DeploymentsAccordions = ({}) => {
812
- const groupedResponses = useContext(GroupedResponsesContext);
813
- return /* @__PURE__ */ React__default.createElement(Grid, {
814
- container: true,
815
- direction: "column",
816
- justifyContent: "flex-start",
817
- alignItems: "flex-start"
818
- }, groupedResponses.deployments.map((deployment, i) => {
819
- var _a;
820
- return /* @__PURE__ */ React__default.createElement(Grid, {
821
- container: true,
822
- item: true,
823
- key: i,
824
- xs: true
825
- }, /* @__PURE__ */ React__default.createElement(Grid, {
826
- item: true,
827
- xs: true
828
- }, /* @__PURE__ */ React__default.createElement(DeploymentAccordion, {
829
- matchingHpa: getMatchingHpa((_a = deployment.metadata) == null ? void 0 : _a.name, "deployment", groupedResponses.horizontalPodAutoscalers),
830
- ownedPods: getOwnedPodsThroughReplicaSets(deployment, groupedResponses.replicaSets, groupedResponses.pods),
831
- deployment
832
- })));
833
- }));
834
- };
835
-
836
- const columns = [
837
- {
838
- title: "cluster",
839
- width: "15%",
840
- render: (detectedError) => detectedError.cluster
841
- },
842
- {
843
- title: "kind",
844
- width: "15%",
845
- render: (detectedError) => detectedError.kind
846
- },
847
- {
848
- title: "name",
849
- width: "30%",
850
- render: (detectedError) => {
851
- const errorCount = detectedError.names.length;
852
- if (errorCount === 0) {
853
- return null;
854
- }
855
- const displayName = detectedError.names[0];
856
- const otherErrorCount = errorCount - 1;
857
- return /* @__PURE__ */ React.createElement(React.Fragment, null, displayName, " ", otherErrorCount > 0 && /* @__PURE__ */ React.createElement(Chip, {
858
- label: `+ ${otherErrorCount} other${otherErrorCount > 1 ? "s" : ""}`,
859
- size: "small"
860
- }));
861
- }
862
- },
863
- {
864
- title: "messages",
865
- width: "40%",
866
- render: (detectedError) => /* @__PURE__ */ React.createElement(React.Fragment, null, detectedError.message.map((m, i) => /* @__PURE__ */ React.createElement("div", {
867
- key: i
868
- }, m)))
869
- }
870
- ];
871
- const sortBySeverity = (a, b) => {
872
- if (a.severity < b.severity) {
873
- return 1;
874
- } else if (b.severity < a.severity) {
875
- return -1;
876
- }
877
- return 0;
878
- };
879
- const ErrorEmptyState = () => {
880
- return /* @__PURE__ */ React.createElement(Grid, {
881
- container: true,
882
- justifyContent: "space-around",
883
- direction: "row",
884
- alignItems: "center",
885
- spacing: 2
886
- }, /* @__PURE__ */ React.createElement(Grid, {
887
- item: true,
888
- xs: 4
889
- }, /* @__PURE__ */ React.createElement(Typography, {
890
- variant: "h5"
891
- }, "Nice! There are no errors to report!")), /* @__PURE__ */ React.createElement(Grid, {
892
- item: true,
893
- xs: 4
894
- }, /* @__PURE__ */ React.createElement("img", {
895
- src: EmptyStateImage,
896
- alt: "EmptyState",
897
- "data-testid": "emptyStateImg"
898
- })));
899
- };
900
- const ErrorReporting = ({detectedErrors}) => {
901
- const errors = Array.from(detectedErrors.values()).flat().sort(sortBySeverity);
902
- return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length === 0 ? /* @__PURE__ */ React.createElement(InfoCard, {
903
- title: "Error Reporting"
904
- }, /* @__PURE__ */ React.createElement(ErrorEmptyState, null)) : /* @__PURE__ */ React.createElement(Table, {
905
- title: "Error Reporting",
906
- data: errors,
907
- columns,
908
- options: {paging: true, search: false}
909
- }));
910
- };
911
-
912
- const groupResponses = (fetchResponse) => {
913
- return fetchResponse.reduce((prev, next) => {
914
- switch (next.type) {
915
- case "deployments":
916
- prev.deployments.push(...next.resources);
917
- break;
918
- case "pods":
919
- prev.pods.push(...next.resources);
920
- break;
921
- case "replicasets":
922
- prev.replicaSets.push(...next.resources);
923
- break;
924
- case "services":
925
- prev.services.push(...next.resources);
926
- break;
927
- case "configmaps":
928
- prev.configMaps.push(...next.resources);
929
- break;
930
- case "horizontalpodautoscalers":
931
- prev.horizontalPodAutoscalers.push(...next.resources);
932
- break;
933
- case "ingresses":
934
- prev.ingresses.push(...next.resources);
935
- break;
936
- case "customresources":
937
- prev.customResources.push(...next.resources);
938
- break;
939
- }
940
- return prev;
941
- }, {
942
- pods: [],
943
- replicaSets: [],
944
- deployments: [],
945
- services: [],
946
- configMaps: [],
947
- horizontalPodAutoscalers: [],
948
- ingresses: [],
949
- customResources: []
950
- });
951
- };
952
-
953
- const detectErrorsInObjects = (objects, kind, clusterName, errorMappers) => {
954
- var _a, _b;
955
- const errors = new Map();
956
- for (const object of objects) {
957
- for (const errorMapper of errorMappers) {
958
- if (errorMapper.errorExists(object)) {
959
- const message = errorMapper.messageAccessor(object);
960
- const dedupKey = message.join("");
961
- const value = errors.get(dedupKey);
962
- const name = (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown";
963
- if (value !== void 0) {
964
- value.names.push(name);
965
- errors.set(dedupKey, value);
966
- } else {
967
- errors.set(dedupKey, {
968
- cluster: clusterName,
969
- kind,
970
- names: [name],
971
- message,
972
- severity: errorMapper.severity
973
- });
974
- }
975
- }
976
- }
977
- }
978
- return Array.from(errors.values());
979
- };
980
-
981
- const podErrorMappers = [
982
- {
983
- severity: 5,
984
- errorExplanation: "status-message",
985
- errorExists: (pod) => {
986
- var _a;
987
- return ((_a = pod.status) == null ? void 0 : _a.message) !== void 0;
988
- },
989
- messageAccessor: (pod) => {
990
- var _a, _b;
991
- return [(_b = (_a = pod.status) == null ? void 0 : _a.message) != null ? _b : ""];
992
- }
993
- },
994
- {
995
- severity: 4,
996
- errorExplanation: "containers-restarting",
997
- errorExists: (pod) => {
998
- return totalRestarts(pod) > 3;
999
- },
1000
- messageAccessor: (pod) => {
1001
- var _a, _b;
1002
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => cs.restartCount > 0).map((cs) => `container=${cs.name} restarted ${cs.restartCount} times`);
1003
- }
1004
- },
1005
- {
1006
- severity: 5,
1007
- errorExplanation: "condition-message-present",
1008
- errorExists: (pod) => {
1009
- var _a, _b;
1010
- return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).some((c) => c.message !== void 0);
1011
- },
1012
- messageAccessor: (pod) => {
1013
- var _a, _b;
1014
- return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.message !== void 0).map((c) => {
1015
- var _a2;
1016
- return (_a2 = c.message) != null ? _a2 : "";
1017
- });
1018
- }
1019
- },
1020
- {
1021
- severity: 6,
1022
- errorExplanation: "container-waiting",
1023
- errorExists: (pod) => {
1024
- var _a, _b;
1025
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
1026
- var _a2, _b2;
1027
- return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
1028
- });
1029
- },
1030
- messageAccessor: (pod) => {
1031
- var _a, _b;
1032
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
1033
- var _a2, _b2;
1034
- return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
1035
- }).map((cs) => {
1036
- var _a2, _b2, _c;
1037
- return (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "";
1038
- });
1039
- }
1040
- },
1041
- {
1042
- severity: 4,
1043
- errorExplanation: "container-last-state-error",
1044
- errorExists: (pod) => {
1045
- var _a, _b;
1046
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
1047
- var _a2, _b2, _c;
1048
- return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
1049
- });
1050
- },
1051
- messageAccessor: (pod) => {
1052
- var _a, _b;
1053
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
1054
- var _a2, _b2, _c;
1055
- return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
1056
- }).map((cs) => {
1057
- var _a2, _b2;
1058
- return `container=${cs.name} exited with error code (${(_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.exitCode})`;
1059
- });
1060
- }
1061
- }
1062
- ];
1063
- const detectErrorsInPods = (pods, clusterName) => detectErrorsInObjects(pods, "Pod", clusterName, podErrorMappers);
1064
-
1065
- const deploymentErrorMappers = [
1066
- {
1067
- severity: 6,
1068
- errorExplanation: "condition-message-present",
1069
- errorExists: (deployment) => {
1070
- var _a, _b;
1071
- return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").some((c) => c.message !== void 0);
1072
- },
1073
- messageAccessor: (deployment) => {
887
+ render: (pod) => {
1074
888
  var _a, _b;
1075
- return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").filter((c) => c.message !== void 0).map((c) => {
1076
- var _a2;
1077
- return (_a2 = c.message) != null ? _a2 : "";
1078
- });
889
+ return (_b = (_a = pod.status) == null ? void 0 : _a.phase) != null ? _b : "unknown";
1079
890
  }
891
+ },
892
+ {
893
+ title: "containers ready",
894
+ align: "center",
895
+ render: containersReady
896
+ },
897
+ {
898
+ title: "total restarts",
899
+ align: "center",
900
+ render: totalRestarts,
901
+ type: "numeric"
902
+ },
903
+ {
904
+ title: "status",
905
+ render: containerStatuses
1080
906
  }
1081
907
  ];
1082
- const detectErrorsInDeployments = (deployments, clusterName) => detectErrorsInObjects(deployments, "Deployment", clusterName, deploymentErrorMappers);
908
+ const PodsTable = ({pods}) => {
909
+ const tableStyle = {
910
+ minWidth: "0",
911
+ width: "100%"
912
+ };
913
+ return /* @__PURE__ */ React__default.createElement("div", {
914
+ style: tableStyle
915
+ }, /* @__PURE__ */ React__default.createElement(Table, {
916
+ options: {paging: true, search: false},
917
+ data: pods,
918
+ columns
919
+ }));
920
+ };
1083
921
 
1084
- const hpaErrorMappers = [
1085
- {
1086
- severity: 8,
1087
- errorExplanation: "hpa-max-current-replicas",
1088
- errorExists: (hpa) => {
1089
- var _a, _b, _c;
1090
- return ((_b = (_a = hpa.spec) == null ? void 0 : _a.maxReplicas) != null ? _b : -1) === ((_c = hpa.status) == null ? void 0 : _c.currentReplicas);
1091
- },
1092
- messageAccessor: (hpa) => {
1093
- var _a, _b, _c;
1094
- return [
1095
- `Current number of replicas (${(_a = hpa.status) == null ? void 0 : _a.currentReplicas}) is equal to the configured max number of replicas (${(_c = (_b = hpa.spec) == null ? void 0 : _b.maxReplicas) != null ? _c : -1})`
1096
- ];
922
+ const DeploymentDrawer = ({
923
+ deployment,
924
+ expanded
925
+ }) => {
926
+ var _a, _b, _c;
927
+ const namespace = (_a = deployment.metadata) == null ? void 0 : _a.namespace;
928
+ return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
929
+ object: deployment,
930
+ expanded,
931
+ kind: "Deployment",
932
+ renderObject: (deploymentObj) => {
933
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h;
934
+ const conditions = ((_b2 = (_a2 = deploymentObj.status) == null ? void 0 : _a2.conditions) != null ? _b2 : []).map(renderCondition).reduce((accum, next) => {
935
+ accum[next[0]] = next[1];
936
+ return accum;
937
+ }, {});
938
+ return {
939
+ strategy: (_d = (_c2 = deploymentObj.spec) == null ? void 0 : _c2.strategy) != null ? _d : "???",
940
+ minReadySeconds: (_f = (_e = deploymentObj.spec) == null ? void 0 : _e.minReadySeconds) != null ? _f : "???",
941
+ progressDeadlineSeconds: (_h = (_g = deploymentObj.spec) == null ? void 0 : _g.progressDeadlineSeconds) != null ? _h : "???",
942
+ ...conditions
943
+ };
1097
944
  }
1098
- }
1099
- ];
1100
- const detectErrorsInHpa = (hpas, clusterName) => detectErrorsInObjects(hpas, "HorizontalPodAutoscaler", clusterName, hpaErrorMappers);
945
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
946
+ container: true,
947
+ direction: "column",
948
+ justifyContent: "flex-start",
949
+ alignItems: "flex-start",
950
+ spacing: 0
951
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
952
+ item: true
953
+ }, /* @__PURE__ */ React__default.createElement(Typography, {
954
+ variant: "h5"
955
+ }, (_c = (_b = deployment.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")), /* @__PURE__ */ React__default.createElement(Grid, {
956
+ item: true
957
+ }, /* @__PURE__ */ React__default.createElement(Typography, {
958
+ color: "textSecondary",
959
+ variant: "body1"
960
+ }, "Deployment")), namespace && /* @__PURE__ */ React__default.createElement(Grid, {
961
+ item: true
962
+ }, /* @__PURE__ */ React__default.createElement(Chip, {
963
+ size: "small",
964
+ label: `namespace: ${namespace}`
965
+ }))));
966
+ };
1101
967
 
1102
- const detectErrors = (objects) => {
1103
- const errors = new Map();
1104
- for (const clusterResponse of objects.items) {
1105
- let clusterErrors = [];
1106
- const groupedResponses = groupResponses(clusterResponse.resources);
1107
- clusterErrors = clusterErrors.concat(detectErrorsInPods(groupedResponses.pods, clusterResponse.cluster.name));
1108
- clusterErrors = clusterErrors.concat(detectErrorsInDeployments(groupedResponses.deployments, clusterResponse.cluster.name));
1109
- clusterErrors = clusterErrors.concat(detectErrorsInHpa(groupedResponses.horizontalPodAutoscalers, clusterResponse.cluster.name));
1110
- errors.set(clusterResponse.cluster.name, clusterErrors);
1111
- }
1112
- return errors;
968
+ const HorizontalPodAutoscalerDrawer = ({
969
+ hpa,
970
+ expanded,
971
+ children
972
+ }) => {
973
+ return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
974
+ kind: "HorizontalPodAutoscaler",
975
+ object: hpa,
976
+ expanded,
977
+ renderObject: (hpaObject) => {
978
+ var _a, _b, _c, _d, _e, _f;
979
+ return {
980
+ targetCPUUtilizationPercentage: (_a = hpaObject.spec) == null ? void 0 : _a.targetCPUUtilizationPercentage,
981
+ currentCPUUtilizationPercentage: (_b = hpaObject.status) == null ? void 0 : _b.currentCPUUtilizationPercentage,
982
+ minReplicas: (_c = hpaObject.spec) == null ? void 0 : _c.minReplicas,
983
+ maxReplicas: (_d = hpaObject.spec) == null ? void 0 : _d.maxReplicas,
984
+ currentReplicas: (_e = hpaObject.status) == null ? void 0 : _e.currentReplicas,
985
+ desiredReplicas: (_f = hpaObject.status) == null ? void 0 : _f.desiredReplicas
986
+ };
987
+ }
988
+ }, children);
989
+ };
990
+
991
+ function getOwnedResources(potentialOwner, possiblyOwned) {
992
+ return possiblyOwned.filter((p) => {
993
+ var _a, _b, _c;
994
+ return (_c = (_b = (_a = p.metadata) == null ? void 0 : _a.ownerReferences) == null ? void 0 : _b.some((o) => {
995
+ var _a2;
996
+ return o.uid === ((_a2 = potentialOwner.metadata) == null ? void 0 : _a2.uid);
997
+ })) != null ? _c : false;
998
+ });
999
+ }
1000
+ const getOwnedPodsThroughReplicaSets = (potentialOwner, replicaSets, pods) => {
1001
+ return getOwnedResources(potentialOwner, replicaSets.filter((rs) => rs.status && rs.status.replicas > 0)).reduce((accum, rs) => {
1002
+ return accum.concat(getOwnedResources(rs, pods));
1003
+ }, []);
1004
+ };
1005
+ const getMatchingHpa = (ownerName, ownerKind, hpas) => {
1006
+ return hpas.find((hpa) => {
1007
+ var _a, _b, _c, _d, _e, _f;
1008
+ return ((_c = (_b = (_a = hpa.spec) == null ? void 0 : _a.scaleTargetRef) == null ? void 0 : _b.kind) != null ? _c : "").toLocaleLowerCase("en-US") === ownerKind.toLocaleLowerCase("en-US") && ((_f = (_e = (_d = hpa.spec) == null ? void 0 : _d.scaleTargetRef) == null ? void 0 : _e.name) != null ? _f : "") === (ownerName != null ? ownerName : "unknown-deployment");
1009
+ });
1010
+ };
1011
+
1012
+ const DeploymentSummary = ({
1013
+ deployment,
1014
+ numberOfCurrentPods,
1015
+ numberOfPodsWithErrors,
1016
+ hpa
1017
+ }) => {
1018
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1019
+ return /* @__PURE__ */ React__default.createElement(Grid, {
1020
+ container: true,
1021
+ direction: "row",
1022
+ justifyContent: "flex-start",
1023
+ alignItems: "center"
1024
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
1025
+ xs: 3,
1026
+ item: true
1027
+ }, /* @__PURE__ */ React__default.createElement(DeploymentDrawer, {
1028
+ deployment
1029
+ })), /* @__PURE__ */ React__default.createElement(Grid, {
1030
+ item: true,
1031
+ xs: 1
1032
+ }, /* @__PURE__ */ React__default.createElement(Divider, {
1033
+ style: {height: "5em"},
1034
+ orientation: "vertical"
1035
+ })), hpa && /* @__PURE__ */ React__default.createElement(Grid, {
1036
+ item: true,
1037
+ xs: 3
1038
+ }, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, {
1039
+ hpa
1040
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
1041
+ item: true,
1042
+ container: true,
1043
+ direction: "column",
1044
+ justifyContent: "flex-start",
1045
+ alignItems: "flex-start",
1046
+ spacing: 0
1047
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
1048
+ item: true
1049
+ }, /* @__PURE__ */ React__default.createElement(Typography, {
1050
+ variant: "subtitle2"
1051
+ }, "min replicas ", (_b = (_a = hpa.spec) == null ? void 0 : _a.minReplicas) != null ? _b : "?", " / max replicas", " ", (_d = (_c = hpa.spec) == null ? void 0 : _c.maxReplicas) != null ? _d : "?")), /* @__PURE__ */ React__default.createElement(Grid, {
1052
+ item: true
1053
+ }, /* @__PURE__ */ React__default.createElement(Typography, {
1054
+ variant: "subtitle2"
1055
+ }, "current CPU usage:", " ", (_f = (_e = hpa.status) == null ? void 0 : _e.currentCPUUtilizationPercentage) != null ? _f : "?", "%")), /* @__PURE__ */ React__default.createElement(Grid, {
1056
+ item: true
1057
+ }, /* @__PURE__ */ React__default.createElement(Typography, {
1058
+ variant: "subtitle2"
1059
+ }, "target CPU usage:", " ", (_h = (_g = hpa.spec) == null ? void 0 : _g.targetCPUUtilizationPercentage) != null ? _h : "?", "%"))))), /* @__PURE__ */ React__default.createElement(Grid, {
1060
+ item: true,
1061
+ container: true,
1062
+ xs: 3,
1063
+ direction: "column",
1064
+ justifyContent: "flex-start",
1065
+ alignItems: "flex-start"
1066
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
1067
+ item: true
1068
+ }, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")), /* @__PURE__ */ React__default.createElement(Grid, {
1069
+ item: true
1070
+ }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pod", numberOfPodsWithErrors > 1 ? "s" : "", " with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))));
1071
+ };
1072
+ const DeploymentAccordion = ({
1073
+ deployment,
1074
+ ownedPods,
1075
+ matchingHpa
1076
+ }) => {
1077
+ const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
1078
+ const podsWithErrors = ownedPods.filter((p) => {
1079
+ var _a, _b;
1080
+ return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1081
+ });
1082
+ return /* @__PURE__ */ React__default.createElement(Accordion, {
1083
+ TransitionProps: {unmountOnExit: true}
1084
+ }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1085
+ expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1086
+ }, /* @__PURE__ */ React__default.createElement(DeploymentSummary, {
1087
+ deployment,
1088
+ numberOfCurrentPods: ownedPods.length,
1089
+ numberOfPodsWithErrors: podsWithErrors.length,
1090
+ hpa: matchingHpa
1091
+ })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(PodsTable, {
1092
+ pods: ownedPods
1093
+ })));
1094
+ };
1095
+ const DeploymentsAccordions = ({}) => {
1096
+ const groupedResponses = useContext(GroupedResponsesContext);
1097
+ return /* @__PURE__ */ React__default.createElement(Grid, {
1098
+ container: true,
1099
+ direction: "column",
1100
+ justifyContent: "flex-start",
1101
+ alignItems: "flex-start"
1102
+ }, groupedResponses.deployments.map((deployment, i) => {
1103
+ var _a;
1104
+ return /* @__PURE__ */ React__default.createElement(Grid, {
1105
+ container: true,
1106
+ item: true,
1107
+ key: i,
1108
+ xs: true
1109
+ }, /* @__PURE__ */ React__default.createElement(Grid, {
1110
+ item: true,
1111
+ xs: true
1112
+ }, /* @__PURE__ */ React__default.createElement(DeploymentAccordion, {
1113
+ matchingHpa: getMatchingHpa((_a = deployment.metadata) == null ? void 0 : _a.name, "deployment", groupedResponses.horizontalPodAutoscalers),
1114
+ ownedPods: getOwnedPodsThroughReplicaSets(deployment, groupedResponses.replicaSets, groupedResponses.pods),
1115
+ deployment
1116
+ })));
1117
+ }));
1113
1118
  };
1114
1119
 
1115
1120
  const IngressDrawer = ({
@@ -1712,6 +1717,7 @@ const Cluster = ({clusterObjects, podsWithErrors}) => {
1712
1717
  item: true
1713
1718
  }, /* @__PURE__ */ React__default.createElement(ServicesAccordions, null))))))));
1714
1719
  };
1720
+
1715
1721
  const KubernetesContent = ({entity}) => {
1716
1722
  var _a;
1717
1723
  const {kubernetesObjects, error} = useKubernetesObjects(entity);