@backstage/plugin-kubernetes 0.9.2-next.0 → 0.9.2-next.2
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 +26 -0
- package/dist/index.d.ts +218 -6
- package/dist/index.esm.js +357 -34
- package/dist/index.esm.js.map +1 -1
- package/package.json +12 -12
package/dist/index.esm.js
CHANGED
|
@@ -5,8 +5,8 @@ import * as React from 'react';
|
|
|
5
5
|
import React__default, { useState, useCallback, useContext, Fragment } from 'react';
|
|
6
6
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
7
7
|
import { Routes, Route } from 'react-router-dom';
|
|
8
|
-
import { Typography, Paper, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Card, CardHeader, CardContent, Grid, CardActions, FormControlLabel, Switch, Drawer, withStyles as withStyles$1, List, ListItem,
|
|
9
|
-
import { WarningPanel, Table, DismissableBanner, LogViewer, StructuredMetadataTable, CodeSnippet, LinkButton, StatusError, StatusOK, StatusWarning, ItemCardGrid, SubvalueCell, StatusAborted, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
|
|
8
|
+
import { Typography, Paper, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Card, CardHeader, CardContent, Grid, CardActions, FormControlLabel, Switch, Drawer, withStyles as withStyles$1, List, ListItem, Container, Tooltip, ListItemText, ListItemAvatar, Avatar, Divider, Chip, Accordion, AccordionSummary, AccordionDetails, Stepper, Step, StepLabel } from '@material-ui/core';
|
|
9
|
+
import { WarningPanel, Table, DismissableBanner, EmptyState, LogViewer, StructuredMetadataTable, CodeSnippet, LinkButton, StatusError, StatusOK, StatusWarning, ItemCardGrid, SubvalueCell, StatusAborted, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
|
|
10
10
|
import lodash from 'lodash';
|
|
11
11
|
import { DateTime } from 'luxon';
|
|
12
12
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
@@ -15,14 +15,22 @@ import useAsync from 'react-use/lib/useAsync';
|
|
|
15
15
|
import SubjectIcon from '@material-ui/icons/Subject';
|
|
16
16
|
import CloseIcon from '@material-ui/icons/Close';
|
|
17
17
|
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
|
|
18
|
-
import { withStyles } from '@material-ui/core/styles';
|
|
18
|
+
import { withStyles, makeStyles as makeStyles$1, createStyles as createStyles$1 } from '@material-ui/core/styles';
|
|
19
19
|
import useInterval from 'react-use/lib/useInterval';
|
|
20
20
|
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
|
21
21
|
import jsyaml from 'js-yaml';
|
|
22
|
+
import Dialog$1 from '@material-ui/core/Dialog';
|
|
23
|
+
import DialogActions from '@material-ui/core/DialogActions';
|
|
24
|
+
import DialogContent$1 from '@material-ui/core/DialogContent';
|
|
25
|
+
import DialogTitle$1 from '@material-ui/core/DialogTitle';
|
|
26
|
+
import IconButton$1 from '@material-ui/core/IconButton';
|
|
27
|
+
import Typography$1 from '@material-ui/core/Typography';
|
|
28
|
+
import HelpIcon from '@material-ui/icons/Help';
|
|
29
|
+
import InfoIcon from '@material-ui/icons/Info';
|
|
30
|
+
import WarningIcon from '@material-ui/icons/Warning';
|
|
22
31
|
import cronstrue from 'cronstrue';
|
|
23
32
|
import PauseIcon from '@material-ui/icons/Pause';
|
|
24
33
|
import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
|
|
25
|
-
import Typography$1 from '@material-ui/core/Typography';
|
|
26
34
|
import EmptyStateImage from './assets/emptystate.svg';
|
|
27
35
|
|
|
28
36
|
class KubernetesBackendClient {
|
|
@@ -296,15 +304,47 @@ class KubernetesProxyClient {
|
|
|
296
304
|
}
|
|
297
305
|
return await response.text();
|
|
298
306
|
}
|
|
307
|
+
async handleJson(response) {
|
|
308
|
+
if (!response.ok) {
|
|
309
|
+
const payload = await response.text();
|
|
310
|
+
let message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
|
|
311
|
+
switch (response.status) {
|
|
312
|
+
case 404:
|
|
313
|
+
message = `Proxy request failed with ${response.status} ${response.statusText}, ${payload}`;
|
|
314
|
+
break;
|
|
315
|
+
default:
|
|
316
|
+
message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
|
|
317
|
+
}
|
|
318
|
+
throw new Error(message);
|
|
319
|
+
}
|
|
320
|
+
return await response.json();
|
|
321
|
+
}
|
|
322
|
+
async getEventsByInvolvedObjectName({
|
|
323
|
+
clusterName,
|
|
324
|
+
involvedObjectName,
|
|
325
|
+
namespace
|
|
326
|
+
}) {
|
|
327
|
+
return await this.kubernetesApi.proxy({
|
|
328
|
+
clusterName,
|
|
329
|
+
path: `/api/v1/namespaces/${namespace}/events?fieldSelector=involvedObject.name=${involvedObjectName}`,
|
|
330
|
+
init: {
|
|
331
|
+
method: "GET"
|
|
332
|
+
}
|
|
333
|
+
}).then((response) => this.handleJson(response)).then((eventList) => eventList.items);
|
|
334
|
+
}
|
|
299
335
|
async getPodLogs({
|
|
300
336
|
podName,
|
|
301
337
|
namespace,
|
|
302
338
|
clusterName,
|
|
303
|
-
containerName
|
|
339
|
+
containerName,
|
|
340
|
+
previous
|
|
304
341
|
}) {
|
|
305
342
|
const params = new URLSearchParams({
|
|
306
343
|
container: containerName
|
|
307
344
|
});
|
|
345
|
+
if (previous) {
|
|
346
|
+
params.append("previous", "");
|
|
347
|
+
}
|
|
308
348
|
return await this.kubernetesApi.proxy({
|
|
309
349
|
clusterName,
|
|
310
350
|
path: `/api/v1/namespaces/${namespace}/pods/${podName}/log?${params.toString()}`,
|
|
@@ -556,6 +596,124 @@ const podToContainerSpecsAndStatuses = (pod) => {
|
|
|
556
596
|
}
|
|
557
597
|
return result;
|
|
558
598
|
};
|
|
599
|
+
const readinessProbeProposedFixes = (pod) => {
|
|
600
|
+
var _a, _b, _c, _d;
|
|
601
|
+
const firstUnreadyContainerStatus = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) == null ? void 0 : _b.find(
|
|
602
|
+
(cs) => {
|
|
603
|
+
return cs.ready === false;
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
return {
|
|
607
|
+
errorType: "ReadinessProbeFailed",
|
|
608
|
+
rootCauseExplanation: `The container ${firstUnreadyContainerStatus == null ? void 0 : firstUnreadyContainerStatus.name} failed to start properly, but is not crashing`,
|
|
609
|
+
actions: [
|
|
610
|
+
"Ensure that the container starts correctly locally",
|
|
611
|
+
"Check the container's logs looking for error during startup"
|
|
612
|
+
],
|
|
613
|
+
type: "events",
|
|
614
|
+
podName: (_d = (_c = pod.metadata) == null ? void 0 : _c.name) != null ? _d : ""
|
|
615
|
+
};
|
|
616
|
+
};
|
|
617
|
+
const restartingPodProposedFixes = (pod) => {
|
|
618
|
+
var _a, _b, _c;
|
|
619
|
+
const lastTerminatedCs = ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).find(
|
|
620
|
+
(cs) => {
|
|
621
|
+
var _a2;
|
|
622
|
+
return ((_a2 = cs.lastState) == null ? void 0 : _a2.terminated) !== void 0;
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
const lastTerminated = (_c = lastTerminatedCs == null ? void 0 : lastTerminatedCs.lastState) == null ? void 0 : _c.terminated;
|
|
626
|
+
if (!lastTerminated) {
|
|
627
|
+
return void 0;
|
|
628
|
+
}
|
|
629
|
+
switch (lastTerminated == null ? void 0 : lastTerminated.reason) {
|
|
630
|
+
case "Unknown":
|
|
631
|
+
return {
|
|
632
|
+
// TODO check this one, it's more likely a cluster issue
|
|
633
|
+
errorType: "Unknown",
|
|
634
|
+
rootCauseExplanation: `This container has exited with a non-zero exit code (${lastTerminated.exitCode})`,
|
|
635
|
+
actions: ["Check the crash logs for stacktraces"],
|
|
636
|
+
container: lastTerminatedCs.name,
|
|
637
|
+
type: "logs"
|
|
638
|
+
};
|
|
639
|
+
case "Error":
|
|
640
|
+
return {
|
|
641
|
+
errorType: "Error",
|
|
642
|
+
rootCauseExplanation: `This container has exited with a non-zero exit code (${lastTerminated.exitCode})`,
|
|
643
|
+
actions: ["Check the crash logs for stacktraces"],
|
|
644
|
+
container: lastTerminatedCs.name,
|
|
645
|
+
type: "logs"
|
|
646
|
+
};
|
|
647
|
+
case "OOMKilled":
|
|
648
|
+
return {
|
|
649
|
+
errorType: "OOMKilled",
|
|
650
|
+
rootCauseExplanation: `The container "${lastTerminatedCs.name}" has crashed because it has tried to use more memory that it has been allocated`,
|
|
651
|
+
actions: [
|
|
652
|
+
`Increase the amount of memory assigned to the container`,
|
|
653
|
+
"Ensure the application is memory bounded and is not trying to consume too much memory"
|
|
654
|
+
],
|
|
655
|
+
docsLink: "https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/#exceed-a-container-s-memory-limit",
|
|
656
|
+
type: "docs"
|
|
657
|
+
};
|
|
658
|
+
default:
|
|
659
|
+
return void 0;
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
const waitingProposedFix = (pod) => {
|
|
663
|
+
var _a, _b, _c, _d, _e;
|
|
664
|
+
const waitingCs = ((_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : []).find(
|
|
665
|
+
(cs) => {
|
|
666
|
+
var _a2;
|
|
667
|
+
return ((_a2 = cs.state) == null ? void 0 : _a2.waiting) !== void 0;
|
|
668
|
+
}
|
|
669
|
+
);
|
|
670
|
+
const waiting = ((_d = (_c = pod.status) == null ? void 0 : _c.containerStatuses) != null ? _d : []).map((cs) => {
|
|
671
|
+
var _a2;
|
|
672
|
+
return (_a2 = cs.state) == null ? void 0 : _a2.waiting;
|
|
673
|
+
}).find((w) => (w == null ? void 0 : w.reason) !== void 0);
|
|
674
|
+
switch (waiting == null ? void 0 : waiting.reason) {
|
|
675
|
+
case "InvalidImageName":
|
|
676
|
+
return {
|
|
677
|
+
errorType: "InvalidImageName",
|
|
678
|
+
rootCauseExplanation: "The image in the pod is invalid",
|
|
679
|
+
actions: ["Ensure the image name is correct and valid image name"],
|
|
680
|
+
type: "docs",
|
|
681
|
+
docsLink: "https://docs.docker.com/engine/reference/commandline/tag/#extended-description"
|
|
682
|
+
};
|
|
683
|
+
case "ImagePullBackOff":
|
|
684
|
+
return {
|
|
685
|
+
errorType: "ImagePullBackOff",
|
|
686
|
+
rootCauseExplanation: "The image either could not be found or Kubernetes does not have permission to pull it",
|
|
687
|
+
actions: [
|
|
688
|
+
"Ensure the image name is correct",
|
|
689
|
+
"Ensure Kubernetes has permission to pull this image"
|
|
690
|
+
],
|
|
691
|
+
type: "docs",
|
|
692
|
+
docsLink: "https://kubernetes.io/docs/concepts/containers/images/#imagepullbackoff"
|
|
693
|
+
};
|
|
694
|
+
case "CrashLoopBackOff":
|
|
695
|
+
return {
|
|
696
|
+
errorType: "CrashLoopBackOff",
|
|
697
|
+
rootCauseExplanation: `The container ${waitingCs == null ? void 0 : waitingCs.name} has crashed many times, it will be exponentially restarted until it stops crashing`,
|
|
698
|
+
actions: ["Check the crash logs for stacktraces"],
|
|
699
|
+
type: "logs",
|
|
700
|
+
container: (_e = waitingCs == null ? void 0 : waitingCs.name) != null ? _e : "unknown"
|
|
701
|
+
};
|
|
702
|
+
case "CreateContainerConfigError":
|
|
703
|
+
return {
|
|
704
|
+
errorType: "CreateContainerConfigError",
|
|
705
|
+
rootCauseExplanation: "There is missing or mismatching configuration required to start the container",
|
|
706
|
+
actions: [
|
|
707
|
+
"Ensure ConfigMaps references in the Deployment manifest are correct and the keys exist",
|
|
708
|
+
"Ensure Secrets references in the Deployment manifest are correct and the keys exist"
|
|
709
|
+
],
|
|
710
|
+
type: "docs",
|
|
711
|
+
docsLink: "https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/"
|
|
712
|
+
};
|
|
713
|
+
default:
|
|
714
|
+
return void 0;
|
|
715
|
+
}
|
|
716
|
+
};
|
|
559
717
|
const podErrorMappers = [
|
|
560
718
|
{
|
|
561
719
|
detectErrors: (pod) => {
|
|
@@ -565,8 +723,7 @@ const podErrorMappers = [
|
|
|
565
723
|
type: "readiness-probe-taking-too-long",
|
|
566
724
|
message: `The container ${cs.container.name} failed to start properly, but is not crashing`,
|
|
567
725
|
severity: 4,
|
|
568
|
-
proposedFix:
|
|
569
|
-
// TODO next PR
|
|
726
|
+
proposedFix: readinessProbeProposedFixes(pod),
|
|
570
727
|
sourceRef: {
|
|
571
728
|
name: (_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown pod",
|
|
572
729
|
namespace: (_d = (_c = pod.metadata) == null ? void 0 : _c.namespace) != null ? _d : "unknown namespace",
|
|
@@ -590,8 +747,7 @@ const podErrorMappers = [
|
|
|
590
747
|
type: "container-waiting",
|
|
591
748
|
message: (_c = (_b2 = (_a2 = cs.state) == null ? void 0 : _a2.waiting) == null ? void 0 : _b2.message) != null ? _c : "container waiting",
|
|
592
749
|
severity: 4,
|
|
593
|
-
proposedFix:
|
|
594
|
-
// TODO next PR
|
|
750
|
+
proposedFix: waitingProposedFix(pod),
|
|
595
751
|
sourceRef: {
|
|
596
752
|
name: (_e = (_d = pod.metadata) == null ? void 0 : _d.name) != null ? _e : "unknown pod",
|
|
597
753
|
namespace: (_g = (_f = pod.metadata) == null ? void 0 : _f.namespace) != null ? _g : "unknown namespace",
|
|
@@ -612,8 +768,7 @@ const podErrorMappers = [
|
|
|
612
768
|
type: "containers-restarting",
|
|
613
769
|
message: `container=${cs.name} restarted ${cs.restartCount} times`,
|
|
614
770
|
severity: 4,
|
|
615
|
-
proposedFix:
|
|
616
|
-
// TODO next PR
|
|
771
|
+
proposedFix: restartingPodProposedFixes(pod),
|
|
617
772
|
sourceRef: {
|
|
618
773
|
name: (_b2 = (_a2 = pod.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "unknown pod",
|
|
619
774
|
namespace: (_d = (_c = pod.metadata) == null ? void 0 : _c.namespace) != null ? _d : "unknown namespace",
|
|
@@ -638,8 +793,6 @@ const deploymentErrorMappers = [
|
|
|
638
793
|
type: "condition-message-present",
|
|
639
794
|
message: (_a2 = c.message) != null ? _a2 : "",
|
|
640
795
|
severity: 6,
|
|
641
|
-
proposedFix: [],
|
|
642
|
-
// TODO next PR
|
|
643
796
|
sourceRef: {
|
|
644
797
|
name: (_c = (_b2 = deployment.metadata) == null ? void 0 : _b2.name) != null ? _c : "unknown hpa",
|
|
645
798
|
namespace: (_e = (_d = deployment.metadata) == null ? void 0 : _d.namespace) != null ? _e : "unknown namespace",
|
|
@@ -664,8 +817,6 @@ const hpaErrorMappers = [
|
|
|
664
817
|
type: "hpa-max-current-replicas",
|
|
665
818
|
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})`,
|
|
666
819
|
severity: 8,
|
|
667
|
-
proposedFix: [],
|
|
668
|
-
// TODO next PR
|
|
669
820
|
sourceRef: {
|
|
670
821
|
name: (_h = (_g = hpa.metadata) == null ? void 0 : _g.name) != null ? _h : "unknown hpa",
|
|
671
822
|
namespace: (_j = (_i = hpa.metadata) == null ? void 0 : _i.namespace) != null ? _j : "unknown namespace",
|
|
@@ -703,21 +854,26 @@ const detectErrors = (objects) => {
|
|
|
703
854
|
return errors;
|
|
704
855
|
};
|
|
705
856
|
|
|
706
|
-
const usePodLogs = ({
|
|
857
|
+
const usePodLogs = ({ containerScope, previous }) => {
|
|
707
858
|
const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
|
|
708
859
|
return useAsync(async () => {
|
|
709
860
|
return await kubernetesProxyApi.getPodLogs({
|
|
710
|
-
podName:
|
|
711
|
-
namespace:
|
|
712
|
-
containerName:
|
|
713
|
-
clusterName:
|
|
861
|
+
podName: containerScope.podName,
|
|
862
|
+
namespace: containerScope.podNamespace,
|
|
863
|
+
containerName: containerScope.containerName,
|
|
864
|
+
clusterName: containerScope.clusterName,
|
|
865
|
+
previous
|
|
714
866
|
});
|
|
715
|
-
}, [JSON.stringify(
|
|
867
|
+
}, [JSON.stringify(containerScope)]);
|
|
716
868
|
};
|
|
717
869
|
|
|
718
|
-
const PodLogs = ({
|
|
870
|
+
const PodLogs = ({
|
|
871
|
+
containerScope,
|
|
872
|
+
previous
|
|
873
|
+
}) => {
|
|
719
874
|
const { value, error, loading } = usePodLogs({
|
|
720
|
-
|
|
875
|
+
containerScope,
|
|
876
|
+
previous
|
|
721
877
|
});
|
|
722
878
|
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, error && /* @__PURE__ */ React__default.createElement(
|
|
723
879
|
DismissableBanner,
|
|
@@ -733,14 +889,21 @@ const PodLogs = ({ podScope }) => {
|
|
|
733
889
|
Paper,
|
|
734
890
|
{
|
|
735
891
|
elevation: 1,
|
|
736
|
-
style: { height: "100%", width: "100%", minHeight: "
|
|
892
|
+
style: { height: "100%", width: "100%", minHeight: "15rem" }
|
|
737
893
|
},
|
|
738
894
|
loading && /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rect", width: "100%", height: "100%" }),
|
|
739
|
-
!loading && value !== void 0 && /* @__PURE__ */ React__default.createElement(
|
|
895
|
+
!loading && value !== void 0 && (value.text === "" ? /* @__PURE__ */ React__default.createElement(
|
|
896
|
+
EmptyState,
|
|
897
|
+
{
|
|
898
|
+
missing: "data",
|
|
899
|
+
title: "No logs emitted",
|
|
900
|
+
description: "No logs were emitted by the container"
|
|
901
|
+
}
|
|
902
|
+
) : /* @__PURE__ */ React__default.createElement(LogViewer, { text: value.text }))
|
|
740
903
|
));
|
|
741
904
|
};
|
|
742
905
|
|
|
743
|
-
const useStyles$
|
|
906
|
+
const useStyles$2 = makeStyles(
|
|
744
907
|
(theme) => createStyles({
|
|
745
908
|
closeButton: {
|
|
746
909
|
position: "absolute",
|
|
@@ -750,8 +913,8 @@ const useStyles$1 = makeStyles(
|
|
|
750
913
|
}
|
|
751
914
|
})
|
|
752
915
|
);
|
|
753
|
-
const PodLogsDialog = ({
|
|
754
|
-
const classes = useStyles$
|
|
916
|
+
const PodLogsDialog = ({ containerScope }) => {
|
|
917
|
+
const classes = useStyles$2();
|
|
755
918
|
const [open, setOpen] = useState(false);
|
|
756
919
|
const openDialog = () => {
|
|
757
920
|
setOpen(true);
|
|
@@ -759,7 +922,7 @@ const PodLogsDialog = ({ podScope }) => {
|
|
|
759
922
|
const closeDialog = () => {
|
|
760
923
|
setOpen(false);
|
|
761
924
|
};
|
|
762
|
-
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Dialog, { maxWidth: "xl", fullWidth: true, open, onClose: closeDialog }, /* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" },
|
|
925
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Dialog, { maxWidth: "xl", fullWidth: true, open, onClose: closeDialog }, /* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" }, containerScope.podName, " - ", containerScope.containerName, " logs on cluster ", containerScope.clusterName, /* @__PURE__ */ React__default.createElement(
|
|
763
926
|
IconButton,
|
|
764
927
|
{
|
|
765
928
|
"aria-label": "close",
|
|
@@ -767,7 +930,7 @@ const PodLogsDialog = ({ podScope }) => {
|
|
|
767
930
|
onClick: closeDialog
|
|
768
931
|
},
|
|
769
932
|
/* @__PURE__ */ React__default.createElement(CloseIcon, null)
|
|
770
|
-
)), /* @__PURE__ */ React__default.createElement(DialogContent, null, /* @__PURE__ */ React__default.createElement(PodLogs, {
|
|
933
|
+
)), /* @__PURE__ */ React__default.createElement(DialogContent, null, /* @__PURE__ */ React__default.createElement(PodLogs, { containerScope }))), /* @__PURE__ */ React__default.createElement(
|
|
771
934
|
Button,
|
|
772
935
|
{
|
|
773
936
|
variant: "outlined",
|
|
@@ -853,7 +1016,7 @@ const ContainerCard = ({
|
|
|
853
1016
|
)))), /* @__PURE__ */ React__default.createElement(CardActions, { disableSpacing: true }, /* @__PURE__ */ React__default.createElement(
|
|
854
1017
|
PodLogsDialog,
|
|
855
1018
|
{
|
|
856
|
-
|
|
1019
|
+
containerScope: {
|
|
857
1020
|
containerName: containerStatus.name,
|
|
858
1021
|
...podScope
|
|
859
1022
|
}
|
|
@@ -1507,6 +1670,159 @@ const PendingPodContent = ({ pod }) => {
|
|
|
1507
1670
|
return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, "Pod is Pending. Conditions:"), /* @__PURE__ */ React__default.createElement(List, null, startupConditions.map((c) => /* @__PURE__ */ React__default.createElement(ListItem, { key: c.type }, /* @__PURE__ */ React__default.createElement(PodCondition, { condition: c }))))));
|
|
1508
1671
|
};
|
|
1509
1672
|
|
|
1673
|
+
const useEvents = ({
|
|
1674
|
+
involvedObjectName,
|
|
1675
|
+
namespace,
|
|
1676
|
+
clusterName
|
|
1677
|
+
}) => {
|
|
1678
|
+
const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
|
|
1679
|
+
return useAsync(async () => {
|
|
1680
|
+
return await kubernetesProxyApi.getEventsByInvolvedObjectName({
|
|
1681
|
+
involvedObjectName,
|
|
1682
|
+
namespace,
|
|
1683
|
+
clusterName
|
|
1684
|
+
});
|
|
1685
|
+
}, [involvedObjectName, namespace, clusterName]);
|
|
1686
|
+
};
|
|
1687
|
+
|
|
1688
|
+
const getAvatarByType = (type) => {
|
|
1689
|
+
return /* @__PURE__ */ React__default.createElement(ListItemAvatar, null, /* @__PURE__ */ React__default.createElement(Avatar, null, type === "Warning" ? /* @__PURE__ */ React__default.createElement(WarningIcon, null) : /* @__PURE__ */ React__default.createElement(InfoIcon, null)));
|
|
1690
|
+
};
|
|
1691
|
+
const EventsContent = ({
|
|
1692
|
+
events,
|
|
1693
|
+
warningEventsOnly
|
|
1694
|
+
}) => {
|
|
1695
|
+
if (events.length === 0) {
|
|
1696
|
+
return /* @__PURE__ */ React__default.createElement(Typography, null, "No events found");
|
|
1697
|
+
}
|
|
1698
|
+
return /* @__PURE__ */ React__default.createElement(Container, null, /* @__PURE__ */ React__default.createElement(Grid, null, /* @__PURE__ */ React__default.createElement(List, null, events.filter((event) => {
|
|
1699
|
+
if (warningEventsOnly) {
|
|
1700
|
+
return event.type === "Warning";
|
|
1701
|
+
}
|
|
1702
|
+
return true;
|
|
1703
|
+
}).map((event) => {
|
|
1704
|
+
var _a;
|
|
1705
|
+
const timeAgo = event.metadata.creationTimestamp ? DateTime.fromISO(event.metadata.creationTimestamp).toRelative(
|
|
1706
|
+
{
|
|
1707
|
+
locale: "en"
|
|
1708
|
+
}
|
|
1709
|
+
) : "unknown";
|
|
1710
|
+
return /* @__PURE__ */ React__default.createElement(ListItem, { key: event.metadata.name }, /* @__PURE__ */ React__default.createElement(Tooltip, { title: `${(_a = event.type) != null ? _a : ""} event` }, getAvatarByType(event.type)), /* @__PURE__ */ React__default.createElement(
|
|
1711
|
+
ListItemText,
|
|
1712
|
+
{
|
|
1713
|
+
primary: `First event ${timeAgo} (count: ${event.count})`,
|
|
1714
|
+
secondary: `${event.reason}: ${event.message}`
|
|
1715
|
+
}
|
|
1716
|
+
));
|
|
1717
|
+
}))));
|
|
1718
|
+
};
|
|
1719
|
+
const Events = ({
|
|
1720
|
+
involvedObjectName,
|
|
1721
|
+
namespace,
|
|
1722
|
+
clusterName,
|
|
1723
|
+
warningEventsOnly
|
|
1724
|
+
}) => {
|
|
1725
|
+
const { value, error, loading } = useEvents({
|
|
1726
|
+
involvedObjectName,
|
|
1727
|
+
namespace,
|
|
1728
|
+
clusterName
|
|
1729
|
+
});
|
|
1730
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, error && /* @__PURE__ */ React__default.createElement(
|
|
1731
|
+
DismissableBanner,
|
|
1732
|
+
{
|
|
1733
|
+
...{
|
|
1734
|
+
message: error.message,
|
|
1735
|
+
variant: "error",
|
|
1736
|
+
fixed: false
|
|
1737
|
+
},
|
|
1738
|
+
id: "events"
|
|
1739
|
+
}
|
|
1740
|
+
), loading && /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rect", width: "100%", height: "100%" }), !loading && value !== void 0 && /* @__PURE__ */ React__default.createElement(EventsContent, { warningEventsOnly, events: value }));
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
const useStyles$1 = makeStyles$1(
|
|
1744
|
+
(theme) => createStyles$1({
|
|
1745
|
+
closeButton: {
|
|
1746
|
+
position: "absolute",
|
|
1747
|
+
right: theme.spacing(1),
|
|
1748
|
+
top: theme.spacing(1),
|
|
1749
|
+
color: theme.palette.grey[500]
|
|
1750
|
+
}
|
|
1751
|
+
})
|
|
1752
|
+
);
|
|
1753
|
+
const FixDialog = ({
|
|
1754
|
+
open,
|
|
1755
|
+
pod,
|
|
1756
|
+
error,
|
|
1757
|
+
clusterName
|
|
1758
|
+
}) => {
|
|
1759
|
+
var _a;
|
|
1760
|
+
const [isOpen, setOpen] = useState(!!open);
|
|
1761
|
+
const classes = useStyles$1();
|
|
1762
|
+
const openDialog = () => {
|
|
1763
|
+
setOpen(true);
|
|
1764
|
+
};
|
|
1765
|
+
const closeDialog = () => {
|
|
1766
|
+
setOpen(false);
|
|
1767
|
+
};
|
|
1768
|
+
const pf = error.proposedFix;
|
|
1769
|
+
const dialogContent = () => {
|
|
1770
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
1771
|
+
return /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Detected error:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, error.message)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Cause explanation:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, (_b = (_a2 = error.proposedFix) == null ? void 0 : _a2.rootCauseExplanation) != null ? _b : "unknown")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Fix:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, /* @__PURE__ */ React__default.createElement("ul", null, ((_d = (_c = error.proposedFix) == null ? void 0 : _c.actions) != null ? _d : []).map((fix, i) => {
|
|
1772
|
+
var _a3, _b2;
|
|
1773
|
+
return /* @__PURE__ */ React__default.createElement("li", { key: `${(_b2 = (_a3 = pod.metadata) == null ? void 0 : _a3.name) != null ? _b2 : "unknown"}-pf-${i}` }, fix);
|
|
1774
|
+
})))), pf && pf.type === "logs" && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Crash logs:")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
|
|
1775
|
+
PodLogs,
|
|
1776
|
+
{
|
|
1777
|
+
previous: true,
|
|
1778
|
+
containerScope: {
|
|
1779
|
+
podName: (_f = (_e = pod.metadata) == null ? void 0 : _e.name) != null ? _f : "unknown",
|
|
1780
|
+
podNamespace: (_h = (_g = pod.metadata) == null ? void 0 : _g.namespace) != null ? _h : "unknown",
|
|
1781
|
+
clusterName,
|
|
1782
|
+
containerName: pf.container
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
))), pf && pf.type === "events" && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Events:")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
|
|
1786
|
+
Events,
|
|
1787
|
+
{
|
|
1788
|
+
warningEventsOnly: true,
|
|
1789
|
+
involvedObjectName: (_j = (_i = pod.metadata) == null ? void 0 : _i.name) != null ? _j : "",
|
|
1790
|
+
namespace: (_l = (_k = pod.metadata) == null ? void 0 : _k.namespace) != null ? _l : "",
|
|
1791
|
+
clusterName
|
|
1792
|
+
}
|
|
1793
|
+
))));
|
|
1794
|
+
};
|
|
1795
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
|
|
1796
|
+
Button,
|
|
1797
|
+
{
|
|
1798
|
+
variant: "outlined",
|
|
1799
|
+
"aria-label": "fix issue",
|
|
1800
|
+
component: "label",
|
|
1801
|
+
onClick: openDialog,
|
|
1802
|
+
startIcon: /* @__PURE__ */ React__default.createElement(HelpIcon, null)
|
|
1803
|
+
},
|
|
1804
|
+
"Help"
|
|
1805
|
+
), /* @__PURE__ */ React__default.createElement(Dialog$1, { maxWidth: "xl", fullWidth: true, open: isOpen, onClose: closeDialog }, /* @__PURE__ */ React__default.createElement(DialogTitle$1, { id: "dialog-title" }, (_a = pod.metadata) == null ? void 0 : _a.name, " - ", error.type, /* @__PURE__ */ React__default.createElement(
|
|
1806
|
+
IconButton$1,
|
|
1807
|
+
{
|
|
1808
|
+
"aria-label": "close",
|
|
1809
|
+
className: classes.closeButton,
|
|
1810
|
+
onClick: closeDialog
|
|
1811
|
+
},
|
|
1812
|
+
/* @__PURE__ */ React__default.createElement(CloseIcon, null)
|
|
1813
|
+
)), /* @__PURE__ */ React__default.createElement(DialogContent$1, null, dialogContent()), /* @__PURE__ */ React__default.createElement(DialogActions, null, pf && pf.type === "docs" && /* @__PURE__ */ React__default.createElement(
|
|
1814
|
+
LinkButton,
|
|
1815
|
+
{
|
|
1816
|
+
to: pf.docsLink,
|
|
1817
|
+
variant: "outlined",
|
|
1818
|
+
startIcon: /* @__PURE__ */ React__default.createElement(OpenInNewIcon, null),
|
|
1819
|
+
target: "_blank",
|
|
1820
|
+
rel: "noopener"
|
|
1821
|
+
},
|
|
1822
|
+
"Open docs"
|
|
1823
|
+
))));
|
|
1824
|
+
};
|
|
1825
|
+
|
|
1510
1826
|
const useStyles = makeStyles(
|
|
1511
1827
|
(_theme) => createStyles({
|
|
1512
1828
|
root: {
|
|
@@ -1528,13 +1844,20 @@ const ErrorList = ({ podAndErrors }) => {
|
|
|
1528
1844
|
key: `${(_b = (_a = onlyPodWithErrors.pod.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown"}-eli-${i}`
|
|
1529
1845
|
},
|
|
1530
1846
|
i > 0 && /* @__PURE__ */ React__default.createElement(Divider, { key: `error-divider${i}` }),
|
|
1531
|
-
/* @__PURE__ */ React__default.createElement(ListItem, null, /* @__PURE__ */ React__default.createElement(
|
|
1847
|
+
/* @__PURE__ */ React__default.createElement(ListItem, null, /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
|
|
1532
1848
|
ListItemText,
|
|
1533
1849
|
{
|
|
1534
1850
|
primary: error.message,
|
|
1535
1851
|
secondary: (_c = onlyPodWithErrors.pod.metadata) == null ? void 0 : _c.name
|
|
1536
1852
|
}
|
|
1537
|
-
))
|
|
1853
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React__default.createElement(
|
|
1854
|
+
FixDialog,
|
|
1855
|
+
{
|
|
1856
|
+
pod: onlyPodWithErrors.pod,
|
|
1857
|
+
error,
|
|
1858
|
+
clusterName: onlyPodWithErrors.clusterName
|
|
1859
|
+
}
|
|
1860
|
+
))))
|
|
1538
1861
|
);
|
|
1539
1862
|
});
|
|
1540
1863
|
})));
|
|
@@ -3050,5 +3373,5 @@ var Router$1 = /*#__PURE__*/Object.freeze({
|
|
|
3050
3373
|
Router: Router
|
|
3051
3374
|
});
|
|
3052
3375
|
|
|
3053
|
-
export { Cluster, ClusterContext, CronJobsAccordions, CustomResources, EntityKubernetesContent, ErrorPanel, ErrorReporting, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PodDrawer, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useKubernetesObjects };
|
|
3376
|
+
export { Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, EntityKubernetesContent, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PodDrawer, PodLogs, PodLogsDialog, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, usePodLogs };
|
|
3054
3377
|
//# sourceMappingURL=index.esm.js.map
|