@backstage/plugin-kubernetes 0.10.3-next.1 → 0.10.3-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/index.d.ts +26 -1
- package/dist/index.esm.js +380 -204
- package/dist/index.esm.js.map +1 -1
- package/package.json +19 -14
package/dist/index.esm.js
CHANGED
|
@@ -2,22 +2,27 @@ import { stringifyEntityRef } from '@backstage/catalog-model';
|
|
|
2
2
|
import { NotFoundError } from '@backstage/errors';
|
|
3
3
|
import { createApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, gitlabAuthApiRef, googleAuthApiRef, microsoftAuthApiRef, oktaAuthApiRef, oneloginAuthApiRef, createRoutableExtension, useApi } from '@backstage/core-plugin-api';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import React__default, { useState,
|
|
5
|
+
import React__default, { useCallback, useContext, useState, useEffect, useMemo, Fragment } from 'react';
|
|
6
6
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
7
7
|
import { Routes, Route } from 'react-router-dom';
|
|
8
|
-
import { Typography,
|
|
9
|
-
import { WarningPanel, Table, DismissableBanner, EmptyState, LogViewer,
|
|
8
|
+
import { Typography, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Grid, Paper, Card, CardHeader, CardContent, 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, LinearGauge, 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';
|
|
13
|
-
import
|
|
13
|
+
import CloseIcon from '@material-ui/icons/Close';
|
|
14
|
+
import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
|
|
14
15
|
import useAsync from 'react-use/lib/useAsync';
|
|
16
|
+
import useInterval from 'react-use/lib/useInterval';
|
|
17
|
+
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
|
18
|
+
import 'xterm/css/xterm.css';
|
|
19
|
+
import { Terminal } from 'xterm';
|
|
20
|
+
import { FitAddon } from 'xterm-addon-fit';
|
|
21
|
+
import { AttachAddon } from 'xterm-addon-attach';
|
|
22
|
+
import { Skeleton } from '@material-ui/lab';
|
|
15
23
|
import SubjectIcon from '@material-ui/icons/Subject';
|
|
16
|
-
import CloseIcon from '@material-ui/icons/Close';
|
|
17
24
|
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
|
|
18
25
|
import { withStyles, makeStyles as makeStyles$1, createStyles as createStyles$1 } from '@material-ui/core/styles';
|
|
19
|
-
import useInterval from 'react-use/lib/useInterval';
|
|
20
|
-
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
|
21
26
|
import jsyaml from 'js-yaml';
|
|
22
27
|
import Dialog$1 from '@material-ui/core/Dialog';
|
|
23
28
|
import DialogActions from '@material-ui/core/DialogActions';
|
|
@@ -892,6 +897,364 @@ const detectErrors = (objects) => {
|
|
|
892
897
|
return errors;
|
|
893
898
|
};
|
|
894
899
|
|
|
900
|
+
const currentToDeclaredResourceToPerc$1 = (current, resource) => {
|
|
901
|
+
if (Number(resource) === 0)
|
|
902
|
+
return 0;
|
|
903
|
+
if (typeof current === "number" && typeof resource === "number") {
|
|
904
|
+
return Math.round(current / resource * 100);
|
|
905
|
+
}
|
|
906
|
+
const numerator = BigInt(current);
|
|
907
|
+
const denominator = BigInt(resource);
|
|
908
|
+
return Number(numerator * BigInt(100) / denominator);
|
|
909
|
+
};
|
|
910
|
+
const bytesToMiB = (value) => {
|
|
911
|
+
return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
|
|
912
|
+
};
|
|
913
|
+
const formatMillicores = (value) => {
|
|
914
|
+
return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
const useIsPodExecTerminalSupported = () => {
|
|
918
|
+
const kubernetesApi = useApi(kubernetesApiRef);
|
|
919
|
+
return useAsync(async () => {
|
|
920
|
+
const clusters = await kubernetesApi.getClusters();
|
|
921
|
+
if (clusters.length !== 1) {
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
924
|
+
const { authProvider } = clusters[0];
|
|
925
|
+
const isClientAuthProvider = ["aks", "google", "oidc"].some(
|
|
926
|
+
(authProviderName) => authProvider.includes(authProviderName)
|
|
927
|
+
);
|
|
928
|
+
return !isClientAuthProvider;
|
|
929
|
+
});
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
|
|
933
|
+
var _a;
|
|
934
|
+
const clusters = await kubernetesApi.getClusters();
|
|
935
|
+
const authProviders = [
|
|
936
|
+
...new Set(
|
|
937
|
+
clusters.map(
|
|
938
|
+
(c) => `${c.authProvider}${c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ""}`
|
|
939
|
+
)
|
|
940
|
+
)
|
|
941
|
+
];
|
|
942
|
+
let requestBody = {
|
|
943
|
+
entity
|
|
944
|
+
};
|
|
945
|
+
for (const authProviderStr of authProviders) {
|
|
946
|
+
requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(
|
|
947
|
+
authProviderStr,
|
|
948
|
+
requestBody
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
return (_a = requestBody.auth) != null ? _a : {};
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
const useKubernetesObjects = (entity, intervalMs = 1e4) => {
|
|
955
|
+
const kubernetesApi = useApi(kubernetesApiRef);
|
|
956
|
+
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
|
|
957
|
+
const getObjects = useCallback(async () => {
|
|
958
|
+
const auth = await generateAuth(
|
|
959
|
+
entity,
|
|
960
|
+
kubernetesApi,
|
|
961
|
+
kubernetesAuthProvidersApi
|
|
962
|
+
);
|
|
963
|
+
return await kubernetesApi.getObjectsByEntity({
|
|
964
|
+
auth,
|
|
965
|
+
entity
|
|
966
|
+
});
|
|
967
|
+
}, [kubernetesApi, entity, kubernetesAuthProvidersApi]);
|
|
968
|
+
const { value, loading, error, retry } = useAsyncRetry(
|
|
969
|
+
() => getObjects(),
|
|
970
|
+
[getObjects]
|
|
971
|
+
);
|
|
972
|
+
useInterval(() => retry(), intervalMs);
|
|
973
|
+
return {
|
|
974
|
+
kubernetesObjects: value,
|
|
975
|
+
loading,
|
|
976
|
+
error: error == null ? void 0 : error.message
|
|
977
|
+
};
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
const useCustomResources = (entity, customResourceMatchers, intervalMs = 1e4) => {
|
|
981
|
+
const kubernetesApi = useApi(kubernetesApiRef);
|
|
982
|
+
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
|
|
983
|
+
const matchersString = JSON.stringify(customResourceMatchers);
|
|
984
|
+
const getCustomObjects = useCallback(
|
|
985
|
+
async () => {
|
|
986
|
+
const auth = await generateAuth(
|
|
987
|
+
entity,
|
|
988
|
+
kubernetesApi,
|
|
989
|
+
kubernetesAuthProvidersApi
|
|
990
|
+
);
|
|
991
|
+
return await kubernetesApi.getCustomObjectsByEntity({
|
|
992
|
+
auth,
|
|
993
|
+
customResources: customResourceMatchers,
|
|
994
|
+
entity
|
|
995
|
+
});
|
|
996
|
+
},
|
|
997
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
998
|
+
[kubernetesApi, entity, kubernetesAuthProvidersApi, matchersString]
|
|
999
|
+
);
|
|
1000
|
+
const { value, loading, error, retry } = useAsyncRetry(
|
|
1001
|
+
() => getCustomObjects(),
|
|
1002
|
+
[getCustomObjects]
|
|
1003
|
+
);
|
|
1004
|
+
useInterval(() => retry(), intervalMs);
|
|
1005
|
+
return {
|
|
1006
|
+
kubernetesObjects: value,
|
|
1007
|
+
loading,
|
|
1008
|
+
error: error == null ? void 0 : error.message
|
|
1009
|
+
};
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
const PodNamesWithErrorsContext = React__default.createContext(
|
|
1013
|
+
/* @__PURE__ */ new Set()
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
|
|
1017
|
+
|
|
1018
|
+
const GroupedResponsesContext = React__default.createContext({
|
|
1019
|
+
pods: [],
|
|
1020
|
+
replicaSets: [],
|
|
1021
|
+
deployments: [],
|
|
1022
|
+
services: [],
|
|
1023
|
+
configMaps: [],
|
|
1024
|
+
horizontalPodAutoscalers: [],
|
|
1025
|
+
ingresses: [],
|
|
1026
|
+
jobs: [],
|
|
1027
|
+
cronJobs: [],
|
|
1028
|
+
customResources: [],
|
|
1029
|
+
statefulsets: []
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
const ClusterContext = React__default.createContext({
|
|
1033
|
+
name: ""
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
|
|
1037
|
+
const usePodMetrics = (clusterName, matcher) => {
|
|
1038
|
+
var _a, _b, _c, _d;
|
|
1039
|
+
const targetRef = {
|
|
1040
|
+
name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
|
|
1041
|
+
namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
|
|
1042
|
+
};
|
|
1043
|
+
const metricsMap = useContext(PodMetricsContext);
|
|
1044
|
+
const metrics = metricsMap.get(clusterName);
|
|
1045
|
+
return metrics == null ? void 0 : metrics.find((m) => {
|
|
1046
|
+
var _a2, _b2, _c2, _d2;
|
|
1047
|
+
const pod = m.pod;
|
|
1048
|
+
return targetRef.name === ((_b2 = (_a2 = pod.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "") && targetRef.namespace === ((_d2 = (_c2 = pod.metadata) == null ? void 0 : _c2.namespace) != null ? _d2 : "");
|
|
1049
|
+
});
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
const DetectedErrorsContext = React__default.createContext([]);
|
|
1053
|
+
const useMatchingErrors = (matcher) => {
|
|
1054
|
+
var _a, _b, _c, _d;
|
|
1055
|
+
const targetRef = {
|
|
1056
|
+
name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
|
|
1057
|
+
namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
|
|
1058
|
+
kind: matcher.kind,
|
|
1059
|
+
apiGroup: matcher.apiVersion
|
|
1060
|
+
};
|
|
1061
|
+
const errors = useContext(DetectedErrorsContext);
|
|
1062
|
+
return errors.filter((e) => {
|
|
1063
|
+
const r = e.sourceRef;
|
|
1064
|
+
return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
|
|
1065
|
+
});
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
const textEncoder = new TextEncoder();
|
|
1069
|
+
class PodExecTerminalAttachAddon extends AttachAddon {
|
|
1070
|
+
constructor(socket, options) {
|
|
1071
|
+
super(socket, options);
|
|
1072
|
+
const thisAddon = this;
|
|
1073
|
+
thisAddon._sendBinary = (data) => {
|
|
1074
|
+
if (!thisAddon._checkOpenSocket()) {
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
const buffer = Uint8Array.from([0, ...textEncoder.encode(data)]);
|
|
1078
|
+
thisAddon._socket.send(buffer);
|
|
1079
|
+
};
|
|
1080
|
+
thisAddon._sendData = (data) => {
|
|
1081
|
+
if (!thisAddon._checkOpenSocket()) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
thisAddon._sendBinary(data);
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
const hasSocketProtocol = (url) => /wss?:\/\//.test(url.toString());
|
|
1090
|
+
const PodExecTerminal = (props) => {
|
|
1091
|
+
const { containerName, podNamespace, podName } = props;
|
|
1092
|
+
const [baseUrl, setBaseUrl] = useState(window.location.host);
|
|
1093
|
+
const terminalRef = React__default.useRef(null);
|
|
1094
|
+
const discoveryApi = useApi(discoveryApiRef);
|
|
1095
|
+
const namespace = podNamespace != null ? podNamespace : "default";
|
|
1096
|
+
useEffect(() => {
|
|
1097
|
+
discoveryApi.getBaseUrl("kubernetes").then((url) => url != null ? url : window.location.host).then((url) => url.replace(/^http(s?):\/\//, "ws$1://")).then((url) => setBaseUrl(url));
|
|
1098
|
+
}, [discoveryApi]);
|
|
1099
|
+
const urlParams = useMemo(() => {
|
|
1100
|
+
const params = new URLSearchParams({
|
|
1101
|
+
container: containerName,
|
|
1102
|
+
stdin: "true",
|
|
1103
|
+
stdout: "true",
|
|
1104
|
+
stderr: "true",
|
|
1105
|
+
tty: "true",
|
|
1106
|
+
command: "/bin/sh"
|
|
1107
|
+
});
|
|
1108
|
+
return params;
|
|
1109
|
+
}, [containerName]);
|
|
1110
|
+
const socketUrl = useMemo(() => {
|
|
1111
|
+
if (!hasSocketProtocol(baseUrl)) {
|
|
1112
|
+
return "";
|
|
1113
|
+
}
|
|
1114
|
+
return new URL(
|
|
1115
|
+
`${baseUrl}/proxy/api/v1/namespaces/${namespace}/pods/${podName}/exec?${urlParams}`
|
|
1116
|
+
);
|
|
1117
|
+
}, [baseUrl, namespace, podName, urlParams]);
|
|
1118
|
+
useEffect(() => {
|
|
1119
|
+
if (!hasSocketProtocol(socketUrl)) {
|
|
1120
|
+
return () => {
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
const terminal = new Terminal();
|
|
1124
|
+
const fitAddon = new FitAddon();
|
|
1125
|
+
terminal.loadAddon(fitAddon);
|
|
1126
|
+
if (terminalRef.current) {
|
|
1127
|
+
terminal.open(terminalRef.current);
|
|
1128
|
+
fitAddon.fit();
|
|
1129
|
+
}
|
|
1130
|
+
terminal.writeln("Starting terminal, please wait...");
|
|
1131
|
+
const socket = new WebSocket(socketUrl, ["channel.k8s.io"]);
|
|
1132
|
+
socket.onopen = () => {
|
|
1133
|
+
terminal.clear();
|
|
1134
|
+
const attachAddon = new PodExecTerminalAttachAddon(socket, {
|
|
1135
|
+
bidirectional: true
|
|
1136
|
+
});
|
|
1137
|
+
terminal.loadAddon(attachAddon);
|
|
1138
|
+
};
|
|
1139
|
+
socket.onclose = () => {
|
|
1140
|
+
terminal.writeln("Socket connection closed");
|
|
1141
|
+
};
|
|
1142
|
+
return () => {
|
|
1143
|
+
terminal == null ? void 0 : terminal.clear();
|
|
1144
|
+
socket == null ? void 0 : socket.close();
|
|
1145
|
+
};
|
|
1146
|
+
}, [baseUrl, socketUrl]);
|
|
1147
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
1148
|
+
"div",
|
|
1149
|
+
{
|
|
1150
|
+
"data-testid": "terminal",
|
|
1151
|
+
ref: terminalRef,
|
|
1152
|
+
style: {
|
|
1153
|
+
width: "100%",
|
|
1154
|
+
height: "100%"
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
);
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
const useStyles$3 = makeStyles(
|
|
1161
|
+
(theme) => createStyles({
|
|
1162
|
+
dialogPaper: { minHeight: "calc(100% - 64px)" },
|
|
1163
|
+
dialogContent: { flexBasis: 0 },
|
|
1164
|
+
closeButton: {
|
|
1165
|
+
position: "absolute",
|
|
1166
|
+
right: theme.spacing(1),
|
|
1167
|
+
top: theme.spacing(1),
|
|
1168
|
+
color: theme.palette.grey[500]
|
|
1169
|
+
}
|
|
1170
|
+
})
|
|
1171
|
+
);
|
|
1172
|
+
const PodExecTerminalDialog = (props) => {
|
|
1173
|
+
const classes = useStyles$3();
|
|
1174
|
+
const { clusterName, containerName, podName } = props;
|
|
1175
|
+
const [open, setOpen] = useState(false);
|
|
1176
|
+
const isPodExecTerminalSupported = useIsPodExecTerminalSupported();
|
|
1177
|
+
const openDialog = () => {
|
|
1178
|
+
setOpen(true);
|
|
1179
|
+
};
|
|
1180
|
+
const closeDialog = () => {
|
|
1181
|
+
setOpen(false);
|
|
1182
|
+
};
|
|
1183
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, !isPodExecTerminalSupported.loading && isPodExecTerminalSupported.value && /* @__PURE__ */ React__default.createElement(
|
|
1184
|
+
Dialog,
|
|
1185
|
+
{
|
|
1186
|
+
maxWidth: false,
|
|
1187
|
+
fullWidth: true,
|
|
1188
|
+
open,
|
|
1189
|
+
onClose: closeDialog,
|
|
1190
|
+
PaperProps: { className: classes.dialogPaper }
|
|
1191
|
+
},
|
|
1192
|
+
/* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" }, podName, " - ", containerName, " terminal shell on cluster", " ", clusterName, /* @__PURE__ */ React__default.createElement(
|
|
1193
|
+
IconButton,
|
|
1194
|
+
{
|
|
1195
|
+
"aria-label": "close",
|
|
1196
|
+
className: classes.closeButton,
|
|
1197
|
+
onClick: closeDialog
|
|
1198
|
+
},
|
|
1199
|
+
/* @__PURE__ */ React__default.createElement(CloseIcon, null)
|
|
1200
|
+
)),
|
|
1201
|
+
/* @__PURE__ */ React__default.createElement(DialogContent, { className: classes.dialogContent }, /* @__PURE__ */ React__default.createElement(PodExecTerminal, { ...props }))
|
|
1202
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
1203
|
+
Button,
|
|
1204
|
+
{
|
|
1205
|
+
variant: "outlined",
|
|
1206
|
+
"aria-label": "open terminal",
|
|
1207
|
+
component: "label",
|
|
1208
|
+
disabled: isPodExecTerminalSupported.loading || !isPodExecTerminalSupported.value,
|
|
1209
|
+
onClick: openDialog,
|
|
1210
|
+
startIcon: /* @__PURE__ */ React__default.createElement(OpenInBrowserIcon, null)
|
|
1211
|
+
},
|
|
1212
|
+
"Terminal"
|
|
1213
|
+
));
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
const getProgressColor = ({
|
|
1217
|
+
palette,
|
|
1218
|
+
value,
|
|
1219
|
+
inverse,
|
|
1220
|
+
max
|
|
1221
|
+
}) => {
|
|
1222
|
+
if (isNaN(value)) {
|
|
1223
|
+
return palette.status.pending;
|
|
1224
|
+
}
|
|
1225
|
+
const actualMax = max ? max : 100;
|
|
1226
|
+
const actualValue = inverse ? actualMax - value : value;
|
|
1227
|
+
if (actualValue >= actualMax) {
|
|
1228
|
+
return palette.status.error;
|
|
1229
|
+
} else if (actualValue > 90 || actualValue < 40) {
|
|
1230
|
+
return palette.status.warning;
|
|
1231
|
+
}
|
|
1232
|
+
return palette.status.ok;
|
|
1233
|
+
};
|
|
1234
|
+
const ResourceUtilization = ({
|
|
1235
|
+
compressed = false,
|
|
1236
|
+
title,
|
|
1237
|
+
usage,
|
|
1238
|
+
total,
|
|
1239
|
+
totalFormatted
|
|
1240
|
+
}) => {
|
|
1241
|
+
const utilization = currentToDeclaredResourceToPerc$1(usage, total);
|
|
1242
|
+
return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
1243
|
+
Typography,
|
|
1244
|
+
{
|
|
1245
|
+
variant: compressed ? "caption" : "subtitle2"
|
|
1246
|
+
},
|
|
1247
|
+
`${title}: ${totalFormatted}`
|
|
1248
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
1249
|
+
LinearGauge,
|
|
1250
|
+
{
|
|
1251
|
+
getColor: getProgressColor,
|
|
1252
|
+
width: compressed ? "thin" : "thick",
|
|
1253
|
+
value: utilization / 100
|
|
1254
|
+
}
|
|
1255
|
+
), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
|
|
1256
|
+
};
|
|
1257
|
+
|
|
895
1258
|
const usePodLogs = ({ containerScope, previous }) => {
|
|
896
1259
|
const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
|
|
897
1260
|
return useAsync(async () => {
|
|
@@ -981,65 +1344,6 @@ const PodLogsDialog = ({ containerScope }) => {
|
|
|
981
1344
|
));
|
|
982
1345
|
};
|
|
983
1346
|
|
|
984
|
-
const currentToDeclaredResourceToPerc$1 = (current, resource) => {
|
|
985
|
-
if (Number(resource) === 0)
|
|
986
|
-
return 0;
|
|
987
|
-
if (typeof current === "number" && typeof resource === "number") {
|
|
988
|
-
return Math.round(current / resource * 100);
|
|
989
|
-
}
|
|
990
|
-
const numerator = BigInt(current);
|
|
991
|
-
const denominator = BigInt(resource);
|
|
992
|
-
return Number(numerator * BigInt(100) / denominator);
|
|
993
|
-
};
|
|
994
|
-
const bytesToMiB = (value) => {
|
|
995
|
-
return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
|
|
996
|
-
};
|
|
997
|
-
const formatMillicores = (value) => {
|
|
998
|
-
return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
|
|
999
|
-
};
|
|
1000
|
-
|
|
1001
|
-
const getProgressColor = ({
|
|
1002
|
-
palette,
|
|
1003
|
-
value,
|
|
1004
|
-
inverse,
|
|
1005
|
-
max
|
|
1006
|
-
}) => {
|
|
1007
|
-
if (isNaN(value)) {
|
|
1008
|
-
return palette.status.pending;
|
|
1009
|
-
}
|
|
1010
|
-
const actualMax = max ? max : 100;
|
|
1011
|
-
const actualValue = inverse ? actualMax - value : value;
|
|
1012
|
-
if (actualValue >= actualMax) {
|
|
1013
|
-
return palette.status.error;
|
|
1014
|
-
} else if (actualValue > 90 || actualValue < 40) {
|
|
1015
|
-
return palette.status.warning;
|
|
1016
|
-
}
|
|
1017
|
-
return palette.status.ok;
|
|
1018
|
-
};
|
|
1019
|
-
const ResourceUtilization = ({
|
|
1020
|
-
compressed = false,
|
|
1021
|
-
title,
|
|
1022
|
-
usage,
|
|
1023
|
-
total,
|
|
1024
|
-
totalFormatted
|
|
1025
|
-
}) => {
|
|
1026
|
-
const utilization = currentToDeclaredResourceToPerc$1(usage, total);
|
|
1027
|
-
return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
1028
|
-
Typography,
|
|
1029
|
-
{
|
|
1030
|
-
variant: compressed ? "caption" : "subtitle2"
|
|
1031
|
-
},
|
|
1032
|
-
`${title}: ${totalFormatted}`
|
|
1033
|
-
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
1034
|
-
LinearGauge,
|
|
1035
|
-
{
|
|
1036
|
-
getColor: getProgressColor,
|
|
1037
|
-
width: compressed ? "thin" : "thick",
|
|
1038
|
-
value: utilization / 100
|
|
1039
|
-
}
|
|
1040
|
-
), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
|
|
1041
|
-
};
|
|
1042
|
-
|
|
1043
1347
|
const getContainerHealthChecks = (containerSpec, containerStatus) => {
|
|
1044
1348
|
var _a, _b, _c, _d;
|
|
1045
1349
|
if (((_b = (_a = containerStatus.state) == null ? void 0 : _a.terminated) == null ? void 0 : _b.reason) === "Completed") {
|
|
@@ -1155,7 +1459,7 @@ const ContainerCard = ({
|
|
|
1155
1459
|
containerMetrics.memoryUsage.limitTotal
|
|
1156
1460
|
)
|
|
1157
1461
|
}
|
|
1158
|
-
))))), /* @__PURE__ */ React__default.createElement(CardActions,
|
|
1462
|
+
))))), /* @__PURE__ */ React__default.createElement(CardActions, null, /* @__PURE__ */ React__default.createElement(
|
|
1159
1463
|
PodLogsDialog,
|
|
1160
1464
|
{
|
|
1161
1465
|
containerScope: {
|
|
@@ -1163,145 +1467,17 @@ const ContainerCard = ({
|
|
|
1163
1467
|
...podScope
|
|
1164
1468
|
}
|
|
1165
1469
|
}
|
|
1470
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
1471
|
+
PodExecTerminalDialog,
|
|
1472
|
+
{
|
|
1473
|
+
clusterName: podScope.clusterName,
|
|
1474
|
+
containerName: containerStatus.name,
|
|
1475
|
+
podName: podScope.podName,
|
|
1476
|
+
podNamespace: podScope.podNamespace
|
|
1477
|
+
}
|
|
1166
1478
|
)));
|
|
1167
1479
|
};
|
|
1168
1480
|
|
|
1169
|
-
const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
|
|
1170
|
-
var _a;
|
|
1171
|
-
const clusters = await kubernetesApi.getClusters();
|
|
1172
|
-
const authProviders = [
|
|
1173
|
-
...new Set(
|
|
1174
|
-
clusters.map(
|
|
1175
|
-
(c) => `${c.authProvider}${c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ""}`
|
|
1176
|
-
)
|
|
1177
|
-
)
|
|
1178
|
-
];
|
|
1179
|
-
let requestBody = {
|
|
1180
|
-
entity
|
|
1181
|
-
};
|
|
1182
|
-
for (const authProviderStr of authProviders) {
|
|
1183
|
-
requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(
|
|
1184
|
-
authProviderStr,
|
|
1185
|
-
requestBody
|
|
1186
|
-
);
|
|
1187
|
-
}
|
|
1188
|
-
return (_a = requestBody.auth) != null ? _a : {};
|
|
1189
|
-
};
|
|
1190
|
-
|
|
1191
|
-
const useKubernetesObjects = (entity, intervalMs = 1e4) => {
|
|
1192
|
-
const kubernetesApi = useApi(kubernetesApiRef);
|
|
1193
|
-
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
|
|
1194
|
-
const getObjects = useCallback(async () => {
|
|
1195
|
-
const auth = await generateAuth(
|
|
1196
|
-
entity,
|
|
1197
|
-
kubernetesApi,
|
|
1198
|
-
kubernetesAuthProvidersApi
|
|
1199
|
-
);
|
|
1200
|
-
return await kubernetesApi.getObjectsByEntity({
|
|
1201
|
-
auth,
|
|
1202
|
-
entity
|
|
1203
|
-
});
|
|
1204
|
-
}, [kubernetesApi, entity, kubernetesAuthProvidersApi]);
|
|
1205
|
-
const { value, loading, error, retry } = useAsyncRetry(
|
|
1206
|
-
() => getObjects(),
|
|
1207
|
-
[getObjects]
|
|
1208
|
-
);
|
|
1209
|
-
useInterval(() => retry(), intervalMs);
|
|
1210
|
-
return {
|
|
1211
|
-
kubernetesObjects: value,
|
|
1212
|
-
loading,
|
|
1213
|
-
error: error == null ? void 0 : error.message
|
|
1214
|
-
};
|
|
1215
|
-
};
|
|
1216
|
-
|
|
1217
|
-
const useCustomResources = (entity, customResourceMatchers, intervalMs = 1e4) => {
|
|
1218
|
-
const kubernetesApi = useApi(kubernetesApiRef);
|
|
1219
|
-
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
|
|
1220
|
-
const matchersString = JSON.stringify(customResourceMatchers);
|
|
1221
|
-
const getCustomObjects = useCallback(
|
|
1222
|
-
async () => {
|
|
1223
|
-
const auth = await generateAuth(
|
|
1224
|
-
entity,
|
|
1225
|
-
kubernetesApi,
|
|
1226
|
-
kubernetesAuthProvidersApi
|
|
1227
|
-
);
|
|
1228
|
-
return await kubernetesApi.getCustomObjectsByEntity({
|
|
1229
|
-
auth,
|
|
1230
|
-
customResources: customResourceMatchers,
|
|
1231
|
-
entity
|
|
1232
|
-
});
|
|
1233
|
-
},
|
|
1234
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1235
|
-
[kubernetesApi, entity, kubernetesAuthProvidersApi, matchersString]
|
|
1236
|
-
);
|
|
1237
|
-
const { value, loading, error, retry } = useAsyncRetry(
|
|
1238
|
-
() => getCustomObjects(),
|
|
1239
|
-
[getCustomObjects]
|
|
1240
|
-
);
|
|
1241
|
-
useInterval(() => retry(), intervalMs);
|
|
1242
|
-
return {
|
|
1243
|
-
kubernetesObjects: value,
|
|
1244
|
-
loading,
|
|
1245
|
-
error: error == null ? void 0 : error.message
|
|
1246
|
-
};
|
|
1247
|
-
};
|
|
1248
|
-
|
|
1249
|
-
const PodNamesWithErrorsContext = React__default.createContext(
|
|
1250
|
-
/* @__PURE__ */ new Set()
|
|
1251
|
-
);
|
|
1252
|
-
|
|
1253
|
-
const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
|
|
1254
|
-
|
|
1255
|
-
const GroupedResponsesContext = React__default.createContext({
|
|
1256
|
-
pods: [],
|
|
1257
|
-
replicaSets: [],
|
|
1258
|
-
deployments: [],
|
|
1259
|
-
services: [],
|
|
1260
|
-
configMaps: [],
|
|
1261
|
-
horizontalPodAutoscalers: [],
|
|
1262
|
-
ingresses: [],
|
|
1263
|
-
jobs: [],
|
|
1264
|
-
cronJobs: [],
|
|
1265
|
-
customResources: [],
|
|
1266
|
-
statefulsets: []
|
|
1267
|
-
});
|
|
1268
|
-
|
|
1269
|
-
const ClusterContext = React__default.createContext({
|
|
1270
|
-
name: ""
|
|
1271
|
-
});
|
|
1272
|
-
|
|
1273
|
-
const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
|
|
1274
|
-
const usePodMetrics = (clusterName, matcher) => {
|
|
1275
|
-
var _a, _b, _c, _d;
|
|
1276
|
-
const targetRef = {
|
|
1277
|
-
name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
|
|
1278
|
-
namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
|
|
1279
|
-
};
|
|
1280
|
-
const metricsMap = useContext(PodMetricsContext);
|
|
1281
|
-
const metrics = metricsMap.get(clusterName);
|
|
1282
|
-
return metrics == null ? void 0 : metrics.find((m) => {
|
|
1283
|
-
var _a2, _b2, _c2, _d2;
|
|
1284
|
-
const pod = m.pod;
|
|
1285
|
-
return targetRef.name === ((_b2 = (_a2 = pod.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "") && targetRef.namespace === ((_d2 = (_c2 = pod.metadata) == null ? void 0 : _c2.namespace) != null ? _d2 : "");
|
|
1286
|
-
});
|
|
1287
|
-
};
|
|
1288
|
-
|
|
1289
|
-
const DetectedErrorsContext = React__default.createContext([]);
|
|
1290
|
-
const useMatchingErrors = (matcher) => {
|
|
1291
|
-
var _a, _b, _c, _d;
|
|
1292
|
-
const targetRef = {
|
|
1293
|
-
name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
|
|
1294
|
-
namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
|
|
1295
|
-
kind: matcher.kind,
|
|
1296
|
-
apiGroup: matcher.apiVersion
|
|
1297
|
-
};
|
|
1298
|
-
const errors = useContext(DetectedErrorsContext);
|
|
1299
|
-
return errors.filter((e) => {
|
|
1300
|
-
const r = e.sourceRef;
|
|
1301
|
-
return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
|
|
1302
|
-
});
|
|
1303
|
-
};
|
|
1304
|
-
|
|
1305
1481
|
const kindMappings$3 = {
|
|
1306
1482
|
deployment: "deployment",
|
|
1307
1483
|
pod: "pod",
|
|
@@ -3558,5 +3734,5 @@ var Router$1 = /*#__PURE__*/Object.freeze({
|
|
|
3558
3734
|
Router: Router
|
|
3559
3735
|
});
|
|
3560
3736
|
|
|
3561
|
-
export { Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, DetectedErrorsContext, EntityKubernetesContent, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PodDrawer, PodLogs, PodLogsDialog, PodMetricsContext, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, ResourceUtilization, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
|
|
3737
|
+
export { Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, DetectedErrorsContext, EntityKubernetesContent, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PodDrawer, PodExecTerminal, PodExecTerminalDialog, PodLogs, PodLogsDialog, PodMetricsContext, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, ResourceUtilization, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useIsPodExecTerminalSupported, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
|
|
3562
3738
|
//# sourceMappingURL=index.esm.js.map
|