@backstage/plugin-kubernetes 0.4.17 → 0.4.21
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/CHANGELOG.md +45 -0
- package/dist/index.esm.js +691 -647
- package/dist/index.esm.js.map +1 -1
- package/package.json +14 -14
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,
|
|
7
|
-
import { WarningPanel, SubvalueCell, StatusError, StatusOK, StatusAborted, Button as Button$1, CodeSnippet, StructuredMetadataTable,
|
|
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
|
|
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';
|
|
@@ -53,9 +54,13 @@ class KubernetesBackendClient {
|
|
|
53
54
|
return await this.postRequired(`/services/${requestBody.entity.metadata.name}`, requestBody);
|
|
54
55
|
}
|
|
55
56
|
async getClusters() {
|
|
57
|
+
const idToken = await this.identityApi.getIdToken();
|
|
56
58
|
const url = `${await this.discoveryApi.getBaseUrl("kubernetes")}/clusters`;
|
|
57
59
|
const response = await fetch(url, {
|
|
58
|
-
method: "GET"
|
|
60
|
+
method: "GET",
|
|
61
|
+
headers: {
|
|
62
|
+
...idToken && {Authorization: `Bearer ${idToken}`}
|
|
63
|
+
}
|
|
59
64
|
});
|
|
60
65
|
return (await this.handleResponse(response)).items;
|
|
61
66
|
}
|
|
@@ -115,8 +120,7 @@ class KubernetesAuthProviders {
|
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
const rootCatalogKubernetesRouteRef = createRouteRef({
|
|
118
|
-
|
|
119
|
-
title: "Kubernetes"
|
|
123
|
+
id: "kubernetes"
|
|
120
124
|
});
|
|
121
125
|
const kubernetesPlugin = createPlugin({
|
|
122
126
|
id: "kubernetes",
|
|
@@ -172,6 +176,123 @@ const ErrorPanel$1 = ({
|
|
|
172
176
|
variant: "body2"
|
|
173
177
|
}, "Errors: ", errorMessage));
|
|
174
178
|
|
|
179
|
+
const columns$1 = [
|
|
180
|
+
{
|
|
181
|
+
title: "cluster",
|
|
182
|
+
width: "15%",
|
|
183
|
+
render: (detectedError) => detectedError.cluster
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: "kind",
|
|
187
|
+
width: "15%",
|
|
188
|
+
render: (detectedError) => detectedError.kind
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
title: "name",
|
|
192
|
+
width: "30%",
|
|
193
|
+
render: (detectedError) => {
|
|
194
|
+
const errorCount = detectedError.names.length;
|
|
195
|
+
if (errorCount === 0) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
const displayName = detectedError.names[0];
|
|
199
|
+
const otherErrorCount = errorCount - 1;
|
|
200
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, displayName, " ", otherErrorCount > 0 && /* @__PURE__ */ React.createElement(Chip, {
|
|
201
|
+
label: `+ ${otherErrorCount} other${otherErrorCount > 1 ? "s" : ""}`,
|
|
202
|
+
size: "small"
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
title: "messages",
|
|
208
|
+
width: "40%",
|
|
209
|
+
render: (detectedError) => /* @__PURE__ */ React.createElement(React.Fragment, null, detectedError.message.map((m, i) => /* @__PURE__ */ React.createElement("div", {
|
|
210
|
+
key: i
|
|
211
|
+
}, m)))
|
|
212
|
+
}
|
|
213
|
+
];
|
|
214
|
+
const sortBySeverity = (a, b) => {
|
|
215
|
+
if (a.severity < b.severity) {
|
|
216
|
+
return 1;
|
|
217
|
+
} else if (b.severity < a.severity) {
|
|
218
|
+
return -1;
|
|
219
|
+
}
|
|
220
|
+
return 0;
|
|
221
|
+
};
|
|
222
|
+
const ErrorEmptyState = () => {
|
|
223
|
+
return /* @__PURE__ */ React.createElement(Grid, {
|
|
224
|
+
container: true,
|
|
225
|
+
justifyContent: "space-around",
|
|
226
|
+
direction: "row",
|
|
227
|
+
alignItems: "center",
|
|
228
|
+
spacing: 2
|
|
229
|
+
}, /* @__PURE__ */ React.createElement(Grid, {
|
|
230
|
+
item: true,
|
|
231
|
+
xs: 4
|
|
232
|
+
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
233
|
+
variant: "h5"
|
|
234
|
+
}, "Nice! There are no errors to report!")), /* @__PURE__ */ React.createElement(Grid, {
|
|
235
|
+
item: true,
|
|
236
|
+
xs: 4
|
|
237
|
+
}, /* @__PURE__ */ React.createElement("img", {
|
|
238
|
+
src: EmptyStateImage,
|
|
239
|
+
alt: "EmptyState",
|
|
240
|
+
"data-testid": "emptyStateImg"
|
|
241
|
+
})));
|
|
242
|
+
};
|
|
243
|
+
const ErrorReporting = ({detectedErrors}) => {
|
|
244
|
+
const errors = Array.from(detectedErrors.values()).flat().sort(sortBySeverity);
|
|
245
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length === 0 ? /* @__PURE__ */ React.createElement(InfoCard, {
|
|
246
|
+
title: "Error Reporting"
|
|
247
|
+
}, /* @__PURE__ */ React.createElement(ErrorEmptyState, null)) : /* @__PURE__ */ React.createElement(Table, {
|
|
248
|
+
title: "Error Reporting",
|
|
249
|
+
data: errors,
|
|
250
|
+
columns: columns$1,
|
|
251
|
+
options: {paging: true, search: false}
|
|
252
|
+
}));
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const groupResponses = (fetchResponse) => {
|
|
256
|
+
return fetchResponse.reduce((prev, next) => {
|
|
257
|
+
switch (next.type) {
|
|
258
|
+
case "deployments":
|
|
259
|
+
prev.deployments.push(...next.resources);
|
|
260
|
+
break;
|
|
261
|
+
case "pods":
|
|
262
|
+
prev.pods.push(...next.resources);
|
|
263
|
+
break;
|
|
264
|
+
case "replicasets":
|
|
265
|
+
prev.replicaSets.push(...next.resources);
|
|
266
|
+
break;
|
|
267
|
+
case "services":
|
|
268
|
+
prev.services.push(...next.resources);
|
|
269
|
+
break;
|
|
270
|
+
case "configmaps":
|
|
271
|
+
prev.configMaps.push(...next.resources);
|
|
272
|
+
break;
|
|
273
|
+
case "horizontalpodautoscalers":
|
|
274
|
+
prev.horizontalPodAutoscalers.push(...next.resources);
|
|
275
|
+
break;
|
|
276
|
+
case "ingresses":
|
|
277
|
+
prev.ingresses.push(...next.resources);
|
|
278
|
+
break;
|
|
279
|
+
case "customresources":
|
|
280
|
+
prev.customResources.push(...next.resources);
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
return prev;
|
|
284
|
+
}, {
|
|
285
|
+
pods: [],
|
|
286
|
+
replicaSets: [],
|
|
287
|
+
deployments: [],
|
|
288
|
+
services: [],
|
|
289
|
+
configMaps: [],
|
|
290
|
+
horizontalPodAutoscalers: [],
|
|
291
|
+
ingresses: [],
|
|
292
|
+
customResources: []
|
|
293
|
+
});
|
|
294
|
+
};
|
|
295
|
+
|
|
175
296
|
const imageChips = (pod) => {
|
|
176
297
|
var _a, _b;
|
|
177
298
|
const containerStatuses2 = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
|
|
@@ -243,152 +364,353 @@ const renderCondition = (condition) => {
|
|
|
243
364
|
return [condition.type, /* @__PURE__ */ React__default.createElement(StatusAborted, null)];
|
|
244
365
|
};
|
|
245
366
|
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(authProviderStr, requestBody);
|
|
269
|
-
} catch (e) {
|
|
270
|
-
setError(e.message);
|
|
271
|
-
return;
|
|
367
|
+
const detectErrorsInObjects = (objects, kind, clusterName, errorMappers) => {
|
|
368
|
+
var _a, _b;
|
|
369
|
+
const errors = new Map();
|
|
370
|
+
for (const object of objects) {
|
|
371
|
+
for (const errorMapper of errorMappers) {
|
|
372
|
+
if (errorMapper.errorExists(object)) {
|
|
373
|
+
const message = errorMapper.messageAccessor(object);
|
|
374
|
+
const dedupKey = message.join("");
|
|
375
|
+
const value = errors.get(dedupKey);
|
|
376
|
+
const name = (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown";
|
|
377
|
+
if (value !== void 0) {
|
|
378
|
+
value.names.push(name);
|
|
379
|
+
errors.set(dedupKey, value);
|
|
380
|
+
} else {
|
|
381
|
+
errors.set(dedupKey, {
|
|
382
|
+
cluster: clusterName,
|
|
383
|
+
kind,
|
|
384
|
+
names: [name],
|
|
385
|
+
message,
|
|
386
|
+
severity: errorMapper.severity
|
|
387
|
+
});
|
|
272
388
|
}
|
|
273
389
|
}
|
|
274
|
-
|
|
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";
|
|
390
|
+
}
|
|
344
391
|
}
|
|
345
|
-
return
|
|
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
|
|
392
|
+
return Array.from(errors.values());
|
|
371
393
|
};
|
|
372
|
-
const defaultFormatterName = "standard";
|
|
373
394
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
395
|
+
const podErrorMappers = [
|
|
396
|
+
{
|
|
397
|
+
severity: 5,
|
|
398
|
+
errorExplanation: "status-message",
|
|
399
|
+
errorExists: (pod) => {
|
|
400
|
+
var _a;
|
|
401
|
+
return ((_a = pod.status) == null ? void 0 : _a.message) !== void 0;
|
|
402
|
+
},
|
|
403
|
+
messageAccessor: (pod) => {
|
|
404
|
+
var _a, _b;
|
|
405
|
+
return [(_b = (_a = pod.status) == null ? void 0 : _a.message) != null ? _b : ""];
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
severity: 4,
|
|
410
|
+
errorExplanation: "containers-restarting",
|
|
411
|
+
errorExists: (pod) => {
|
|
412
|
+
return totalRestarts(pod) > 3;
|
|
413
|
+
},
|
|
414
|
+
messageAccessor: (pod) => {
|
|
415
|
+
var _a, _b;
|
|
416
|
+
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`);
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
severity: 5,
|
|
421
|
+
errorExplanation: "condition-message-present",
|
|
422
|
+
errorExists: (pod) => {
|
|
423
|
+
var _a, _b;
|
|
424
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).some((c) => c.message !== void 0);
|
|
425
|
+
},
|
|
426
|
+
messageAccessor: (pod) => {
|
|
427
|
+
var _a, _b;
|
|
428
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.message !== void 0).map((c) => {
|
|
429
|
+
var _a2;
|
|
430
|
+
return (_a2 = c.message) != null ? _a2 : "";
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
severity: 6,
|
|
436
|
+
errorExplanation: "container-waiting",
|
|
437
|
+
errorExists: (pod) => {
|
|
438
|
+
var _a, _b;
|
|
439
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
|
|
440
|
+
var _a2, _b2;
|
|
441
|
+
return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
|
|
442
|
+
});
|
|
443
|
+
},
|
|
444
|
+
messageAccessor: (pod) => {
|
|
445
|
+
var _a, _b;
|
|
446
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
|
|
447
|
+
var _a2, _b2;
|
|
448
|
+
return ((_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) !== void 0;
|
|
449
|
+
}).map((cs) => {
|
|
450
|
+
var _a2, _b2, _c;
|
|
451
|
+
return (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "";
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
severity: 4,
|
|
457
|
+
errorExplanation: "container-last-state-error",
|
|
458
|
+
errorExists: (pod) => {
|
|
459
|
+
var _a, _b;
|
|
460
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).some((cs) => {
|
|
461
|
+
var _a2, _b2, _c;
|
|
462
|
+
return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
|
|
463
|
+
});
|
|
464
|
+
},
|
|
465
|
+
messageAccessor: (pod) => {
|
|
466
|
+
var _a, _b;
|
|
467
|
+
return ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).filter((cs) => {
|
|
468
|
+
var _a2, _b2, _c;
|
|
469
|
+
return ((_c = (_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.reason) != null ? _c : "") === "Error";
|
|
470
|
+
}).map((cs) => {
|
|
471
|
+
var _a2, _b2;
|
|
472
|
+
return `container=${cs.name} exited with error code (${(_b2 = (_a2 = cs.lastState) == null ? void 0 : _a2.terminated) == null ? void 0 : _b2.exitCode})`;
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
];
|
|
477
|
+
const detectErrorsInPods = (pods, clusterName) => detectErrorsInObjects(pods, "Pod", clusterName, podErrorMappers);
|
|
478
|
+
|
|
479
|
+
const deploymentErrorMappers = [
|
|
480
|
+
{
|
|
481
|
+
severity: 6,
|
|
482
|
+
errorExplanation: "condition-message-present",
|
|
483
|
+
errorExists: (deployment) => {
|
|
484
|
+
var _a, _b;
|
|
485
|
+
return ((_b = (_a = deployment.status) == null ? void 0 : _a.conditions) != null ? _b : []).filter((c) => c.status === "False").some((c) => c.message !== void 0);
|
|
486
|
+
},
|
|
487
|
+
messageAccessor: (deployment) => {
|
|
488
|
+
var _a, _b;
|
|
489
|
+
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) => {
|
|
490
|
+
var _a2;
|
|
491
|
+
return (_a2 = c.message) != null ? _a2 : "";
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
];
|
|
496
|
+
const detectErrorsInDeployments = (deployments, clusterName) => detectErrorsInObjects(deployments, "Deployment", clusterName, deploymentErrorMappers);
|
|
497
|
+
|
|
498
|
+
const hpaErrorMappers = [
|
|
499
|
+
{
|
|
500
|
+
severity: 8,
|
|
501
|
+
errorExplanation: "hpa-max-current-replicas",
|
|
502
|
+
errorExists: (hpa) => {
|
|
503
|
+
var _a, _b, _c;
|
|
504
|
+
return ((_b = (_a = hpa.spec) == null ? void 0 : _a.maxReplicas) != null ? _b : -1) === ((_c = hpa.status) == null ? void 0 : _c.currentReplicas);
|
|
505
|
+
},
|
|
506
|
+
messageAccessor: (hpa) => {
|
|
507
|
+
var _a, _b, _c;
|
|
508
|
+
return [
|
|
509
|
+
`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})`
|
|
510
|
+
];
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
];
|
|
514
|
+
const detectErrorsInHpa = (hpas, clusterName) => detectErrorsInObjects(hpas, "HorizontalPodAutoscaler", clusterName, hpaErrorMappers);
|
|
515
|
+
|
|
516
|
+
const detectErrors = (objects) => {
|
|
517
|
+
const errors = new Map();
|
|
518
|
+
for (const clusterResponse of objects.items) {
|
|
519
|
+
let clusterErrors = [];
|
|
520
|
+
const groupedResponses = groupResponses(clusterResponse.resources);
|
|
521
|
+
clusterErrors = clusterErrors.concat(detectErrorsInPods(groupedResponses.pods, clusterResponse.cluster.name));
|
|
522
|
+
clusterErrors = clusterErrors.concat(detectErrorsInDeployments(groupedResponses.deployments, clusterResponse.cluster.name));
|
|
523
|
+
clusterErrors = clusterErrors.concat(detectErrorsInHpa(groupedResponses.horizontalPodAutoscalers, clusterResponse.cluster.name));
|
|
524
|
+
errors.set(clusterResponse.cluster.name, clusterErrors);
|
|
525
|
+
}
|
|
526
|
+
return errors;
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const useKubernetesObjects = (entity, intervalMs = 1e4) => {
|
|
530
|
+
const kubernetesApi = useApi(kubernetesApiRef);
|
|
531
|
+
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
|
|
532
|
+
const [kubernetesObjects, setKubernetesObjects] = useState(void 0);
|
|
533
|
+
const [error, setError] = useState(void 0);
|
|
534
|
+
const getObjects = async () => {
|
|
535
|
+
let clusters = [];
|
|
536
|
+
try {
|
|
537
|
+
clusters = await kubernetesApi.getClusters();
|
|
538
|
+
} catch (e) {
|
|
539
|
+
setError(e.message);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const authProviders = [
|
|
543
|
+
...new Set(clusters.map((c) => c.authProvider))
|
|
544
|
+
];
|
|
545
|
+
let requestBody = {
|
|
546
|
+
entity
|
|
547
|
+
};
|
|
548
|
+
for (const authProviderStr of authProviders) {
|
|
549
|
+
try {
|
|
550
|
+
requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(authProviderStr, requestBody);
|
|
551
|
+
} catch (e) {
|
|
552
|
+
setError(e.message);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
setKubernetesObjects(await kubernetesApi.getObjectsByEntity(requestBody));
|
|
558
|
+
} catch (e) {
|
|
559
|
+
setError(e.message);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
useEffect(() => {
|
|
564
|
+
getObjects();
|
|
565
|
+
}, [entity.metadata.name, kubernetesApi, kubernetesAuthProvidersApi]);
|
|
566
|
+
useInterval(() => {
|
|
567
|
+
getObjects();
|
|
568
|
+
}, intervalMs);
|
|
569
|
+
return {
|
|
570
|
+
kubernetesObjects,
|
|
571
|
+
error
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
const PodNamesWithErrorsContext = React__default.createContext(new Set());
|
|
576
|
+
|
|
577
|
+
const GroupedResponsesContext = React__default.createContext({
|
|
578
|
+
pods: [],
|
|
579
|
+
replicaSets: [],
|
|
580
|
+
deployments: [],
|
|
581
|
+
services: [],
|
|
582
|
+
configMaps: [],
|
|
583
|
+
horizontalPodAutoscalers: [],
|
|
584
|
+
ingresses: [],
|
|
585
|
+
customResources: []
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
const ClusterContext = React__default.createContext({
|
|
589
|
+
name: ""
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
const kindMappings$2 = {
|
|
593
|
+
deployment: "deployment",
|
|
594
|
+
ingress: "ingress",
|
|
595
|
+
service: "service",
|
|
596
|
+
horizontalpodautoscaler: "deployment"
|
|
597
|
+
};
|
|
598
|
+
function standardFormatter(options) {
|
|
599
|
+
var _a, _b, _c, _d;
|
|
600
|
+
const result = new URL(options.dashboardUrl.href);
|
|
601
|
+
const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
|
|
602
|
+
const namespace = encodeURIComponent((_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : "");
|
|
603
|
+
const validKind = kindMappings$2[options.kind.toLocaleLowerCase("en-US")];
|
|
604
|
+
if (!result.pathname.endsWith("/")) {
|
|
605
|
+
result.pathname += "/";
|
|
606
|
+
}
|
|
607
|
+
if (validKind && name && namespace) {
|
|
608
|
+
result.hash = `/${validKind}/${namespace}/${name}`;
|
|
609
|
+
} else if (namespace) {
|
|
610
|
+
result.hash = "/workloads";
|
|
611
|
+
}
|
|
612
|
+
if (namespace) {
|
|
613
|
+
result.hash += `?namespace=${namespace}`;
|
|
614
|
+
}
|
|
615
|
+
return result;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const kindMappings$1 = {
|
|
619
|
+
deployment: "apps.deployment",
|
|
620
|
+
ingress: "networking.k8s.io.ingress",
|
|
621
|
+
service: "service",
|
|
622
|
+
horizontalpodautoscaler: "autoscaling.horizontalpodautoscaler"
|
|
623
|
+
};
|
|
624
|
+
function rancherFormatter(options) {
|
|
625
|
+
var _a, _b, _c, _d;
|
|
626
|
+
const basePath = new URL(options.dashboardUrl.href);
|
|
627
|
+
const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
|
|
628
|
+
const namespace = encodeURIComponent((_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : "");
|
|
629
|
+
const validKind = kindMappings$1[options.kind.toLocaleLowerCase("en-US")];
|
|
630
|
+
if (!basePath.pathname.endsWith("/")) {
|
|
631
|
+
basePath.pathname += "/";
|
|
632
|
+
}
|
|
633
|
+
let path = "";
|
|
634
|
+
if (validKind && name && namespace) {
|
|
635
|
+
path = `explorer/${validKind}/${namespace}/${name}`;
|
|
636
|
+
} else if (namespace) {
|
|
637
|
+
path = "explorer/workload";
|
|
638
|
+
}
|
|
639
|
+
return new URL(path, basePath);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const kindMappings = {
|
|
643
|
+
deployment: "deployments",
|
|
644
|
+
ingress: "ingresses",
|
|
645
|
+
service: "services",
|
|
646
|
+
horizontalpodautoscaler: "horizontalpodautoscalers",
|
|
647
|
+
persistentvolume: "persistentvolumes"
|
|
648
|
+
};
|
|
649
|
+
function openshiftFormatter(options) {
|
|
650
|
+
var _a, _b, _c, _d;
|
|
651
|
+
const basePath = new URL(options.dashboardUrl.href);
|
|
652
|
+
const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
|
|
653
|
+
const namespace = encodeURIComponent((_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : "");
|
|
654
|
+
const validKind = kindMappings[options.kind.toLocaleLowerCase("en-US")];
|
|
655
|
+
if (!basePath.pathname.endsWith("/")) {
|
|
656
|
+
basePath.pathname += "/";
|
|
657
|
+
}
|
|
658
|
+
let path = "";
|
|
659
|
+
if (namespace) {
|
|
660
|
+
if (name && validKind) {
|
|
661
|
+
path = `k8s/ns/${namespace}/${validKind}/${name}`;
|
|
662
|
+
} else {
|
|
663
|
+
path = `k8s/cluster/projects/${namespace}`;
|
|
664
|
+
}
|
|
665
|
+
} else if (validKind) {
|
|
666
|
+
path = `k8s/cluster/${validKind}`;
|
|
667
|
+
if (name) {
|
|
668
|
+
path += `/${name}`;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return new URL(path, basePath);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function aksFormatter(_options) {
|
|
675
|
+
throw new Error("AKS formatter is not yet implemented. Please, contribute!");
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function eksFormatter(_options) {
|
|
679
|
+
throw new Error("EKS formatter is not yet implemented. Please, contribute!");
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function gkeFormatter(_options) {
|
|
683
|
+
throw new Error("GKE formatter is not yet implemented. Please, contribute!");
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const clusterLinksFormatters = {
|
|
687
|
+
standard: standardFormatter,
|
|
688
|
+
rancher: rancherFormatter,
|
|
689
|
+
openshift: openshiftFormatter,
|
|
690
|
+
aks: aksFormatter,
|
|
691
|
+
eks: eksFormatter,
|
|
692
|
+
gke: gkeFormatter
|
|
693
|
+
};
|
|
694
|
+
const defaultFormatterName = "standard";
|
|
695
|
+
|
|
696
|
+
function formatClusterLink(options) {
|
|
697
|
+
if (!options.dashboardUrl) {
|
|
698
|
+
return void 0;
|
|
699
|
+
}
|
|
700
|
+
if (!options.object) {
|
|
701
|
+
return options.dashboardUrl;
|
|
702
|
+
}
|
|
703
|
+
const app = options.dashboardApp || defaultFormatterName;
|
|
704
|
+
const formatter = clusterLinksFormatters[app];
|
|
705
|
+
if (!formatter) {
|
|
706
|
+
throw new Error(`Could not find Kubernetes dashboard app named '${app}'`);
|
|
707
|
+
}
|
|
386
708
|
const url = formatter({
|
|
387
709
|
dashboardUrl: new URL(options.dashboardUrl),
|
|
388
710
|
object: options.object,
|
|
389
711
|
kind: options.kind
|
|
390
712
|
});
|
|
391
|
-
return
|
|
713
|
+
return url.toString();
|
|
392
714
|
}
|
|
393
715
|
|
|
394
716
|
const useDrawerStyles = makeStyles((theme) => createStyles({
|
|
@@ -590,7 +912,7 @@ const PodDrawer = ({
|
|
|
590
912
|
});
|
|
591
913
|
};
|
|
592
914
|
|
|
593
|
-
const columns
|
|
915
|
+
const columns = [
|
|
594
916
|
{
|
|
595
917
|
title: "name",
|
|
596
918
|
highlight: true,
|
|
@@ -600,516 +922,237 @@ const columns$1 = [
|
|
|
600
922
|
},
|
|
601
923
|
{
|
|
602
924
|
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) => {
|
|
925
|
+
render: (pod) => {
|
|
1074
926
|
var _a, _b;
|
|
1075
|
-
return (
|
|
1076
|
-
var _a2;
|
|
1077
|
-
return (_a2 = c.message) != null ? _a2 : "";
|
|
1078
|
-
});
|
|
927
|
+
return (_b = (_a = pod.status) == null ? void 0 : _a.phase) != null ? _b : "unknown";
|
|
1079
928
|
}
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
title: "containers ready",
|
|
932
|
+
align: "center",
|
|
933
|
+
render: containersReady
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
title: "total restarts",
|
|
937
|
+
align: "center",
|
|
938
|
+
render: totalRestarts,
|
|
939
|
+
type: "numeric"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
title: "status",
|
|
943
|
+
render: containerStatuses
|
|
1080
944
|
}
|
|
1081
945
|
];
|
|
1082
|
-
const
|
|
946
|
+
const PodsTable = ({pods}) => {
|
|
947
|
+
const tableStyle = {
|
|
948
|
+
minWidth: "0",
|
|
949
|
+
width: "100%"
|
|
950
|
+
};
|
|
951
|
+
return /* @__PURE__ */ React__default.createElement("div", {
|
|
952
|
+
style: tableStyle
|
|
953
|
+
}, /* @__PURE__ */ React__default.createElement(Table, {
|
|
954
|
+
options: {paging: true, search: false},
|
|
955
|
+
data: pods,
|
|
956
|
+
columns
|
|
957
|
+
}));
|
|
958
|
+
};
|
|
1083
959
|
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
]
|
|
960
|
+
const DeploymentDrawer = ({
|
|
961
|
+
deployment,
|
|
962
|
+
expanded
|
|
963
|
+
}) => {
|
|
964
|
+
var _a, _b, _c;
|
|
965
|
+
const namespace = (_a = deployment.metadata) == null ? void 0 : _a.namespace;
|
|
966
|
+
return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
|
|
967
|
+
object: deployment,
|
|
968
|
+
expanded,
|
|
969
|
+
kind: "Deployment",
|
|
970
|
+
renderObject: (deploymentObj) => {
|
|
971
|
+
var _a2, _b2, _c2, _d, _e, _f, _g, _h;
|
|
972
|
+
const conditions = ((_b2 = (_a2 = deploymentObj.status) == null ? void 0 : _a2.conditions) != null ? _b2 : []).map(renderCondition).reduce((accum, next) => {
|
|
973
|
+
accum[next[0]] = next[1];
|
|
974
|
+
return accum;
|
|
975
|
+
}, {});
|
|
976
|
+
return {
|
|
977
|
+
strategy: (_d = (_c2 = deploymentObj.spec) == null ? void 0 : _c2.strategy) != null ? _d : "???",
|
|
978
|
+
minReadySeconds: (_f = (_e = deploymentObj.spec) == null ? void 0 : _e.minReadySeconds) != null ? _f : "???",
|
|
979
|
+
progressDeadlineSeconds: (_h = (_g = deploymentObj.spec) == null ? void 0 : _g.progressDeadlineSeconds) != null ? _h : "???",
|
|
980
|
+
...conditions
|
|
981
|
+
};
|
|
1097
982
|
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
|
|
983
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
984
|
+
container: true,
|
|
985
|
+
direction: "column",
|
|
986
|
+
justifyContent: "flex-start",
|
|
987
|
+
alignItems: "flex-start",
|
|
988
|
+
spacing: 0
|
|
989
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
990
|
+
item: true
|
|
991
|
+
}, /* @__PURE__ */ React__default.createElement(Typography, {
|
|
992
|
+
variant: "h5"
|
|
993
|
+
}, (_c = (_b = deployment.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")), /* @__PURE__ */ React__default.createElement(Grid, {
|
|
994
|
+
item: true
|
|
995
|
+
}, /* @__PURE__ */ React__default.createElement(Typography, {
|
|
996
|
+
color: "textSecondary",
|
|
997
|
+
variant: "body1"
|
|
998
|
+
}, "Deployment")), namespace && /* @__PURE__ */ React__default.createElement(Grid, {
|
|
999
|
+
item: true
|
|
1000
|
+
}, /* @__PURE__ */ React__default.createElement(Chip, {
|
|
1001
|
+
size: "small",
|
|
1002
|
+
label: `namespace: ${namespace}`
|
|
1003
|
+
}))));
|
|
1004
|
+
};
|
|
1101
1005
|
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1006
|
+
const HorizontalPodAutoscalerDrawer = ({
|
|
1007
|
+
hpa,
|
|
1008
|
+
expanded,
|
|
1009
|
+
children
|
|
1010
|
+
}) => {
|
|
1011
|
+
return /* @__PURE__ */ React__default.createElement(KubernetesDrawer, {
|
|
1012
|
+
kind: "HorizontalPodAutoscaler",
|
|
1013
|
+
object: hpa,
|
|
1014
|
+
expanded,
|
|
1015
|
+
renderObject: (hpaObject) => {
|
|
1016
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1017
|
+
return {
|
|
1018
|
+
targetCPUUtilizationPercentage: (_a = hpaObject.spec) == null ? void 0 : _a.targetCPUUtilizationPercentage,
|
|
1019
|
+
currentCPUUtilizationPercentage: (_b = hpaObject.status) == null ? void 0 : _b.currentCPUUtilizationPercentage,
|
|
1020
|
+
minReplicas: (_c = hpaObject.spec) == null ? void 0 : _c.minReplicas,
|
|
1021
|
+
maxReplicas: (_d = hpaObject.spec) == null ? void 0 : _d.maxReplicas,
|
|
1022
|
+
currentReplicas: (_e = hpaObject.status) == null ? void 0 : _e.currentReplicas,
|
|
1023
|
+
desiredReplicas: (_f = hpaObject.status) == null ? void 0 : _f.desiredReplicas
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
}, children);
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
function getOwnedResources(potentialOwner, possiblyOwned) {
|
|
1030
|
+
return possiblyOwned.filter((p) => {
|
|
1031
|
+
var _a, _b, _c;
|
|
1032
|
+
return (_c = (_b = (_a = p.metadata) == null ? void 0 : _a.ownerReferences) == null ? void 0 : _b.some((o) => {
|
|
1033
|
+
var _a2;
|
|
1034
|
+
return o.uid === ((_a2 = potentialOwner.metadata) == null ? void 0 : _a2.uid);
|
|
1035
|
+
})) != null ? _c : false;
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
const getOwnedPodsThroughReplicaSets = (potentialOwner, replicaSets, pods) => {
|
|
1039
|
+
return getOwnedResources(potentialOwner, replicaSets.filter((rs) => rs.status && rs.status.replicas > 0)).reduce((accum, rs) => {
|
|
1040
|
+
return accum.concat(getOwnedResources(rs, pods));
|
|
1041
|
+
}, []);
|
|
1042
|
+
};
|
|
1043
|
+
const getMatchingHpa = (ownerName, ownerKind, hpas) => {
|
|
1044
|
+
return hpas.find((hpa) => {
|
|
1045
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1046
|
+
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");
|
|
1047
|
+
});
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
const DeploymentSummary = ({
|
|
1051
|
+
deployment,
|
|
1052
|
+
numberOfCurrentPods,
|
|
1053
|
+
numberOfPodsWithErrors,
|
|
1054
|
+
hpa
|
|
1055
|
+
}) => {
|
|
1056
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1057
|
+
return /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1058
|
+
container: true,
|
|
1059
|
+
direction: "row",
|
|
1060
|
+
justifyContent: "flex-start",
|
|
1061
|
+
alignItems: "center"
|
|
1062
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1063
|
+
xs: 3,
|
|
1064
|
+
item: true
|
|
1065
|
+
}, /* @__PURE__ */ React__default.createElement(DeploymentDrawer, {
|
|
1066
|
+
deployment
|
|
1067
|
+
})), /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1068
|
+
item: true,
|
|
1069
|
+
xs: 1
|
|
1070
|
+
}, /* @__PURE__ */ React__default.createElement(Divider, {
|
|
1071
|
+
style: {height: "5em"},
|
|
1072
|
+
orientation: "vertical"
|
|
1073
|
+
})), hpa && /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1074
|
+
item: true,
|
|
1075
|
+
xs: 3
|
|
1076
|
+
}, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, {
|
|
1077
|
+
hpa
|
|
1078
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1079
|
+
item: true,
|
|
1080
|
+
container: true,
|
|
1081
|
+
direction: "column",
|
|
1082
|
+
justifyContent: "flex-start",
|
|
1083
|
+
alignItems: "flex-start",
|
|
1084
|
+
spacing: 0
|
|
1085
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1086
|
+
item: true
|
|
1087
|
+
}, /* @__PURE__ */ React__default.createElement(Typography, {
|
|
1088
|
+
variant: "subtitle2"
|
|
1089
|
+
}, "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, {
|
|
1090
|
+
item: true
|
|
1091
|
+
}, /* @__PURE__ */ React__default.createElement(Typography, {
|
|
1092
|
+
variant: "subtitle2"
|
|
1093
|
+
}, "current CPU usage:", " ", (_f = (_e = hpa.status) == null ? void 0 : _e.currentCPUUtilizationPercentage) != null ? _f : "?", "%")), /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1094
|
+
item: true
|
|
1095
|
+
}, /* @__PURE__ */ React__default.createElement(Typography, {
|
|
1096
|
+
variant: "subtitle2"
|
|
1097
|
+
}, "target CPU usage:", " ", (_h = (_g = hpa.spec) == null ? void 0 : _g.targetCPUUtilizationPercentage) != null ? _h : "?", "%"))))), /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1098
|
+
item: true,
|
|
1099
|
+
container: true,
|
|
1100
|
+
xs: 3,
|
|
1101
|
+
direction: "column",
|
|
1102
|
+
justifyContent: "flex-start",
|
|
1103
|
+
alignItems: "flex-start"
|
|
1104
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1105
|
+
item: true
|
|
1106
|
+
}, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")), /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1107
|
+
item: true
|
|
1108
|
+
}, 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"))));
|
|
1109
|
+
};
|
|
1110
|
+
const DeploymentAccordion = ({
|
|
1111
|
+
deployment,
|
|
1112
|
+
ownedPods,
|
|
1113
|
+
matchingHpa
|
|
1114
|
+
}) => {
|
|
1115
|
+
const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
|
|
1116
|
+
const podsWithErrors = ownedPods.filter((p) => {
|
|
1117
|
+
var _a, _b;
|
|
1118
|
+
return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
|
|
1119
|
+
});
|
|
1120
|
+
return /* @__PURE__ */ React__default.createElement(Accordion, {
|
|
1121
|
+
TransitionProps: {unmountOnExit: true}
|
|
1122
|
+
}, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
|
|
1123
|
+
expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
|
|
1124
|
+
}, /* @__PURE__ */ React__default.createElement(DeploymentSummary, {
|
|
1125
|
+
deployment,
|
|
1126
|
+
numberOfCurrentPods: ownedPods.length,
|
|
1127
|
+
numberOfPodsWithErrors: podsWithErrors.length,
|
|
1128
|
+
hpa: matchingHpa
|
|
1129
|
+
})), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(PodsTable, {
|
|
1130
|
+
pods: ownedPods
|
|
1131
|
+
})));
|
|
1132
|
+
};
|
|
1133
|
+
const DeploymentsAccordions = ({}) => {
|
|
1134
|
+
const groupedResponses = useContext(GroupedResponsesContext);
|
|
1135
|
+
return /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1136
|
+
container: true,
|
|
1137
|
+
direction: "column",
|
|
1138
|
+
justifyContent: "flex-start",
|
|
1139
|
+
alignItems: "flex-start"
|
|
1140
|
+
}, groupedResponses.deployments.map((deployment, i) => {
|
|
1141
|
+
var _a;
|
|
1142
|
+
return /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1143
|
+
container: true,
|
|
1144
|
+
item: true,
|
|
1145
|
+
key: i,
|
|
1146
|
+
xs: true
|
|
1147
|
+
}, /* @__PURE__ */ React__default.createElement(Grid, {
|
|
1148
|
+
item: true,
|
|
1149
|
+
xs: true
|
|
1150
|
+
}, /* @__PURE__ */ React__default.createElement(DeploymentAccordion, {
|
|
1151
|
+
matchingHpa: getMatchingHpa((_a = deployment.metadata) == null ? void 0 : _a.name, "deployment", groupedResponses.horizontalPodAutoscalers),
|
|
1152
|
+
ownedPods: getOwnedPodsThroughReplicaSets(deployment, groupedResponses.replicaSets, groupedResponses.pods),
|
|
1153
|
+
deployment
|
|
1154
|
+
})));
|
|
1155
|
+
}));
|
|
1113
1156
|
};
|
|
1114
1157
|
|
|
1115
1158
|
const IngressDrawer = ({
|
|
@@ -1712,6 +1755,7 @@ const Cluster = ({clusterObjects, podsWithErrors}) => {
|
|
|
1712
1755
|
item: true
|
|
1713
1756
|
}, /* @__PURE__ */ React__default.createElement(ServicesAccordions, null))))))));
|
|
1714
1757
|
};
|
|
1758
|
+
|
|
1715
1759
|
const KubernetesContent = ({entity}) => {
|
|
1716
1760
|
var _a;
|
|
1717
1761
|
const {kubernetesObjects, error} = useKubernetesObjects(entity);
|
|
@@ -1799,7 +1843,7 @@ const Router = (_props) => {
|
|
|
1799
1843
|
const kubernetesLabelSelectorQueryAnnotationValue = (_b = entity.metadata.annotations) == null ? void 0 : _b[KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION];
|
|
1800
1844
|
if (kubernetesAnnotationValue || kubernetesLabelSelectorQueryAnnotationValue) {
|
|
1801
1845
|
return /* @__PURE__ */ React__default.createElement(Routes, null, /* @__PURE__ */ React__default.createElement(Route, {
|
|
1802
|
-
path:
|
|
1846
|
+
path: "/",
|
|
1803
1847
|
element: /* @__PURE__ */ React__default.createElement(KubernetesContent, {
|
|
1804
1848
|
entity
|
|
1805
1849
|
})
|