@kui-shell/plugin-kubectl
Version:
Kubernetes visualization plugin for kubernetes
328 lines (327 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ready = exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _core = require("@kui-shell/core");
var _Select = _interopRequireDefault(require("@kui-shell/plugin-client-common/mdist/components/spi/Select"));
var _TextWithIconWidget = _interopRequireDefault(require("@kui-shell/plugin-client-common/mdist/components/Client/StatusStripe/TextWithIconWidget"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
* Copyright 2020 The Kubernetes Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const strings = (0, _core.i18n)('plugin-kubectl');
function KubernetesIcon() {
return _react.default.createElement("svg", {
xmlns: "http://www.w3.org/2000/svg",
role: "img",
width: "16",
height: "16",
viewBox: "9.70 9.20 210.86 204.86"
}, _react.default.createElement("path", {
d: "M134.358 126.46551a3.59023 3.59023 0 00-.855-.065 3.68515 3.68515 0 00-1.425.37 3.725 3.725 0 00-1.803 4.825l-.026.037 8.528 20.603a43.53012 43.53012 0 0017.595-22.102l-21.976-3.714zm-34.194 2.92a3.72 3.72 0 00-3.568-2.894 3.6556 3.6556 0 00-.733.065l-.037-.045-21.785 3.698a43.69506 43.69506 0 0017.54 21.946l8.442-20.399-.066-.08a3.68318 3.68318 0 00.207-2.291zm18.245 8a3.718 3.718 0 00-6.557.008h-.018l-10.713 19.372a43.637 43.637 0 0023.815 1.225q2.197-.5 4.292-1.199l-10.738-19.407zm33.914-45l-16.483 14.753.009.047a3.725 3.725 0 001.46 6.395l.02.089 21.35 6.15a44.278 44.278 0 00-6.356-27.432zM121.7 94.0385a3.725 3.725 0 005.913 2.84l.065.028 18.036-12.789a43.85 43.85 0 00-25.287-12.19l1.253 22.105zm-19.1 2.922a3.72 3.72 0 005.904-2.85l.092-.044 1.253-22.139a44.68209 44.68209 0 00-4.501.775 43.4669 43.4669 0 00-20.937 11.409l18.154 12.869zm-9.678 16.728a3.72 3.72 0 001.462-6.396l.018-.087-16.574-14.825a43.454 43.454 0 00-6.168 27.511l21.245-6.13zm16.098 6.512l6.114 2.94 6.096-2.933 1.514-6.582-4.219-5.276h-6.79l-4.231 5.268z",
className: "cls-1"
}), _react.default.createElement("path", {
d: "M216.208 133.16651l-17.422-75.675a13.60207 13.60207 0 00-7.293-9.073l-70.521-33.67a13.589 13.589 0 00-11.705 0l-70.507 33.688a13.598 13.598 0 00-7.295 9.072l-17.394 75.673a13.315 13.315 0 00-.004 5.81 13.50607 13.50607 0 00.491 1.718 13.0998 13.0998 0 001.343 2.726c.239.365.491.72.765 1.064l48.804 60.678c.213.264.448.505.681.75a13.42334 13.42334 0 002.574 2.133 13.9237 13.9237 0 003.857 1.677 13.29785 13.29785 0 003.43.473h.759l77.504-.018a12.99345 12.99345 0 001.41-.083 13.46921 13.46921 0 001.989-.378 13.872 13.872 0 001.381-.442c.353-.135.705-.27 1.045-.433a13.94127 13.94127 0 001.479-.822 13.30347 13.30347 0 003.237-2.865l1.488-1.85 47.299-58.84a13.185 13.185 0 002.108-3.785 13.67036 13.67036 0 00.5-1.724 13.28215 13.28215 0 00-.004-5.809zm-73.147 29.432a14.51575 14.51575 0 00.703 1.703 3.314 3.314 0 00-.327 2.49 39.37244 39.37244 0 003.742 6.7 35.06044 35.06044 0 012.263 3.364c.17.315.392.803.553 1.136a4.24 4.24 0 11-7.63 3.607c-.161-.33-.385-.77-.522-1.082a35.27528 35.27528 0 01-1.225-3.868 39.3046 39.3046 0 00-2.896-7.097 3.335 3.335 0 00-2.154-1.307c-.135-.233-.635-1.149-.903-1.623a54.617 54.617 0 01-38.948-.1l-.955 1.731a3.429 3.429 0 00-1.819.886 29.51728 29.51728 0 00-3.268 7.582 34.89931 34.89931 0 01-1.218 3.868c-.135.31-.361.744-.522 1.073v.009l-.007.008a4.238 4.238 0 11-7.619-3.616c.159-.335.372-.82.54-1.135a35.17706 35.17706 0 012.262-3.373 41.22786 41.22786 0 003.82-6.866 4.18792 4.18792 0 00-.376-2.387l.768-1.84a54.922 54.922 0 01-24.338-30.387l-1.839.313a4.68007 4.68007 0 00-2.428-.855 39.52352 39.52352 0 00-7.356 2.165 35.58886 35.58886 0 01-3.787 1.45c-.305.084-.745.168-1.093.244-.028.01-.052.022-.08.029a.60518.60518 0 01-.065.006 4.236 4.236 0 11-1.874-8.224l.061-.015.037-.01c.353-.083.805-.2 1.127-.262a35.27 35.27 0 014.05-.326 39.38835 39.38835 0 007.564-1.242 5.83506 5.83506 0 001.814-1.83l1.767-.516a54.613 54.613 0 018.613-38.073l-1.353-1.206a4.688 4.688 0 00-.848-2.436 39.36558 39.36558 0 00-6.277-4.41 35.2503 35.2503 0 01-3.499-2.046c-.256-.191-.596-.478-.874-.704l-.063-.044a4.473 4.473 0 01-1.038-6.222 4.066 4.066 0 013.363-1.488 5.03 5.03 0 012.942 1.11c.287.225.68.526.935.745a35.25285 35.25285 0 012.78 2.95 39.38314 39.38314 0 005.69 5.142 3.333 3.333 0 002.507.243q.754.55 1.522 1.082a54.28892 54.28892 0 0127.577-15.754 55.05181 55.05181 0 017.63-1.173l.1-1.784a4.6001 4.6001 0 001.37-2.184 39.47551 39.47551 0 00-.47-7.654 35.466 35.466 0 01-.576-4.014c-.011-.307.006-.731.01-1.081 0-.04-.01-.079-.01-.118a4.242 4.242 0 118.441-.004c0 .37.022.861.009 1.2a35.109 35.109 0 01-.579 4.013 39.53346 39.53346 0 00-.478 7.656 3.344 3.344 0 001.379 2.11c.015.305.065 1.323.102 1.884a55.309 55.309 0 0135.032 16.927l1.606-1.147a4.6901 4.6901 0 002.56-.278 39.53152 39.53152 0 005.69-5.148 35.00382 35.00382 0 012.787-2.95c.259-.222.65-.52.936-.746a4.242 4.242 0 115.258 6.598c-.283.229-.657.548-.929.75a35.09523 35.09523 0 01-3.507 2.046 39.49476 39.49476 0 00-6.277 4.41 3.337 3.337 0 00-.792 2.39c-.235.216-1.06.947-1.497 1.343a54.837 54.837 0 018.792 37.983l1.704.496a4.7449 4.7449 0 001.82 1.831 39.46448 39.46448 0 007.568 1.245 35.64041 35.64041 0 014.046.324c.355.065.868.207 1.23.29a4.236 4.236 0 11-1.878 8.223l-.061-.008c-.028-.007-.054-.022-.083-.029-.348-.076-.785-.152-1.09-.232a35.1407 35.1407 0 01-3.785-1.462 39.47672 39.47672 0 00-7.363-2.165 3.337 3.337 0 00-2.362.877q-.9-.171-1.804-.316a54.91994 54.91994 0 01-24.328 30.605z",
className: "cls-1"
}));
}
let ready = false;
exports.ready = ready;
_core.Events.eventBus.once('/tab/new', () => exports.ready = ready = true);
class CurrentContext extends _react.default.PureComponent {
constructor(props) {
super(props);
this.handler = this.reportCurrentContext.bind(this);
this.handlerForCommandComplete = this.reportCurrentContextFromCommandComplete.bind(this);
this.handlerForConfigChange = this.getCurrentContextFromChange.bind(this);
this.handlerNotCallingKubectl = this.getCurrentContextFromTab.bind(this);
/** So we don't handle events after unmounting */
this._unmounted = true;
this.state = {
currentContext: null,
allContexts: [],
options: [],
viewLevel: 'loading'
};
}
/** @return e.g. name/uuid -> name; or name:nnnn -> name */
renderName(context) {
// ibmcloud: {clustername}/{uuid}
const match1 = context.match(/^([^/]+)[/:][0-9a-z]+$/);
if (match1) {
return match1[1];
}
// openshift: {namespace}/{clusterhost}:{port}/{user}
const match2 = context.match(/^[^/]+\/([^/]+):\d+\/[^/]+$/);
if (match2) {
return match2[1];
}
// AWS: arn:aws:eks:{region}:{uuid}:cluster/{clustername}
// e.g. region us-east-1
// e.g. uuid 581274594392
const match3 = context.match(/arn:[^:]+:[^:]+:[^:]+:[^:]+:cluster\/(.*)$/);
if (match3) {
return match3[1];
}
return context;
}
get unmounted() {
return this._unmounted;
}
set unmounted(umm) {
this._unmounted = umm;
}
debounce() {
const now = Date.now();
const last = this.last;
this.last = now;
return last && now - last < 250;
}
getCurrentContextFromChange() {
return __awaiter(this, void 0, void 0, function* () {
if (this.unmounted) {
return;
}
const {
kubectl,
getAllContexts,
getCurrentDefaultContextName
} = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl'));
const tab = (0, _core.getCurrentTab)();
const defaultCurrentContext = yield getCurrentDefaultContextName(tab);
const currentContext = defaultCurrentContext;
const allContexts = this.state.allContexts.find(_ => _.metadata.name === currentContext) ? this.state.allContexts : yield getAllContexts(tab);
this.setState({
allContexts,
currentContext,
options: this.options(currentContext, allContexts, kubectl)
});
});
}
options(currentContext, allContexts, kubectl) {
return allContexts.map(context => {
const {
name
} = context.metadata;
const label = this.renderName(name);
const isSelected = name === currentContext;
return {
label,
isSelected,
description: isSelected ? strings('This is your current context') : undefined,
quietExec: true,
command: `${kubectl} config use-context ${(0, _core.encodeComponent)(name)}`
};
});
}
setNoContext() {
this.last = undefined;
this.setState({
viewLevel: 'hidden',
allContexts: [],
options: []
});
}
reportCurrentContextFromCommandComplete(evt) {
return __awaiter(this, void 0, void 0, function* () {
this.reportCurrentContext(evt.tab);
});
}
reportCurrentContext(idx) {
return __awaiter(this, void 0, void 0, function* () {
if (this.unmounted) {
return;
}
const tab = (0, _core.getTab)(typeof idx === 'string' ? undefined : idx);
if (!tab || !tab.REPL) {
if (tab && !tab.REPL) {
_core.Events.eventChannelUnsafe.once(`/tab/new/${tab.uuid}`, () => this.reportCurrentContext());
}
return;
} else if (this.debounce()) {
return;
}
try {
const {
kubectl,
getAllContexts
} = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl'));
const allContexts = yield getAllContexts(tab);
const currentContextSpec = allContexts.find(context => context.spec.isCurrent);
const currentContext = currentContextSpec && currentContextSpec.metadata.name;
if (currentContext) {
this.setState({
allContexts,
currentContext,
options: this.options(currentContext, allContexts, kubectl),
viewLevel: 'normal' // only show normally if we succeed; see https://github.com/IBM/kui/issues/3537
});
} else {
this.setNoContext();
}
} catch (err) {
console.error(err);
this.setNoContext();
}
});
}
getCurrentContextFromTab(args) {
return __awaiter(this, void 0, void 0, function* () {
const {
tab
} = args;
if (tab) {
const {
kubectl,
getTabState
} = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl'));
const currentContext = getTabState(tab, 'context');
if (currentContext) {
this.setState(curState => ({
currentContext,
options: this.options(currentContext, curState.allContexts, kubectl),
viewLevel: 'normal'
}));
}
}
});
}
/** @return UI for listing full context table */
listContext() {
return _react.default.createElement("a", {
href: "#",
onClick: () => (0, _core.pexecInCurrentTab)('contexts')
}, strings('Show Full Details'));
}
/** @return the header for the Popover component */
popoverHeader() {
return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("div", null, strings('Kubernetes Context')), _react.default.createElement("div", {
className: "do-not-overflow"
}, _react.default.createElement("strong", null, this.renderName(this.state.currentContext))), _react.default.createElement("div", {
className: "sub-text even-smaller-text"
}, this.listContext()));
}
switchContext() {
if (this.state.allContexts.length === 0) {
return;
}
return _react.default.createElement(_react.default.Suspense, {
fallback: _react.default.createElement("div", null)
}, _react.default.createElement(_Select.default, {
isOpen: true,
isClosable: false,
maxHeight: "15rem",
variant: "typeahead",
options: this.state.options,
selected: this.state.currentContext,
key: this.state.currentContext /* pf 4.152.4 regression? "This is the current" does not show on change */
}));
}
/** @return the body for the Popover component */
popoverBody() {
return _react.default.createElement("div", {
className: "top-pad bottom-pad"
}, this.switchContext());
}
/** @return desired Popover model */
popover() {
return {
className: 'kui--popover-select',
bodyContent: this.popoverBody(),
headerContent: this.popoverHeader()
};
}
setLoadingMessage() {
setTimeout(() => {
if (!this.unmounted) {
this.setState(curState => {
if (curState.currentContext === null) {
return {
currentContext: strings('Loading...')
};
} else {
return null;
}
});
}
}, 2000);
}
/**
* Once we have mounted, we immediately check the current branch,
* and schedule an update based on standard REPL events.
*
*/
componentDidMount() {
this.unmounted = false;
this.setLoadingMessage();
if (!ready) {
_core.Events.eventBus.once('/tab/new', this.handler);
} else {
this.handler();
}
_core.Events.eventBus.on('/tab/switch/request/done', this.handlerNotCallingKubectl);
_core.Events.eventBus.onAnyCommandComplete(this.handlerForCommandComplete);
Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')).then(_ => _.onKubectlConfigChangeEvents(this.handlerForConfigChange));
}
/** Bye! */
componentWillUnmount() {
this.unmounted = true;
_core.Events.eventBus.off('/tab/new', this.handler);
_core.Events.eventBus.off('/tab/switch/request/done', this.handlerNotCallingKubectl);
_core.Events.eventBus.offAnyCommandComplete(this.handlerForCommandComplete);
Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')).then(_ => _.offKubectlConfigChangeEvents(this.handlerForConfigChange));
}
render() {
return this.state.currentContext === null ? _react.default.createElement(_react.default.Fragment, null) : _react.default.createElement(_TextWithIconWidget.default, Object.assign({
className: this.props.className,
text: this.state.currentContext,
viewLevel: this.state.viewLevel,
id: "kui--plugin-kubeui--current-context",
title: strings('Kubernetes context')
}, this.props, {
popover: this.popover()
}), _react.default.createElement(KubernetesIcon, null));
}
}
exports.default = CurrentContext;