@backstage/plugin-kubernetes 0.7.10-next.1 → 0.8.0-next.3

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
@@ -1,4 +1,5 @@
1
1
  import { stringifyEntityRef } from '@backstage/catalog-model';
2
+ import { NotFoundError } from '@backstage/errors';
2
3
  import { createApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, gitlabAuthApiRef, googleAuthApiRef, microsoftAuthApiRef, oktaAuthApiRef, oneloginAuthApiRef, createRoutableExtension, useApi } from '@backstage/core-plugin-api';
3
4
  import * as React from 'react';
4
5
  import React__default, { Fragment, useCallback, useState, useContext } from 'react';
@@ -6,6 +7,8 @@ import { useEntity } from '@backstage/plugin-catalog-react';
6
7
  import { Routes, Route } from 'react-router-dom';
7
8
  import { Typography, Chip, makeStyles, createStyles, Button, Drawer, Grid, IconButton, FormControlLabel, Switch, Accordion, AccordionSummary, AccordionDetails, Stepper, Step, StepLabel } from '@material-ui/core';
8
9
  import { WarningPanel, Table, StatusOK, SubvalueCell, StatusError, StatusAborted, LinkButton, CodeSnippet, StructuredMetadataTable, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
10
+ import lodash from 'lodash';
11
+ import { DateTime } from 'luxon';
9
12
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
10
13
  import Close from '@material-ui/icons/Close';
11
14
  import OpenInNewIcon from '@material-ui/icons/OpenInNew';
@@ -14,10 +17,8 @@ import jsYaml from 'js-yaml';
14
17
  import useInterval from 'react-use/lib/useInterval';
15
18
  import useAsyncRetry from 'react-use/lib/useAsyncRetry';
16
19
  import cronstrue from 'cronstrue';
17
- import lodash from 'lodash';
18
20
  import PauseIcon from '@material-ui/icons/Pause';
19
21
  import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
20
- import { DateTime } from 'luxon';
21
22
  import Typography$1 from '@material-ui/core/Typography';
22
23
  import EmptyStateImage from './assets/emptystate.svg';
23
24
 
@@ -25,6 +26,7 @@ class KubernetesBackendClient {
25
26
  constructor(options) {
26
27
  this.discoveryApi = options.discoveryApi;
27
28
  this.identityApi = options.identityApi;
29
+ this.kubernetesAuthProvidersApi = options.kubernetesAuthProvidersApi;
28
30
  }
29
31
  async handleResponse(response) {
30
32
  if (!response.ok) {
@@ -54,6 +56,18 @@ class KubernetesBackendClient {
54
56
  });
55
57
  return this.handleResponse(response);
56
58
  }
59
+ async getCluster(clusterName) {
60
+ const cluster = await this.getClusters().then(
61
+ (clusters) => clusters.find((c) => c.name === clusterName)
62
+ );
63
+ if (!cluster) {
64
+ throw new NotFoundError(`Cluster ${clusterName} not found`);
65
+ }
66
+ return cluster;
67
+ }
68
+ async getCredentials(authProvider) {
69
+ return await this.kubernetesAuthProvidersApi.getCredentials(authProvider);
70
+ }
57
71
  async getObjectsByEntity(requestBody) {
58
72
  return await this.postRequired(
59
73
  `/services/${requestBody.entity.metadata.name}`,
@@ -84,6 +98,24 @@ class KubernetesBackendClient {
84
98
  });
85
99
  return (await this.handleResponse(response)).items;
86
100
  }
101
+ async proxy(options) {
102
+ var _a;
103
+ const { authProvider } = await this.getCluster(options.clusterName);
104
+ const { token: k8sToken } = await this.getCredentials(authProvider);
105
+ const url = `${await this.discoveryApi.getBaseUrl("kubernetes")}/proxy${options.path}`;
106
+ const identityResponse = await this.identityApi.getCredentials();
107
+ const headers = {
108
+ ...(_a = options.init) == null ? void 0 : _a.headers,
109
+ [`Backstage-Kubernetes-Cluster`]: options.clusterName,
110
+ ...k8sToken && {
111
+ [`Backstage-Kubernetes-Authorization`]: `Bearer ${k8sToken}`
112
+ },
113
+ ...identityResponse.token && {
114
+ Authorization: `Bearer ${identityResponse.token}`
115
+ }
116
+ };
117
+ return await fetch(url, { ...options.init, headers });
118
+ }
87
119
  }
88
120
 
89
121
  const kubernetesApiRef = createApiRef({
@@ -99,9 +131,7 @@ class GoogleKubernetesAuthProvider {
99
131
  this.authProvider = authProvider;
100
132
  }
101
133
  async decorateRequestBodyForAuth(requestBody) {
102
- const googleAuthToken = await this.authProvider.getAccessToken(
103
- "https://www.googleapis.com/auth/cloud-platform"
104
- );
134
+ const googleAuthToken = (await this.getCredentials()).token;
105
135
  if ("auth" in requestBody) {
106
136
  requestBody.auth.google = googleAuthToken;
107
137
  } else {
@@ -109,12 +139,22 @@ class GoogleKubernetesAuthProvider {
109
139
  }
110
140
  return requestBody;
111
141
  }
142
+ async getCredentials() {
143
+ return {
144
+ token: await this.authProvider.getAccessToken(
145
+ "https://www.googleapis.com/auth/cloud-platform"
146
+ )
147
+ };
148
+ }
112
149
  }
113
150
 
114
151
  class ServerSideKubernetesAuthProvider {
115
152
  async decorateRequestBodyForAuth(requestBody) {
116
153
  return requestBody;
117
154
  }
155
+ async getCredentials() {
156
+ return {};
157
+ }
118
158
  }
119
159
 
120
160
  class OidcKubernetesAuthProvider {
@@ -123,7 +163,7 @@ class OidcKubernetesAuthProvider {
123
163
  this.authProvider = authProvider;
124
164
  }
125
165
  async decorateRequestBodyForAuth(requestBody) {
126
- const authToken = await this.authProvider.getIdToken();
166
+ const authToken = (await this.getCredentials()).token;
127
167
  const auth = { ...requestBody.auth };
128
168
  if (auth.oidc) {
129
169
  auth.oidc[this.providerName] = authToken;
@@ -133,6 +173,11 @@ class OidcKubernetesAuthProvider {
133
173
  requestBody.auth = auth;
134
174
  return requestBody;
135
175
  }
176
+ async getCredentials() {
177
+ return {
178
+ token: await this.authProvider.getIdToken()
179
+ };
180
+ }
136
181
  }
137
182
 
138
183
  class KubernetesAuthProviders {
@@ -190,6 +235,20 @@ class KubernetesAuthProviders {
190
235
  `authProvider "${authProvider}" has no KubernetesAuthProvider defined for it`
191
236
  );
192
237
  }
238
+ async getCredentials(authProvider) {
239
+ const kubernetesAuthProvider = this.kubernetesAuthProviderMap.get(authProvider);
240
+ if (kubernetesAuthProvider) {
241
+ return await kubernetesAuthProvider.getCredentials();
242
+ }
243
+ if (authProvider.startsWith("oidc.")) {
244
+ throw new Error(
245
+ `KubernetesAuthProviders has no oidcProvider configured for ${authProvider}`
246
+ );
247
+ }
248
+ throw new Error(
249
+ `authProvider "${authProvider}" has no KubernetesAuthProvider defined for it`
250
+ );
251
+ }
193
252
  }
194
253
 
195
254
  const rootCatalogKubernetesRouteRef = createRouteRef({
@@ -202,9 +261,14 @@ const kubernetesPlugin = createPlugin({
202
261
  api: kubernetesApiRef,
203
262
  deps: {
204
263
  discoveryApi: discoveryApiRef,
205
- identityApi: identityApiRef
264
+ identityApi: identityApiRef,
265
+ kubernetesAuthProvidersApi: kubernetesAuthProvidersApiRef
206
266
  },
207
- factory: ({ discoveryApi, identityApi }) => new KubernetesBackendClient({ discoveryApi, identityApi })
267
+ factory: ({ discoveryApi, identityApi, kubernetesAuthProvidersApi }) => new KubernetesBackendClient({
268
+ discoveryApi,
269
+ identityApi,
270
+ kubernetesAuthProvidersApi
271
+ })
208
272
  }),
209
273
  createApiFactory({
210
274
  api: kubernetesAuthProvidersApiRef,
@@ -270,53 +334,46 @@ const columns = [
270
334
  {
271
335
  title: "cluster",
272
336
  width: "10%",
273
- render: (detectedError) => detectedError.cluster
337
+ render: (row) => row.clusterName
274
338
  },
275
339
  {
276
340
  title: "namespace",
277
341
  width: "10%",
278
- render: (detectedError) => detectedError.namespace
342
+ render: (row) => row.error.sourceRef.namespace
279
343
  },
280
344
  {
281
345
  title: "kind",
282
346
  width: "10%",
283
- render: (detectedError) => detectedError.kind
347
+ render: (row) => row.error.sourceRef.kind
284
348
  },
285
349
  {
286
350
  title: "name",
287
351
  width: "30%",
288
- render: (detectedError) => {
289
- const errorCount = detectedError.names.length;
290
- if (errorCount === 0) {
291
- return null;
292
- }
293
- const displayName = detectedError.names[0];
294
- const otherErrorCount = errorCount - 1;
295
- return /* @__PURE__ */ React.createElement(React.Fragment, null, displayName, " ", otherErrorCount > 0 && /* @__PURE__ */ React.createElement(
296
- Chip,
297
- {
298
- label: `+ ${otherErrorCount} other${otherErrorCount > 1 ? "s" : ""}`,
299
- size: "small"
300
- }
301
- ));
352
+ render: (row) => {
353
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, row.error.sourceRef.name, " ");
302
354
  }
303
355
  },
304
356
  {
305
357
  title: "messages",
306
358
  width: "40%",
307
- render: (detectedError) => /* @__PURE__ */ React.createElement(React.Fragment, null, detectedError.message.map((m, i) => /* @__PURE__ */ React.createElement("div", { key: i }, m)))
359
+ render: (row) => row.error.message
308
360
  }
309
361
  ];
310
362
  const sortBySeverity = (a, b) => {
311
- if (a.severity < b.severity) {
363
+ if (a.error.severity < b.error.severity) {
312
364
  return 1;
313
- } else if (b.severity < a.severity) {
365
+ } else if (b.error.severity < a.error.severity) {
314
366
  return -1;
315
367
  }
316
368
  return 0;
317
369
  };
318
370
  const ErrorReporting = ({ detectedErrors }) => {
319
- const errors = Array.from(detectedErrors.values()).flat().sort(sortBySeverity);
371
+ const errors = Array.from(detectedErrors.entries()).flatMap(([clusterName, resourceErrors]) => {
372
+ return resourceErrors.map((e) => ({
373
+ clusterName,
374
+ error: e
375
+ }));
376
+ }).sort(sortBySeverity);
320
377
  return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length !== 0 && /* @__PURE__ */ React.createElement(
321
378
  Table,
322
379
  {
@@ -384,6 +441,191 @@ const groupResponses = (fetchResponse) => {
384
441
  );
385
442
  };
386
443
 
444
+ const detectErrorsInObjects = (objects, errorMappers) => {
445
+ return objects.flatMap((o) => {
446
+ return errorMappers.flatMap((em) => em.detectErrors(o));
447
+ });
448
+ };
449
+
450
+ function isPodReadinessProbeUnready({
451
+ container,
452
+ containerStatus
453
+ }) {
454
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
455
+ if (containerStatus.ready || ((_b = (_a = containerStatus.state) == null ? void 0 : _a.running) == null ? void 0 : _b.startedAt) === void 0 || !container.readinessProbe) {
456
+ return false;
457
+ }
458
+ const startDateTime = DateTime.fromISO(
459
+ (_d = (_c = containerStatus.state) == null ? void 0 : _c.running) == null ? void 0 : _d.startedAt
460
+ ).plus({
461
+ seconds: (_f = (_e = container.readinessProbe) == null ? void 0 : _e.initialDelaySeconds) != null ? _f : 0
462
+ }).plus({
463
+ seconds: ((_h = (_g = container.readinessProbe) == null ? void 0 : _g.periodSeconds) != null ? _h : 0) * ((_j = (_i = container.readinessProbe) == null ? void 0 : _i.failureThreshold) != null ? _j : 0)
464
+ });
465
+ return startDateTime < DateTime.now();
466
+ }
467
+ const podToContainerSpecsAndStatuses = (pod) => {
468
+ var _a, _b, _c, _d;
469
+ const specs = lodash.groupBy((_b = (_a = pod.spec) == null ? void 0 : _a.containers) != null ? _b : [], (value) => value.name);
470
+ const result = [];
471
+ for (const cs of (_d = (_c = pod.status) == null ? void 0 : _c.containerStatuses) != null ? _d : []) {
472
+ const spec = specs[cs.name];
473
+ if (spec.length > 0) {
474
+ result.push({
475
+ container: spec[0],
476
+ containerStatus: cs
477
+ });
478
+ }
479
+ }
480
+ return result;
481
+ };
482
+ const podErrorMappers = [
483
+ {
484
+ detectErrors: (pod) => {
485
+ return podToContainerSpecsAndStatuses(pod).filter(isPodReadinessProbeUnready).map((cs) => {
486
+ var _a, _b, _c, _d;
487
+ return {
488
+ type: "readiness-probe-taking-too-long",
489
+ message: `The container ${cs.container.name} failed to start properly, but is not crashing`,
490
+ severity: 4,
491
+ proposedFix: [],
492
+ // TODO next PR
493
+ sourceRef: {
494
+ name: (_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown pod",
495
+ namespace: (_d = (_c = pod.metadata) == null ? void 0 : _c.namespace) != null ? _d : "unknown namespace",
496
+ kind: "Pod",
497
+ apiGroup: "v1"
498
+ },
499
+ occuranceCount: 1
500
+ };
501
+ });
502
+ }
503
+ },
504
+ {
505
+ detectErrors: (pod) => {
506
+ var _a, _b;
507
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
508
+ var _a2, _b2;
509
+ return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
510
+ }).map((cs) => {
511
+ var _a2, _b2, _c, _d, _e, _f, _g;
512
+ return {
513
+ type: "container-waiting",
514
+ message: (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "container waiting",
515
+ severity: 4,
516
+ proposedFix: [],
517
+ // TODO next PR
518
+ sourceRef: {
519
+ name: (_e = (_d = pod.metadata) == null ? void 0 : _d.name) != null ? _e : "unknown pod",
520
+ namespace: (_g = (_f = pod.metadata) == null ? void 0 : _f.namespace) != null ? _g : "unknown namespace",
521
+ kind: "Pod",
522
+ apiGroup: "v1"
523
+ },
524
+ occuranceCount: 1
525
+ };
526
+ });
527
+ }
528
+ },
529
+ {
530
+ detectErrors: (pod) => {
531
+ var _a, _b;
532
+ return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => cs.restartCount > 0).map((cs) => {
533
+ var _a2, _b2, _c, _d;
534
+ return {
535
+ type: "containers-restarting",
536
+ message: `container=${cs.name} restarted ${cs.restartCount} times`,
537
+ severity: 4,
538
+ proposedFix: [],
539
+ // TODO next PR
540
+ sourceRef: {
541
+ name: (_b2 = (_a2 = pod.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "unknown pod",
542
+ namespace: (_d = (_c = pod.metadata) == null ? void 0 : _c.namespace) != null ? _d : "unknown namespace",
543
+ kind: "Pod",
544
+ apiGroup: "v1"
545
+ },
546
+ occuranceCount: cs.restartCount
547
+ };
548
+ });
549
+ }
550
+ }
551
+ ];
552
+ const detectErrorsInPods = (pods) => detectErrorsInObjects(pods, podErrorMappers);
553
+
554
+ const deploymentErrorMappers = [
555
+ {
556
+ detectErrors: (deployment) => {
557
+ var _a, _b;
558
+ 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) => {
559
+ var _a2, _b2, _c, _d, _e;
560
+ return {
561
+ type: "condition-message-present",
562
+ message: (_a2 = c.message) != null ? _a2 : "",
563
+ severity: 6,
564
+ proposedFix: [],
565
+ // TODO next PR
566
+ sourceRef: {
567
+ name: (_c = (_b2 = deployment.metadata) == null ? void 0 : _b2.name) != null ? _c : "unknown hpa",
568
+ namespace: (_e = (_d = deployment.metadata) == null ? void 0 : _d.namespace) != null ? _e : "unknown namespace",
569
+ kind: "Deployment",
570
+ apiGroup: "apps/v1"
571
+ },
572
+ occuranceCount: 1
573
+ };
574
+ });
575
+ }
576
+ }
577
+ ];
578
+ const detectErrorsInDeployments = (deployments) => detectErrorsInObjects(deployments, deploymentErrorMappers);
579
+
580
+ const hpaErrorMappers = [
581
+ {
582
+ detectErrors: (hpa) => {
583
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
584
+ if (((_b = (_a = hpa.spec) == null ? void 0 : _a.maxReplicas) != null ? _b : -1) === ((_c = hpa.status) == null ? void 0 : _c.currentReplicas)) {
585
+ return [
586
+ {
587
+ type: "hpa-max-current-replicas",
588
+ message: `Current number of replicas (${(_d = hpa.status) == null ? void 0 : _d.currentReplicas}) is equal to the configured max number of replicas (${(_f = (_e = hpa.spec) == null ? void 0 : _e.maxReplicas) != null ? _f : -1})`,
589
+ severity: 8,
590
+ proposedFix: [],
591
+ // TODO next PR
592
+ sourceRef: {
593
+ name: (_h = (_g = hpa.metadata) == null ? void 0 : _g.name) != null ? _h : "unknown hpa",
594
+ namespace: (_j = (_i = hpa.metadata) == null ? void 0 : _i.namespace) != null ? _j : "unknown namespace",
595
+ kind: "HorizontalPodAutoscaler",
596
+ apiGroup: "autoscaling/v1"
597
+ },
598
+ occuranceCount: 1
599
+ }
600
+ ];
601
+ }
602
+ return [];
603
+ }
604
+ }
605
+ ];
606
+ const detectErrorsInHpa = (hpas) => detectErrorsInObjects(hpas, hpaErrorMappers);
607
+
608
+ const detectErrors = (objects) => {
609
+ const errors = /* @__PURE__ */ new Map();
610
+ for (const clusterResponse of objects.items) {
611
+ let clusterErrors = [];
612
+ const groupedResponses = groupResponses(clusterResponse.resources);
613
+ clusterErrors = clusterErrors.concat(
614
+ detectErrorsInPods(groupedResponses.pods)
615
+ );
616
+ clusterErrors = clusterErrors.concat(
617
+ detectErrorsInDeployments(groupedResponses.deployments)
618
+ );
619
+ clusterErrors = clusterErrors.concat(
620
+ detectErrorsInHpa(
621
+ groupedResponses.horizontalPodAutoscalers
622
+ )
623
+ );
624
+ errors.set(clusterResponse.cluster.name, clusterErrors);
625
+ }
626
+ return errors;
627
+ };
628
+
387
629
  const imageChips = (pod) => {
388
630
  var _a, _b;
389
631
  const containerStatuses2 = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
@@ -507,200 +749,6 @@ const podStatusToMemoryUtil = (podStatus) => {
507
749
  );
508
750
  };
509
751
 
510
- const detectErrorsInObjects = (objects, kind, clusterName, errorMappers) => {
511
- var _a, _b, _c, _d;
512
- const errors = /* @__PURE__ */ new Map();
513
- for (const object of objects) {
514
- for (const errorMapper of errorMappers) {
515
- if (errorMapper.errorExists(object)) {
516
- const message = errorMapper.messageAccessor(object);
517
- const dedupKey = message.join("");
518
- const value = errors.get(dedupKey);
519
- const name = (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown";
520
- const namespace = (_d = (_c = object.metadata) == null ? void 0 : _c.namespace) != null ? _d : "unknown";
521
- if (value !== void 0) {
522
- value.names.push(name);
523
- errors.set(dedupKey, value);
524
- } else {
525
- errors.set(dedupKey, {
526
- cluster: clusterName,
527
- kind,
528
- names: [name],
529
- message,
530
- severity: errorMapper.severity,
531
- namespace
532
- });
533
- }
534
- }
535
- }
536
- }
537
- return Array.from(errors.values());
538
- };
539
-
540
- const podErrorMappers = [
541
- {
542
- severity: 5,
543
- errorExplanation: "status-message",
544
- errorExists: (pod) => {
545
- var _a;
546
- return ((_a = pod.status) == null ? void 0 : _a.message) !== void 0;
547
- },
548
- messageAccessor: (pod) => {
549
- var _a, _b;
550
- return [(_b = (_a = pod.status) == null ? void 0 : _a.message) != null ? _b : ""];
551
- }
552
- },
553
- {
554
- severity: 4,
555
- errorExplanation: "containers-restarting",
556
- errorExists: (pod) => {
557
- return totalRestarts(pod) > 3;
558
- },
559
- messageAccessor: (pod) => {
560
- var _a, _b;
561
- 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`);
562
- }
563
- },
564
- {
565
- severity: 5,
566
- errorExplanation: "condition-message-present",
567
- errorExists: (pod) => {
568
- var _a, _b;
569
- return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).some((c) => c.message !== void 0);
570
- },
571
- messageAccessor: (pod) => {
572
- var _a, _b;
573
- return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.message !== void 0).map((c) => {
574
- var _a2;
575
- return (_a2 = c.message) != null ? _a2 : "";
576
- });
577
- }
578
- },
579
- {
580
- severity: 6,
581
- errorExplanation: "container-waiting",
582
- errorExists: (pod) => {
583
- var _a, _b;
584
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some(
585
- (cs) => {
586
- var _a2, _b2;
587
- return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
588
- }
589
- );
590
- },
591
- messageAccessor: (pod) => {
592
- var _a, _b;
593
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
594
- var _a2, _b2;
595
- return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
596
- }).map((cs) => {
597
- var _a2, _b2, _c;
598
- return (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "";
599
- });
600
- }
601
- },
602
- {
603
- severity: 4,
604
- errorExplanation: "container-last-state-error",
605
- errorExists: (pod) => {
606
- var _a, _b;
607
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some(
608
- (cs) => {
609
- var _a2, _b2, _c;
610
- return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
611
- }
612
- );
613
- },
614
- messageAccessor: (pod) => {
615
- var _a, _b;
616
- return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
617
- var _a2, _b2, _c;
618
- return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
619
- }).map(
620
- (cs) => {
621
- var _a2, _b2;
622
- return `container=${cs.name} exited with error code (${(_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.exitCode})`;
623
- }
624
- );
625
- }
626
- }
627
- ];
628
- const detectErrorsInPods = (pods, clusterName) => detectErrorsInObjects(pods, "Pod", clusterName, podErrorMappers);
629
-
630
- const deploymentErrorMappers = [
631
- {
632
- // this is probably important
633
- severity: 6,
634
- errorExplanation: "condition-message-present",
635
- errorExists: (deployment) => {
636
- var _a, _b;
637
- return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").some((c) => c.message !== void 0);
638
- },
639
- messageAccessor: (deployment) => {
640
- var _a, _b;
641
- 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) => {
642
- var _a2;
643
- return (_a2 = c.message) != null ? _a2 : "";
644
- });
645
- }
646
- }
647
- ];
648
- const detectErrorsInDeployments = (deployments, clusterName) => detectErrorsInObjects(
649
- deployments,
650
- "Deployment",
651
- clusterName,
652
- deploymentErrorMappers
653
- );
654
-
655
- const hpaErrorMappers = [
656
- {
657
- // this is probably important
658
- severity: 8,
659
- errorExplanation: "hpa-max-current-replicas",
660
- errorExists: (hpa) => {
661
- var _a, _b, _c;
662
- return ((_b = (_a = hpa.spec) == null ? void 0 : _a.maxReplicas) != null ? _b : -1) === ((_c = hpa.status) == null ? void 0 : _c.currentReplicas);
663
- },
664
- messageAccessor: (hpa) => {
665
- var _a, _b, _c;
666
- return [
667
- `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})`
668
- ];
669
- }
670
- }
671
- ];
672
- const detectErrorsInHpa = (hpas, clusterName) => detectErrorsInObjects(
673
- hpas,
674
- "HorizontalPodAutoscaler",
675
- clusterName,
676
- hpaErrorMappers
677
- );
678
-
679
- const detectErrors = (objects) => {
680
- const errors = /* @__PURE__ */ new Map();
681
- for (const clusterResponse of objects.items) {
682
- let clusterErrors = [];
683
- const groupedResponses = groupResponses(clusterResponse.resources);
684
- clusterErrors = clusterErrors.concat(
685
- detectErrorsInPods(groupedResponses.pods, clusterResponse.cluster.name)
686
- );
687
- clusterErrors = clusterErrors.concat(
688
- detectErrorsInDeployments(
689
- groupedResponses.deployments,
690
- clusterResponse.cluster.name
691
- )
692
- );
693
- clusterErrors = clusterErrors.concat(
694
- detectErrorsInHpa(
695
- groupedResponses.horizontalPodAutoscalers,
696
- clusterResponse.cluster.name
697
- )
698
- );
699
- errors.set(clusterResponse.cluster.name, clusterErrors);
700
- }
701
- return errors;
702
- };
703
-
704
752
  const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
705
753
  var _a;
706
754
  const clusters = await kubernetesApi.getClusters();
@@ -2476,9 +2524,9 @@ const KubernetesContent = ({
2476
2524
  }
2477
2525
  ))
2478
2526
  ), (kubernetesObjects == null ? void 0 : kubernetesObjects.items.length) > 0 && (kubernetesObjects == null ? void 0 : kubernetesObjects.items.map((item, i) => {
2479
- var _a2, _b;
2527
+ var _a2;
2480
2528
  const podsWithErrors = new Set(
2481
- (_b = (_a2 = detectedErrors.get(item.cluster.name)) == null ? void 0 : _a2.filter((de) => de.kind === "Pod").map((de) => de.names).flat()) != null ? _b : []
2529
+ (_a2 = detectedErrors.get(item.cluster.name)) == null ? void 0 : _a2.filter((de) => de.sourceRef.kind === "Pod").map((de) => de.sourceRef.name)
2482
2530
  );
2483
2531
  return /* @__PURE__ */ React__default.createElement(Grid, { item: true, key: i, xs: 12 }, /* @__PURE__ */ React__default.createElement(
2484
2532
  Cluster,